diff options
author | Steve Langasek <steve.langasek@canonical.com> | 2019-02-09 21:28:06 -0800 |
---|---|---|
committer | Steve Langasek <steve.langasek@canonical.com> | 2019-02-09 21:32:44 -0800 |
commit | ab4c731c1dd379acd3e95971af57401fb0a650a1 (patch) | |
tree | 6a26fb8d0746cbbaa6c2d4b242c73442bcc1df06 /fallback.c | |
parent | 0d63079c7da8e86104ce4bbdae2f6cb8d2ea40c6 (diff) | |
parent | 9c12130f9cd2ae11a9336813dd1f1669c0b64ad0 (diff) | |
download | efi-boot-shim-debian/15+1533136590.3beb971-1.tar.gz efi-boot-shim-debian/15+1533136590.3beb971-1.zip |
* New upstream release.debian/15+1533136590.3beb971-1
- debian/patches/second-stage-path: dropped; the default loader path now
includes an arch suffix.
- debian/patches/sbsigntool-no-pesign: dropped; no longer needed.
* Drop remaining patches that were not being applied.
* Sync packaging from Ubuntu:
- debian/copyright: Update upstream source location.
- debian/control: add a Build-Depends on libelf-dev.
- Enable arm64 build.
- debian/patches/fixup_git.patch: don't run git in clean; we're not
really in a git tree.
- debian/rules, debian/shim.install: use the upstream install target as
intended, and move files to the target directory using dh_install.
- define RELEASE and COMMIT_ID for the snapshot.
- Set ENABLE_HTTPBOOT to enable the HTTP Boot feature.
- Update dh_auto_build/dh_auto_clean/dh_auto_install for new upstream
options: set MAKELEVEL.
- Define an EFI_ARCH variable, and use that for paths to shim. This
makes it possible to build a shim for other architectures than amd64.
- Set EFIDIR=$distro for dh_auto_install; that will let files be installed
in the "right" final directories, and makes boot.csv for us.
- Set ENABLE_SHIM_CERT, to keep using ephemeral self-signed certs built
at compile-time for MokManager and fallback.
- Set ENABLE_SBSIGN, to use sbsign instead of pesign for signing fallback
and MokManager.
Diffstat (limited to 'fallback.c')
-rw-r--r-- | fallback.c | 778 |
1 files changed, 478 insertions, 300 deletions
@@ -10,11 +10,60 @@ #include <efi.h> #include <efilib.h> -#include "ucs2.h" -#include "variables.h" +#include "shim.h" EFI_LOADED_IMAGE *this_image = NULL; +int +get_fallback_verbose(void) +{ + UINT8 *data = NULL; + UINTN dataSize = 0; + EFI_STATUS efi_status; + unsigned int i; + static int state = -1; + + if (state != -1) + return state; + + efi_status = get_variable(L"FALLBACK_VERBOSE", + &data, &dataSize, SHIM_LOCK_GUID); + if (EFI_ERROR(efi_status)) { + state = 0; + return state; + } + + state = 0; + for (i = 0; i < dataSize; i++) { + if (data[i]) { + state = 1; + break; + } + } + + if (data) + FreePool(data); + return state; +} + +#define VerbosePrintUnprefixed(fmt, ...) \ + ({ \ + UINTN ret_ = 0; \ + if (get_fallback_verbose()) \ + ret_ = console_print((fmt), ##__VA_ARGS__); \ + ret_; \ + }) + +#define VerbosePrint(fmt, ...) \ + ({ UINTN line_ = __LINE__; \ + UINTN ret_ = 0; \ + if (get_fallback_verbose()) { \ + console_print(L"%a:%d: ", __func__, line_); \ + ret_ = console_print((fmt), ##__VA_ARGS__); \ + } \ + ret_; \ + }) + static EFI_STATUS FindSubDevicePath(EFI_DEVICE_PATH *In, UINT8 Type, UINT8 SubType, EFI_DEVICE_PATH **Out) @@ -23,9 +72,18 @@ FindSubDevicePath(EFI_DEVICE_PATH *In, UINT8 Type, UINT8 SubType, if (!In || !Out) return EFI_INVALID_PARAMETER; + CHAR16 *dps = DevicePathToStr(In); + VerbosePrint(L"input device path: \"%s\"\n", dps); + FreePool(dps); + for (dp = In; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp)) { if (DevicePathType(dp) == Type && DevicePathSubType(dp) == SubType) { + dps = DevicePathToStr(dp); + VerbosePrint(L"sub-path (%hhd,%hhd): \"%s\"\n", + Type, SubType, dps); + FreePool(dps); + *Out = DuplicateDevicePath(dp); if (!*Out) return EFI_OUT_OF_RESOURCES; @@ -39,31 +97,32 @@ FindSubDevicePath(EFI_DEVICE_PATH *In, UINT8 Type, UINT8 SubType, static EFI_STATUS get_file_size(EFI_FILE_HANDLE fh, UINTN *retsize) { - EFI_STATUS rc; + EFI_STATUS efi_status; void *buffer = NULL; UINTN bs = 0; - EFI_GUID finfo = EFI_FILE_INFO_ID; /* The API here is "Call it once with bs=0, it fills in bs, * then allocate a buffer and ask again to get it filled. */ - rc = uefi_call_wrapper(fh->GetInfo, 4, fh, &finfo, &bs, NULL); - if (rc == EFI_BUFFER_TOO_SMALL) { - buffer = AllocateZeroPool(bs); - if (!buffer) { - Print(L"Could not allocate memory\n"); - return EFI_OUT_OF_RESOURCES; - } - rc = uefi_call_wrapper(fh->GetInfo, 4, fh, &finfo, - &bs, buffer); + efi_status = fh->GetInfo(fh, &EFI_FILE_INFO_GUID, &bs, NULL); + if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) + return efi_status; + if (bs == 0) + return EFI_SUCCESS; + + buffer = AllocateZeroPool(bs); + if (!buffer) { + console_print(L"Could not allocate memory\n"); + return EFI_OUT_OF_RESOURCES; } + efi_status = fh->GetInfo(fh, &EFI_FILE_INFO_GUID, &bs, buffer); /* This checks *either* the error from the first GetInfo, if it isn't - * the EFI_BUFFER_TOO_SMALL we're expecting, or the second GetInfo call - * in *any* case. */ - if (EFI_ERROR(rc)) { - Print(L"Could not get file info: %d\n", rc); + * the EFI_BUFFER_TOO_SMALL we're expecting, or the second GetInfo + * call in *any* case. */ + if (EFI_ERROR(efi_status)) { + console_print(L"Could not get file info: %r\n", efi_status); if (buffer) FreePool(buffer); - return rc; + return efi_status; } EFI_FILE_INFO *fi = buffer; *retsize = fi->FileSize; @@ -75,38 +134,46 @@ EFI_STATUS read_file(EFI_FILE_HANDLE fh, CHAR16 *fullpath, CHAR16 **buffer, UINT64 *bs) { EFI_FILE_HANDLE fh2; - EFI_STATUS rc = uefi_call_wrapper(fh->Open, 5, fh, &fh2, fullpath, - EFI_FILE_READ_ONLY, 0); - if (EFI_ERROR(rc)) { - Print(L"Couldn't open \"%s\": %d\n", fullpath, rc); - return rc; + EFI_STATUS efi_status; + + efi_status = fh->Open(fh, &fh2, fullpath, EFI_FILE_READ_ONLY, 0); + if (EFI_ERROR(efi_status)) { + console_print(L"Couldn't open \"%s\": %r\n", fullpath, efi_status); + return efi_status; } UINTN len = 0; CHAR16 *b = NULL; - rc = get_file_size(fh2, &len); - if (EFI_ERROR(rc)) { - uefi_call_wrapper(fh2->Close, 1, fh2); - return rc; + efi_status = get_file_size(fh2, &len); + if (EFI_ERROR(efi_status)) { + console_print(L"Could not get file size for \"%s\": %r\n", + fullpath, efi_status); + fh2->Close(fh2); + return efi_status; + } + + if (len > 1024 * PAGE_SIZE) { + fh2->Close(fh2); + return EFI_BAD_BUFFER_SIZE; } b = AllocateZeroPool(len + 2); if (!buffer) { - Print(L"Could not allocate memory\n"); - uefi_call_wrapper(fh2->Close, 1, fh2); + console_print(L"Could not allocate memory\n"); + fh2->Close(fh2); return EFI_OUT_OF_RESOURCES; } - rc = uefi_call_wrapper(fh->Read, 3, fh, &len, b); - if (EFI_ERROR(rc)) { + efi_status = fh->Read(fh, &len, b); + if (EFI_ERROR(efi_status)) { FreePool(buffer); - uefi_call_wrapper(fh2->Close, 1, fh2); - Print(L"Could not read file: %d\n", rc); - return rc; + fh2->Close(fh2); + console_print(L"Could not read file: %r\n", efi_status); + return efi_status; } *buffer = b; *bs = len; - uefi_call_wrapper(fh2->Close, 1, fh2); + fh2->Close(fh2); return EFI_SUCCESS; } @@ -114,14 +181,14 @@ EFI_STATUS make_full_path(CHAR16 *dirname, CHAR16 *filename, CHAR16 **out, UINT64 *outlen) { UINT64 len; - + len = StrLen(L"\\EFI\\") + StrLen(dirname) + StrLen(L"\\") + StrLen(filename) + 2; CHAR16 *fullpath = AllocateZeroPool(len*sizeof(CHAR16)); if (!fullpath) { - Print(L"Could not allocate memory\n"); + console_print(L"Could not allocate memory\n"); return EFI_OUT_OF_RESOURCES; } @@ -149,8 +216,7 @@ add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp, static int i = 0; CHAR16 varname[] = L"Boot0000"; CHAR16 hexmap[] = L"0123456789ABCDEF"; - EFI_GUID global = EFI_GLOBAL_VARIABLE; - EFI_STATUS rc; + EFI_STATUS efi_status; for(; i <= 0xffff; i++) { varname[4] = hexmap[(i & 0xf000) >> 12]; @@ -158,7 +224,7 @@ add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp, varname[6] = hexmap[(i & 0x00f0) >> 4]; varname[7] = hexmap[(i & 0x000f) >> 0]; - void *var = LibGetVariable(varname, &global); + void *var = LibGetVariable(varname, &GV_GUID); if (!var) { int size = sizeof(UINT32) + sizeof (UINT16) + StrLen(label)*2 + 2 + DevicePathSize(hddp) + @@ -176,9 +242,9 @@ add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp, cursor += DevicePathSize(hddp); StrCpy((CHAR16 *)cursor, arguments); - Print(L"Creating boot entry \"%s\" with label \"%s\" " - L"for file \"%s\"\n", - varname, label, filename); + console_print(L"Creating boot entry \"%s\" with label \"%s\" " + L"for file \"%s\"\n", + varname, label, filename); if (!first_new_option) { first_new_option = DuplicateDevicePath(fulldp); @@ -186,17 +252,18 @@ add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp, first_new_option_size = StrLen(arguments) * sizeof (CHAR16); } - rc = uefi_call_wrapper(RT->SetVariable, 5, varname, - &global, EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS, - size, data); + efi_status = gRT->SetVariable(varname, &GV_GUID, + EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + size, data); FreePool(data); - if (EFI_ERROR(rc)) { - Print(L"Could not create variable: %d\n", rc); - return rc; + if (EFI_ERROR(efi_status)) { + console_print(L"Could not create variable: %r\n", + efi_status); + return efi_status; } CHAR16 *newbootorder = AllocateZeroPool(sizeof (CHAR16) @@ -214,10 +281,11 @@ add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp, bootorder = newbootorder; nbootorder += 1; #ifdef DEBUG_FALLBACK - Print(L"nbootorder: %d\nBootOrder: ", nbootorder); + console_print(L"nbootorder: %d\nBootOrder: ", + nbootorder); for (j = 0 ; j < nbootorder ; j++) - Print(L"%04x ", bootorder[j]); - Print(L"\n"); + console_print(L"%04x ", bootorder[j]); + console_print(L"\n"); #endif return EFI_SUCCESS; @@ -226,6 +294,105 @@ add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp, return EFI_OUT_OF_RESOURCES; } +/* + * AMI BIOS (e.g, Intel NUC5i3MYHE) may automatically hide and patch BootXXXX + * variables with ami_masked_device_path_guid. We can get the valid device path + * if just skipping it and its next end path. + */ + +static EFI_GUID ami_masked_device_path_guid = { + 0x99e275e7, 0x75a0, 0x4b37, + { 0xa2, 0xe6, 0xc5, 0x38, 0x5e, 0x6c, 0x0, 0xcb } +}; + +static unsigned int +calc_masked_boot_option_size(unsigned int size) +{ + return size + sizeof(EFI_DEVICE_PATH) + + sizeof(ami_masked_device_path_guid) + sizeof(EFI_DEVICE_PATH); +} + +static int +check_masked_boot_option(CHAR8 *candidate, unsigned int candidate_size, + CHAR8 *data, unsigned int data_size) +{ + /* + * The patched BootXXXX variables contain a hardware device path and + * an end path, preceding the real device path. + */ + if (calc_masked_boot_option_size(data_size) != candidate_size) + return 1; + + CHAR8 *cursor = candidate; + + /* Check whether the BootXXXX is patched */ + cursor += sizeof(UINT32) + sizeof(UINT16); + cursor += StrSize((CHAR16 *)cursor); + + unsigned int min_valid_size = cursor - candidate + sizeof(EFI_DEVICE_PATH); + + if (candidate_size <= min_valid_size) + return 1; + + EFI_DEVICE_PATH *dp = (EFI_DEVICE_PATH *)cursor; + unsigned int node_size = DevicePathNodeLength(dp) - sizeof(EFI_DEVICE_PATH); + + min_valid_size += node_size; + if (candidate_size <= min_valid_size || + DevicePathType(dp) != HARDWARE_DEVICE_PATH || + DevicePathSubType(dp) != HW_VENDOR_DP || + node_size != sizeof(ami_masked_device_path_guid) || + CompareGuid((EFI_GUID *)(cursor + sizeof(EFI_DEVICE_PATH)), + &ami_masked_device_path_guid)) + return 1; + + /* Check whether the patched guid is followed by an end path */ + min_valid_size += sizeof(EFI_DEVICE_PATH); + if (candidate_size <= min_valid_size) + return 1; + + dp = NextDevicePathNode(dp); + if (!IsDevicePathEnd(dp)) + return 1; + + /* + * OK. We may really get a masked BootXXXX variable. The next + * step is to test whether it is hidden. + */ + UINT32 attrs = *(UINT32 *)candidate; +#ifndef LOAD_OPTION_HIDDEN +# define LOAD_OPTION_HIDDEN 0x00000008 +#endif + if (!(attrs & LOAD_OPTION_HIDDEN)) + return 1; + + attrs &= ~LOAD_OPTION_HIDDEN; + + /* Compare the field Attributes */ + if (attrs != *(UINT32 *)data) + return 1; + + /* Compare the field FilePathListLength */ + data += sizeof(UINT32); + candidate += sizeof(UINT32); + if (calc_masked_boot_option_size(*(UINT16 *)data) != + *(UINT16 *)candidate) + return 1; + + /* Compare the field Description */ + data += sizeof(UINT16); + candidate += sizeof(UINT16); + if (CompareMem(candidate, data, cursor - candidate)) + return 1; + + /* Compare the filed FilePathList */ + cursor = (CHAR8 *)NextDevicePathNode(dp); + data += sizeof(UINT16); + data += StrSize((CHAR16 *)data); + + return CompareMem(cursor, data, candidate_size - min_valid_size); +} + EFI_STATUS find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp, CHAR16 *filename, CHAR16 *label, CHAR16 *arguments, @@ -252,10 +419,10 @@ find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp, int i = 0; CHAR16 varname[] = L"Boot0000"; CHAR16 hexmap[] = L"0123456789ABCDEF"; - EFI_GUID global = EFI_GLOBAL_VARIABLE; - EFI_STATUS rc; + EFI_STATUS efi_status; - CHAR8 *candidate = AllocateZeroPool(size); + UINTN max_candidate_size = calc_masked_boot_option_size(size); + CHAR8 *candidate = AllocateZeroPool(max_candidate_size); if (!candidate) { FreePool(data); return EFI_OUT_OF_RESOURCES; @@ -267,17 +434,21 @@ find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp, varname[6] = hexmap[(bootorder[i] & 0x00f0) >> 4]; varname[7] = hexmap[(bootorder[i] & 0x000f) >> 0]; - UINTN candidate_size = size; - rc = uefi_call_wrapper(RT->GetVariable, 5, varname, &global, - NULL, &candidate_size, candidate); - if (EFI_ERROR(rc)) + UINTN candidate_size = max_candidate_size; + efi_status = gRT->GetVariable(varname, &GV_GUID, NULL, + &candidate_size, candidate); + if (EFI_ERROR(efi_status)) continue; - if (candidate_size != size) + if (candidate_size != size) { + if (check_masked_boot_option(candidate, candidate_size, + data, size)) + continue; + } else if (CompareMem(candidate, data, size)) continue; - if (CompareMem(candidate, data, size)) - continue; + VerbosePrint(L"Found boot entry \"%s\" with label \"%s\" " + L"for file \"%s\"\n", varname, label, filename); /* at this point, we have duplicate data. */ if (!first_new_option) { @@ -301,9 +472,8 @@ set_boot_order(void) { CHAR16 *oldbootorder; UINTN size; - EFI_GUID global = EFI_GLOBAL_VARIABLE; - oldbootorder = LibGetVariableAndSize(L"BootOrder", &global, &size); + oldbootorder = LibGetVariableAndSize(L"BootOrder", &GV_GUID, &size); if (oldbootorder) { nbootorder = size / sizeof (CHAR16); bootorder = oldbootorder; @@ -317,9 +487,8 @@ update_boot_order(void) { UINTN size; UINTN len = 0; - EFI_GUID global = EFI_GLOBAL_VARIABLE; CHAR16 *newbootorder = NULL; - EFI_STATUS rc; + EFI_STATUS efi_status; size = nbootorder * sizeof(CHAR16); newbootorder = AllocateZeroPool(size); @@ -327,93 +496,85 @@ update_boot_order(void) return EFI_OUT_OF_RESOURCES; CopyMem(newbootorder, bootorder, size); -#ifdef DEBUG_FALLBACK - Print(L"nbootorder: %d\nBootOrder: ", size / sizeof (CHAR16)); + VerbosePrint(L"nbootorder: %d\nBootOrder: ", size / sizeof (CHAR16)); UINTN j; for (j = 0 ; j < size / sizeof (CHAR16); j++) - Print(L"%04x ", newbootorder[j]); - Print(L"\n"); -#endif - rc = uefi_call_wrapper(RT->GetVariable, 5, L"BootOrder", &global, - NULL, &len, NULL); - if (rc == EFI_BUFFER_TOO_SMALL) - LibDeleteVariable(L"BootOrder", &global); - - rc = uefi_call_wrapper(RT->SetVariable, 5, L"BootOrder", &global, - EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS, - size, newbootorder); + VerbosePrintUnprefixed(L"%04x ", newbootorder[j]); + console_print(L"\n"); + efi_status = gRT->GetVariable(L"BootOrder", &GV_GUID, NULL, &len, NULL); + if (efi_status == EFI_BUFFER_TOO_SMALL) + LibDeleteVariable(L"BootOrder", &GV_GUID); + + efi_status = gRT->SetVariable(L"BootOrder", &GV_GUID, + EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + size, newbootorder); FreePool(newbootorder); - return rc; + return efi_status; } EFI_STATUS -add_to_boot_list(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename, CHAR16 *label, CHAR16 *arguments) +add_to_boot_list(CHAR16 *dirname, CHAR16 *filename, CHAR16 *label, CHAR16 *arguments) { CHAR16 *fullpath = NULL; UINT64 pathlen = 0; - EFI_STATUS rc = EFI_SUCCESS; - - rc = make_full_path(dirname, filename, &fullpath, &pathlen); - if (EFI_ERROR(rc)) - return rc; - - EFI_DEVICE_PATH *dph = NULL; - EFI_DEVICE_PATH *file = NULL; + EFI_STATUS efi_status; + + efi_status = make_full_path(dirname, filename, &fullpath, &pathlen); + if (EFI_ERROR(efi_status)) + return efi_status; + EFI_DEVICE_PATH *full_device_path = NULL; EFI_DEVICE_PATH *dp = NULL; - - dph = DevicePathFromHandle(this_image->DeviceHandle); - if (!dph) { - rc = EFI_OUT_OF_RESOURCES; - goto err; - } + CHAR16 *dps; - file = FileDevicePath(fh, fullpath); - if (!file) { - rc = EFI_OUT_OF_RESOURCES; - goto err; - } - - full_device_path = AppendDevicePath(dph, file); + full_device_path = FileDevicePath(this_image->DeviceHandle, fullpath); if (!full_device_path) { - rc = EFI_OUT_OF_RESOURCES; + efi_status = EFI_OUT_OF_RESOURCES; goto err; } + dps = DevicePathToStr(full_device_path); + VerbosePrint(L"file DP: %s\n", dps); + FreePool(dps); - rc = FindSubDevicePath(full_device_path, - MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP, &dp); - if (EFI_ERROR(rc)) { - if (rc == EFI_NOT_FOUND) { + efi_status = FindSubDevicePath(full_device_path, + MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP, + &dp); + if (EFI_ERROR(efi_status)) { + if (efi_status == EFI_NOT_FOUND) { dp = full_device_path; } else { - rc = EFI_OUT_OF_RESOURCES; + efi_status = EFI_OUT_OF_RESOURCES; goto err; } } -#ifdef DEBUG_FALLBACK { - UINTN s = DevicePathSize(dp); - UINTN i; - UINT8 *dpv = (void *)dp; - for (i = 0; i < s; i++) { - if (i > 0 && i % 16 == 0) - Print(L"\n"); - Print(L"%02x ", dpv[i]); - } - Print(L"\n"); + UINTN s = DevicePathSize(dp); + UINTN i; + UINT8 *dpv = (void *)dp; + for (i = 0; i < s; i++) { + if (i % 16 == 0) { + if (i > 0) + VerbosePrintUnprefixed(L"\n"); + VerbosePrint(L""); + } + VerbosePrintUnprefixed(L"%02x ", dpv[i]); + } + VerbosePrintUnprefixed(L"\n"); - CHAR16 *dps = DevicePathToStr(dp); - Print(L"device path: \"%s\"\n", dps); + CHAR16 *dps = DevicePathToStr(dp); + VerbosePrint(L"device path: \"%s\"\n", dps); + FreePool(dps); } -#endif UINT16 option; - rc = find_boot_option(dp, full_device_path, fullpath, label, arguments, &option); - if (EFI_ERROR(rc)) { - add_boot_option(dp, full_device_path, fullpath, label, arguments); + efi_status = find_boot_option(dp, full_device_path, fullpath, label, + arguments, &option); + if (EFI_ERROR(efi_status)) { + add_boot_option(dp, full_device_path, fullpath, label, + arguments); } else if (option != 0) { CHAR16 *newbootorder; newbootorder = AllocateZeroPool(sizeof (CHAR16) * nbootorder); @@ -429,51 +590,41 @@ add_to_boot_list(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename, CHAR16 * } err: - if (file) - FreePool(file); if (full_device_path) FreePool(full_device_path); - if (dp) + if (dp && dp != full_device_path) FreePool(dp); if (fullpath) FreePool(fullpath); - return rc; + return efi_status; } EFI_STATUS -populate_stanza(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename, CHAR16 *csv) +populate_stanza(CHAR16 *dirname, CHAR16 *filename, CHAR16 *csv) { -#ifdef DEBUG_FALLBACK - Print(L"CSV data: \"%s\"\n", csv); -#endif CHAR16 *file = csv; + VerbosePrint(L"CSV data: \"%s\"\n", csv); UINTN comma0 = StrCSpn(csv, L","); if (comma0 == 0) return EFI_INVALID_PARAMETER; file[comma0] = L'\0'; -#ifdef DEBUG_FALLBACK - Print(L"filename: \"%s\"\n", file); -#endif + VerbosePrint(L"filename: \"%s\"\n", file); CHAR16 *label = csv + comma0 + 1; UINTN comma1 = StrCSpn(label, L","); if (comma1 == 0) return EFI_INVALID_PARAMETER; label[comma1] = L'\0'; -#ifdef DEBUG_FALLBACK - Print(L"label: \"%s\"\n", label); -#endif + VerbosePrint(L"label: \"%s\"\n", label); CHAR16 *arguments = csv + comma0 +1 + comma1 +1; UINTN comma2 = StrCSpn(arguments, L","); arguments[comma2] = L'\0'; /* This one is optional, so don't check if comma2 is 0 */ -#ifdef DEBUG_FALLBACK - Print(L"arguments: \"%s\"\n", arguments); -#endif + VerbosePrint(L"arguments: \"%s\"\n", arguments); - add_to_boot_list(fh, dirname, file, label, arguments); + add_to_boot_list(dirname, file, label, arguments); return EFI_SUCCESS; } @@ -483,29 +634,26 @@ try_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename) { CHAR16 *fullpath = NULL; UINT64 pathlen = 0; - EFI_STATUS rc; + EFI_STATUS efi_status; - rc = make_full_path(dirname, filename, &fullpath, &pathlen); - if (EFI_ERROR(rc)) - return rc; + efi_status = make_full_path(dirname, filename, &fullpath, &pathlen); + if (EFI_ERROR(efi_status)) + return efi_status; -#ifdef DEBUG_FALLBACK - Print(L"Found file \"%s\"\n", fullpath); -#endif + VerbosePrint(L"Found file \"%s\"\n", fullpath); CHAR16 *buffer; UINT64 bs; - rc = read_file(fh, fullpath, &buffer, &bs); - if (EFI_ERROR(rc)) { - Print(L"Could not read file \"%s\": %d\n", fullpath, rc); + efi_status = read_file(fh, fullpath, &buffer, &bs); + if (EFI_ERROR(efi_status)) { + console_print(L"Could not read file \"%s\": %r\n", + fullpath, efi_status); FreePool(fullpath); - return rc; + return efi_status; } FreePool(fullpath); -#ifdef DEBUG_FALLBACK - Print(L"File looks like:\n%s\n", buffer); -#endif + VerbosePrint(L"File looks like:\n%s\n", buffer); CHAR16 *start = buffer; /* The file may or may not start with the Unicode byte order marker. @@ -531,7 +679,7 @@ try_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename) CHAR16 c = start[l]; start[l] = L'\0'; - populate_stanza(fh, dirname, filename, start); + populate_stanza(dirname, filename, start); start[l] = c; start += l; @@ -544,31 +692,37 @@ try_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename) EFI_STATUS find_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname) { - EFI_STATUS rc; + EFI_STATUS efi_status; void *buffer = NULL; UINTN bs = 0; - EFI_GUID finfo = EFI_FILE_INFO_ID; /* The API here is "Call it once with bs=0, it fills in bs, * then allocate a buffer and ask again to get it filled. */ - rc = uefi_call_wrapper(fh->GetInfo, 4, fh, &finfo, &bs, NULL); - if (rc == EFI_BUFFER_TOO_SMALL) { - buffer = AllocateZeroPool(bs); - if (!buffer) { - Print(L"Could not allocate memory\n"); - return EFI_OUT_OF_RESOURCES; - } - rc = uefi_call_wrapper(fh->GetInfo, 4, fh, &finfo, - &bs, buffer); + efi_status = fh->GetInfo(fh, &EFI_FILE_INFO_GUID, &bs, NULL); + if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) { + console_print(L"Could not get directory info for \\EFI\\%s\\: %r\n", + dirname, efi_status); + return efi_status; + } + if (bs == 0) + return EFI_SUCCESS; + + buffer = AllocateZeroPool(bs); + if (!buffer) { + console_print(L"Could not allocate memory\n"); + return EFI_OUT_OF_RESOURCES; } + + efi_status = fh->GetInfo(fh, &EFI_FILE_INFO_GUID, &bs, buffer); /* This checks *either* the error from the first GetInfo, if it isn't - * the EFI_BUFFER_TOO_SMALL we're expecting, or the second GetInfo call - * in *any* case. */ - if (EFI_ERROR(rc)) { - Print(L"Could not get info for \"%s\": %d\n", dirname, rc); + * the EFI_BUFFER_TOO_SMALL we're expecting, or the second GetInfo + * call in *any* case. */ + if (EFI_ERROR(efi_status)) { + console_print(L"Could not get info for \"%s\": %r\n", dirname, + efi_status); if (buffer) FreePool(buffer); - return rc; + return efi_status; } EFI_FILE_INFO *fi = buffer; @@ -584,25 +738,30 @@ find_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname) bs = 0; do { bs = 0; - rc = uefi_call_wrapper(fh->Read, 3, fh, &bs, NULL); - if (EFI_ERROR(rc) && rc != EFI_BUFFER_TOO_SMALL) { - Print(L"Could not read \\EFI\\%s\\: %d\n", dirname, rc); - if (buffer) - FreePool(buffer); - return rc; + efi_status = fh->Read(fh, &bs, NULL); + if (EFI_ERROR(efi_status) && + efi_status != EFI_BUFFER_TOO_SMALL) { + console_print(L"Could not read \\EFI\\%s\\: %r\n", + dirname, efi_status); + return efi_status; } + /* If there's no data to read, don't try to allocate 0 bytes + * and read the data... */ + if (bs == 0) + break; buffer = AllocateZeroPool(bs); if (!buffer) { - Print(L"Could not allocate memory\n"); + console_print(L"Could not allocate memory\n"); return EFI_OUT_OF_RESOURCES; } - rc = uefi_call_wrapper(fh->Read, 3, fh, &bs, buffer); - if (EFI_ERROR(rc)) { - Print(L"Could not read \\EFI\\%s\\: %d\n", dirname, rc); + efi_status = fh->Read(fh, &bs, buffer); + if (EFI_ERROR(efi_status)) { + console_print(L"Could not read \\EFI\\%s\\: %r\n", + dirname, efi_status); FreePool(buffer); - return rc; + return efi_status; } if (bs == 0) @@ -621,105 +780,108 @@ find_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname) buffer = NULL; } while (bs != 0); - rc = EFI_SUCCESS; + efi_status = EFI_SUCCESS; if (bootarchcsv) { EFI_FILE_HANDLE fh2; - rc = uefi_call_wrapper(fh->Open, 5, fh, &fh2, - bootarchcsv, EFI_FILE_READ_ONLY, 0); - if (EFI_ERROR(rc) || fh2 == NULL) { - Print(L"Couldn't open \\EFI\\%s\\%s: %d\n", - dirname, bootarchcsv, rc); + efi_status = fh->Open(fh, &fh2, bootarchcsv, + EFI_FILE_READ_ONLY, 0); + if (EFI_ERROR(efi_status) || fh2 == NULL) { + console_print(L"Couldn't open \\EFI\\%s\\%s: %r\n", + dirname, bootarchcsv, efi_status); } else { - rc = try_boot_csv(fh2, dirname, bootarchcsv); - uefi_call_wrapper(fh2->Close, 1, fh2); + efi_status = try_boot_csv(fh2, dirname, bootarchcsv); + fh2->Close(fh2); + if (EFI_ERROR(efi_status)) + console_print(L"Could not process \\EFI\\%s\\%s: %r\n", + dirname, bootarchcsv, efi_status); } } - if ((EFI_ERROR(rc) || !bootarchcsv) && bootcsv) { + if ((EFI_ERROR(efi_status) || !bootarchcsv) && bootcsv) { EFI_FILE_HANDLE fh2; - rc = uefi_call_wrapper(fh->Open, 5, fh, &fh2, - bootcsv, EFI_FILE_READ_ONLY, 0); - if (EFI_ERROR(rc) || fh2 == NULL) { - Print(L"Couldn't open \\EFI\\%s\\%s: %d\n", - dirname, bootcsv, rc); + efi_status = fh->Open(fh, &fh2, bootcsv, + EFI_FILE_READ_ONLY, 0); + if (EFI_ERROR(efi_status) || fh2 == NULL) { + console_print(L"Couldn't open \\EFI\\%s\\%s: %r\n", + dirname, bootcsv, efi_status); } else { - rc = try_boot_csv(fh2, dirname, bootcsv); - uefi_call_wrapper(fh2->Close, 1, fh2); + efi_status = try_boot_csv(fh2, dirname, bootcsv); + fh2->Close(fh2); + if (EFI_ERROR(efi_status)) + console_print(L"Could not process \\EFI\\%s\\%s: %r\n", + dirname, bootarchcsv, efi_status); } } - rc = EFI_SUCCESS; - - return rc; + return EFI_SUCCESS; } EFI_STATUS find_boot_options(EFI_HANDLE device) { - EFI_STATUS rc = EFI_SUCCESS; - + EFI_STATUS efi_status; EFI_FILE_IO_INTERFACE *fio = NULL; - rc = uefi_call_wrapper(BS->HandleProtocol, 3, device, - &FileSystemProtocol, (void **)&fio); - if (EFI_ERROR(rc)) { - Print(L"Couldn't find file system: %d\n", rc); - return rc; + + efi_status = gBS->HandleProtocol(device, &FileSystemProtocol, + (void **) &fio); + if (EFI_ERROR(efi_status)) { + console_print(L"Couldn't find file system: %r\n", efi_status); + return efi_status; } /* EFI_FILE_HANDLE is a pointer to an EFI_FILE, and I have * *no idea* what frees the memory allocated here. Hopefully * Close() does. */ EFI_FILE_HANDLE fh = NULL; - rc = uefi_call_wrapper(fio->OpenVolume, 2, fio, &fh); - if (EFI_ERROR(rc) || fh == NULL) { - Print(L"Couldn't open file system: %d\n", rc); - return rc; + efi_status = fio->OpenVolume(fio, &fh); + if (EFI_ERROR(efi_status) || fh == NULL) { + console_print(L"Couldn't open file system: %r\n", efi_status); + return efi_status; } EFI_FILE_HANDLE fh2 = NULL; - rc = uefi_call_wrapper(fh->Open, 5, fh, &fh2, L"EFI", - EFI_FILE_READ_ONLY, 0); - if (EFI_ERROR(rc) || fh2 == NULL) { - Print(L"Couldn't open EFI: %d\n", rc); - uefi_call_wrapper(fh->Close, 1, fh); - return rc; + efi_status = fh->Open(fh, &fh2, L"EFI", EFI_FILE_READ_ONLY, 0); + if (EFI_ERROR(efi_status) || fh2 == NULL) { + console_print(L"Couldn't open EFI: %r\n", efi_status); + fh->Close(fh); + return efi_status; } - rc = uefi_call_wrapper(fh2->SetPosition, 2, fh2, 0); - if (EFI_ERROR(rc)) { - Print(L"Couldn't set file position: %d\n", rc); - uefi_call_wrapper(fh2->Close, 1, fh2); - uefi_call_wrapper(fh->Close, 1, fh); - return rc; + efi_status = fh2->SetPosition(fh2, 0); + if (EFI_ERROR(efi_status)) { + console_print(L"Couldn't set file position: %r\n", efi_status); + fh2->Close(fh2); + fh->Close(fh); + return efi_status; } void *buffer; UINTN bs; do { bs = 0; - rc = uefi_call_wrapper(fh2->Read, 3, fh2, &bs, NULL); - if (rc == EFI_BUFFER_TOO_SMALL || - (rc == EFI_SUCCESS && bs != 0)) { - buffer = AllocateZeroPool(bs); - if (!buffer) { - Print(L"Could not allocate memory\n"); - /* sure, this might work, why not? */ - uefi_call_wrapper(fh2->Close, 1, fh2); - uefi_call_wrapper(fh->Close, 1, fh); - return EFI_OUT_OF_RESOURCES; - } - - rc = uefi_call_wrapper(fh2->Read, 3, fh2, &bs, buffer); + efi_status = fh2->Read(fh2, &bs, NULL); + if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) { + console_print(L"Could not read \\EFI\\: %r\n", efi_status); + return efi_status; } if (bs == 0) break; - if (EFI_ERROR(rc)) { - Print(L"Could not read \\EFI\\: %d\n", rc); + buffer = AllocateZeroPool(bs); + if (!buffer) { + console_print(L"Could not allocate memory\n"); + /* sure, this might work, why not? */ + fh2->Close(fh2); + fh->Close(fh); + return EFI_OUT_OF_RESOURCES; + } + + efi_status = fh2->Read(fh2, &bs, buffer); + if (EFI_ERROR(efi_status)) { if (buffer) { FreePool(buffer); buffer = NULL; } - uefi_call_wrapper(fh2->Close, 1, fh2); - uefi_call_wrapper(fh->Close, 1, fh); - return rc; + fh2->Close(fh2); + fh->Close(fh); + return efi_status; } EFI_FILE_INFO *fi = buffer; @@ -735,82 +897,82 @@ find_boot_options(EFI_HANDLE device) buffer = NULL; continue; } -#ifdef DEBUG_FALLBACK - Print(L"Found directory named \"%s\"\n", fi->FileName); -#endif + VerbosePrint(L"Found directory named \"%s\"\n", fi->FileName); EFI_FILE_HANDLE fh3; - rc = uefi_call_wrapper(fh->Open, 5, fh2, &fh3, fi->FileName, - EFI_FILE_READ_ONLY, 0); - if (EFI_ERROR(rc)) { - Print(L"%d Couldn't open %s: %d\n", __LINE__, fi->FileName, rc); + efi_status = fh2->Open(fh2, &fh3, fi->FileName, + EFI_FILE_READ_ONLY, 0); + if (EFI_ERROR(efi_status)) { + console_print(L"%d Couldn't open %s: %r\n", __LINE__, + fi->FileName, efi_status); FreePool(buffer); buffer = NULL; continue; } - rc = find_boot_csv(fh3, fi->FileName); + efi_status = find_boot_csv(fh3, fi->FileName); + fh3->Close(fh3); FreePool(buffer); buffer = NULL; - if (rc == EFI_OUT_OF_RESOURCES) + if (efi_status == EFI_OUT_OF_RESOURCES) break; } while (1); - if (rc == EFI_SUCCESS && nbootorder > 0) - rc = update_boot_order(); + if (!EFI_ERROR(efi_status) && nbootorder > 0) + efi_status = update_boot_order(); - uefi_call_wrapper(fh2->Close, 1, fh2); - uefi_call_wrapper(fh->Close, 1, fh); - return rc; + fh2->Close(fh2); + fh->Close(fh); + return efi_status; } static EFI_STATUS try_start_first_option(EFI_HANDLE parent_image_handle) { - EFI_STATUS rc; + EFI_STATUS efi_status; EFI_HANDLE image_handle; if (!first_new_option) { return EFI_SUCCESS; } - rc = uefi_call_wrapper(BS->LoadImage, 6, 0, parent_image_handle, - first_new_option, NULL, 0, - &image_handle); - if (EFI_ERROR(rc)) { + efi_status = gBS->LoadImage(0, parent_image_handle, first_new_option, + NULL, 0, &image_handle); + if (EFI_ERROR(efi_status)) { CHAR16 *dps = DevicePathToStr(first_new_option); UINTN s = DevicePathSize(first_new_option); unsigned int i; UINT8 *dpv = (void *)first_new_option; - Print(L"LoadImage failed: %d\nDevice path: \"%s\"\n", rc, dps); + console_print(L"LoadImage failed: %r\nDevice path: \"%s\"\n", + efi_status, dps); for (i = 0; i < s; i++) { if (i > 0 && i % 16 == 0) - Print(L"\n"); - Print(L"%02x ", dpv[i]); + console_print(L"\n"); + console_print(L"%02x ", dpv[i]); } - Print(L"\n"); + console_print(L"\n"); - uefi_call_wrapper(BS->Stall, 1, 500000000); - return rc; + msleep(500000000); + return efi_status; } EFI_LOADED_IMAGE *image; - rc = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle, &LoadedImageProtocol, (void *)&image); - if (!EFI_ERROR(rc)) { + efi_status = gBS->HandleProtocol(image_handle, &LoadedImageProtocol, + (void *) &image); + if (!EFI_ERROR(efi_status)) { image->LoadOptions = first_new_option_args; image->LoadOptionsSize = first_new_option_size; } - rc = uefi_call_wrapper(BS->StartImage, 3, image_handle, NULL, NULL); - if (EFI_ERROR(rc)) { - Print(L"StartImage failed: %d\n", rc); - uefi_call_wrapper(BS->Stall, 1, 500000000); + efi_status = gBS->StartImage(image_handle, NULL, NULL); + if (EFI_ERROR(efi_status)) { + console_print(L"StartImage failed: %r\n", efi_status); + msleep(500000000); } - return rc; + return efi_status; } -EFI_GUID SHIM_LOCK_GUID = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }; extern EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab); @@ -818,31 +980,33 @@ static void __attribute__((__optimize__("0"))) debug_hook(void) { - EFI_GUID guid = SHIM_LOCK_GUID; UINT8 *data = NULL; UINTN dataSize = 0; EFI_STATUS efi_status; volatile register int x = 0; extern char _etext, _edata; - efi_status = get_variable(L"SHIM_DEBUG", &data, &dataSize, guid); + efi_status = get_variable(L"SHIM_DEBUG", &data, &dataSize, + SHIM_LOCK_GUID); if (EFI_ERROR(efi_status)) { return; } + if (data) + FreePool(data); if (x) return; x = 1; - Print(L"add-symbol-file "DEBUGDIR - L"fb" EFI_ARCH L".efi.debug %p -s .data %p\n", &_etext, - &_edata); + console_print(L"add-symbol-file "DEBUGDIR + L"fb" EFI_ARCH L".efi.debug %p -s .data %p\n", + &_etext, &_edata); } EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) { - EFI_STATUS rc; + EFI_STATUS efi_status; InitializeLib(image, systab); @@ -851,27 +1015,41 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) */ debug_hook(); - rc = uefi_call_wrapper(BS->HandleProtocol, 3, image, &LoadedImageProtocol, (void *)&this_image); - if (EFI_ERROR(rc)) { - Print(L"Error: could not find loaded image: %d\n", rc); - return rc; + efi_status = gBS->HandleProtocol(image, &LoadedImageProtocol, + (void *) &this_image); + if (EFI_ERROR(efi_status)) { + console_print(L"Error: could not find loaded image: %r\n", + efi_status); + return efi_status; } - Print(L"System BootOrder not found. Initializing defaults.\n"); + console_print(L"System BootOrder not found. Initializing defaults.\n"); set_boot_order(); - rc = find_boot_options(this_image->DeviceHandle); - if (EFI_ERROR(rc)) { - Print(L"Error: could not find boot options: %d\n", rc); - return rc; + efi_status = find_boot_options(this_image->DeviceHandle); + if (EFI_ERROR(efi_status)) { + console_print(L"Error: could not find boot options: %r\n", + efi_status); + return efi_status; + } + + efi_status = fallback_should_prefer_reset(); + if (EFI_ERROR(efi_status)) { + VerbosePrint(L"tpm not present, starting the first image\n"); + try_start_first_option(image); + } else { + VerbosePrint(L"tpm present, resetting system\n"); } - try_start_first_option(image); + console_print(L"Reset System\n"); + + if (get_fallback_verbose()) { + console_print(L"Verbose enabled, sleeping for half a second\n"); + msleep(500000); + } - Print(L"Reset System\n"); - uefi_call_wrapper(RT->ResetSystem, 4, EfiResetCold, - EFI_SUCCESS, 0, NULL); + gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); return EFI_SUCCESS; } |