[PATCH 3/3 v5] efi: ESRT creation tests
AKASHI Takahiro
takahiro.akashi at linaro.org
Wed Mar 3 00:48:49 CET 2021
On Tue, Mar 02, 2021 at 07:30:31PM +0100, Heinrich Schuchardt wrote:
> On 02.03.21 13:13, Jose Marinho wrote:
> > This commmit exercises the ESRT creation 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:
> > add to sandbox_defconfig:
> > +CONFIG_EFI_SELFTEST=y
>
> EFI_SELFTEST is active on many QEMU devices. So the test could run there.
>
> >
> > make sandbox_capsule_defconfig all
> > ./u-boot -d arch/sandbox/dts/test.dtb
> > bootefi selftest
> >
> > 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 at arm.com>
> >
> > CC: Heinrich Schuchardt <xypron.glpk at gmx.de>
> > CC: Sughosh Ganu <sughosh.ganu at linaro.org>
> > CC: AKASHI Takahiro <takahiro.akashi at linaro.org>
> > CC: Ilias Apalodimas <ilias.apalodimas at linaro.org>
> > CC: Andre Przywara <andre.przywara at arm.com>
> > CC: Alexander Graf <agraf at csgraf.de>
> > CC: nd at arm.com
> >
> > ---
> > lib/efi_selftest/Makefile | 2 +
> > lib/efi_selftest/efi_selftest_esrt.c | 227 ++++++++++++++++++
> > .../test_efi_capsule/test_capsule_firmware.py | 4 +
> > 3 files changed, 233 insertions(+)
> > create mode 100644 lib/efi_selftest/efi_selftest_esrt.c
> >
> > diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile
> > index 7d6ea30102..017b191a46 100644
> > --- a/lib/efi_selftest/Makefile
> > +++ b/lib/efi_selftest/Makefile
> > @@ -72,6 +72,8 @@ ifeq ($(CONFIG_BLK)$(CONFIG_DOS_PARTITION),yy)
> > obj-y += efi_selftest_block_device.o
> > endif
> >
> > +obj-$(CONFIG_EFI_ESRT) += efi_selftest_esrt.o
> > +
> > targets += \
> > efi_miniapp_file_image_exception.h \
> > efi_miniapp_file_image_exit.h \
> > diff --git a/lib/efi_selftest/efi_selftest_esrt.c b/lib/efi_selftest/efi_selftest_esrt.c
> > new file mode 100644
> > index 0000000000..b053b2e6c6
> > --- /dev/null
> > +++ b/lib/efi_selftest/efi_selftest_esrt.c
> > @@ -0,0 +1,227 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Test ESRT tables support
> > + *
> > + * Copyright (C) 2021 Arm Ltd.
> > + */
> > +#include <common.h>
> > +#include <efi_loader.h>
> > +#include <efi_selftest.h>
> > +
> > +// This value must not exceed 255.
> > +// An FMP cannot contain more than 255 FW images.
> > +#define TEST_ESRT_NUM_ENTRIES 255
> > +
> > +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 = idx;
> > +
> > + // 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;
> > +}
> > +
> > +static 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;
> > +}
> > +
> > +/*
> > + * Setup unit test.
> > + *
> > + * Initialize the test FMP datastructure.
> > + * Install the FMP in the system.
> > + *
> > + * @handle: handle of the loaded image
> > + * @systable: system table
> > + * @return: EFI_ST_SUCCESS for success
> > + */
> > +static int setup(const efi_handle_t handle,
> > + const struct efi_system_table *systable)
> > +{
> > + efi_status_t ret = EFI_SUCCESS;
> > + struct efi_boot_services *bt = systab.boottime;
>
> Please, use the value from systable. We want to be able to make the
> selftests a standalone UEFI application.
>
> > +
> > + if (!bt)
> > + return EFI_ST_FAILURE;
> > +
> > + efi_test_esrt_init_info();
> > +
> > + ret = EFI_CALL(bt->install_multiple_protocol_interfaces
>
> No EFI_CALL here. You are in the UEFI world.
>
> > + (&efi_root,
> > + &efi_guid_firmware_management_protocol,
> > + &efi_test_fmp,
> > + NULL));
> > +
> > + if (ret != EFI_SUCCESS)
> > + return EFI_ST_FAILURE;
> > +
> > + return EFI_ST_SUCCESS;
> > +}
> > +
> > +/*
> > + * Tear down unit test.
> > + *
> > + * Uninstall the test FMP.
> > + *
> > + * @return: EFI_ST_SUCCESS for success
> > + */
> > +static int teardown(void)
> > +{
> > + efi_status_t ret = EFI_SUCCESS;
> > + struct efi_boot_services *bt = systab.boottime;
> > +
> > + if (!bt)
>
> Please use the value from setup's systable parameter.
>
> > + return EFI_ST_FAILURE;
> > +
> > + ret = EFI_CALL(bt->uninstall_multiple_protocol_interfaces
>
> No EFI_CALL here. You are in the UEFI world.
>
> > + (efi_root, &efi_guid_firmware_management_protocol,
> > + &efi_test_fmp, NULL));
> > +
> > + if (ret != EFI_SUCCESS)
> > + return EFI_ST_FAILURE;
> > +
> > + return EFI_ST_SUCCESS;
> > +}
> > +
> > +static int execute(void)
> > +{
> > + struct efi_system_resource_table *esrt;
> > + efi_status_t ret = EFI_SUCCESS;
> > +
> > + esrt = lib_test_get_esrt();
> > + if (!esrt)
> > + return EFI_ST_FAILURE;
> > +
> > + if (esrt->fw_resource_count != TEST_ESRT_NUM_ENTRIES)
> > + return EFI_ST_FAILURE;
> > +
> > + /* Update the ESRT. */
> > + ret = efi_esrt_populate();
>
> This is not an EFI API function you cannot call it here.
> The ESRT is already populated by your registered function. There is no
> need to call it.
>
> > + if (ret != EFI_SUCCESS)
>
> Please, write a message with efi_st_error() before returning the error
> status.
>
> > + return EFI_ST_FAILURE;
> > +
> > + esrt = lib_test_get_esrt();
>
> You have to the the configuration table from the system table. Cf.
> lib/efi_selftest/efi_selftest_fdt.c
>
> > + if (!esrt)
> > + return EFI_ST_FAILURE;
> > +
> > + /* Verify that the number of images remains the same. */
> > + if (esrt->fw_resource_count != TEST_ESRT_NUM_ENTRIES)
> > + return EFI_ST_FAILURE;
>
> You may already have other FMP protocols installed before 'bootefi
> selftest' is invoked.
>
> You have to count before installing the new FMP protocol and compare
> that number to the number of instances after installing the new FMP
> protocols.
>
> > +
> > + for (u32 idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++)
> > + if (!lib_test_check_uuid_entry(esrt, &static_img_info[idx]))
>
> Please, write a message with efi_st_error() before returning the error
> status.
>
> > + return EFI_ST_FAILURE;
> > +
> > + return EFI_ST_SUCCESS;
> > +}
> > +
> > +EFI_UNIT_TEST(esrt) = {
> > + .name = "esrt",
> > + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
> > + .setup = setup,
> > + .execute = execute,
> > + .teardown = teardown,
> > +};
> > 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'])
>
> Please, add a comment that this is EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID.
>
> > + assert 'AE13FF2D-9AD4-4E25-9AC8-6D80B3B22147' in ''.join(output)
>
> This seems to be EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID.
>
> > + assert 'E2BB9C06-70E9-4B14-97A3-5A7913176E3F' in ''.join(output)
Those values are constant as they are "fw_class".
How do you confirm that data in an entry is updated?
-Takahiro Akashi
> As this is a separate test it could be in a separate patch.
>
> Best regards
>
> Heinrich
>
> > +
> > output = u_boot_console.run_command_list([
> > 'host bind 0 %s' % disk_img,
> > 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> >
>
More information about the U-Boot
mailing list