diff options
Diffstat (limited to 'src/boot/efi/boot.c')
-rw-r--r-- | src/boot/efi/boot.c | 108 |
1 files changed, 60 insertions, 48 deletions
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 827c11844c..30c1ead1aa 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /* * 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 @@ -18,11 +16,13 @@ #include <efi.h> #include <efilib.h> -#include "util.h" #include "console.h" +#include "disk.h" #include "graphics.h" -#include "pefile.h" #include "linux.h" +#include "pefile.h" +#include "util.h" +#include "measure.h" #ifndef EFI_OS_INDICATIONS_BOOT_TO_FW_UI #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001ULL @@ -69,16 +69,14 @@ typedef struct { BOOLEAN no_editor; } Config; -static VOID cursor_left(UINTN *cursor, UINTN *first) -{ +static VOID cursor_left(UINTN *cursor, UINTN *first) { if ((*cursor) > 0) (*cursor)--; else if ((*first) > 0) (*first)--; } -static VOID cursor_right(UINTN *cursor, UINTN *first, UINTN x_max, UINTN len) -{ +static VOID cursor_right(UINTN *cursor, UINTN *first, UINTN x_max, UINTN len) { if ((*cursor)+1 < x_max) (*cursor)++; else if ((*first) + (*cursor) < len) @@ -855,13 +853,11 @@ static VOID config_entry_free(ConfigEntry *entry) { FreePool(entry->options); } -static BOOLEAN is_digit(CHAR16 c) -{ +static BOOLEAN is_digit(CHAR16 c) { return (c >= '0') && (c <= '9'); } -static UINTN c_order(CHAR16 c) -{ +static UINTN c_order(CHAR16 c) { if (c == '\0') return 0; if (is_digit(c)) @@ -872,8 +868,7 @@ static UINTN c_order(CHAR16 c) return c + 0x10000; } -static INTN str_verscmp(CHAR16 *s1, CHAR16 *s2) -{ +static INTN str_verscmp(CHAR16 *s1, CHAR16 *s2) { CHAR16 *os1 = s1; CHAR16 *os2 = s2; @@ -1139,13 +1134,11 @@ static VOID config_entry_add_from_file(Config *config, EFI_HANDLE *device, CHAR1 config_add_entry(config, entry); } -static VOID config_load(Config *config, EFI_HANDLE *device, EFI_FILE *root_dir, CHAR16 *loaded_image_path) { - EFI_FILE_HANDLE entries_dir; - EFI_STATUS err; +static VOID config_load_defaults(Config *config, EFI_FILE *root_dir) { CHAR8 *content = NULL; UINTN sec; UINTN len; - UINTN i; + EFI_STATUS err; len = file_read(root_dir, L"\\loader\\loader.conf", 0, 0, &content); if (len > 0) @@ -1158,6 +1151,11 @@ static VOID config_load(Config *config, EFI_HANDLE *device, EFI_FILE *root_dir, config->timeout_sec = sec; } else config->timeout_sec_efivar = -1; +} + +static VOID config_load_entries(Config *config, EFI_HANDLE *device, EFI_FILE *root_dir, CHAR16 *loaded_image_path) { + EFI_FILE_HANDLE entries_dir; + EFI_STATUS err; err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &entries_dir, L"\\loader\\entries", EFI_FILE_MODE_READ, 0ULL); if (!EFI_ERROR(err)) { @@ -1194,8 +1192,11 @@ static VOID config_load(Config *config, EFI_HANDLE *device, EFI_FILE *root_dir, } uefi_call_wrapper(entries_dir->Close, 1, entries_dir); } +} + +static VOID config_sort_entries(Config *config) { + UINTN i; - /* sort entries after version number */ for (i = 1; i < config->entry_count; i++) { BOOLEAN more; UINTN k; @@ -1495,6 +1496,7 @@ 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) { 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)) { @@ -1504,6 +1506,7 @@ static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_ima EFI_FILE_INFO *f; CHAR8 *sections[] = { (UINT8 *)".osrel", + (UINT8 *)".cmdline", NULL }; UINTN offs[ELEMENTSOF(sections)-1] = {}; @@ -1535,7 +1538,7 @@ static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_ima if (StriCmp(f->FileName + len - 4, L".efi") != 0) continue; - /* look for an .osrel section in the .efi binary */ + /* look for .osrel and .cmdline sections in the .efi binary */ err = pefile_locate_sections(linux_dir, f->FileName, sections, addrs, offs, szs); if (EFI_ERROR(err)) continue; @@ -1575,10 +1578,21 @@ static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_ima 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); - config_entry_add_loader(config, loaded_image->DeviceHandle, LOADER_LINUX, conf, 'l', os_name, path); + 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); } @@ -1631,6 +1645,18 @@ static EFI_STATUS image_start(EFI_HANDLE parent_image, const Config *config, con } loaded_image->LoadOptions = options; loaded_image->LoadOptionsSize = (StrLen(loaded_image->LoadOptions)+1) * sizeof(CHAR16); + +#ifdef SD_BOOT_LOG_TPM + /* Try to log any options to the TPM, escpecially to catch manually edited options */ + err = tpm_log_event(SD_TPM_PCR, + (EFI_PHYSICAL_ADDRESS) loaded_image->LoadOptions, + loaded_image->LoadOptionsSize, loaded_image->LoadOptions); + if (EFI_ERROR(err)) { + Print(L"Unable to add image options measurement: %r", err); + uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000); + return err; + } +#endif } efivar_set_time_usec(L"LoaderTimeExecUSec", 0); @@ -1683,11 +1709,11 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { EFI_LOADED_IMAGE *loaded_image; EFI_FILE *root_dir; CHAR16 *loaded_image_path; - EFI_DEVICE_PATH *device_path; EFI_STATUS err; Config config; UINT64 init_usec; BOOLEAN menu = FALSE; + CHAR16 uuid[37]; InitializeLib(image, sys_table); init_usec = time_usec(); @@ -1709,29 +1735,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { } /* export the device path this image is started from */ - device_path = DevicePathFromHandle(loaded_image->DeviceHandle); - if (device_path) { - EFI_DEVICE_PATH *path, *paths; - - paths = UnpackDevicePath(device_path); - for (path = paths; !IsDevicePathEnd(path); path = NextDevicePathNode(path)) { - HARDDRIVE_DEVICE_PATH *drive; - CHAR16 uuid[37]; - - if (DevicePathType(path) != MEDIA_DEVICE_PATH) - continue; - if (DevicePathSubType(path) != MEDIA_HARDDRIVE_DP) - continue; - drive = (HARDDRIVE_DEVICE_PATH *)path; - if (drive->SignatureType != SIGNATURE_TYPE_GUID) - continue; - - GuidToString(uuid, (EFI_GUID *)&drive->Signature); - efivar_set(L"LoaderDevicePartUUID", uuid, FALSE); - break; - } - FreePool(paths); - } + if (disk_get_part_uuid(loaded_image->DeviceHandle, uuid) == EFI_SUCCESS) + efivar_set(L"LoaderDevicePartUUID", uuid, FALSE); root_dir = LibOpenRoot(loaded_image->DeviceHandle); if (!root_dir) { @@ -1745,12 +1750,19 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { loaded_image_path = DevicePathToStr(loaded_image->FilePath); efivar_set(L"LoaderImageIdentifier", loaded_image_path, FALSE); - /* scan "\loader\entries\*.conf" files */ ZeroMem(&config, sizeof(Config)); - config_load(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path); + config_load_defaults(&config, root_dir); - /* if we find some well-known loaders, add them to the end of the list */ + /* scan /EFI/Linux/ directory */ config_entry_add_linux(&config, loaded_image, root_dir); + + /* scan /loader/entries/\*.conf files */ + config_load_entries(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path); + + /* sort entries after version number */ + 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, 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, |