[PATCH 2/2 v4] efi: ESRT creation tests

Jose Marinho
2021-02-23T16:50:01Z

This commmit exercises the ESRT creation -- introduced in the previous
commit -- in two tests.

test 1:
A fake FMP, with TEST_ESRT_NUM_ENTRIES FW images, is installed in the
system leading to the corresponding ESRT entries being populated.
The ESRT entries are checked against the datastructure used to
initialize the FMP.

test 1 invocation:
make sandbox_capsule_defconfig all
./u-boot -d arch/sandbox/dts/test.dtb
ut lib

test 2:
The test is part of test_efi_capsule_fw3.

In order to run the test the following must be added to
sandbox_defconfig:
+CONFIG_CMD_SF=y
+CONFIG_CMD_MEMORY=y
+CONFIG_CMD_FAT=y
+CONFIG_DFU=y

The ESRT is printed in the u-boot shell by calling efidebug esrt.
The test ensures that, after the capsule is installed, the ESRT
contains entries with the GUIDs:
- EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID;
- EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID;

test 2 invocation:
sudo ./test/py/test.py --bd sandbox -k capsule_fw3 -l --build

Signed-off-by: Jose Marinho <jose.marinho@arm.com>

CC: Heinrich Schuchardt <xypron.glpk@gmx.de>
CC: Sughosh Ganu <sughosh.ganu@linaro.org>
CC: AKASHI Takahiro <takahiro.akashi@linaro.org>
CC: Ilias Apalodimas <ilias.apalodimas@linaro.org>
CC: Andre Przywara <andre.przywara@arm.com>
CC: Alexander Graf <agraf@csgraf.de>
CC: nd at arm.com

---
cmd/efidebug.c | 64 ++++++
test/lib/Makefile | 1 +
test/lib/efi_esrt.c | 191 ++++++++++++++++++
.../test_efi_capsule/test_capsule_firmware.py | 4 +
4 files changed, 260 insertions(+)
create mode 100644 test/lib/efi_esrt.c

diff --git a/cmd/efidebug.c b/cmd/efidebug.c
index a7dace2f80..5a9ff2bd9a 100644
--- a/cmd/efidebug.c
+++ b/cmd/efidebug.c
@@ -129,6 +129,61 @@ static int do_efi_capsule_show(struct cmd_tbl *cmdtp, int flag,
return CMD_RET_SUCCESS;
}

+#ifdef CONFIG_EFI_ESRT
+/**
+ * do_efi_capsule_esrt() - manage UEFI capsules
+ *
+ * @cmdtp: Command table
+ * @flag: Command flag
+ * @argc: Number of arguments
+ * @argv: Argument array
+ * Return: CMD_RET_SUCCESS on success,
+ * CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
+ *
+ * Implement efidebug "capsule esrt" sub-command.
+ * The prints the current ESRT table.
+ *
+ * efidebug capsule esrt
+ */
+static int do_efi_capsule_esrt(struct cmd_tbl *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ struct efi_system_resource_table *esrt = NULL;
+
+ if (argc != 1)
+ return CMD_RET_USAGE;
+
+ for (int idx = 0; idx < systab.nr_tables; idx++)
+ if (!guidcmp(&efi_esrt_guid, &systab.tables[idx].guid))
+ esrt = (struct efi_system_resource_table *)systab.tables[idx].table;
+
+ if (!esrt)
+ return CMD_RET_FAILURE;
+
+ printf("========================================\n");
+ printf("ESRT: fw_resource_count=%d\n", esrt->fw_resource_count);
+ printf("ESRT: fw_resource_count_max=%d\n", esrt->fw_resource_count_max);
+ printf("ESRT: fw_resource_version=%lld\n", esrt->fw_resource_version);
+
+ for (int idx = 0; idx < esrt->fw_resource_count; idx++) {
+ printf("[entry %d]==============================\n", idx);
+ printf("ESRT: fw_class=%pUL\n", &esrt->entries[idx].fw_class);
+ printf("ESRT: fw_type=%d\n", esrt->entries[idx].fw_type);
+ printf("ESRT: fw_version=%d\n", esrt->entries[idx].fw_version);
+ printf("ESRT: lowest_supported_fw_version=%d\n",
+ esrt->entries[idx].lowest_supported_fw_version);
+ printf("ESRT: capsule_flags=%d\n",
+ esrt->entries[idx].capsule_flags);
+ printf("ESRT: last_attempt_version=%d\n",
+ esrt->entries[idx].last_attempt_version);
+ printf("ESRT: last_attempt_status=%d\n",
+ esrt->entries[idx].last_attempt_status);
+ }
+ printf("========================================\n");
+
+ return CMD_RET_SUCCESS;
+}
+#endif /* CONFIG_EFI_ESRT */
/**
* do_efi_capsule_res() - show a capsule update result
*
@@ -221,6 +276,10 @@ static struct cmd_tbl cmd_efidebug_capsule_sub[] = {
"", ""),
U_BOOT_CMD_MKENT(show, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_show,
"", ""),
+#ifdef CONFIG_EFI_ESRT
+ U_BOOT_CMD_MKENT(esrt, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_esrt,
+ "", ""),
+#endif
U_BOOT_CMD_MKENT(disk-update, 0, 0, do_efi_capsule_on_disk_update,
"", ""),
U_BOOT_CMD_MKENT(result, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_res,
@@ -256,6 +315,7 @@ static int do_efi_capsule(struct cmd_tbl *cmdtp, int flag,

return cp->cmd(cmdtp, flag, argc, argv);
}
+
#endif /* CONFIG_EFI_HAVE_CAPSULE_SUPPORT */

