366 lines
11 KiB
Diff
366 lines
11 KiB
Diff
|
From 9ba08c4e8e7cf9b001497a0752652e0ece0b2b84 Mon Sep 17 00:00:00 2001
|
||
|
From: Peter Jones <pjones@redhat.com>
|
||
|
Date: Fri, 31 Jan 2014 10:30:24 -0500
|
||
|
Subject: [PATCH 1/2] For HD() device paths, use just the media node and later.
|
||
|
|
||
|
UEFI 2.x section 3.1.2 provides for "short-form device path", where the
|
||
|
first element specified is a "hard drive media device path", so that you
|
||
|
can move a disk around on different buses without invalidating your
|
||
|
device path. Fallback has not been using this option, though in most
|
||
|
cases efibootmgr has.
|
||
|
|
||
|
Note that we still keep the full device path, because LoadImage()
|
||
|
isn't necessarily the layer where HD() works - one some systems BDS is
|
||
|
responsible for resolving the full path and passes that to LoadImage()
|
||
|
instead. So we have to do LoadImage() with the full path.
|
||
|
---
|
||
|
fallback.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++---------------
|
||
|
1 file changed, 78 insertions(+), 25 deletions(-)
|
||
|
|
||
|
diff --git a/fallback.c b/fallback.c
|
||
|
index 82ddbf2..7f4201e 100644
|
||
|
--- a/fallback.c
|
||
|
+++ b/fallback.c
|
||
|
@@ -15,6 +15,27 @@
|
||
|
EFI_LOADED_IMAGE *this_image = NULL;
|
||
|
|
||
|
static EFI_STATUS
|
||
|
+FindSubDevicePath(EFI_DEVICE_PATH *In, UINT8 Type, UINT8 SubType,
|
||
|
+ EFI_DEVICE_PATH **Out)
|
||
|
+{
|
||
|
+ EFI_DEVICE_PATH *dp = In;
|
||
|
+ if (!In || !Out)
|
||
|
+ return EFI_INVALID_PARAMETER;
|
||
|
+
|
||
|
+ for (dp = In; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp)) {
|
||
|
+ if (DevicePathType(dp) == Type &&
|
||
|
+ DevicePathSubType(dp) == SubType) {
|
||
|
+ *Out = DuplicateDevicePath(dp);
|
||
|
+ if (!*Out)
|
||
|
+ return EFI_OUT_OF_RESOURCES;
|
||
|
+ return EFI_SUCCESS;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ *Out = NULL;
|
||
|
+ return EFI_NOT_FOUND;
|
||
|
+}
|
||
|
+
|
||
|
+static EFI_STATUS
|
||
|
get_file_size(EFI_FILE_HANDLE fh, UINT64 *retsize)
|
||
|
{
|
||
|
EFI_STATUS rc;
|
||
|
@@ -93,7 +114,9 @@ make_full_path(CHAR16 *dirname, CHAR16 *filename, CHAR16 **out, UINT64 *outlen)
|
||
|
{
|
||
|
UINT64 len;
|
||
|
|
||
|
- len = StrLen(dirname) + StrLen(filename) + StrLen(L"\\EFI\\\\") + 2;
|
||
|
+ len = StrLen(L"\\EFI\\") + StrLen(dirname)
|
||
|
+ + StrLen(L"\\") + StrLen(filename)
|
||
|
+ + 2;
|
||
|
|
||
|
CHAR16 *fullpath = AllocateZeroPool(len*sizeof(CHAR16));
|
||
|
if (!fullpath) {
|
||
|
@@ -119,7 +142,8 @@ VOID *first_new_option_args = NULL;
|
||
|
UINTN first_new_option_size = 0;
|
||
|
|
||
|
EFI_STATUS
|
||
|
-add_boot_option(EFI_DEVICE_PATH *dp, CHAR16 *filename, CHAR16 *label, CHAR16 *arguments)
|
||
|
+add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp,
|
||
|
+ CHAR16 *filename, CHAR16 *label, CHAR16 *arguments)
|
||
|
{
|
||
|
static int i = 0;
|
||
|
CHAR16 varname[] = L"Boot0000";
|
||
|
@@ -136,24 +160,31 @@ add_boot_option(EFI_DEVICE_PATH *dp, CHAR16 *filename, CHAR16 *label, CHAR16 *ar
|
||
|
void *var = LibGetVariable(varname, &global);
|
||
|
if (!var) {
|
||
|
int size = sizeof(UINT32) + sizeof (UINT16) +
|
||
|
- StrLen(label)*2 + 2 + DevicePathSize(dp) +
|
||
|
- StrLen(arguments) * 2 + 2;
|
||
|
+ StrLen(label)*2 + 2 + DevicePathSize(hddp) +
|
||
|
+ StrLen(arguments) * 2;
|
||
|
|
||
|
CHAR8 *data = AllocateZeroPool(size);
|
||
|
CHAR8 *cursor = data;
|
||
|
*(UINT32 *)cursor = LOAD_OPTION_ACTIVE;
|
||
|
cursor += sizeof (UINT32);
|
||
|
- *(UINT16 *)cursor = DevicePathSize(dp);
|
||
|
+ *(UINT16 *)cursor = DevicePathSize(hddp);
|
||
|
cursor += sizeof (UINT16);
|
||
|
StrCpy((CHAR16 *)cursor, label);
|
||
|
cursor += StrLen(label)*2 + 2;
|
||
|
- CopyMem(cursor, dp, DevicePathSize(dp));
|
||
|
- cursor += DevicePathSize(dp);
|
||
|
+ CopyMem(cursor, hddp, DevicePathSize(hddp));
|
||
|
+ cursor += DevicePathSize(hddp);
|
||
|
StrCpy((CHAR16 *)cursor, arguments);
|
||
|
|
||
|
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);
|
||
|
+ 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 |
|
||
|
@@ -254,7 +285,10 @@ add_to_boot_list(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename, CHAR16 *
|
||
|
if (EFI_ERROR(rc))
|
||
|
return rc;
|
||
|
|
||
|
- EFI_DEVICE_PATH *dph = NULL, *dpf = NULL, *dp = NULL;
|
||
|
+ EFI_DEVICE_PATH *dph = NULL;
|
||
|
+ EFI_DEVICE_PATH *file = NULL;
|
||
|
+ EFI_DEVICE_PATH *full_device_path = NULL;
|
||
|
+ EFI_DEVICE_PATH *dp = NULL;
|
||
|
|
||
|
dph = DevicePathFromHandle(this_image->DeviceHandle);
|
||
|
if (!dph) {
|
||
|
@@ -262,19 +296,31 @@ add_to_boot_list(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename, CHAR16 *
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
- dpf = FileDevicePath(fh, fullpath);
|
||
|
- if (!dpf) {
|
||
|
+ file = FileDevicePath(fh, fullpath);
|
||
|
+ if (!file) {
|
||
|
rc = EFI_OUT_OF_RESOURCES;
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
- dp = AppendDevicePath(dph, dpf);
|
||
|
- if (!dp) {
|
||
|
+ full_device_path = AppendDevicePath(dph, file);
|
||
|
+ if (!full_device_path) {
|
||
|
rc = EFI_OUT_OF_RESOURCES;
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
+ rc = FindSubDevicePath(full_device_path,
|
||
|
+ MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP, &dp);
|
||
|
+ if (EFI_ERROR(rc)) {
|
||
|
+ if (rc == EFI_NOT_FOUND) {
|
||
|
+ dp = full_device_path;
|
||
|
+ } else {
|
||
|
+ rc = EFI_OUT_OF_RESOURCES;
|
||
|
+ goto err;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
#ifdef DEBUG_FALLBACK
|
||
|
+ {
|
||
|
UINTN s = DevicePathSize(dp);
|
||
|
int i;
|
||
|
UINT8 *dpv = (void *)dp;
|
||
|
@@ -287,20 +333,16 @@ add_to_boot_list(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename, CHAR16 *
|
||
|
|
||
|
CHAR16 *dps = DevicePathToStr(dp);
|
||
|
Print(L"device path: \"%s\"\n", dps);
|
||
|
-#endif
|
||
|
- if (!first_new_option) {
|
||
|
- CHAR16 *dps = DevicePathToStr(dp);
|
||
|
- Print(L"device path: \"%s\"\n", dps);
|
||
|
- first_new_option = DuplicateDevicePath(dp);
|
||
|
- first_new_option_args = arguments;
|
||
|
- first_new_option_size = StrLen(arguments) * sizeof (CHAR16);
|
||
|
}
|
||
|
+#endif
|
||
|
|
||
|
- add_boot_option(dp, fullpath, label, arguments);
|
||
|
+ add_boot_option(dp, full_device_path, fullpath, label, arguments);
|
||
|
|
||
|
err:
|
||
|
- if (dpf)
|
||
|
- FreePool(dpf);
|
||
|
+ if (file)
|
||
|
+ FreePool(file);
|
||
|
+ if (full_device_path)
|
||
|
+ FreePool(full_device_path);
|
||
|
if (dp)
|
||
|
FreePool(dp);
|
||
|
if (fullpath)
|
||
|
@@ -622,8 +664,19 @@ try_start_first_option(EFI_HANDLE parent_image_handle)
|
||
|
first_new_option, NULL, 0,
|
||
|
&image_handle);
|
||
|
if (EFI_ERROR(rc)) {
|
||
|
- Print(L"LoadImage failed: %d\n", rc);
|
||
|
- uefi_call_wrapper(BS->Stall, 1, 2000000);
|
||
|
+ CHAR16 *dps = DevicePathToStr(first_new_option);
|
||
|
+ UINTN s = DevicePathSize(first_new_option);
|
||
|
+ int i;
|
||
|
+ UINT8 *dpv = (void *)first_new_option;
|
||
|
+ Print(L"LoadImage failed: %d\nDevice path: \"%s\"\n", rc, dps);
|
||
|
+ for (i = 0; i < s; i++) {
|
||
|
+ if (i > 0 && i % 16 == 0)
|
||
|
+ Print(L"\n");
|
||
|
+ Print(L"%02x ", dpv[i]);
|
||
|
+ }
|
||
|
+ Print(L"\n");
|
||
|
+
|
||
|
+ uefi_call_wrapper(BS->Stall, 1, 500000000);
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
@@ -637,7 +690,7 @@ try_start_first_option(EFI_HANDLE parent_image_handle)
|
||
|
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, 2000000);
|
||
|
+ uefi_call_wrapper(BS->Stall, 1, 500000000);
|
||
|
}
|
||
|
return rc;
|
||
|
}
|
||
|
--
|
||
|
1.8.4.5
|
||
|
|
||
|
|
||
|
From 23ed6291df5dd34789829607a97b3605b739a629 Mon Sep 17 00:00:00 2001
|
||
|
From: Peter Jones <pjones@redhat.com>
|
||
|
Date: Fri, 31 Jan 2014 10:31:10 -0500
|
||
|
Subject: [PATCH 2/2] 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>
|
||
|
---
|
||
|
fallback.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||
|
1 file changed, 98 insertions(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/fallback.c b/fallback.c
|
||
|
index 7f4201e..044e4ba 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)
|
||
|
@@ -710,6 +805,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);
|
||
|
--
|
||
|
1.8.4.5
|
||
|
|