efi_selftest: test EFI_DEVICE_PATH_UTILITIES_PROTOCOL
authorHeinrich Schuchardt <xypron.glpk@gmx.de>
Mon, 16 Apr 2018 05:59:10 +0000 (07:59 +0200)
committerAlexander Graf <agraf@suse.de>
Mon, 23 Apr 2018 19:34:28 +0000 (21:34 +0200)
Provide unit tests for the EFI_DEVICE_PATH_UTILITIES_PROTOCOL.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
lib/efi_selftest/Makefile
lib/efi_selftest/efi_selftest_devicepath_util.c [new file with mode: 0644]

index 31b444fc8b18dcad6aca77c2012daf67e49714be..0e4980c8a0bfc2073948ee6beb69f03eee2d4d95 100644 (file)
@@ -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 (file)
index 0000000..2b5384f
--- /dev/null
@@ -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,
+};