diff options
Diffstat (limited to 'src/boot/efi/boot.c')
-rw-r--r-- | src/boot/efi/boot.c | 448 |
1 files changed, 239 insertions, 209 deletions
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 06331da2d4..2f014446be 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -1,17 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * Copyright (C) 2012-2015 Kay Sievers <kay@vrfy.org> - * Copyright (C) 2012-2015 Harald Hoyer <harald@redhat.com> + * Copyright © 2012-2015 Harald Hoyer <harald@redhat.com> */ #include <efi.h> @@ -68,7 +57,11 @@ typedef struct { CHAR16 *entry_default_pattern; CHAR16 *entry_oneshot; CHAR16 *options_edit; - BOOLEAN no_editor; + BOOLEAN editor; + BOOLEAN auto_entries; + BOOLEAN auto_firmware; + UINTN console_mode; + enum console_mode_change_type console_mode_change; } Config; static VOID cursor_left(UINTN *cursor, UINTN *first) { @@ -86,15 +79,9 @@ static VOID cursor_right(UINTN *cursor, UINTN *first, UINTN x_max, UINTN len) { } static BOOLEAN line_edit(CHAR16 *line_in, CHAR16 **line_out, UINTN x_max, UINTN y_pos) { - CHAR16 *line; - UINTN size; - UINTN len; - UINTN first; - CHAR16 *print; - UINTN cursor; - UINTN clear; - BOOLEAN exit; - BOOLEAN enter; + _cleanup_freepool_ CHAR16 *line = NULL, *print = NULL; + UINTN size, len, first, cursor, clear; + BOOLEAN exit, enter; if (!line_in) line_in = L""; @@ -322,8 +309,6 @@ static BOOLEAN line_edit(CHAR16 *line_in, CHAR16 **line_out, UINTN x_max, UINTN } uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, FALSE); - FreePool(print); - FreePool(line); return enter; } @@ -356,11 +341,9 @@ static UINTN entry_lookup_key(Config *config, UINTN start, CHAR16 key) { static VOID print_status(Config *config, CHAR16 *loaded_image_path) { UINT64 key; UINTN i; - CHAR16 *s; - CHAR8 *b; - UINTN x; - UINTN y; - UINTN size; + _cleanup_freepool_ CHAR8 *bootvar = NULL, *modevar = NULL, *indvar = NULL; + _cleanup_freepool_ CHAR16 *partstr = NULL, *defaultstr = NULL; + UINTN x, y, size; uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK); uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); @@ -375,24 +358,20 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) { if (uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &x, &y) == EFI_SUCCESS) Print(L"console size: %d x %d\n", x, y); - if (efivar_get_raw(&global_guid, L"SecureBoot", &b, &size) == EFI_SUCCESS) { - Print(L"SecureBoot: %s\n", yes_no(*b > 0)); - FreePool(b); - } + if (efivar_get_raw(&global_guid, L"SecureBoot", &bootvar, &size) == EFI_SUCCESS) + Print(L"SecureBoot: %s\n", yes_no(*bootvar > 0)); - if (efivar_get_raw(&global_guid, L"SetupMode", &b, &size) == EFI_SUCCESS) { - Print(L"SetupMode: %s\n", *b > 0 ? L"setup" : L"user"); - FreePool(b); - } + if (efivar_get_raw(&global_guid, L"SetupMode", &modevar, &size) == EFI_SUCCESS) + Print(L"SetupMode: %s\n", *modevar > 0 ? L"setup" : L"user"); if (shim_loaded()) Print(L"Shim: present\n"); - if (efivar_get_raw(&global_guid, L"OsIndicationsSupported", &b, &size) == EFI_SUCCESS) { - Print(L"OsIndicationsSupported: %d\n", (UINT64)*b); - FreePool(b); - } - Print(L"\n"); + if (efivar_get_raw(&global_guid, L"OsIndicationsSupported", &indvar, &size) == EFI_SUCCESS) + Print(L"OsIndicationsSupported: %d\n", (UINT64)*indvar); + + Print(L"\n--- press key ---\n\n"); + console_key_read(&key, TRUE); Print(L"timeout: %d\n", config->timeout_sec); if (config->timeout_sec_efivar >= 0) @@ -400,7 +379,9 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) { Print(L"timeout (config): %d\n", config->timeout_sec_config); if (config->entry_default_pattern) Print(L"default pattern: '%s'\n", config->entry_default_pattern); - Print(L"editor: %s\n", yes_no(!config->no_editor)); + Print(L"editor: %s\n", yes_no(config->editor)); + Print(L"auto-entries: %s\n", yes_no(config->auto_entries)); + Print(L"auto-firmware: %s\n", yes_no(config->auto_firmware)); Print(L"\n"); Print(L"config entry count: %d\n", config->entry_count); @@ -413,14 +394,10 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) { Print(L"LoaderConfigTimeout: %d\n", i); if (config->entry_oneshot) Print(L"LoaderEntryOneShot: %s\n", config->entry_oneshot); - if (efivar_get(L"LoaderDevicePartUUID", &s) == EFI_SUCCESS) { - Print(L"LoaderDevicePartUUID: %s\n", s); - FreePool(s); - } - if (efivar_get(L"LoaderEntryDefault", &s) == EFI_SUCCESS) { - Print(L"LoaderEntryDefault: %s\n", s); - FreePool(s); - } + if (efivar_get(L"LoaderDevicePartUUID", &partstr) == EFI_SUCCESS) + Print(L"LoaderDevicePartUUID: %s\n", partstr); + if (efivar_get(L"LoaderEntryDefault", &defaultstr) == EFI_SUCCESS) + Print(L"LoaderEntryDefault: %s\n", defaultstr); Print(L"\n--- press key ---\n\n"); console_key_read(&key, TRUE); @@ -444,13 +421,13 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) { Print(L"machine-id '%s'\n", entry->machine_id); if (entry->device) { EFI_DEVICE_PATH *device_path; - CHAR16 *str; device_path = DevicePathFromHandle(entry->device); if (device_path) { + _cleanup_freepool_ CHAR16 *str; + str = DevicePathToStr(device_path); Print(L"device handle '%s'\n", str); - FreePool(str); } } if (entry->loader) @@ -491,6 +468,7 @@ static BOOLEAN menu_run(Config *config, ConfigEntry **chosen_entry, CHAR16 *load BOOLEAN exit = FALSE; BOOLEAN run = TRUE; BOOLEAN wait = FALSE; + BOOLEAN cleared_screen = FALSE; graphics_mode(FALSE); uefi_call_wrapper(ST->ConIn->Reset, 2, ST->ConIn, FALSE); @@ -499,7 +477,18 @@ static BOOLEAN menu_run(Config *config, ConfigEntry **chosen_entry, CHAR16 *load /* draw a single character to make ClearScreen work on some firmware */ uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, L" "); - uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); + + if (config->console_mode_change != CONSOLE_MODE_KEEP) { + err = console_set_mode(&config->console_mode, config->console_mode_change); + if (!EFI_ERROR(err)) + cleared_screen = TRUE; + } + + if (!cleared_screen) + uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); + + if (config->console_mode_change != CONSOLE_MODE_KEEP && EFI_ERROR(err)) + Print(L"Error switching console mode to %ld: %r.\r", (UINT64)config->console_mode, err); err = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &x_max, &y_max); if (EFI_ERROR(err)) { @@ -774,7 +763,7 @@ static BOOLEAN menu_run(Config *config, ConfigEntry **chosen_entry, CHAR16 *load case KEYPRESS(0, 0, 'e'): /* only the options of configured entries can be edited */ - if (config->no_editor || config->entries[idx_highlight]->type == LOADER_UNDEFINED) + if (!config->editor || config->entries[idx_highlight]->type == LOADER_UNDEFINED) break; uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK); uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_max-1); @@ -985,12 +974,11 @@ static VOID config_defaults_load_from_file(Config *config, CHAR8 *content) { line = content; while ((line = line_get_key_value(content, (CHAR8 *)" \t", &pos, &key, &value))) { if (strcmpa((CHAR8 *)"timeout", key) == 0) { - CHAR16 *s; + _cleanup_freepool_ CHAR16 *s = NULL; s = stra_to_str(value); config->timeout_sec_config = Atoi(s); config->timeout_sec = config->timeout_sec_config; - FreePool(s); continue; } @@ -1006,7 +994,41 @@ static VOID config_defaults_load_from_file(Config *config, CHAR8 *content) { if (EFI_ERROR(parse_boolean(value, &on))) continue; - config->no_editor = !on; + config->editor = on; + } + + if (strcmpa((CHAR8 *)"auto-entries", key) == 0) { + BOOLEAN on; + + if (EFI_ERROR(parse_boolean(value, &on))) + continue; + config->auto_entries = on; + } + + if (strcmpa((CHAR8 *)"auto-firmware", key) == 0) { + BOOLEAN on; + + if (EFI_ERROR(parse_boolean(value, &on))) + continue; + config->auto_firmware = on; + } + + if (strcmpa((CHAR8 *)"console-mode", key) == 0) { + if (strcmpa((CHAR8 *)"auto", value) == 0) + config->console_mode_change = CONSOLE_MODE_AUTO; + else if (strcmpa((CHAR8 *)"max", value) == 0) + config->console_mode_change = CONSOLE_MODE_MAX; + else if (strcmpa((CHAR8 *)"keep", value) == 0) + config->console_mode_change = CONSOLE_MODE_KEEP; + else { + _cleanup_freepool_ CHAR16 *s = NULL; + + s = stra_to_str(value); + config->console_mode = Atoi(s); + config->console_mode_change = CONSOLE_MODE_SET; + } + + continue; } } } @@ -1017,7 +1039,7 @@ static VOID config_entry_add_from_file(Config *config, EFI_HANDLE *device, CHAR1 UINTN pos = 0; CHAR8 *key, *value; UINTN len; - CHAR16 *initrd = NULL; + _cleanup_freepool_ CHAR16 *initrd = NULL; entry = AllocateZeroPool(sizeof(ConfigEntry)); @@ -1072,7 +1094,7 @@ static VOID config_entry_add_from_file(Config *config, EFI_HANDLE *device, CHAR1 } if (strcmpa((CHAR8 *)"initrd", key) == 0) { - CHAR16 *new; + _cleanup_freepool_ CHAR16 *new = NULL; new = stra_to_path(value); if (initrd) { @@ -1083,12 +1105,12 @@ static VOID config_entry_add_from_file(Config *config, EFI_HANDLE *device, CHAR1 initrd = s; } else initrd = PoolPrint(L"initrd=%s", new); - FreePool(new); + continue; } if (strcmpa((CHAR8 *)"options", key) == 0) { - CHAR16 *new; + _cleanup_freepool_ CHAR16 *new = NULL; new = stra_to_str(value); if (entry->options) { @@ -1101,14 +1123,13 @@ static VOID config_entry_add_from_file(Config *config, EFI_HANDLE *device, CHAR1 entry->options = new; new = NULL; } - FreePool(new); + continue; } } if (entry->type == LOADER_UNDEFINED) { config_entry_free(entry); - FreePool(initrd); FreePool(entry); return; } @@ -1126,7 +1147,6 @@ static VOID config_entry_add_from_file(Config *config, EFI_HANDLE *device, CHAR1 initrd = NULL; } } - FreePool(initrd); entry->device = device; entry->file = StrDuplicate(file); @@ -1140,15 +1160,17 @@ static VOID config_entry_add_from_file(Config *config, EFI_HANDLE *device, CHAR1 } static VOID config_load_defaults(Config *config, EFI_FILE *root_dir) { - CHAR8 *content = NULL; + _cleanup_freepool_ CHAR8 *content = NULL; UINTN sec; - UINTN len; EFI_STATUS err; - len = file_read(root_dir, L"\\loader\\loader.conf", 0, 0, &content); - if (len > 0) + config->editor = TRUE; + config->auto_entries = TRUE; + config->auto_firmware = TRUE; + + err = file_read(root_dir, L"\\loader\\loader.conf", 0, 0, &content, NULL); + if (!EFI_ERROR(err)) config_defaults_load_from_file(config, content); - FreePool(content); err = efivar_get_int(L"LoaderConfigTimeout", &sec); if (!EFI_ERROR(err)) { @@ -1168,7 +1190,7 @@ static VOID config_load_entries(Config *config, EFI_HANDLE *device, EFI_FILE *ro CHAR16 buf[256]; UINTN bufsize; EFI_FILE_INFO *f; - CHAR8 *content = NULL; + _cleanup_freepool_ CHAR8 *content = NULL; UINTN len; bufsize = sizeof(buf); @@ -1190,10 +1212,9 @@ static VOID config_load_entries(Config *config, EFI_HANDLE *device, EFI_FILE *ro if (StrnCmp(f->FileName, L"auto-", 5) == 0) continue; - len = file_read(entries_dir, f->FileName, 0, 0, &content); - if (len > 0) + err = file_read(entries_dir, f->FileName, 0, 0, &content, NULL); + if (!EFI_ERROR(err)) config_entry_add_from_file(config, device, f->FileName, content, loaded_image_path); - FreePool(content); } uefi_call_wrapper(entries_dir->Close, 1, entries_dir); } @@ -1223,7 +1244,7 @@ static VOID config_sort_entries(Config *config) { } static VOID config_default_entry_select(Config *config) { - CHAR16 *var; + _cleanup_freepool_ CHAR16 *entry_oneshot = NULL, *entry_default = NULL; EFI_STATUS err; UINTN i; @@ -1231,21 +1252,19 @@ static VOID config_default_entry_select(Config *config) { * The EFI variable to specify a boot entry for the next, and only the * next reboot. The variable is always cleared directly after it is read. */ - err = efivar_get(L"LoaderEntryOneShot", &var); + err = efivar_get(L"LoaderEntryOneShot", &entry_oneshot); if (!EFI_ERROR(err)) { BOOLEAN found = FALSE; - for (i = 0; i < config->entry_count; i++) { - if (StrCmp(config->entries[i]->file, var) == 0) { + for (i = 0; i < config->entry_count; i++) + if (StrCmp(config->entries[i]->file, entry_oneshot) == 0) { config->idx_default = i; found = TRUE; break; } - } - config->entry_oneshot = StrDuplicate(var); + config->entry_oneshot = StrDuplicate(entry_oneshot); efivar_set(L"LoaderEntryOneShot", NULL, TRUE); - FreePool(var); if (found) return; } @@ -1256,21 +1275,14 @@ static VOID config_default_entry_select(Config *config) { * the 'd' key in the loader selection menu, the entry is marked with * an '*'. */ - err = efivar_get(L"LoaderEntryDefault", &var); + err = efivar_get(L"LoaderEntryDefault", &entry_default); if (!EFI_ERROR(err)) { - BOOLEAN found = FALSE; - - for (i = 0; i < config->entry_count; i++) { - if (StrCmp(config->entries[i]->file, var) == 0) { + for (i = 0; i < config->entry_count; i++) + if (StrCmp(config->entries[i]->file, entry_default) == 0) { config->idx_default = i; config->idx_default_efivar = i; - found = TRUE; - break; + return; } - } - FreePool(var); - if (found) - return; } config->idx_default_efivar = -1; @@ -1364,7 +1376,7 @@ static VOID config_title_generate(Config *config) { /* add machine-id to non-unique titles */ for (i = 0; i < config->entry_count; i++) { CHAR16 *s; - CHAR16 *m; + _cleanup_freepool_ CHAR16 *m = NULL; if (!config->entries[i]->non_unique) continue; @@ -1376,7 +1388,6 @@ static VOID config_title_generate(Config *config) { s = PoolPrint(L"%s (%s)", config->entries[i]->title_show, m); FreePool(config->entries[i]->title_show); config->entries[i]->title_show = s; - FreePool(m); } if (!find_nonunique(config->entries, config->entry_count)) @@ -1429,10 +1440,29 @@ static BOOLEAN config_entry_add_loader_auto(Config *config, EFI_HANDLE *device, ConfigEntry *entry; EFI_STATUS err; - /* do not add an entry for ourselves */ - if (loaded_image_path && StriCmp(loader, loaded_image_path) == 0) + if (!config->auto_entries) return FALSE; + /* do not add an entry for ourselves */ + if (loaded_image_path) { + UINTN len; + _cleanup_freepool_ CHAR8 *content = NULL; + + if (StriCmp(loader, loaded_image_path) == 0) + return FALSE; + + /* look for systemd-boot magic string */ + err = file_read(root_dir, loader, 0, 100*1024, &content, &len); + if (!EFI_ERROR(err)) { + CHAR8 *start = content; + CHAR8 *last = content + len - sizeof(magic) - 1; + + for (; start <= last; start++) + if (start[0] == magic[0] && CompareMem(start, magic, sizeof(magic) - 1) == 0) + return FALSE; + } + } + /* check existence */ err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &handle, loader, EFI_FILE_MODE_READ, 0ULL); if (EFI_ERROR(err)) @@ -1452,7 +1482,10 @@ static BOOLEAN config_entry_add_loader_auto(Config *config, EFI_HANDLE *device, static VOID config_entry_add_osx(Config *config) { EFI_STATUS err; UINTN handle_count = 0; - EFI_HANDLE *handles = NULL; + _cleanup_freepool_ EFI_HANDLE *handles = NULL; + + if (!config->auto_entries) + return; err = LibLocateHandle(ByProtocol, &FileSystemProtocol, NULL, &handle_count, &handles); if (!EFI_ERROR(err)) { @@ -1471,128 +1504,128 @@ static VOID config_entry_add_osx(Config *config) { if (found) break; } - - FreePool(handles); } } -static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_image, EFI_FILE *root_dir) { +static VOID config_entry_add_linux(Config *config, EFI_LOADED_IMAGE *loaded_image, EFI_FILE *root_dir) { EFI_FILE_HANDLE linux_dir; EFI_STATUS err; ConfigEntry *entry; err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &linux_dir, L"\\EFI\\Linux", EFI_FILE_MODE_READ, 0ULL); - if (!EFI_ERROR(err)) { - for (;;) { - CHAR16 buf[256]; - UINTN bufsize; - EFI_FILE_INFO *f; - CHAR8 *sections[] = { - (UINT8 *)".osrel", - (UINT8 *)".cmdline", - NULL - }; - UINTN offs[ELEMENTSOF(sections)-1] = {}; - UINTN szs[ELEMENTSOF(sections)-1] = {}; - UINTN addrs[ELEMENTSOF(sections)-1] = {}; - CHAR8 *content = NULL; - UINTN len; - CHAR8 *line; - UINTN pos = 0; - CHAR8 *key, *value; - CHAR16 *os_name = NULL; - CHAR16 *os_id = NULL; - CHAR16 *os_version = NULL; - CHAR16 *os_build = NULL; - - bufsize = sizeof(buf); - err = uefi_call_wrapper(linux_dir->Read, 3, linux_dir, &bufsize, buf); - if (bufsize == 0 || EFI_ERROR(err)) - break; + if (EFI_ERROR(err)) + return; - f = (EFI_FILE_INFO *) buf; - if (f->FileName[0] == '.') - continue; - if (f->Attribute & EFI_FILE_DIRECTORY) - continue; - len = StrLen(f->FileName); - if (len < 5) - continue; - if (StriCmp(f->FileName + len - 4, L".efi") != 0) - continue; + for (;;) { + CHAR16 buf[256]; + UINTN bufsize = sizeof buf; + EFI_FILE_INFO *f; + CHAR8 *sections[] = { + (UINT8 *)".osrel", + (UINT8 *)".cmdline", + NULL + }; + UINTN offs[ELEMENTSOF(sections)-1] = {}; + UINTN szs[ELEMENTSOF(sections)-1] = {}; + UINTN addrs[ELEMENTSOF(sections)-1] = {}; + CHAR8 *content = NULL; + UINTN len; + CHAR8 *line; + UINTN pos = 0; + CHAR8 *key, *value; + CHAR16 *os_name = NULL; + CHAR16 *os_id = NULL; + CHAR16 *os_version = NULL; + CHAR16 *os_build = NULL; + + err = uefi_call_wrapper(linux_dir->Read, 3, linux_dir, &bufsize, buf); + if (bufsize == 0 || EFI_ERROR(err)) + break; - /* look for .osrel and .cmdline sections in the .efi binary */ - err = pe_file_locate_sections(linux_dir, f->FileName, sections, addrs, offs, szs); - if (EFI_ERROR(err)) - continue; + f = (EFI_FILE_INFO *) buf; + if (f->FileName[0] == '.') + continue; + if (f->Attribute & EFI_FILE_DIRECTORY) + continue; + len = StrLen(f->FileName); + if (len < 5) + continue; + if (StriCmp(f->FileName + len - 4, L".efi") != 0) + continue; - len = file_read(linux_dir, f->FileName, offs[0], szs[0], &content); - if (len <= 0) - continue; + /* look for .osrel and .cmdline sections in the .efi binary */ + err = pe_file_locate_sections(linux_dir, f->FileName, sections, addrs, offs, szs); + if (EFI_ERROR(err)) + continue; - /* read properties from the embedded os-release file */ - line = content; - while ((line = line_get_key_value(content, (CHAR8 *)"=", &pos, &key, &value))) { - if (strcmpa((CHAR8 *)"PRETTY_NAME", key) == 0) { - FreePool(os_name); - os_name = stra_to_str(value); - continue; - } + err = file_read(linux_dir, f->FileName, offs[0], szs[0], &content, NULL); + if (EFI_ERROR(err)) + continue; - if (strcmpa((CHAR8 *)"ID", key) == 0) { - FreePool(os_id); - os_id = stra_to_str(value); - continue; - } + /* read properties from the embedded os-release file */ + line = content; + while ((line = line_get_key_value(content, (CHAR8 *)"=", &pos, &key, &value))) { + if (strcmpa((CHAR8 *)"PRETTY_NAME", key) == 0) { + FreePool(os_name); + os_name = stra_to_str(value); + continue; + } - if (strcmpa((CHAR8 *)"VERSION_ID", key) == 0) { - FreePool(os_version); - os_version = stra_to_str(value); - continue; - } + if (strcmpa((CHAR8 *)"ID", key) == 0) { + FreePool(os_id); + os_id = stra_to_str(value); + continue; + } - if (strcmpa((CHAR8 *)"BUILD_ID", key) == 0) { - FreePool(os_build); - os_build = stra_to_str(value); - continue; - } + if (strcmpa((CHAR8 *)"VERSION_ID", key) == 0) { + FreePool(os_version); + os_version = stra_to_str(value); + continue; } - if (os_name && os_id && (os_version || os_build)) { - CHAR16 *conf; - CHAR16 *path; - CHAR16 *cmdline; - - conf = PoolPrint(L"%s-%s", os_id, os_version ? : os_build); - path = PoolPrint(L"\\EFI\\Linux\\%s", f->FileName); - entry = config_entry_add_loader(config, loaded_image->DeviceHandle, LOADER_LINUX, conf, 'l', os_name, path); - - FreePool(content); - /* read the embedded cmdline file */ - len = file_read(linux_dir, f->FileName, offs[1], szs[1] - 1 , &content); - if (len > 0) { - cmdline = stra_to_str(content); - entry->options = cmdline; - cmdline = NULL; - } - FreePool(cmdline); - FreePool(conf); - FreePool(path); + if (strcmpa((CHAR8 *)"BUILD_ID", key) == 0) { + FreePool(os_build); + os_build = stra_to_str(value); + continue; } + } + + if (os_name && os_id && (os_version || os_build)) { + CHAR16 *conf; + CHAR16 *path; + CHAR16 *cmdline; + + conf = PoolPrint(L"%s-%s", os_id, os_version ? : os_build); + path = PoolPrint(L"\\EFI\\Linux\\%s", f->FileName); + entry = config_entry_add_loader(config, loaded_image->DeviceHandle, LOADER_LINUX, conf, 'l', os_name, path); - FreePool(os_name); - FreePool(os_id); - FreePool(os_version); - FreePool(os_build); FreePool(content); + content = NULL; + /* read the embedded cmdline file */ + err = file_read(linux_dir, f->FileName, offs[1], szs[1] - 1, &content, NULL); + if (!EFI_ERROR(err)) { + cmdline = stra_to_str(content); + entry->options = cmdline; + cmdline = NULL; + } + FreePool(cmdline); + FreePool(conf); + FreePool(path); } - uefi_call_wrapper(linux_dir->Close, 1, linux_dir); + + FreePool(os_name); + FreePool(os_id); + FreePool(os_version); + FreePool(os_build); + FreePool(content); } + + uefi_call_wrapper(linux_dir->Close, 1, linux_dir); } static EFI_STATUS image_start(EFI_HANDLE parent_image, const Config *config, const ConfigEntry *entry) { EFI_HANDLE image; - EFI_DEVICE_PATH *path; + _cleanup_freepool_ EFI_DEVICE_PATH *path = NULL; CHAR16 *options; EFI_STATUS err; @@ -1607,7 +1640,7 @@ static EFI_STATUS image_start(EFI_HANDLE parent_image, const Config *config, con if (EFI_ERROR(err)) { Print(L"Error loading %s: %r", entry->loader, err); uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000); - goto out; + return err; } if (config->options_edit) @@ -1632,7 +1665,7 @@ static EFI_STATUS image_start(EFI_HANDLE parent_image, const Config *config, con #if ENABLE_TPM /* Try to log any options to the TPM, especially to catch manually edited options */ err = tpm_log_event(SD_TPM_PCR, - (EFI_PHYSICAL_ADDRESS) loaded_image->LoadOptions, + (EFI_PHYSICAL_ADDRESS) (UINTN) loaded_image->LoadOptions, loaded_image->LoadOptionsSize, loaded_image->LoadOptions); if (EFI_ERROR(err)) { Print(L"Unable to add image options measurement: %r", err); @@ -1645,13 +1678,11 @@ static EFI_STATUS image_start(EFI_HANDLE parent_image, const Config *config, con err = uefi_call_wrapper(BS->StartImage, 3, image, NULL, NULL); out_unload: uefi_call_wrapper(BS->UnloadImage, 1, image); -out: - FreePool(path); return err; } static EFI_STATUS reboot_into_firmware(VOID) { - CHAR8 *b; + _cleanup_freepool_ CHAR8 *b = NULL; UINTN size; UINT64 osind; EFI_STATUS err; @@ -1661,7 +1692,6 @@ static EFI_STATUS reboot_into_firmware(VOID) { err = efivar_get_raw(&global_guid, L"OsIndications", &b, &size); if (!EFI_ERROR(err)) osind |= (UINT64)*b; - FreePool(b); err = efivar_set_raw(&global_guid, L"OsIndications", (CHAR8 *)&osind, sizeof(UINT64), TRUE); if (EFI_ERROR(err)) @@ -1685,7 +1715,7 @@ static VOID config_free(Config *config) { } EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { - CHAR16 *s; + _cleanup_freepool_ CHAR16 *infostr = NULL, *typestr = NULL; CHAR8 *b; UINTN size; EFI_LOADED_IMAGE *loaded_image; @@ -1701,12 +1731,12 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { init_usec = time_usec(); efivar_set_time_usec(L"LoaderTimeInitUSec", init_usec); efivar_set(L"LoaderInfo", L"systemd-boot " PACKAGE_VERSION, FALSE); - s = PoolPrint(L"%s %d.%02d", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); - efivar_set(L"LoaderFirmwareInfo", s, FALSE); - FreePool(s); - s = PoolPrint(L"UEFI %d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff); - efivar_set(L"LoaderFirmwareType", s, FALSE); - FreePool(s); + + infostr = PoolPrint(L"%s %d.%02d", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); + efivar_set(L"LoaderFirmwareInfo", infostr, FALSE); + + typestr = PoolPrint(L"UEFI %d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff); + efivar_set(L"LoaderFirmwareType", typestr, FALSE); err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); @@ -1753,15 +1783,15 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { config_sort_entries(&config); /* if we find some well-known loaders, add them to the end of the list */ - config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path, + config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, NULL, L"auto-windows", 'w', L"Windows Boot Manager", L"\\EFI\\Microsoft\\Boot\\bootmgfw.efi"); - config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path, + config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, NULL, L"auto-efi-shell", 's', L"EFI Shell", L"\\shell" EFI_MACHINE_TYPE_NAME ".efi"); config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path, L"auto-efi-default", '\0', L"EFI Default Loader", L"\\EFI\\Boot\\boot" EFI_MACHINE_TYPE_NAME ".efi"); config_entry_add_osx(&config); - if (efivar_get_raw(&global_guid, L"OsIndicationsSupported", &b, &size) == EFI_SUCCESS) { + if (config.auto_firmware && efivar_get_raw(&global_guid, L"OsIndicationsSupported", &b, &size) == EFI_SUCCESS) { UINT64 osind = (UINT64)*b; if (osind & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) |