From e6d7dc9ada482e1a7a26197a5bf93714292c7958 Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Sat, 7 Jan 2023 11:39:07 +0100 Subject: [PATCH] boot: Split out device path functions No code changes aside from renaming path_replace_hd() and making its parameter take any device path node type. --- src/boot/efi/boot.c | 1 + src/boot/efi/cpio.c | 1 + src/boot/efi/device-path-util.c | 134 ++++++++++++++++++++++++++++++++ src/boot/efi/device-path-util.h | 10 +++ src/boot/efi/drivers.c | 1 + src/boot/efi/meson.build | 2 + src/boot/efi/part-discovery.c | 30 +------ src/boot/efi/shim.c | 1 + src/boot/efi/stub.c | 1 + src/boot/efi/util.c | 85 -------------------- src/boot/efi/util.h | 2 - src/boot/efi/vmm.c | 22 +----- 12 files changed, 155 insertions(+), 135 deletions(-) create mode 100644 src/boot/efi/device-path-util.c create mode 100644 src/boot/efi/device-path-util.h diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 3bd3469f82..ee507e379a 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -3,6 +3,7 @@ #include "bcd.h" #include "bootspec-fundamental.h" #include "console.h" +#include "device-path-util.h" #include "devicetree.h" #include "drivers.h" #include "efivars-fundamental.h" diff --git a/src/boot/efi/cpio.c b/src/boot/efi/cpio.c index 2e971a9167..acfefbb001 100644 --- a/src/boot/efi/cpio.c +++ b/src/boot/efi/cpio.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "cpio.h" +#include "device-path-util.h" #include "measure.h" #include "proto/device-path.h" #include "util.h" diff --git a/src/boot/efi/device-path-util.c b/src/boot/efi/device-path-util.c new file mode 100644 index 0000000000..4e0b3db611 --- /dev/null +++ b/src/boot/efi/device-path-util.c @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "device-path-util.h" +#include "proto/device-path.h" +#include "util.h" + +EFI_STATUS make_file_device_path(EFI_HANDLE device, const char16_t *file, EFI_DEVICE_PATH **ret_dp) { + EFI_STATUS err; + EFI_DEVICE_PATH *dp; + + assert(file); + assert(ret_dp); + + err = BS->HandleProtocol(device, MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL), (void **) &dp); + if (err != EFI_SUCCESS) + return err; + + EFI_DEVICE_PATH *end_node = dp; + while (!IsDevicePathEnd(end_node)) + end_node = NextDevicePathNode(end_node); + + size_t file_size = strsize16(file); + 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 + sizeof(FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH)); + dp = mempcpy(*ret_dp, dp, dp_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; + dp->Length = sizeof(FILEPATH_DEVICE_PATH) + file_size; + memcpy((uint8_t *) dp + sizeof(FILEPATH_DEVICE_PATH), file, file_size); + + dp = NextDevicePathNode(dp); + SetDevicePathEndNode(dp); + return EFI_SUCCESS; +} + +EFI_STATUS device_path_to_str(const EFI_DEVICE_PATH *dp, char16_t **ret) { + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *dp_to_text; + EFI_STATUS err; + _cleanup_free_ char16_t *str = NULL; + + assert(dp); + assert(ret); + + err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_DEVICE_PATH_TO_TEXT_PROTOCOL), NULL, (void **) &dp_to_text); + if (err != EFI_SUCCESS) { + /* If the device path to text protocol is not available we can still do a best-effort attempt + * to convert it ourselves if we are given filepath-only device path. */ + + size_t size = 0; + for (const EFI_DEVICE_PATH *node = dp; !IsDevicePathEnd(node); + node = NextDevicePathNode(node)) { + + if (DevicePathType(node) != MEDIA_DEVICE_PATH || + DevicePathSubType(node) != MEDIA_FILEPATH_DP) + return err; + + size_t path_size = DevicePathNodeLength(node); + if (path_size <= offsetof(FILEPATH_DEVICE_PATH, PathName) || path_size % sizeof(char16_t)) + return EFI_INVALID_PARAMETER; + path_size -= offsetof(FILEPATH_DEVICE_PATH, PathName); + + _cleanup_free_ char16_t *old = str; + str = xmalloc(size + path_size); + if (old) { + memcpy(str, old, size); + str[size / sizeof(char16_t) - 1] = '\\'; + } + + memcpy(str + (size / sizeof(char16_t)), + ((uint8_t *) node) + offsetof(FILEPATH_DEVICE_PATH, PathName), + path_size); + size += path_size; + } + + *ret = TAKE_PTR(str); + return EFI_SUCCESS; + } + + str = dp_to_text->ConvertDevicePathToText(dp, false, false); + if (!str) + return EFI_OUT_OF_RESOURCES; + + *ret = TAKE_PTR(str); + return EFI_SUCCESS; +} + +bool device_path_startswith(const EFI_DEVICE_PATH *dp, const EFI_DEVICE_PATH *start) { + if (!start) + return true; + if (!dp) + return false; + for (;;) { + if (IsDevicePathEnd(start)) + return true; + if (IsDevicePathEnd(dp)) + return false; + size_t l1 = DevicePathNodeLength(start); + size_t l2 = DevicePathNodeLength(dp); + if (l1 != l2) + return false; + if (memcmp(dp, start, l1) != 0) + return false; + start = NextDevicePathNode(start); + dp = NextDevicePathNode(dp); + } +} + +EFI_DEVICE_PATH *device_path_replace_node( + const EFI_DEVICE_PATH *path, const EFI_DEVICE_PATH *node, const EFI_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); + + size_t len = (uint8_t *) node - (uint8_t *) path, new_node_len = 0; + if (new_node) + new_node_len = DevicePathNodeLength(new_node); + + EFI_DEVICE_PATH *ret = xmalloc(len + new_node_len + sizeof(EFI_DEVICE_PATH)); + EFI_DEVICE_PATH *end = mempcpy(ret, path, len); + + if (new_node) + end = mempcpy(end, new_node, new_node_len); + + SetDevicePathEndNode(end); + return ret; +} diff --git a/src/boot/efi/device-path-util.h b/src/boot/efi/device-path-util.h new file mode 100644 index 0000000000..acc6ed0b74 --- /dev/null +++ b/src/boot/efi/device-path-util.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "efi.h" + +EFI_STATUS make_file_device_path(EFI_HANDLE device, const char16_t *file, EFI_DEVICE_PATH **ret_dp); +EFI_STATUS device_path_to_str(const EFI_DEVICE_PATH *dp, char16_t **ret); +bool device_path_startswith(const EFI_DEVICE_PATH *dp, const EFI_DEVICE_PATH *start); +EFI_DEVICE_PATH *device_path_replace_node( + const EFI_DEVICE_PATH *path, const EFI_DEVICE_PATH *node, const EFI_DEVICE_PATH *new_node); diff --git a/src/boot/efi/drivers.c b/src/boot/efi/drivers.c index 25bf694723..067455771f 100644 --- a/src/boot/efi/drivers.c +++ b/src/boot/efi/drivers.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include "device-path-util.h" #include "drivers.h" #include "util.h" diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build index e6166075be..bf595c3390 100644 --- a/src/boot/efi/meson.build +++ b/src/boot/efi/meson.build @@ -332,6 +332,7 @@ efi_headers = files( 'bcd.h', 'console.h', 'cpio.h', + 'device-path-util.h', 'devicetree.h', 'drivers.h', 'efi-string.h', @@ -366,6 +367,7 @@ efi_headers = files( common_sources = files( 'console.c', + 'device-path-util.c', 'devicetree.c', 'drivers.c', 'efi-string.c', diff --git a/src/boot/efi/part-discovery.c b/src/boot/efi/part-discovery.c index 5d39995509..e71daf0382 100644 --- a/src/boot/efi/part-discovery.c +++ b/src/boot/efi/part-discovery.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include "device-path-util.h" #include "part-discovery.h" #include "proto/block-io.h" #include "proto/device-path.h" @@ -29,31 +30,6 @@ typedef struct { } _packed_ GptHeader; assert_cc(sizeof(GptHeader) == 512); -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); - - size_t len = (uint8_t *) node - (uint8_t *) path, new_node_len = 0; - if (new_node) - new_node_len = DevicePathNodeLength(&new_node->Header); - - EFI_DEVICE_PATH *ret = xmalloc(len + new_node_len + sizeof(EFI_DEVICE_PATH)); - EFI_DEVICE_PATH *end = mempcpy(ret, path, len); - - if (new_node) - end = mempcpy(end, new_node, new_node_len); - - SetDevicePathEndNode(end); - return ret; -} - static bool verify_gpt(/*const*/ GptHeader *h, EFI_LBA lba_expected) { uint32_t crc32, crc32_saved; EFI_STATUS err; @@ -204,7 +180,7 @@ static EFI_STATUS find_device(const EFI_GUID *type, EFI_HANDLE *device, EFI_DEVI /* 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_replace_hd(partition_path, part_node, NULL); + EFI_DEVICE_PATH *p = disk_path = device_path_replace_node(partition_path, part_node, NULL); EFI_HANDLE disk_handle; EFI_BLOCK_IO_PROTOCOL *block_io; @@ -258,7 +234,7 @@ static EFI_STATUS find_device(const EFI_GUID *type, EFI_HANDLE *device, EFI_DEVI } /* Patch in the data we found */ - *ret_device_path = path_replace_hd(partition_path, part_node, &hd); + *ret_device_path = device_path_replace_node(partition_path, part_node, (EFI_DEVICE_PATH *) &hd); return EFI_SUCCESS; } diff --git a/src/boot/efi/shim.c b/src/boot/efi/shim.c index e0bb470cf2..dda727ee8e 100644 --- a/src/boot/efi/shim.c +++ b/src/boot/efi/shim.c @@ -8,6 +8,7 @@ * https://github.com/mjg59/efitools */ +#include "device-path-util.h" #include "secure-boot.h" #include "shim.h" #include "util.h" diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c index 4b8e1e69d9..2635445b04 100644 --- a/src/boot/efi/stub.c +++ b/src/boot/efi/stub.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "cpio.h" +#include "device-path-util.h" #include "devicetree.h" #include "graphics.h" #include "linux.h" diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c index 96c62e6bfa..19c4788b8f 100644 --- a/src/boot/efi/util.c +++ b/src/boot/efi/util.c @@ -622,91 +622,6 @@ EFI_STATUS open_volume(EFI_HANDLE device, EFI_FILE **ret_file) { return EFI_SUCCESS; } -EFI_STATUS make_file_device_path(EFI_HANDLE device, const char16_t *file, EFI_DEVICE_PATH **ret_dp) { - EFI_STATUS err; - EFI_DEVICE_PATH *dp; - - assert(file); - assert(ret_dp); - - err = BS->HandleProtocol(device, MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL), (void **) &dp); - if (err != EFI_SUCCESS) - return err; - - EFI_DEVICE_PATH *end_node = dp; - while (!IsDevicePathEnd(end_node)) - end_node = NextDevicePathNode(end_node); - - size_t file_size = strsize16(file); - 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 + sizeof(FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH)); - dp = mempcpy(*ret_dp, dp, dp_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; - dp->Length = sizeof(FILEPATH_DEVICE_PATH) + file_size; - memcpy((uint8_t *) dp + sizeof(FILEPATH_DEVICE_PATH), file, file_size); - - dp = NextDevicePathNode(dp); - SetDevicePathEndNode(dp); - return EFI_SUCCESS; -} - -EFI_STATUS device_path_to_str(const EFI_DEVICE_PATH *dp, char16_t **ret) { - EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *dp_to_text; - EFI_STATUS err; - _cleanup_free_ char16_t *str = NULL; - - assert(dp); - assert(ret); - - err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_DEVICE_PATH_TO_TEXT_PROTOCOL), NULL, (void **) &dp_to_text); - if (err != EFI_SUCCESS) { - /* If the device path to text protocol is not available we can still do a best-effort attempt - * to convert it ourselves if we are given filepath-only device path. */ - - size_t size = 0; - for (const EFI_DEVICE_PATH *node = dp; !IsDevicePathEnd(node); - node = NextDevicePathNode(node)) { - - if (DevicePathType(node) != MEDIA_DEVICE_PATH || - DevicePathSubType(node) != MEDIA_FILEPATH_DP) - return err; - - size_t path_size = DevicePathNodeLength(node); - if (path_size <= offsetof(FILEPATH_DEVICE_PATH, PathName) || path_size % sizeof(char16_t)) - return EFI_INVALID_PARAMETER; - path_size -= offsetof(FILEPATH_DEVICE_PATH, PathName); - - _cleanup_free_ char16_t *old = str; - str = xmalloc(size + path_size); - if (old) { - memcpy(str, old, size); - str[size / sizeof(char16_t) - 1] = '\\'; - } - - memcpy(str + (size / sizeof(char16_t)), - ((uint8_t *) node) + offsetof(FILEPATH_DEVICE_PATH, PathName), - path_size); - size += path_size; - } - - *ret = TAKE_PTR(str); - return EFI_SUCCESS; - } - - str = dp_to_text->ConvertDevicePathToText(dp, false, false); - if (!str) - return EFI_OUT_OF_RESOURCES; - - *ret = TAKE_PTR(str); - return EFI_SUCCESS; -} - void *find_configuration_table(const EFI_GUID *guid) { for (size_t i = 0; i < ST->NumberOfTableEntries; i++) if (efi_guid_equal(&ST->ConfigurationTable[i].VendorGuid, guid)) diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h index 614d83fb71..198e844971 100644 --- a/src/boot/efi/util.h +++ b/src/boot/efi/util.h @@ -184,8 +184,6 @@ static inline void beep(unsigned beep_count) {} #endif EFI_STATUS open_volume(EFI_HANDLE device, EFI_FILE **ret_file); -EFI_STATUS make_file_device_path(EFI_HANDLE device, const char16_t *file, EFI_DEVICE_PATH **ret_dp); -EFI_STATUS device_path_to_str(const EFI_DEVICE_PATH *dp, char16_t **ret); static inline bool efi_guid_equal(const EFI_GUID *a, const EFI_GUID *b) { return memcmp(a, b, sizeof(EFI_GUID)) == 0; diff --git a/src/boot/efi/vmm.c b/src/boot/efi/vmm.c index c3816e1b2d..61b50a3b94 100644 --- a/src/boot/efi/vmm.c +++ b/src/boot/efi/vmm.c @@ -4,6 +4,7 @@ # include #endif +#include "device-path-util.h" #include "drivers.h" #include "efi-string.h" #include "proto/device-path.h" @@ -39,27 +40,6 @@ bool is_direct_boot(EFI_HANDLE device) { return false; } -static bool device_path_startswith(const EFI_DEVICE_PATH *dp, const EFI_DEVICE_PATH *start) { - if (!start) - return true; - if (!dp) - return false; - for (;;) { - if (IsDevicePathEnd(start)) - return true; - if (IsDevicePathEnd(dp)) - return false; - size_t l1 = DevicePathNodeLength(start); - size_t l2 = DevicePathNodeLength(dp); - if (l1 != l2) - return false; - if (memcmp(dp, start, l1) != 0) - return false; - start = NextDevicePathNode(start); - dp = NextDevicePathNode(dp); - } -} - /* * Try find ESP when not loaded from ESP * -- 2.25.1