/**
@@ -1580,6 +1640,10 @@ static char efidebug_help_text[] =
" - show capsule information\n"
"efidebug capsule result [<capsule result var>]\n"
" - show a capsule update result\n"
+#ifdef CONFIG_EFI_ESRT
+ "efidebug capsule esrt\n"
+ " - print the ESRT\n"
+#endif
"\n"
#endif
"efidebug devices\n"
diff --git a/test/lib/Makefile b/test/lib/Makefile
index 97c11e35a8..aeb8c13eb0 100644
--- a/test/lib/Makefile
+++ b/test/lib/Makefile
@@ -15,3 +15,4 @@ obj-$(CONFIG_UT_LIB_ASN1) += asn1.o
obj-$(CONFIG_UT_LIB_RSA) += rsa.o
obj-$(CONFIG_AES) += test_aes.o
obj-$(CONFIG_GETOPT) += getopt.o
+obj-$(CONFIG_EFI_ESRT) += efi_esrt.o
diff --git a/test/lib/efi_esrt.c b/test/lib/efi_esrt.c
new file mode 100644
index 0000000000..e8cfe671e2
--- /dev/null
+++ b/test/lib/efi_esrt.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test ESRT tables support
+ *
+ * Copyright (C) 2021 Arm Ltd.
+ */
+#include <common.h>
+#include <efi_loader.h>
+#include <net.h>
+#include <test/lib.h>
+#include <test/test.h>
+#include <test/ut.h>
+
+#define TEST_ESRT_NUM_ENTRIES 255
+
+#if 0x100 < TEST_ESRT_NUM_ENTRIES
+#error TEST_ESRT_NUM_ENTRIES must be lower or equal to 255.
+#endif
+
+static
+struct efi_firmware_image_descriptor static_img_info[TEST_ESRT_NUM_ENTRIES];
+
+static void efi_test_esrt_init_info(void)
+{
+ for (int idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++) {
+ static_img_info[idx].image_index = 1;
+
+ // Note: the 16 byte value present in
+ // static_img_info[idx].image_type_id is not strictly a GUID.
+ // The value is used for the sake of code testing.
+ static_img_info[idx].image_type_id.b[0] = idx;
+
+ static_img_info[idx].image_id = 0;
+ static_img_info[idx].image_id_name = NULL;
+ static_img_info[idx].version = 0;
+ static_img_info[idx].version_name = NULL;
+ static_img_info[idx].size = 0;
+ static_img_info[idx].lowest_supported_image_version = 1;
+ static_img_info[idx].last_attempt_version = 2;
+ static_img_info[idx].last_attempt_status = 3;
+ static_img_info[idx].hardware_instance = 1;
+ }
+}
+
+static efi_status_t
+EFIAPI efi_test_fmp_get_image_info(struct efi_firmware_management_protocol *this,
+ efi_uintn_t *image_info_size,
+ struct efi_firmware_image_descriptor *image_info,
+ u32 *descriptor_version,
+ u8 *descriptor_count,
+ efi_uintn_t *descriptor_size,
+ u32 *package_version,
+ u16 **package_version_name)
+{
+ efi_status_t ret = EFI_SUCCESS;
+
+ if (!image_info_size)
+ return EFI_INVALID_PARAMETER;
+
+ if (descriptor_version)
+ *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
+ if (descriptor_count)
+ *descriptor_count = TEST_ESRT_NUM_ENTRIES;
+ if (descriptor_size)
+ *descriptor_size = sizeof(*image_info);
+ if (package_version)
+ *package_version = 0xffffffff;
+ if (package_version_name)
+ *package_version_name = NULL;
+
+ if (*image_info_size < sizeof(*image_info)) {
+ *image_info_size = *descriptor_size * *descriptor_count;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ for (int idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++)
+ image_info[idx] = static_img_info[idx];
+
+ return ret;
+}
+
+struct efi_firmware_management_protocol efi_test_fmp = {
+ .get_image_info = efi_test_fmp_get_image_info,
+ .get_image = NULL,
+ .set_image = NULL,
+ .check_image = NULL,
+ .get_package_info = NULL,
+ .set_package_info = NULL,
+};
+
+static void *lib_test_get_esrt(void)
+{
+ for (int idx = 0; idx < systab.nr_tables; idx++)
+ if (!guidcmp(&efi_esrt_guid, &systab.tables[idx].guid))
+ return systab.tables[idx].table;
+
+ return NULL;
+}
+
+static bool lib_test_check_uuid_entry(struct efi_system_resource_table *esrt,
+ struct efi_firmware_image_descriptor
+ *img_info)
+{
+ const u32 filled_entries = esrt->fw_resource_count;
+ struct efi_system_resource_entry *entry = esrt->entries;
+
+ for (u32 idx = 0; idx < filled_entries; idx++) {
+ if (!guidcmp(&entry[idx].fw_class, &img_info->image_type_id)) {
+ if (entry[idx].fw_version != img_info->version)
+ return false;
+
+ if (entry[idx].lowest_supported_fw_version !=
+ img_info->lowest_supported_image_version)
+ return false;
+
+ if (entry[idx].last_attempt_version !=
+ img_info->last_attempt_version)
+ return false;
+
+ if (entry[idx].last_attempt_status !=
+ img_info->last_attempt_status)
+ return false;
+
+ /*
+ * The entry with fw_class = img_uuid matches with the
+ * remainder fmp input.
+ */
+ return true;
+ }
+ }
+
+ /* There exists no entry with fw_class equal to img_uuid in the ESRT. */
+ return false;
+}
+
+int lib_test_efi_esrt(struct unit_test_state *uts)
+{
+ struct efi_system_resource_table *esrt;
+ efi_status_t ret = EFI_SUCCESS;
+ struct efi_boot_services *bt;
+
+ efi_test_esrt_init_info();
+
+ ret = efi_init_obj_list();
+
+ bt = systab.boottime;
+ ut_asserteq(ret, EFI_SUCCESS);
+
+ assert(bt);
+
+ ret = EFI_CALL(bt->install_multiple_protocol_interfaces
+ (&efi_root,
+ &efi_guid_firmware_management_protocol,
+ &efi_test_fmp,
+ NULL));
+
+ ut_asserteq(ret, EFI_SUCCESS);
+
+ esrt = lib_test_get_esrt();
+ ut_assert(esrt);
+
+ ut_asserteq(esrt->fw_resource_count, TEST_ESRT_NUM_ENTRIES);
+
+ /* Update the ESRT. */
+ ut_asserteq(efi_esrt_populate(), EFI_SUCCESS);
+ esrt = lib_test_get_esrt();
+ ut_assert(esrt);
+
+ /* Verify that the number of images remains the same. */
+ ut_asserteq(esrt->fw_resource_count, TEST_ESRT_NUM_ENTRIES);
+
+ for (u32 idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++)
+ ut_assert(lib_test_check_uuid_entry(esrt, &static_img_info[idx]));
+
+ ret = EFI_CALL(bt->uninstall_multiple_protocol_interfaces
+ (efi_root, &efi_guid_firmware_management_protocol,
+ &efi_test_fmp, NULL));
+
+ ut_asserteq(ret, EFI_SUCCESS);
+
+ /* Update the ESRT after FMP removal. */
+ ut_asserteq(efi_esrt_populate(), EFI_SUCCESS);
+ esrt = lib_test_get_esrt();
+ ut_assert(esrt);
+
+ ut_asserteq(esrt->fw_resource_count, 0);
+
+ return ret;
+}
+
+LIB_TEST(lib_test_efi_esrt, 0);
diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware.py b/test/py/tests/test_efi_capsule/test_capsule_firmware.py
index f006fa95d6..3a7c2e1ac8 100644
--- a/test/py/tests/test_efi_capsule/test_capsule_firmware.py
+++ b/test/py/tests/test_efi_capsule/test_capsule_firmware.py
@@ -229,6 +229,10 @@ class TestEfiCapsuleFirmwareFit(object):
output = u_boot_console.run_command(
'env print -e -all Capsule0000')

+ output = u_boot_console.run_command_list(['efidebug capsule esrt'])
+ assert 'AE13FF2D-9AD4-4E25-9AC8-6D80B3B22147' in ''.join(output)
+ assert 'E2BB9C06-70E9-4B14-97A3-5A7913176E3F' in ''.join(output)
+
output = u_boot_console.run_command_list([
'host bind 0 %s' % disk_img,
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
--
2.17.1