mirror of
https://git.proxmox.com/git/efi-boot-shim
synced 2025-05-29 17:18:22 +00:00
[fallback] 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.
This commit is contained in:
parent
1762111831
commit
6edc6ec0a3
103
fallback.c
103
fallback.c
@ -14,6 +14,27 @@
|
|||||||
|
|
||||||
EFI_LOADED_IMAGE *this_image = NULL;
|
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
|
static EFI_STATUS
|
||||||
get_file_size(EFI_FILE_HANDLE fh, UINTN *retsize)
|
get_file_size(EFI_FILE_HANDLE fh, UINTN *retsize)
|
||||||
{
|
{
|
||||||
@ -93,7 +114,9 @@ make_full_path(CHAR16 *dirname, CHAR16 *filename, CHAR16 **out, UINT64 *outlen)
|
|||||||
{
|
{
|
||||||
UINT64 len;
|
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));
|
CHAR16 *fullpath = AllocateZeroPool(len*sizeof(CHAR16));
|
||||||
if (!fullpath) {
|
if (!fullpath) {
|
||||||
@ -119,7 +142,8 @@ VOID *first_new_option_args = NULL;
|
|||||||
UINTN first_new_option_size = 0;
|
UINTN first_new_option_size = 0;
|
||||||
|
|
||||||
EFI_STATUS
|
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;
|
static int i = 0;
|
||||||
CHAR16 varname[] = L"Boot0000";
|
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);
|
void *var = LibGetVariable(varname, &global);
|
||||||
if (!var) {
|
if (!var) {
|
||||||
int size = sizeof(UINT32) + sizeof (UINT16) +
|
int size = sizeof(UINT32) + sizeof (UINT16) +
|
||||||
StrLen(label)*2 + 2 + DevicePathSize(dp) +
|
StrLen(label)*2 + 2 + DevicePathSize(hddp) +
|
||||||
StrLen(arguments) * 2 + 2;
|
StrLen(arguments) * 2;
|
||||||
|
|
||||||
CHAR8 *data = AllocateZeroPool(size);
|
CHAR8 *data = AllocateZeroPool(size);
|
||||||
CHAR8 *cursor = data;
|
CHAR8 *cursor = data;
|
||||||
*(UINT32 *)cursor = LOAD_OPTION_ACTIVE;
|
*(UINT32 *)cursor = LOAD_OPTION_ACTIVE;
|
||||||
cursor += sizeof (UINT32);
|
cursor += sizeof (UINT32);
|
||||||
*(UINT16 *)cursor = DevicePathSize(dp);
|
*(UINT16 *)cursor = DevicePathSize(hddp);
|
||||||
cursor += sizeof (UINT16);
|
cursor += sizeof (UINT16);
|
||||||
StrCpy((CHAR16 *)cursor, label);
|
StrCpy((CHAR16 *)cursor, label);
|
||||||
cursor += StrLen(label)*2 + 2;
|
cursor += StrLen(label)*2 + 2;
|
||||||
CopyMem(cursor, dp, DevicePathSize(dp));
|
CopyMem(cursor, hddp, DevicePathSize(hddp));
|
||||||
cursor += DevicePathSize(dp);
|
cursor += DevicePathSize(hddp);
|
||||||
StrCpy((CHAR16 *)cursor, arguments);
|
StrCpy((CHAR16 *)cursor, arguments);
|
||||||
|
|
||||||
Print(L"Creating boot entry \"%s\" with label \"%s\" "
|
Print(L"Creating boot entry \"%s\" with label \"%s\" "
|
||||||
L"for file \"%s\"\n",
|
L"for file \"%s\"\n",
|
||||||
varname, label, filename);
|
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,
|
rc = uefi_call_wrapper(RT->SetVariable, 5, varname,
|
||||||
&global, EFI_VARIABLE_NON_VOLATILE |
|
&global, EFI_VARIABLE_NON_VOLATILE |
|
||||||
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
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))
|
if (EFI_ERROR(rc))
|
||||||
return 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);
|
dph = DevicePathFromHandle(this_image->DeviceHandle);
|
||||||
if (!dph) {
|
if (!dph) {
|
||||||
@ -262,19 +296,31 @@ add_to_boot_list(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename, CHAR16 *
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
dpf = FileDevicePath(fh, fullpath);
|
file = FileDevicePath(fh, fullpath);
|
||||||
if (!dpf) {
|
if (!file) {
|
||||||
rc = EFI_OUT_OF_RESOURCES;
|
rc = EFI_OUT_OF_RESOURCES;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
dp = AppendDevicePath(dph, dpf);
|
full_device_path = AppendDevicePath(dph, file);
|
||||||
if (!dp) {
|
if (!full_device_path) {
|
||||||
rc = EFI_OUT_OF_RESOURCES;
|
rc = EFI_OUT_OF_RESOURCES;
|
||||||
goto err;
|
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
|
#ifdef DEBUG_FALLBACK
|
||||||
|
{
|
||||||
UINTN s = DevicePathSize(dp);
|
UINTN s = DevicePathSize(dp);
|
||||||
int i;
|
int i;
|
||||||
UINT8 *dpv = (void *)dp;
|
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);
|
CHAR16 *dps = DevicePathToStr(dp);
|
||||||
Print(L"device path: \"%s\"\n", dps);
|
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:
|
err:
|
||||||
if (dpf)
|
if (file)
|
||||||
FreePool(dpf);
|
FreePool(file);
|
||||||
|
if (full_device_path)
|
||||||
|
FreePool(full_device_path);
|
||||||
if (dp)
|
if (dp)
|
||||||
FreePool(dp);
|
FreePool(dp);
|
||||||
if (fullpath)
|
if (fullpath)
|
||||||
@ -629,8 +671,19 @@ try_start_first_option(EFI_HANDLE parent_image_handle)
|
|||||||
first_new_option, NULL, 0,
|
first_new_option, NULL, 0,
|
||||||
&image_handle);
|
&image_handle);
|
||||||
if (EFI_ERROR(rc)) {
|
if (EFI_ERROR(rc)) {
|
||||||
Print(L"LoadImage failed: %d\n", rc);
|
CHAR16 *dps = DevicePathToStr(first_new_option);
|
||||||
uefi_call_wrapper(BS->Stall, 1, 2000000);
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -644,7 +697,7 @@ try_start_first_option(EFI_HANDLE parent_image_handle)
|
|||||||
rc = uefi_call_wrapper(BS->StartImage, 3, image_handle, NULL, NULL);
|
rc = uefi_call_wrapper(BS->StartImage, 3, image_handle, NULL, NULL);
|
||||||
if (EFI_ERROR(rc)) {
|
if (EFI_ERROR(rc)) {
|
||||||
Print(L"StartImage failed: %d\n", rc);
|
Print(L"StartImage failed: %d\n", rc);
|
||||||
uefi_call_wrapper(BS->Stall, 1, 2000000);
|
uefi_call_wrapper(BS->Stall, 1, 500000000);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user