diff options
-rw-r--r-- | doc/README.uefi | 2 | ||||
-rw-r--r-- | include/efi_api.h | 1 | ||||
-rw-r--r-- | include/efi_loader.h | 19 | ||||
-rw-r--r-- | include/efi_selftest.h | 2 | ||||
-rw-r--r-- | include/log.h | 2 | ||||
-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 |
13 files changed, 556 insertions, 36 deletions
diff --git a/doc/README.uefi b/doc/README.uefi index 7403be3614..bb89b7ac2f 100644 --- a/doc/README.uefi +++ b/doc/README.uefi @@ -324,6 +324,8 @@ This driver is only available if U-Boot is configured with * persistence * runtime support +* support bootefi booting ARMv7 in non-secure mode (CONFIG_ARMV7_NONSEC=y) + ## Links * [1](http://uefi.org/specifications) diff --git a/include/efi_api.h b/include/efi_api.h index ae93061160..64c27e494b 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -343,6 +343,7 @@ struct efi_loaded_image { 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b ) #define DEVICE_PATH_TYPE_END 0x7f +# define DEVICE_PATH_SUB_TYPE_INSTANCE_END 0x01 # define DEVICE_PATH_SUB_TYPE_END 0xff struct efi_device_path { diff --git a/include/efi_loader.h b/include/efi_loader.h index 17f9d3d1ef..8d21ba74b1 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -324,13 +324,28 @@ int efi_dp_match(const struct efi_device_path *a, const struct efi_device_path *b); struct efi_object *efi_dp_find_obj(struct efi_device_path *dp, struct efi_device_path **rem); -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); +/* size of multi-instance device path excluding end node */ +efi_uintn_t efi_dp_size(const struct efi_device_path *dp); struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp); struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1, const struct efi_device_path *dp2); struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp, const struct efi_device_path *node); - +/* Create a device path node of given type, sub-type, length */ +struct efi_device_path *efi_dp_create_device_node(const u8 type, + const u8 sub_type, + const u16 length); +/* Append device path instance */ +struct efi_device_path *efi_dp_append_instance( + const struct efi_device_path *dp, + const struct efi_device_path *dpi); +/* Get next device path instance */ +struct efi_device_path *efi_dp_get_next_instance(struct efi_device_path **dp, + efi_uintn_t *size); +/* Check if a device path contains muliple instances */ +bool efi_dp_is_multi_instance(const struct efi_device_path *dp); struct efi_device_path *efi_dp_from_dev(struct udevice *dev); struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part); diff --git a/include/efi_selftest.h b/include/efi_selftest.h index 08dd8e43ad..c23bc24bed 100644 --- a/include/efi_selftest.h +++ b/include/efi_selftest.h @@ -114,6 +114,7 @@ u16 efi_st_get_key(void); * @setup: set up the unit test * @teardown: tear down the unit test * @execute: execute the unit test + * @setup_ok: setup was successful (set at runtime) * @on_request: test is only executed on request */ struct efi_unit_test { @@ -123,6 +124,7 @@ struct efi_unit_test { const struct efi_system_table *systable); int (*execute)(void); int (*teardown)(void); + int setup_ok; bool on_request; }; diff --git a/include/log.h b/include/log.h index 20dc5289c7..3cf08de6d0 100644 --- a/include/log.h +++ b/include/log.h @@ -46,7 +46,7 @@ enum log_category_t { LOGC_CORE, LOGC_DM, /* Core driver-model */ LOGC_DT, /* Device-tree */ - LOGL_EFI, /* EFI implementation */ + LOGC_EFI, /* EFI implementation */ LOGC_COUNT, LOGC_END, 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, +}; |