diff --git a/docs/BOOT_LOADER_INTERFACE.md b/docs/BOOT_LOADER_INTERFACE.md
index f7be50421c..fc9336085b 100644
--- a/docs/BOOT_LOADER_INTERFACE.md
+++ b/docs/BOOT_LOADER_INTERFACE.md
@@ -31,7 +31,11 @@ variables. All EFI variables use the vendor UUID
* The EFI variable `LoaderConfigTimeout` contains the boot menu timeout
currently in use. It may be modified both by the boot loader and by the
host. The value should be formatted as numeric, NUL-terminated, decimal
- string, in UTF-16. The time is specified in µs.
+ string, in UTF-16. The time is specified in seconds. A value of `menu-force`
+ will disable the timeout and show the menu indefinitely. If set to `0` or
+ `menu-hidden` the default entry is booted immediately without showing a menu.
+ The boot loader should provide a way to interrupt this by for example
+ listening for key presses for a brief moment before booting.
* Similarly, the EFI variable `LoaderConfigTimeoutOneShot` contains a boot menu
timeout for a single following boot. It is set by the OS in order to request
diff --git a/man/systemd-boot.xml b/man/systemd-boot.xml
index 99a749b327..7a2d3ec826 100644
--- a/man/systemd-boot.xml
+++ b/man/systemd-boot.xml
@@ -257,12 +257,13 @@
Esc
+ Ctrlc
Abort the edit and quit the editor
Ctrlk
- Clear the command line
+ Clear the command line forwards
@@ -272,6 +273,7 @@
+ CtrlDel
Altd
Delete word forwards
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index 9c1d95e672..a7ef57cb99 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -254,6 +254,7 @@ static bool line_edit(
cursor_left(&cursor, &first);
continue;
+ case KEYPRESS(EFI_CONTROL_PRESSED, SCAN_DELETE, 0):
case KEYPRESS(EFI_ALT_PRESSED, 0, 'd'):
/* kill-word */
clear = 0;
@@ -317,8 +318,8 @@ static bool line_edit(
case KEYPRESS(0, 0, CHAR_LINEFEED):
case KEYPRESS(0, 0, CHAR_CARRIAGE_RETURN):
- case KEYPRESS(0, CHAR_CARRIAGE_RETURN, 0): /* EZpad Mini 4s firmware sends malformed events */
- case KEYPRESS(0, CHAR_CARRIAGE_RETURN, CHAR_CARRIAGE_RETURN): /* Teclast X98+ II firmware sends malformed events */
+ case KEYPRESS(0, SCAN_F3, 0): /* EZpad Mini 4s firmware sends malformed events */
+ case KEYPRESS(0, SCAN_F3, CHAR_CARRIAGE_RETURN): /* Teclast X98+ II firmware sends malformed events */
if (!streq16(line, *line_in)) {
free(*line_in);
*line_in = TAKE_PTR(line);
@@ -868,8 +869,8 @@ static bool menu_run(
case KEYPRESS(0, 0, CHAR_LINEFEED):
case KEYPRESS(0, 0, CHAR_CARRIAGE_RETURN):
- case KEYPRESS(0, CHAR_CARRIAGE_RETURN, 0): /* EZpad Mini 4s firmware sends malformed events */
- case KEYPRESS(0, CHAR_CARRIAGE_RETURN, CHAR_CARRIAGE_RETURN): /* Teclast X98+ II firmware sends malformed events */
+ case KEYPRESS(0, SCAN_F3, 0): /* EZpad Mini 4s firmware sends malformed events */
+ case KEYPRESS(0, SCAN_F3, CHAR_CARRIAGE_RETURN): /* Teclast X98+ II firmware sends malformed events */
case KEYPRESS(0, SCAN_RIGHT, 0):
exit = true;
break;
@@ -1036,11 +1037,20 @@ static bool menu_run(
}
if (timeout_efivar_saved != config->timeout_sec_efivar) {
- if (config->timeout_sec_efivar == TIMEOUT_UNSET)
+ switch (config->timeout_sec_efivar) {
+ case TIMEOUT_UNSET:
efivar_set(LOADER_GUID, L"LoaderConfigTimeout", NULL, EFI_VARIABLE_NON_VOLATILE);
- else
+ break;
+ case TIMEOUT_MENU_FORCE:
+ efivar_set(LOADER_GUID, u"LoaderConfigTimeout", u"menu-force", EFI_VARIABLE_NON_VOLATILE);
+ break;
+ case TIMEOUT_MENU_HIDDEN:
+ efivar_set(LOADER_GUID, u"LoaderConfigTimeout", u"menu-hidden", EFI_VARIABLE_NON_VOLATILE);
+ break;
+ default:
efivar_set_uint_string(LOADER_GUID, L"LoaderConfigTimeout",
config->timeout_sec_efivar, EFI_VARIABLE_NON_VOLATILE);
+ }
}
clear_screen(COLOR_NORMAL);
@@ -1531,6 +1541,34 @@ static void config_entry_add_type1(
TAKE_PTR(entry);
}
+static EFI_STATUS efivar_get_timeout(const char16_t *var, uint32_t *ret_value) {
+ _cleanup_free_ char16_t *value = NULL;
+ EFI_STATUS err;
+
+ assert(var);
+ assert(ret_value);
+
+ err = efivar_get(LOADER_GUID, var, &value);
+ if (err != EFI_SUCCESS)
+ return err;
+
+ if (streq16(value, u"menu-force")) {
+ *ret_value = TIMEOUT_MENU_FORCE;
+ return EFI_SUCCESS;
+ }
+ if (streq16(value, u"menu-hidden")) {
+ *ret_value = TIMEOUT_MENU_HIDDEN;
+ return EFI_SUCCESS;
+ }
+
+ uint64_t timeout;
+ if (!parse_number16(value, &timeout, NULL))
+ return EFI_INVALID_PARAMETER;
+
+ *ret_value = MIN(timeout, TIMEOUT_TYPE_MAX);
+ return EFI_SUCCESS;
+}
+
static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
_cleanup_free_ char *content = NULL;
UINTN value;
@@ -1556,20 +1594,20 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
if (err == EFI_SUCCESS)
config_defaults_load_from_file(config, content);
- err = efivar_get_uint_string(LOADER_GUID, L"LoaderConfigTimeout", &value);
- if (err == EFI_SUCCESS) {
- config->timeout_sec_efivar = MIN(value, TIMEOUT_TYPE_MAX);
+ err = efivar_get_timeout(u"LoaderConfigTimeout", &config->timeout_sec_efivar);
+ if (err == EFI_SUCCESS)
config->timeout_sec = config->timeout_sec_efivar;
- }
+ else if (err != EFI_NOT_FOUND)
+ log_error_stall(u"Error reading LoaderConfigTimeout EFI variable: %r", err);
- err = efivar_get_uint_string(LOADER_GUID, L"LoaderConfigTimeoutOneShot", &value);
+ err = efivar_get_timeout(u"LoaderConfigTimeoutOneShot", &config->timeout_sec);
if (err == EFI_SUCCESS) {
/* Unset variable now, after all it's "one shot". */
(void) efivar_set(LOADER_GUID, L"LoaderConfigTimeoutOneShot", NULL, EFI_VARIABLE_NON_VOLATILE);
- config->timeout_sec = MIN(value, TIMEOUT_TYPE_MAX);
config->force_menu = true; /* force the menu when this is set */
- }
+ } else if (err != EFI_NOT_FOUND)
+ log_error_stall(u"Error reading LoaderConfigTimeoutOneShot EFI variable: %r", err);
err = efivar_get_uint_string(LOADER_GUID, L"LoaderConfigConsoleMode", &value);
if (err == EFI_SUCCESS)
@@ -2416,14 +2454,8 @@ static void config_write_entries_to_variable(Config *config) {
p = buffer = xmalloc(sz);
- for (UINTN i = 0; i < config->entry_count; i++) {
- UINTN l;
-
- l = strsize16(config->entries[i]->id);
- memcpy(p, config->entries[i]->id, l);
-
- p += l;
- }
+ for (UINTN i = 0; i < config->entry_count; i++)
+ p = mempcpy(p, config->entries[i]->id, strsize16(config->entries[i]->id));
assert(p == buffer + sz);
diff --git a/src/boot/efi/console.c b/src/boot/efi/console.c
index f61199ccfd..14c0008afb 100644
--- a/src/boot/efi/console.c
+++ b/src/boot/efi/console.c
@@ -132,14 +132,19 @@ EFI_STATUS console_key_read(uint64_t *key, uint64_t timeout_usec) {
if (FLAGS_SET(keydata.KeyState.KeyShiftState, EFI_SHIFT_STATE_VALID)) {
/* Do not distinguish between left and right keys (set both flags). */
- if (keydata.KeyState.KeyShiftState & EFI_SHIFT_PRESSED)
- shift |= EFI_SHIFT_PRESSED;
if (keydata.KeyState.KeyShiftState & EFI_CONTROL_PRESSED)
shift |= EFI_CONTROL_PRESSED;
if (keydata.KeyState.KeyShiftState & EFI_ALT_PRESSED)
shift |= EFI_ALT_PRESSED;
if (keydata.KeyState.KeyShiftState & EFI_LOGO_PRESSED)
shift |= EFI_LOGO_PRESSED;
+
+ /* Shift is not supposed to be reported for keys that can be represented as uppercase
+ * unicode chars (Shift+f is reported as F instead). Some firmware does it anyway, so
+ * filter those out. */
+ if ((keydata.KeyState.KeyShiftState & EFI_SHIFT_PRESSED) &&
+ keydata.Key.UnicodeChar == 0)
+ shift |= EFI_SHIFT_PRESSED;
}
/* 32 bit modifier keys + 16 bit scan code + 16 bit unicode */
diff --git a/src/boot/efi/cpio.c b/src/boot/efi/cpio.c
index 9ffa935e0f..b21cf53b46 100644
--- a/src/boot/efi/cpio.c
+++ b/src/boot/efi/cpio.c
@@ -116,8 +116,7 @@ static EFI_STATUS pack_cpio_one(
*cpio_buffer = a;
a = (char *) *cpio_buffer + *cpio_buffer_size;
- memcpy(a, "070701", 6); /* magic ID */
- a += 6;
+ a = mempcpy(a, "070701", 6); /* magic ID */
a = write_cpio_word(a, (*inode_counter)++); /* inode */
a = write_cpio_word(a, access_mode | 0100000 /* = S_IFREG */); /* mode */
@@ -139,16 +138,14 @@ static EFI_STATUS pack_cpio_one(
a = write_cpio_word(a, target_dir_prefix_size + fname_size + 2); /* fname size */
a = write_cpio_word(a, 0); /* "crc" */
- memcpy(a, target_dir_prefix, target_dir_prefix_size);
- a += target_dir_prefix_size;
+ a = mempcpy(a, target_dir_prefix, target_dir_prefix_size);
*(a++) = '/';
a = mangle_filename(a, fname);
/* Pad to next multiple of 4 */
a = pad4(a, *cpio_buffer);
- memcpy(a, contents, contents_size);
- a += contents_size;
+ a = mempcpy(a, contents, contents_size);
/* Pad to next multiple of 4 */
a = pad4(a, *cpio_buffer);
@@ -198,8 +195,7 @@ static EFI_STATUS pack_cpio_dir(
*cpio_buffer = a = xrealloc(*cpio_buffer, *cpio_buffer_size, *cpio_buffer_size + l);
a = (char *) *cpio_buffer + *cpio_buffer_size;
- memcpy(a, "070701", 6); /* magic ID */
- a += 6;
+ a = mempcpy(a, "070701", 6); /* magic ID */
a = write_cpio_word(a, (*inode_counter)++); /* inode */
a = write_cpio_word(a, access_mode | 0040000 /* = S_IFDIR */); /* mode */
@@ -215,8 +211,7 @@ static EFI_STATUS pack_cpio_dir(
a = write_cpio_word(a, path_size + 1); /* fname size */
a = write_cpio_word(a, 0); /* "crc" */
- memcpy(a, path, path_size + 1);
- a += path_size + 1;
+ a = mempcpy(a, path, path_size + 1);
/* Pad to next multiple of 4 */
a = pad4(a, *cpio_buffer);
diff --git a/src/boot/efi/disk.c b/src/boot/efi/disk.c
index 5f889a365c..524662603c 100644
--- a/src/boot/efi/disk.c
+++ b/src/boot/efi/disk.c
@@ -25,15 +25,14 @@ EFI_STATUS disk_get_part_uuid(EFI_HANDLE *handle, char16_t uuid[static 37]) {
if (DevicePathSubType(dp) != MEDIA_HARDDRIVE_DP)
continue;
- HARDDRIVE_DEVICE_PATH *hd = (HARDDRIVE_DEVICE_PATH *) dp;
- if (hd->SignatureType != SIGNATURE_TYPE_GUID)
+ /* The HD device path may be misaligned. */
+ HARDDRIVE_DEVICE_PATH hd;
+ memcpy(&hd, dp, MIN(sizeof(hd), (size_t) DevicePathNodeLength(dp)));
+
+ if (hd.SignatureType != SIGNATURE_TYPE_GUID)
continue;
- /* Use memcpy in case the device path node is misaligned. */
- EFI_GUID sig;
- memcpy(&sig, hd->Signature, sizeof(hd->Signature));
-
- GuidToString(uuid, &sig);
+ GuidToString(uuid, (EFI_GUID *) &hd.Signature);
return EFI_SUCCESS;
}
diff --git a/src/boot/efi/efi-string.h b/src/boot/efi/efi-string.h
index c25349c0e1..57899c978b 100644
--- a/src/boot/efi/efi-string.h
+++ b/src/boot/efi/efi-string.h
@@ -112,6 +112,13 @@ bool parse_number16(const char16_t *s, uint64_t *ret_u, const char16_t **ret_tai
# define memcmp __builtin_memcmp
# define memcpy __builtin_memcpy
# define memset __builtin_memset
+
+static inline void *mempcpy(void * restrict dest, const void * restrict src, size_t n) {
+ if (!dest || !src || n == 0)
+ return dest;
+ memcpy(dest, src, n);
+ return (uint8_t *) dest + n;
+}
#endif
/* The actual implementations of builtins with efi_ prefix so we can unit test them. */
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index 003ae8c99a..3f6832e0c2 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -69,8 +69,7 @@ static EFI_STATUS combine_initrd(
/* Order matters, the real initrd must come first, since it might include microcode updates
* which the kernel only looks for in the first cpio archive */
- memcpy(p, PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size);
- p += initrd_size;
+ p = mempcpy(p, PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size);
pad = ALIGN4(initrd_size) - initrd_size;
if (pad > 0) {
@@ -79,20 +78,12 @@ static EFI_STATUS combine_initrd(
}
}
- if (credential_initrd) {
- memcpy(p, credential_initrd, credential_initrd_size);
- p += credential_initrd_size;
- }
-
- if (global_credential_initrd) {
- memcpy(p, global_credential_initrd, global_credential_initrd_size);
- p += global_credential_initrd_size;
- }
-
- if (sysext_initrd) {
- memcpy(p, sysext_initrd, sysext_initrd_size);
- p += sysext_initrd_size;
- }
+ if (credential_initrd)
+ p = mempcpy(p, credential_initrd, credential_initrd_size);
+ if (global_credential_initrd)
+ p = mempcpy(p, global_credential_initrd, global_credential_initrd_size);
+ if (sysext_initrd)
+ p = mempcpy(p, sysext_initrd, sysext_initrd_size);
assert((uint8_t*) PHYSICAL_ADDRESS_TO_POINTER(base) + n == p);
diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c
index a41dbaa43e..e17a8e18a4 100644
--- a/src/boot/efi/util.c
+++ b/src/boot/efi/util.c
@@ -751,21 +751,18 @@ EFI_STATUS make_file_device_path(EFI_HANDLE device, const char16_t *file, EFI_DE
end_node = NextDevicePathNode(end_node);
size_t file_size = strsize16(file);
- size_t dp_size = ((uint8_t *) end_node - (uint8_t *) dp) + END_DEVICE_PATH_LENGTH;
+ size_t dp_size = (uint8_t *) end_node - (uint8_t *) dp;
/* Make a copy that can also hold a file media device path. */
- *ret_dp = xmalloc(dp_size + file_size + SIZE_OF_FILEPATH_DEVICE_PATH);
- memcpy(*ret_dp, dp, dp_size);
+ *ret_dp = xmalloc(dp_size + file_size + SIZE_OF_FILEPATH_DEVICE_PATH + END_DEVICE_PATH_LENGTH);
+ dp = mempcpy(*ret_dp, dp, dp_size);
- /* Point dp to the end node of the copied device path. */
- dp = (EFI_DEVICE_PATH *) ((uint8_t *) *ret_dp + dp_size - END_DEVICE_PATH_LENGTH);
-
- /* Replace end node with file media device path. */
- FILEPATH_DEVICE_PATH *file_dp = (FILEPATH_DEVICE_PATH *) dp;
- file_dp->Header.Type = MEDIA_DEVICE_PATH;
- file_dp->Header.SubType = MEDIA_FILEPATH_DP;
- memcpy(&file_dp->PathName, file, file_size);
- SetDevicePathNodeLength(&file_dp->Header, SIZE_OF_FILEPATH_DEVICE_PATH + file_size);
+ /* Replace end node with file media device path. Use memcpy() in case dp is unaligned (if accessed as
+ * FILEPATH_DEVICE_PATH). */
+ dp->Type = MEDIA_DEVICE_PATH;
+ dp->SubType = MEDIA_FILEPATH_DP;
+ memcpy((uint8_t *) dp + offsetof(FILEPATH_DEVICE_PATH, PathName), file, file_size);
+ SetDevicePathNodeLength(dp, offsetof(FILEPATH_DEVICE_PATH, PathName) + file_size);
dp = NextDevicePathNode(dp);
SetDevicePathEndNode(dp);
diff --git a/src/boot/efi/xbootldr.c b/src/boot/efi/xbootldr.c
index 3ccf9fa8b1..e5b9ca7268 100644
--- a/src/boot/efi/xbootldr.c
+++ b/src/boot/efi/xbootldr.c
@@ -12,33 +12,29 @@ union GptHeaderBuffer {
uint8_t space[CONST_ALIGN_TO(sizeof(EFI_PARTITION_TABLE_HEADER), 512)];
};
-static EFI_DEVICE_PATH *path_chop(EFI_DEVICE_PATH *path, EFI_DEVICE_PATH *node) {
+static EFI_DEVICE_PATH *path_replace_hd(
+ const EFI_DEVICE_PATH *path,
+ const EFI_DEVICE_PATH *node,
+ const HARDDRIVE_DEVICE_PATH *new_node) {
+
+ /* Create a new device path as a copy of path, while chopping off the remainder starting at the given
+ * node. If new_node is provided, it is appended at the end of the new path. */
+
assert(path);
assert(node);
- UINTN len = (uint8_t *) node - (uint8_t *) path;
- EFI_DEVICE_PATH *chopped = xmalloc(len + END_DEVICE_PATH_LENGTH);
+ size_t len = (uint8_t *) node - (uint8_t *) path, new_node_len = 0;
+ if (new_node)
+ new_node_len = DevicePathNodeLength(&new_node->Header);
- memcpy(chopped, path, len);
- SetDevicePathEndNode((EFI_DEVICE_PATH *) ((uint8_t *) chopped + len));
+ EFI_DEVICE_PATH *ret = xmalloc(len + new_node_len + END_DEVICE_PATH_LENGTH);
+ EFI_DEVICE_PATH *end = mempcpy(ret, path, len);
- return chopped;
-}
+ if (new_node)
+ end = mempcpy(end, new_node, new_node_len);
-static EFI_DEVICE_PATH *path_dup(const EFI_DEVICE_PATH *dp) {
- assert(dp);
-
- const EFI_DEVICE_PATH *node = dp;
- size_t size = 0;
- while (!IsDevicePathEnd(node)) {
- size += DevicePathNodeLength(node);
- node = NextDevicePathNode(node);
- }
- size += DevicePathNodeLength(node);
-
- EFI_DEVICE_PATH *dup = xmalloc(size);
- memcpy(dup, dp, size);
- return dup;
+ SetDevicePathEndNode(end);
+ return ret;
}
static bool verify_gpt(union GptHeaderBuffer *gpt_header_buffer, EFI_LBA lba_expected) {
@@ -71,7 +67,7 @@ static bool verify_gpt(union GptHeaderBuffer *gpt_header_buffer, EFI_LBA lba_exp
if (h->MyLBA != lba_expected)
return false;
- if (h->SizeOfPartitionEntry < sizeof(EFI_PARTITION_ENTRY))
+ if ((h->SizeOfPartitionEntry % sizeof(EFI_PARTITION_ENTRY)) != 0)
return false;
if (h->NumberOfPartitionEntries <= 0 || h->NumberOfPartitionEntries > 1024)
@@ -134,28 +130,33 @@ static EFI_STATUS try_gpt(
/* Now we can finally look for xbootloader partitions. */
for (UINTN i = 0; i < gpt.gpt_header.NumberOfPartitionEntries; i++) {
- EFI_PARTITION_ENTRY *entry;
- EFI_LBA start, end;
-
- entry = (EFI_PARTITION_ENTRY*) ((uint8_t*) entries + gpt.gpt_header.SizeOfPartitionEntry * i);
+ EFI_PARTITION_ENTRY *entry =
+ (EFI_PARTITION_ENTRY *) ((uint8_t *) entries + gpt.gpt_header.SizeOfPartitionEntry * i);
if (memcmp(&entry->PartitionTypeGUID, XBOOTLDR_GUID, sizeof(entry->PartitionTypeGUID)) != 0)
continue;
- /* Let's use memcpy(), in case the structs are not aligned (they really should be though) */
- memcpy(&start, &entry->StartingLBA, sizeof(start));
- memcpy(&end, &entry->EndingLBA, sizeof(end));
-
- if (end < start) /* Bogus? */
+ if (entry->EndingLBA < entry->StartingLBA) /* Bogus? */
continue;
- ret_hd->PartitionNumber = i + 1;
- ret_hd->PartitionStart = start;
- ret_hd->PartitionSize = end - start + 1;
- ret_hd->MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
- ret_hd->SignatureType = SIGNATURE_TYPE_GUID;
+ *ret_hd = (HARDDRIVE_DEVICE_PATH) {
+ .Header = {
+ .Type = MEDIA_DEVICE_PATH,
+ .SubType = MEDIA_HARDDRIVE_DP,
+ },
+ .PartitionNumber = i + 1,
+ .PartitionStart = entry->StartingLBA,
+ .PartitionSize = entry->EndingLBA - entry->StartingLBA + 1,
+ .MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER,
+ .SignatureType = SIGNATURE_TYPE_GUID,
+ };
memcpy(ret_hd->Signature, &entry->UniquePartitionGUID, sizeof(ret_hd->Signature));
+ /* HARDDRIVE_DEVICE_PATH has padding, which at least OVMF does not like. */
+ SetDevicePathNodeLength(
+ &ret_hd->Header,
+ offsetof(HARDDRIVE_DEVICE_PATH, SignatureType) + sizeof(ret_hd->SignatureType));
+
return EFI_SUCCESS;
}
@@ -192,7 +193,7 @@ static EFI_STATUS find_device(EFI_HANDLE *device, EFI_DEVICE_PATH **ret_device_p
/* Chop off the partition part, leaving us with the full path to the disk itself. */
_cleanup_free_ EFI_DEVICE_PATH *disk_path = NULL;
- EFI_DEVICE_PATH *p = disk_path = path_chop(partition_path, part_node);
+ EFI_DEVICE_PATH *p = disk_path = path_replace_hd(partition_path, part_node, NULL);
EFI_HANDLE disk_handle;
EFI_BLOCK_IO_PROTOCOL *block_io;
@@ -214,7 +215,6 @@ static EFI_STATUS find_device(EFI_HANDLE *device, EFI_DEVICE_PATH **ret_device_p
/* Try several copies of the GPT header, in case one is corrupted */
EFI_LBA backup_lba = 0;
- HARDDRIVE_DEVICE_PATH hd = *((HARDDRIVE_DEVICE_PATH *) part_node);
for (UINTN nr = 0; nr < 3; nr++) {
EFI_LBA lba;
@@ -230,6 +230,7 @@ static EFI_STATUS find_device(EFI_HANDLE *device, EFI_DEVICE_PATH **ret_device_p
else
continue;
+ HARDDRIVE_DEVICE_PATH hd;
err = try_gpt(
block_io, lba,
nr == 0 ? &backup_lba : NULL, /* Only get backup LBA location from first GPT header. */
@@ -243,9 +244,7 @@ static EFI_STATUS find_device(EFI_HANDLE *device, EFI_DEVICE_PATH **ret_device_p
}
/* Patch in the data we found */
- EFI_DEVICE_PATH *xboot_path = path_dup(partition_path);
- memcpy((uint8_t *) xboot_path + ((uint8_t *) part_node - (uint8_t *) partition_path), &hd, sizeof(hd));
- *ret_device_path = xboot_path;
+ *ret_device_path = path_replace_hd(partition_path, part_node, &hd);
return EFI_SUCCESS;
}