From b45652aba2d797b64516ba2867d756c39a6735d1 Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Mon, 13 Feb 2017 14:03:11 -0500 Subject: fallback: Consider all Boot* vars when checking for duplicates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some firmware implementations like the one on the Acer TravelMate P449-G2-MG completely ignore the contents of BootOrder on boot, and overwrite it with a value of its own. On this particular machine, the boot entry that was just created by fallback on the previous boot is not included by the firmware on this new BootOrder, so it is not considered when checking for duplicates. This problem is agravated by the fact that the aformentioned firmware does not give the user the possibility to boot from the entry created by fallback (or any other entry created by the OS). The only way to boot a distro that deploys the fallback setup (no grub inside \EFI\BOOT) with this firmware is to select the entry pointing to \EFI\BOOT\bootx64.efi, leading to a new boot entry being created by fallback on every boot. This commit makes fallback try every Boot* variable when checking for duplicates, working around this problem. Signed-off-by: João Paulo Rechi Vita https://phabricator.endlessm.com/T15481 --- fallback.c | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/fallback.c b/fallback.c index 22629340..174fd8cb 100644 --- a/fallback.c +++ b/fallback.c @@ -245,22 +245,40 @@ add_new_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp, return EFI_OUT_OF_RESOURCES; } +int +isxdigit(CHAR16 c) +{ + return ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || + (c >= 'a' && c <= 'f')); +} + int find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp, CHAR16 *filename, CHAR16 *label, CHAR16 *arguments) { - int i = 0; - CHAR16 varname[] = L"Boot0000"; - CHAR16 hexmap[] = L"0123456789ABCDEF"; - EFI_GUID global = EFI_GLOBAL_VARIABLE; + EFI_STATUS status; + EFI_GUID global; + int ret = -1; - for(i = 0; i < nbootorder && i < 0x10000; i++) { - varname[4] = hexmap[(bootorder[i] & 0xf000) >> 12]; - varname[5] = hexmap[(bootorder[i] & 0x0f00) >> 8]; - varname[6] = hexmap[(bootorder[i] & 0x00f0) >> 4]; - varname[7] = hexmap[(bootorder[i] & 0x000f) >> 0]; + UINTN CANDIDATE_SIZE = 256; + CHAR16 *varname = AllocateZeroPool(CANDIDATE_SIZE * sizeof(CHAR16)); + if (!varname) { + Print(L"Could not allocate memory\n"); + return ret; + } + + while (1) { + UINTN candidate_size = CANDIDATE_SIZE; + status = uefi_call_wrapper(RT->GetNextVariableName, 3, + &candidate_size, varname, &global); + if (status != EFI_SUCCESS) + break; + + if (StrLen(varname) != 8 || StrnCmp(varname, L"Boot", 4) || + !isxdigit(varname[4]) || !isxdigit(varname[5]) || + !isxdigit(varname[6]) || !isxdigit(varname[7])) + continue; - UINTN candidate_size; CHAR8 *candidate = LibGetVariableAndSize(varname, &global, &candidate_size); if (!candidate) @@ -280,9 +298,11 @@ find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp, /* at this point, we have duplicate data. */ FreePool(candidate); - return i; + ret = xtoi(varname + 4); + break; } - return -1; + FreePool(varname); + return ret; } EFI_STATUS -- cgit v1.2.3