diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 06331da2d41..68b3e79155d 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -68,7 +68,9 @@ typedef struct { CHAR16 *entry_default_pattern; CHAR16 *entry_oneshot; CHAR16 *options_edit; - BOOLEAN no_editor; + BOOLEAN editor; + BOOLEAN auto_entries; + BOOLEAN auto_firmware; } Config; static VOID cursor_left(UINTN *cursor, UINTN *first) { @@ -392,7 +394,9 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) { Print(L"OsIndicationsSupported: %d\n", (UINT64)*b); FreePool(b); } - Print(L"\n"); + + 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 +404,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); @@ -774,7 +780,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); @@ -1006,7 +1012,23 @@ 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; } } } @@ -1142,11 +1164,14 @@ 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; 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); @@ -1190,8 +1215,8 @@ 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); } @@ -1429,10 +1454,33 @@ 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; + CHAR8 *content; + + 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) { + FreePool(content); + return FALSE; + } + + FreePool(content); + } + } + /* check existence */ err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &handle, loader, EFI_FILE_MODE_READ, 0ULL); if (EFI_ERROR(err)) @@ -1454,6 +1502,9 @@ static VOID config_entry_add_osx(Config *config) { UINTN handle_count = 0; EFI_HANDLE *handles = NULL; + if (!config->auto_entries) + return; + err = LibLocateHandle(ByProtocol, &FileSystemProtocol, NULL, &handle_count, &handles); if (!EFI_ERROR(err)) { UINTN i; @@ -1476,118 +1527,120 @@ static VOID config_entry_add_osx(Config *config) { } } -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; + if (EFI_ERROR(err)) + return; - bufsize = sizeof(buf); - err = uefi_call_wrapper(linux_dir->Read, 3, linux_dir, &bufsize, buf); - if (bufsize == 0 || EFI_ERROR(err)) - break; + 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; - f = (EFI_FILE_INFO *) buf; - if (f->FileName[0] == '.') + err = uefi_call_wrapper(linux_dir->Read, 3, linux_dir, &bufsize, buf); + if (bufsize == 0 || EFI_ERROR(err)) + break; + + 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; + + /* 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; + + err = file_read(linux_dir, f->FileName, offs[0], szs[0], &content, NULL); + 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; - 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; - - /* 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; - - len = file_read(linux_dir, f->FileName, offs[0], szs[0], &content); - if (len <= 0) - 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 *)"ID", key) == 0) { - FreePool(os_id); - os_id = 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 *)"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(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 *)"ID", key) == 0) { + FreePool(os_id); + os_id = stra_to_str(value); + continue; } - FreePool(os_name); - FreePool(os_id); - FreePool(os_version); - FreePool(os_build); - FreePool(content); + if (strcmpa((CHAR8 *)"VERSION_ID", key) == 0) { + FreePool(os_version); + os_version = stra_to_str(value); + continue; + } + + if (strcmpa((CHAR8 *)"BUILD_ID", key) == 0) { + FreePool(os_build); + os_build = stra_to_str(value); + continue; + } } - uefi_call_wrapper(linux_dir->Close, 1, linux_dir); + + 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); + 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); + } + + 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) { @@ -1753,15 +1806,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) diff --git a/src/boot/efi/shim.c b/src/boot/efi/shim.c index 6d7d814c5cc..7c479048c10 100644 --- a/src/boot/efi/shim.c +++ b/src/boot/efi/shim.c @@ -179,7 +179,10 @@ static EFIAPI EFI_STATUS security_policy_authentication (const EFI_SECURITY_PROT dev_path_str = DevicePathToStr(dev_path); FreePool(dev_path); - file_size = file_read(root, dev_path_str, 0, 0, &file_buffer); + status = file_read(root, dev_path_str, 0, 0, &file_buffer, &file_size); + if (EFI_ERROR(status)) + return status; + FreePool(dev_path_str); uefi_call_wrapper(root->Close, 1, root); diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c index b165f31005f..cd75c13f2b4 100644 --- a/src/boot/efi/util.c +++ b/src/boot/efi/util.c @@ -304,12 +304,10 @@ CHAR8 *strchra(CHAR8 *s, CHAR8 c) { return NULL; } -INTN file_read(EFI_FILE_HANDLE dir, CHAR16 *name, UINTN off, UINTN size, CHAR8 **content) { +EFI_STATUS file_read(EFI_FILE_HANDLE dir, CHAR16 *name, UINTN off, UINTN size, CHAR8 **content, UINTN *content_size) { EFI_FILE_HANDLE handle; CHAR8 *buf; - UINTN buflen; EFI_STATUS err; - UINTN len; err = uefi_call_wrapper(dir->Open, 5, dir, &handle, name, EFI_FILE_MODE_READ, 0ULL); if (EFI_ERROR(err)) @@ -319,10 +317,9 @@ INTN file_read(EFI_FILE_HANDLE dir, CHAR16 *name, UINTN off, UINTN size, CHAR8 * EFI_FILE_INFO *info; info = LibFileInfo(handle); - buflen = info->FileSize+1; + size = info->FileSize+1; FreePool(info); - } else - buflen = size; + } if (off > 0) { err = uefi_call_wrapper(handle->SetPosition, 2, handle, off); @@ -330,17 +327,16 @@ INTN file_read(EFI_FILE_HANDLE dir, CHAR16 *name, UINTN off, UINTN size, CHAR8 * return err; } - buf = AllocatePool(buflen); - err = uefi_call_wrapper(handle->Read, 3, handle, &buflen, buf); + buf = AllocatePool(size + 1); + err = uefi_call_wrapper(handle->Read, 3, handle, &size, buf); if (!EFI_ERROR(err)) { - buf[buflen] = '\0'; + buf[size] = '\0'; *content = buf; - len = buflen; - } else { - len = err; + if (content_size) + *content_size = size; + } else FreePool(buf); - } uefi_call_wrapper(handle->Close, 1, handle); - return len; + return err; } diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h index 35150aea769..49632ffcbc4 100644 --- a/src/boot/efi/util.h +++ b/src/boot/efi/util.h @@ -45,5 +45,5 @@ CHAR8 *strchra(CHAR8 *s, CHAR8 c); CHAR16 *stra_to_path(CHAR8 *stra); CHAR16 *stra_to_str(CHAR8 *stra); -INTN file_read(EFI_FILE_HANDLE dir, CHAR16 *name, UINTN off, UINTN size, CHAR8 **content); +EFI_STATUS file_read(EFI_FILE_HANDLE dir, CHAR16 *name, UINTN off, UINTN size, CHAR8 **content, UINTN *content_size); #endif diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index 0e3e17a7763..1c9ef400191 100644 --- a/src/shared/bootspec.c +++ b/src/shared/bootspec.c @@ -145,6 +145,8 @@ void boot_config_free(BootConfig *config) { free(config->default_pattern); free(config->timeout); free(config->editor); + free(config->auto_entries); + free(config->auto_firmware); free(config->entry_oneshot); free(config->entry_default); @@ -200,6 +202,10 @@ int boot_loader_read_conf(const char *path, BootConfig *config) { r = free_and_strdup(&config->timeout, p); else if (streq(field, "editor")) r = free_and_strdup(&config->editor, p); + else if (streq(buf, "auto-entries")) + r = free_and_strdup(&config->auto_entries, p); + else if (streq(buf, "auto-firmware")) + r = free_and_strdup(&config->auto_firmware, p); else { log_notice("%s:%u: Unknown line \"%s\"", path, line, field); continue; diff --git a/src/shared/bootspec.h b/src/shared/bootspec.h index d9c641bf081..fe875454b1d 100644 --- a/src/shared/bootspec.h +++ b/src/shared/bootspec.h @@ -40,6 +40,8 @@ typedef struct BootConfig { char *default_pattern; char *timeout; char *editor; + char *auto_entries; + char *auto_firmware; char *entry_oneshot; char *entry_default;