diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/efi_loader/Kconfig | 2 | ||||
-rw-r--r-- | lib/efi_loader/efi_boottime.c | 4 | ||||
-rw-r--r-- | lib/efi_loader/efi_device_path.c | 124 | ||||
-rw-r--r-- | lib/efi_loader/efi_device_path_utilities.c | 133 | ||||
-rw-r--r-- | lib/efi_selftest/Makefile | 1 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest.c | 14 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_devicepath.c | 2 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_devicepath_util.c | 286 |
8 files changed, 533 insertions, 33 deletions
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 83d75c4fdc..d38780b604 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -1,6 +1,8 @@ config EFI_LOADER bool "Support running EFI Applications in U-Boot" depends on (ARM || X86) && OF_LIBFDT + # We do not support bootefi booting ARMv7 in non-secure mode + depends on !ARMV7_NONSEC # We need EFI_STUB_64BIT to be set on x86_64 with EFI_STUB depends on !EFI_STUB || !X86_64 || EFI_STUB_64BIT # We need EFI_STUB_32BIT to be set on x86_32 with EFI_STUB diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 7a9449f59c..1cfdabf6eb 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -2219,7 +2219,7 @@ static efi_status_t EFIAPI efi_locate_device_path( } /* Find end of device path */ - len = efi_dp_size(*device_path); + len = efi_dp_instance_size(*device_path); /* Get all handles implementing the protocol */ ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, protocol, NULL, @@ -2234,7 +2234,7 @@ static efi_status_t EFIAPI efi_locate_device_path( if (ret != EFI_SUCCESS) continue; dp = (struct efi_device_path *)handler->protocol_interface; - len_dp = efi_dp_size(dp); + len_dp = efi_dp_instance_size(dp); /* * This handle can only be a better fit * if its device path length is longer than the best fit and diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index e965f1d88e..634dacf41b 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -149,7 +149,7 @@ static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path, struct efi_device_path **rem) { struct efi_object *efiobj; - unsigned int dp_size = efi_dp_size(dp); + efi_uintn_t dp_size = efi_dp_instance_size(dp); list_for_each_entry(efiobj, &efi_obj_list, link) { struct efi_handler *handler; @@ -170,11 +170,12 @@ static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path, * the caller. */ *rem = ((void *)dp) + - efi_dp_size(obj_dp); + efi_dp_instance_size(obj_dp); return efiobj; } else { /* Only return on exact matches */ - if (efi_dp_size(obj_dp) == dp_size) + if (efi_dp_instance_size(obj_dp) == + dp_size) return efiobj; } } @@ -229,11 +230,13 @@ const struct efi_device_path *efi_dp_last_node(const struct efi_device_path *dp) return ret; } -/* return size not including End node: */ -unsigned efi_dp_size(const struct efi_device_path *dp) +/* get size of the first device path instance excluding end node */ +efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp) { - unsigned sz = 0; + efi_uintn_t sz = 0; + if (!dp || dp->type == DEVICE_PATH_TYPE_END) + return 0; while (dp) { sz += dp->length; dp = efi_dp_next(dp); @@ -242,10 +245,25 @@ unsigned efi_dp_size(const struct efi_device_path *dp) return sz; } +/* get size of multi-instance device path excluding end node */ +efi_uintn_t efi_dp_size(const struct efi_device_path *dp) +{ + const struct efi_device_path *p = dp; + + if (!p) + return 0; + while (p->type != DEVICE_PATH_TYPE_END || + p->sub_type != DEVICE_PATH_SUB_TYPE_END) + p = (void *)p + p->length; + + return (void *)p - (void *)dp; +} + +/* copy multi-instance device path */ struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp) { struct efi_device_path *ndp; - unsigned sz = efi_dp_size(dp) + sizeof(END); + size_t sz = efi_dp_size(dp) + sizeof(END); if (!dp) return NULL; @@ -263,7 +281,10 @@ struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1, { struct efi_device_path *ret; - if (!dp1) { + if (!dp1 && !dp2) { + /* return an end node */ + ret = efi_dp_dup(&END); + } else if (!dp1) { ret = efi_dp_dup(dp2); } else if (!dp2) { ret = efi_dp_dup(dp1); @@ -275,8 +296,8 @@ struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1, if (!p) return NULL; memcpy(p, dp1, sz1); - memcpy(p + sz1, dp2, sz2); - memcpy(p + sz1 + sz2, &END, sizeof(END)); + /* the end node of the second device path has to be retained */ + memcpy(p + sz1, dp2, sz2 + sizeof(END)); ret = p; } @@ -293,7 +314,7 @@ struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp, } else if (!node) { ret = efi_dp_dup(dp); } else if (!dp) { - unsigned sz = node->length; + size_t sz = node->length; void *p = dp_alloc(sz + sizeof(END)); if (!p) return NULL; @@ -302,7 +323,7 @@ struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp, ret = p; } else { /* both dp and node are non-null */ - unsigned sz = efi_dp_size(dp); + size_t sz = efi_dp_size(dp); void *p = dp_alloc(sz + node->length + sizeof(END)); if (!p) return NULL; @@ -315,6 +336,85 @@ struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp, return ret; } +struct efi_device_path *efi_dp_create_device_node(const u8 type, + const u8 sub_type, + const u16 length) +{ + struct efi_device_path *ret; + + ret = dp_alloc(length); + if (!ret) + return ret; + ret->type = type; + ret->sub_type = sub_type; + ret->length = length; + return ret; +} + +struct efi_device_path *efi_dp_append_instance( + const struct efi_device_path *dp, + const struct efi_device_path *dpi) +{ + size_t sz, szi; + struct efi_device_path *p, *ret; + + if (!dpi) + return NULL; + if (!dp) + return efi_dp_dup(dpi); + sz = efi_dp_size(dp); + szi = efi_dp_instance_size(dpi); + p = dp_alloc(sz + szi + 2 * sizeof(END)); + if (!p) + return NULL; + ret = p; + memcpy(p, dp, sz + sizeof(END)); + p = (void *)p + sz; + p->sub_type = DEVICE_PATH_SUB_TYPE_INSTANCE_END; + p = (void *)p + sizeof(END); + memcpy(p, dpi, szi); + p = (void *)p + szi; + memcpy(p, &END, sizeof(END)); + return ret; +} + +struct efi_device_path *efi_dp_get_next_instance(struct efi_device_path **dp, + efi_uintn_t *size) +{ + size_t sz; + struct efi_device_path *p; + + if (size) + *size = 0; + if (!dp || !*dp) + return NULL; + p = *dp; + sz = efi_dp_instance_size(*dp); + p = dp_alloc(sz + sizeof(END)); + if (!p) + return NULL; + memcpy(p, *dp, sz + sizeof(END)); + *dp = (void *)*dp + sz; + if ((*dp)->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END) + *dp = (void *)*dp + sizeof(END); + else + *dp = NULL; + if (size) + *size = sz + sizeof(END); + return p; +} + +bool efi_dp_is_multi_instance(const struct efi_device_path *dp) +{ + const struct efi_device_path *p = dp; + + if (!p) + return false; + while (p->type != DEVICE_PATH_TYPE_END) + p = (void *)p + p->length; + return p->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END; +} + #ifdef CONFIG_DM /* size of device-path not including END node for device and all parents * up to the root device. diff --git a/lib/efi_loader/efi_device_path_utilities.c b/lib/efi_loader/efi_device_path_utilities.c index bc97eeee31..0ada2111db 100644 --- a/lib/efi_loader/efi_device_path_utilities.c +++ b/lib/efi_loader/efi_device_path_utilities.c @@ -12,69 +12,180 @@ const efi_guid_t efi_guid_device_path_utilities_protocol = EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID; +/* + * Get size of a device path. + * + * This function implements the GetDevicePathSize service of the device path + * utilities protocol. The device path length includes the end of path tag + * which may be an instance end. + * + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @device_path device path + * @return size in bytes + */ static efi_uintn_t EFIAPI get_device_path_size( const struct efi_device_path *device_path) { efi_uintn_t sz = 0; - EFI_ENTRY("%p", device_path); + EFI_ENTRY("%pD", device_path); /* size includes the END node: */ if (device_path) sz = efi_dp_size(device_path) + sizeof(struct efi_device_path); return EFI_EXIT(sz); } +/* + * Duplicate a device path. + * + * This function implements the DuplicateDevicePath service of the device path + * utilities protocol. + * + * The UEFI spec does not indicate what happens to the end tag. We follow the + * EDK2 logic: In case the device path ends with an end of instance tag, the + * copy will also end with an end of instance tag. + * + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @device_path device path + * @return copy of the device path + */ static struct efi_device_path * EFIAPI duplicate_device_path( const struct efi_device_path *device_path) { - EFI_ENTRY("%p", device_path); + EFI_ENTRY("%pD", device_path); return EFI_EXIT(efi_dp_dup(device_path)); } +/* + * Append device path. + * + * This function implements the AppendDevicePath service of the device path + * utilities protocol. + * + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @src1 1st device path + * @src2 2nd device path + * @return concatenated device path + */ static struct efi_device_path * EFIAPI append_device_path( const struct efi_device_path *src1, const struct efi_device_path *src2) { - EFI_ENTRY("%p, %p", src1, src2); + EFI_ENTRY("%pD, %pD", src1, src2); return EFI_EXIT(efi_dp_append(src1, src2)); } +/* + * Append device path node. + * + * This function implements the AppendDeviceNode service of the device path + * utilities protocol. + * + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @device_path device path + * @device_node device node + * @return concatenated device path + */ static struct efi_device_path * EFIAPI append_device_node( const struct efi_device_path *device_path, const struct efi_device_path *device_node) { - EFI_ENTRY("%p, %p", device_path, device_node); + EFI_ENTRY("%pD, %p", device_path, device_node); return EFI_EXIT(efi_dp_append_node(device_path, device_node)); } +/* + * Append device path instance. + * + * This function implements the AppendDevicePathInstance service of the device + * path utilities protocol. + * + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @device_path 1st device path + * @device_path_instance 2nd device path + * @return concatenated device path + */ static struct efi_device_path * EFIAPI append_device_path_instance( const struct efi_device_path *device_path, const struct efi_device_path *device_path_instance) { - EFI_ENTRY("%p, %p", device_path, device_path_instance); - return EFI_EXIT(NULL); + EFI_ENTRY("%pD, %pD", device_path, device_path_instance); + return EFI_EXIT(efi_dp_append_instance(device_path, + device_path_instance)); } +/* + * Get next device path instance. + * + * This function implements the GetNextDevicePathInstance service of the device + * path utilities protocol. + * + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @device_path_instance next device path instance + * @device_path_instance_size size of the device path instance + * @return concatenated device path + */ static struct efi_device_path * EFIAPI get_next_device_path_instance( struct efi_device_path **device_path_instance, efi_uintn_t *device_path_instance_size) { - EFI_ENTRY("%p, %p", device_path_instance, device_path_instance_size); - return EFI_EXIT(NULL); + EFI_ENTRY("%pD, %p", device_path_instance, device_path_instance_size); + return EFI_EXIT(efi_dp_get_next_instance(device_path_instance, + device_path_instance_size)); } +/* + * Check if a device path contains more than one instance. + * + * This function implements the AppendDeviceNode service of the device path + * utilities protocol. + * + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @device_path device path + * @device_node device node + * @return concatenated device path + */ static bool EFIAPI is_device_path_multi_instance( const struct efi_device_path *device_path) { - EFI_ENTRY("%p", device_path); - return EFI_EXIT(false); + EFI_ENTRY("%pD", device_path); + return EFI_EXIT(efi_dp_is_multi_instance(device_path)); } +/* + * Create device node. + * + * This function implements the CreateDeviceNode service of the device path + * utilities protocol. + * + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @node_type node type + * @node_sub_type node sub type + * @node_length node length + * @return device path node + */ static struct efi_device_path * EFIAPI create_device_node( uint8_t node_type, uint8_t node_sub_type, uint16_t node_length) { EFI_ENTRY("%u, %u, %u", node_type, node_sub_type, node_length); - return EFI_EXIT(NULL); + return EFI_EXIT(efi_dp_create_device_node(node_type, node_sub_type, + node_length)); } const struct efi_device_path_utilities_protocol efi_device_path_utilities = { diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 31b444fc8b..0e4980c8a0 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -18,6 +18,7 @@ efi_selftest_bitblt.o \ efi_selftest_controllers.o \ efi_selftest_console.o \ efi_selftest_devicepath.o \ +efi_selftest_devicepath_util.o \ efi_selftest_events.o \ efi_selftest_event_groups.o \ efi_selftest_exitbootservices.o \ diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c index fc5ef254a1..fd4fee726f 100644 --- a/lib/efi_selftest/efi_selftest.c +++ b/lib/efi_selftest/efi_selftest.c @@ -77,20 +77,20 @@ void efi_st_exit_boot_services(void) */ static int setup(struct efi_unit_test *test, unsigned int *failures) { - int ret; - - if (!test->setup) + if (!test->setup) { + test->setup_ok = EFI_ST_SUCCESS; return EFI_ST_SUCCESS; + } efi_st_printc(EFI_LIGHTBLUE, "\nSetting up '%s'\n", test->name); - ret = test->setup(handle, systable); - if (ret != EFI_ST_SUCCESS) { + test->setup_ok = test->setup(handle, systable); + if (test->setup_ok != EFI_ST_SUCCESS) { efi_st_error("Setting up '%s' failed\n", test->name); ++*failures; } else { efi_st_printc(EFI_LIGHTGREEN, "Setting up '%s' succeeded\n", test->name); } - return ret; + return test->setup_ok; } /* @@ -200,7 +200,7 @@ void efi_st_do_tests(const u16 *testname, unsigned int phase, continue; if (steps & EFI_ST_SETUP) setup(test, failures); - if (steps & EFI_ST_EXECUTE) + if (steps & EFI_ST_EXECUTE && test->setup_ok == EFI_ST_SUCCESS) execute(test, failures); if (steps & EFI_ST_TEARDOWN) teardown(test, failures); diff --git a/lib/efi_selftest/efi_selftest_devicepath.c b/lib/efi_selftest/efi_selftest_devicepath.c index 92940c7ab6..da68102eb2 100644 --- a/lib/efi_selftest/efi_selftest_devicepath.c +++ b/lib/efi_selftest/efi_selftest_devicepath.c @@ -52,7 +52,7 @@ struct efi_device_path_to_text_protocol *device_path_to_text; * Setup unit test. * * Create three handles. Install a new protocol on two of them and - * provice device paths. + * provide device paths. * * handle1 * guid interface diff --git a/lib/efi_selftest/efi_selftest_devicepath_util.c b/lib/efi_selftest/efi_selftest_devicepath_util.c new file mode 100644 index 0000000000..2b5384f21b --- /dev/null +++ b/lib/efi_selftest/efi_selftest_devicepath_util.c @@ -0,0 +1,286 @@ +/* + * efi_selftest_devicepath_util + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This unit test checks the device path utilities protocol. + */ + +#include <efi_selftest.h> + +static struct efi_boot_services *boottime; + +static efi_guid_t guid_device_path_utilities_protocol = + EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID; + +struct efi_device_path_utilities_protocol *dpu; + +/* + * Setup unit test. + * + * Locate the device path utilities protocol. + * + * @handle: handle of the loaded image + * @systable: system table + */ +static int setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + int ret; + + boottime = systable->boottime; + + ret = boottime->locate_protocol(&guid_device_path_utilities_protocol, + NULL, (void **)&dpu); + if (ret != EFI_SUCCESS) { + dpu = NULL; + efi_st_error( + "Device path to text protocol is not available.\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * Create a device path consisting of a single media device node followed by an + * end node. + * + * @length: length of the media device node + * @dp: device path + * @return: status code + */ +static int create_single_node_device_path(unsigned int length, + struct efi_device_path **dp) +{ + struct efi_device_path *node; + efi_uintn_t len; + int ret; + + node = dpu->create_device_node(DEVICE_PATH_TYPE_MEDIA_DEVICE, + DEVICE_PATH_SUB_TYPE_FILE_PATH, length); + if (!node) { + efi_st_error("CreateDeviceNode failed\n"); + return EFI_ST_FAILURE; + } + *dp = dpu->append_device_node(NULL, node); + if (!*dp) { + efi_st_error("AppendDeviceNode failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(node); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + len = dpu->get_device_path_size(*dp); + if (len != length + 4) { + efi_st_error("Wrong device path length %u, expected %u\n", + (unsigned int)len, length); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * In the test device paths are created, copied, and concatenated. The device + * path length is used as a measure of success. + */ +static int execute(void) +{ + struct efi_device_path *dp1; + struct efi_device_path *dp2; + struct efi_device_path *dp3; + + efi_uintn_t len; + int ret; + + /* IsDevicePathMultiInstance(NULL) */ + if (dpu->is_device_path_multi_instance(NULL)) { + efi_st_error("IsDevicePathMultiInstance(NULL) returned true\n"); + return EFI_ST_FAILURE; + } + /* GetDevicePathSize(NULL) */ + len = dpu->get_device_path_size(NULL); + if (len) { + efi_st_error("Wrong device path length %u, expected 0\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + /* DuplicateDevicePath(NULL) */ + dp1 = dpu->duplicate_device_path(NULL); + if (dp1) { + efi_st_error("DuplicateDevicePath(NULL) failed\n"); + return EFI_ST_FAILURE; + } + /* AppendDevicePath(NULL, NULL) */ + dp1 = dpu->append_device_path(NULL, NULL); + if (!dp1) { + efi_st_error("AppendDevicePath(NULL, NULL) failed\n"); + return EFI_ST_FAILURE; + } + len = dpu->get_device_path_size(dp1); + if (len != 4) { + efi_st_error("Wrong device path length %u, expected 4\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp1); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + /* CreateDeviceNode */ + ret = create_single_node_device_path(21, &dp1); + if (ret != EFI_ST_SUCCESS) + return ret; + ret = create_single_node_device_path(17, &dp2); + if (ret != EFI_ST_SUCCESS) + return ret; + /* AppendDevicePath */ + dp3 = dpu->append_device_path(dp1, dp2); + if (!dp3) { + efi_st_error("AppendDevicePath failed\n"); + return EFI_ST_FAILURE; + } + if (dp3 == dp1 || dp3 == dp2) { + efi_st_error("AppendDevicePath reused buffer\n"); + return EFI_ST_FAILURE; + } + len = dpu->get_device_path_size(dp3); + /* 21 + 17 + 4 */ + if (len != 42) { + efi_st_error("Wrong device path length %u, expected 42\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp2); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + /* AppendDeviceNode */ + dp2 = dpu->append_device_node(dp1, dp3); + if (!dp2) { + efi_st_error("AppendDevicePath failed\n"); + return EFI_ST_FAILURE; + } + len = dpu->get_device_path_size(dp2); + /* 21 + 21 + 4 */ + if (len != 46) { + printf("%s(%d) %s\n", __FILE__, __LINE__, __func__); + efi_st_error("Wrong device path length %u, expected 46\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp1); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + /* IsDevicePathMultiInstance */ + if (dpu->is_device_path_multi_instance(dp2)) { + printf("%s(%d) %s\n", __FILE__, __LINE__, __func__); + efi_st_error("IsDevicePathMultiInstance returned true\n"); + return EFI_ST_FAILURE; + } + /* AppendDevicePathInstance */ + dp1 = dpu->append_device_path_instance(dp2, dp3); + if (!dp1) { + efi_st_error("AppendDevicePathInstance failed\n"); + return EFI_ST_FAILURE; + } + len = dpu->get_device_path_size(dp1); + /* 46 + 42 */ + if (len != 88) { + efi_st_error("Wrong device path length %u, expected 88\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + /* IsDevicePathMultiInstance */ + if (!dpu->is_device_path_multi_instance(dp1)) { + efi_st_error("IsDevicePathMultiInstance returned false\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp2); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp3); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + /* GetNextDevicePathInstance */ + dp3 = dp1; + dp2 = dpu->get_next_device_path_instance(&dp1, &len); + if (!dp2) { + efi_st_error("GetNextDevicePathInstance failed\n"); + return EFI_ST_FAILURE; + } + if (!dp1) { + efi_st_error("GetNextDevicePathInstance no 2nd instance\n"); + return EFI_ST_FAILURE; + } + if (len != 46) { + efi_st_error("Wrong device path length %u, expected 46\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + len = dpu->get_device_path_size(dp1); + if (len != 42) { + efi_st_error("Wrong device path length %u, expected 42\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp2); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + dp2 = dpu->get_next_device_path_instance(&dp1, &len); + if (!dp2) { + efi_st_error("GetNextDevicePathInstance failed\n"); + return EFI_ST_FAILURE; + } + if (len != 42) { + efi_st_error("Wrong device path length %u, expected 46\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + if (dp1) { + efi_st_error("GetNextDevicePathInstance did not signal end\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp2); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + + /* Clean up */ + ret = boottime->free_pool(dp2); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp3); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(dputil) = { + .name = "device path utilities protocol", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; |