From fb08d687562b47899bd3333f40d25c3f92b479c3 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Thu, 5 Jan 2017 12:45:59 -0600 Subject: fallback: replace any existing boot entry with the same name Tweak the dupliate boot entry detection code to consider any existing entries as duplicate if they have the same name (rather than requiring the existing entry to be completely identical to the one we would add). When a duplicate is detected, rewrite the whole variable (as the device details might have changed) in addition to making it the new default boot entry. This means that when partition UUIDs are changed, or when doing a fresh reflash, we will avoid creating duplicate entries with the same name. https://phabricator.endlessm.com/T14430 --- fallback.c | 225 +++++++++++++++++++++++++++---------------------------------- 1 file changed, 101 insertions(+), 124 deletions(-) (limited to 'fallback.c') diff --git a/fallback.c b/fallback.c index b61d3bcc..22629340 100644 --- a/fallback.c +++ b/fallback.c @@ -143,125 +143,116 @@ VOID *first_new_option_args = NULL; UINTN first_new_option_size = 0; EFI_STATUS -add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp, - CHAR16 *filename, CHAR16 *label, CHAR16 *arguments) +do_add_boot_option(int boot_entry_num, EFI_DEVICE_PATH *hddp, + EFI_DEVICE_PATH *fulldp, CHAR16 *filename, CHAR16 *label, + CHAR16 *arguments) { - static int i = 0; CHAR16 varname[] = L"Boot0000"; CHAR16 hexmap[] = L"0123456789ABCDEF"; EFI_GUID global = EFI_GLOBAL_VARIABLE; EFI_STATUS rc; - for(; i <= 0xffff; i++) { - varname[4] = hexmap[(i & 0xf000) >> 12]; - varname[5] = hexmap[(i & 0x0f00) >> 8]; - varname[6] = hexmap[(i & 0x00f0) >> 4]; - varname[7] = hexmap[(i & 0x000f) >> 0]; + varname[4] = hexmap[(boot_entry_num & 0xf000) >> 12]; + varname[5] = hexmap[(boot_entry_num & 0x0f00) >> 8]; + varname[6] = hexmap[(boot_entry_num & 0x00f0) >> 4]; + varname[7] = hexmap[(boot_entry_num & 0x000f) >> 0]; - void *var = LibGetVariable(varname, &global); - if (!var) { - int size = sizeof(UINT32) + sizeof (UINT16) + - StrLen(label)*2 + 2 + DevicePathSize(hddp) + - StrLen(arguments) * 2; - - CHAR8 *data = AllocateZeroPool(size + 2); - CHAR8 *cursor = data; - *(UINT32 *)cursor = LOAD_OPTION_ACTIVE; - cursor += sizeof (UINT32); - *(UINT16 *)cursor = DevicePathSize(hddp); - cursor += sizeof (UINT16); - StrCpy((CHAR16 *)cursor, label); - cursor += StrLen(label)*2 + 2; - CopyMem(cursor, hddp, DevicePathSize(hddp)); - cursor += DevicePathSize(hddp); - StrCpy((CHAR16 *)cursor, arguments); + int size = sizeof(UINT32) + sizeof (UINT16) + + StrLen(label)*2 + 2 + DevicePathSize(hddp) + + StrLen(arguments) * 2; + + CHAR8 *data = AllocateZeroPool(size + 2); + CHAR8 *cursor = data; + *(UINT32 *)cursor = LOAD_OPTION_ACTIVE; + cursor += sizeof (UINT32); + *(UINT16 *)cursor = DevicePathSize(hddp); + cursor += sizeof (UINT16); + StrCpy((CHAR16 *)cursor, label); + cursor += StrLen(label)*2 + 2; + CopyMem(cursor, hddp, DevicePathSize(hddp)); + cursor += DevicePathSize(hddp); + StrCpy((CHAR16 *)cursor, arguments); #ifdef DEBUG_FALLBACK - Print(L"Creating boot entry \"%s\" with label \"%s\" " - L"for file \"%s\"\n", - varname, label, filename); + Print(L"Creating boot entry \"%s\" with label \"%s\" " + L"for file \"%s\"\n", + varname, label, filename); #endif - if (!first_new_option) { - first_new_option = DuplicateDevicePath(fulldp); - first_new_option_args = arguments; - first_new_option_size = StrLen(arguments) * sizeof (CHAR16); - } + if (!first_new_option) { + first_new_option = DuplicateDevicePath(fulldp); + first_new_option_args = arguments; + 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); + rc = uefi_call_wrapper(RT->SetVariable, 5, varname, + &global, EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + size, data); - FreePool(data); + FreePool(data); - if (EFI_ERROR(rc)) { - Print(L"Could not create variable: %d\n", rc); - return rc; - } + if (EFI_ERROR(rc)) { + Print(L"Could not create variable: %d\n", rc); + return rc; + } - CHAR16 *newbootorder = AllocateZeroPool(sizeof (CHAR16) - * (nbootorder + 1)); - if (!newbootorder) - return EFI_OUT_OF_RESOURCES; + CHAR16 *newbootorder = AllocateZeroPool(sizeof (CHAR16) + * (nbootorder + 1)); + if (!newbootorder) + return EFI_OUT_OF_RESOURCES; - int j = 0; - newbootorder[0] = i & 0xffff; - if (nbootorder) { - for (j = 0; j < nbootorder; j++) - newbootorder[j+1] = bootorder[j]; - FreePool(bootorder); - } - bootorder = newbootorder; - nbootorder += 1; + int j = 0; + newbootorder[0] = boot_entry_num & 0xffff; + if (nbootorder) { + for (j = 0; j < nbootorder; j++) + newbootorder[j+1] = bootorder[j]; + FreePool(bootorder); + } + bootorder = newbootorder; + nbootorder += 1; #ifdef DEBUG_FALLBACK - Print(L"nbootorder: %d\nBootOrder: ", nbootorder); - for (j = 0 ; j < nbootorder ; j++) - Print(L"%04x ", bootorder[j]); - Print(L"\n"); + Print(L"nbootorder: %d\nBootOrder: ", nbootorder); + for (j = 0 ; j < nbootorder ; j++) + Print(L"%04x ", bootorder[j]); + Print(L"\n"); #endif - return EFI_SUCCESS; - } - } - return EFI_OUT_OF_RESOURCES; + return EFI_SUCCESS; } EFI_STATUS -find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp, - CHAR16 *filename, CHAR16 *label, CHAR16 *arguments, - UINT16 *optnum) +add_new_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp, + CHAR16 *filename, CHAR16 *label, CHAR16 *arguments) { - unsigned int size = sizeof(UINT32) + sizeof (UINT16) + - StrLen(label)*2 + 2 + DevicePathSize(dp) + - StrLen(arguments) * 2; + static int i = 0; + CHAR16 varname[] = L"Boot0000"; + CHAR16 hexmap[] = L"0123456789ABCDEF"; + EFI_GUID global = EFI_GLOBAL_VARIABLE; - CHAR8 *data = AllocateZeroPool(size + 2); - if (!data) - return EFI_OUT_OF_RESOURCES; - CHAR8 *cursor = data; - *(UINT32 *)cursor = LOAD_OPTION_ACTIVE; - cursor += sizeof (UINT32); - *(UINT16 *)cursor = DevicePathSize(dp); - cursor += sizeof (UINT16); - StrCpy((CHAR16 *)cursor, label); - cursor += StrLen(label)*2 + 2; - CopyMem(cursor, dp, DevicePathSize(dp)); - cursor += DevicePathSize(dp); - StrCpy((CHAR16 *)cursor, arguments); + for(; i <= 0xffff; i++) { + varname[4] = hexmap[(i & 0xf000) >> 12]; + varname[5] = hexmap[(i & 0x0f00) >> 8]; + varname[6] = hexmap[(i & 0x00f0) >> 4]; + varname[7] = hexmap[(i & 0x000f) >> 0]; + + void *var = LibGetVariable(varname, &global); + if (!var) + return do_add_boot_option(i, hddp, fulldp, filename, + label, arguments); + } + return EFI_OUT_OF_RESOURCES; +} +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 rc; - - CHAR8 *candidate = AllocateZeroPool(size); - if (!candidate) { - FreePool(data); - return EFI_OUT_OF_RESOURCES; - } for(i = 0; i < nbootorder && i < 0x10000; i++) { varname[4] = hexmap[(bootorder[i] & 0xf000) >> 12]; @@ -269,33 +260,29 @@ 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; + CHAR8 *candidate = LibGetVariableAndSize(varname, &global, + &candidate_size); + if (!candidate) continue; - if (candidate_size != size) + /* Check that we won't overrun the buffer when comparing */ + if (candidate_size < (StrLen(label) * 2) + 2 + 6) { + FreePool(candidate); continue; + } - if (CompareMem(candidate, data, size)) + /* Check if this entry has the same label */ + if (CompareMem(candidate + 6, label, StrLen(label) * 2 + 2)) { + FreePool(candidate); continue; - - /* at this point, we have duplicate data. */ - if (!first_new_option) { - first_new_option = DuplicateDevicePath(fulldp); - first_new_option_args = arguments; - first_new_option_size = StrLen(arguments) * sizeof (CHAR16); } - *optnum = i; + /* at this point, we have duplicate data. */ FreePool(candidate); - FreePool(data); - return EFI_SUCCESS; + return i; } - FreePool(candidate); - FreePool(data); - return EFI_NOT_FOUND; + return -1; } EFI_STATUS @@ -412,22 +399,12 @@ add_to_boot_list(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename, CHAR16 * } #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); - } else if (option != 0) { - CHAR16 *newbootorder; - newbootorder = AllocateZeroPool(sizeof (CHAR16) * nbootorder); - if (!newbootorder) - return EFI_OUT_OF_RESOURCES; - - newbootorder[0] = bootorder[option]; - CopyMem(newbootorder + 1, bootorder, sizeof (CHAR16) * option); - CopyMem(newbootorder + option + 1, bootorder + option + 1, - sizeof (CHAR16) * (nbootorder - option - 1)); - FreePool(bootorder); - bootorder = newbootorder; + int boot_entry_num = find_boot_option(dp, full_device_path, fullpath, + label, arguments); + if (boot_entry_num < 0) { + add_new_boot_option(dp, full_device_path, fullpath, label, arguments); + } else { + do_add_boot_option(boot_entry_num, dp, full_device_path, fullpath, label, arguments); } err: -- cgit v1.2.3