summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Jones <pjones@redhat.com>2014-01-31 10:31:10 -0500
committerPeter Jones <pjones@redhat.com>2014-01-31 10:31:10 -0500
commit9fcd221ef143df5a52671a6f23240eb246ccf448 (patch)
treefbb0b1b0869323883cb07c3c81c29ebc8b36b302
parent6edc6ec0a3da59e4519dec3f8af6fd48be00b980 (diff)
downloadefi-boot-shim-9fcd221ef143df5a52671a6f23240eb246ccf448.tar.gz
efi-boot-shim-9fcd221ef143df5a52671a6f23240eb246ccf448.zip
[fallback] Attempt to re-use existing entries when possible.
Some firmwares seem to ignore our boot entries and put their fallback entries back on top. Right now that results in a lot of boot entries for our stuff, a la https://bugzilla.redhat.com/show_bug.cgi?id=995834 . Instead of that happening, if we simply find existing entries that match the entry we would create and move them to the top of the boot order, the machine will continue to operate in failure mode (which we can't avoid), but at least we won't create thousands of extra entries. Signed-off-by: Peter Jones <pjones@redhat.com>
-rw-r--r--fallback.c99
1 files changed, 98 insertions, 1 deletions
diff --git a/fallback.c b/fallback.c
index a12bb741..44638ec0 100644
--- a/fallback.c
+++ b/fallback.c
@@ -226,6 +226,85 @@ add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp,
}
EFI_STATUS
+find_boot_option(EFI_DEVICE_PATH *dp, CHAR16 *filename, CHAR16 *label,
+ CHAR16 *arguments, UINT16 *optnum)
+{
+ int size = sizeof(UINT32) + sizeof (UINT16) +
+ StrLen(label)*2 + 2 + DevicePathSize(dp) +
+ StrLen(arguments) * 2 + 2;
+
+ CHAR8 *data = AllocateZeroPool(size);
+ 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);
+
+ 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];
+ varname[5] = hexmap[(bootorder[i] & 0x0f00) >> 8];
+ 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))
+ continue;
+
+ if (candidate_size != size)
+ continue;
+
+ if (CompareMem(candidate, data, size))
+ continue;
+
+ /* at this point, we have duplicate data. */
+ *optnum = i;
+ FreePool(candidate);
+ FreePool(data);
+ return EFI_SUCCESS;
+ }
+ FreePool(candidate);
+ FreePool(data);
+ return EFI_NOT_FOUND;
+}
+
+EFI_STATUS
+set_boot_order(void)
+{
+ CHAR16 *oldbootorder;
+ UINTN size;
+ EFI_GUID global = EFI_GLOBAL_VARIABLE;
+
+ oldbootorder = LibGetVariableAndSize(L"BootOrder", &global, &size);
+ if (oldbootorder) {
+ nbootorder = size / sizeof (CHAR16);
+ bootorder = oldbootorder;
+ }
+ return EFI_SUCCESS;
+
+}
+
+EFI_STATUS
update_boot_order(void)
{
CHAR16 *oldbootorder;
@@ -336,7 +415,23 @@ add_to_boot_list(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename, CHAR16 *
}
#endif
- add_boot_option(dp, full_device_path, fullpath, label, arguments);
+ UINT16 option;
+ rc = find_boot_option(dp, 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;
+ }
err:
if (file)
@@ -717,6 +812,8 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
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);