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.
This commit is contained in:
Jan Janssen
2023-02-22 21:54:11 +01:00
parent 8e760b3fcd
commit e6d7dc9ada
12 changed files with 155 additions and 135 deletions
+1
View File
@@ -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"
+1
View File
@@ -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"
+134
View File
@@ -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;
}
+10
View File
@@ -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);
+1
View File
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "device-path-util.h"
#include "drivers.h"
#include "util.h"
+2
View File
@@ -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',
+3 -27
View File
@@ -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;
}
+1
View File
@@ -8,6 +8,7 @@
* https://github.com/mjg59/efitools
*/
#include "device-path-util.h"
#include "secure-boot.h"
#include "shim.h"
#include "util.h"
+1
View File
@@ -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"
-85
View File
@@ -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))
-2
View File
@@ -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;
+1 -21
View File
@@ -4,6 +4,7 @@
# include <cpuid.h>
#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
*