diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 31b444fc8b1..0e4980c8a0b 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_devicepath_util.c b/lib/efi_selftest/efi_selftest_devicepath_util.c new file mode 100644 index 00000000000..2b5384f21ba --- /dev/null +++ b/lib/efi_selftest/efi_selftest_devicepath_util.c @@ -0,0 +1,286 @@ +/* + * efi_selftest_devicepath_util + * + * Copyright (c) 2018 Heinrich Schuchardt + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This unit test checks the device path utilities protocol. + */ + +#include + +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, +};