[U-Boot] [PATCH v2 0/7] efi_loader: correct EFI table headers

This patch series fixes several errors in the the headers of the system table, the boot services table, and the runtime services table.
The array used for the configuration tables is allocated at runtime.
A unit test for InstallConfigurationTable() is provided.
The patch series depends on Bin's efi_loader: Increase number of configuration tables to 16 https://lists.denx.de/pipermail/u-boot/2018-June/333064.html
v2: no need to prefix VERSION, PATCHLEVEL by 0x0, 0x is sufficient
Heinrich Schuchardt (7): efi_loader: specify UEFI spec revision efi_loader: correct EFI_RUNTIME_SERVICES_SIGNATURE efi_loader: correct headersize EFI tables efi_loader: provide firmware revision efi_loader: calculate crc32 for EFI tables efi_loader: allocate configuration table array efi_selftest: test InstallConfigurationTable()
cmd/bootefi.c | 5 + include/efi_api.h | 9 +- include/efi_loader.h | 5 + lib/efi_loader/Makefile | 3 + lib/efi_loader/efi_boottime.c | 83 ++++--- lib/efi_loader/efi_runtime.c | 4 +- lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_config_table.c | 223 +++++++++++++++++++ 8 files changed, 300 insertions(+), 33 deletions(-) create mode 100644 lib/efi_selftest/efi_selftest_config_table.c

Both in the boot and the runtime services tables we have to specify the UEFI spec revision. The same value is already used for the system table. So let's use a common constant.
In the boot services table we have to provide the header signature.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de Reviewed-by: Bin Meng bmeng.cn@gmail.com --- v2 no change --- include/efi_api.h | 5 ++++- lib/efi_loader/efi_boottime.c | 4 +++- lib/efi_loader/efi_runtime.c | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/include/efi_api.h b/include/efi_api.h index 094be6edf9..2d58359333 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -21,6 +21,9 @@ #include <asm/setjmp.h> #endif
+/* UEFI spec version 2.7 */ +#define EFI_SPECIFICATION_VERSION (2 << 16 | 70) + /* Types and defines for EFI CreateEvent */ enum efi_timer_delay { EFI_TIMER_STOP = 0, @@ -46,6 +49,7 @@ typedef uint16_t *efi_string_t; struct efi_event;
/* EFI Boot Services table */ +#define EFI_BOOT_SERVICES_SIGNATURE 0x56524553544f4f42 struct efi_boot_services { struct efi_table_hdr hdr; efi_status_t (EFIAPI *raise_tpl)(efi_uintn_t new_tpl); @@ -186,7 +190,6 @@ enum efi_reset_type {
/* EFI Runtime Services table */ #define EFI_RUNTIME_SERVICES_SIGNATURE 0x5652453544e5552ULL -#define EFI_RUNTIME_SERVICES_REVISION 0x00010000
#define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000 #define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000 diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 3654410666..c804af181e 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -2990,6 +2990,8 @@ out:
static const struct efi_boot_services efi_boot_services = { .hdr = { + .signature = EFI_BOOT_SERVICES_SIGNATURE, + .revision = EFI_SPECIFICATION_VERSION, .headersize = sizeof(struct efi_table_hdr), }, .raise_tpl = efi_raise_tpl, @@ -3045,7 +3047,7 @@ static uint16_t __efi_runtime_data firmware_vendor[] = L"Das U-Boot"; struct efi_system_table __efi_runtime_data systab = { .hdr = { .signature = EFI_SYSTEM_TABLE_SIGNATURE, - .revision = 2 << 16 | 70, /* 2.7 */ + .revision = EFI_SPECIFICATION_VERSION, .headersize = sizeof(struct efi_table_hdr), }, .fw_vendor = (long)firmware_vendor, diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index dd3ff8ad23..cfa60b8ff7 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -459,7 +459,7 @@ efi_status_t __efi_runtime EFIAPI efi_query_variable_info( struct efi_runtime_services __efi_runtime_data efi_runtime_services = { .hdr = { .signature = EFI_RUNTIME_SERVICES_SIGNATURE, - .revision = EFI_RUNTIME_SERVICES_REVISION, + .revision = EFI_SPECIFICATION_VERSION, .headersize = sizeof(struct efi_table_hdr), }, .get_time = &efi_get_time_boottime,

The value for EFI_RUNTIME_SERVICES_SIGNATURE does not match the UEFI spec 2.7.
Reported-by: Takahiro Akashi takahiro.akashi@linaro.org Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de Reviewed-by: Bin Meng bmeng.cn@gmail.com --- v2 no change --- include/efi_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/efi_api.h b/include/efi_api.h index 2d58359333..c409fc0bd0 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -189,7 +189,7 @@ enum efi_reset_type { };
/* EFI Runtime Services table */ -#define EFI_RUNTIME_SERVICES_SIGNATURE 0x5652453544e5552ULL +#define EFI_RUNTIME_SERVICES_SIGNATURE 0x56524553544e5552ULL
#define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000 #define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000

The headersize field has to be set to the size of the whole table including the header.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de Reviewed-by: Bin Meng bmeng.cn@gmail.com --- v2 no change --- lib/efi_loader/efi_boottime.c | 4 ++-- lib/efi_loader/efi_runtime.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index c804af181e..fe9a86b44b 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -2992,7 +2992,7 @@ static const struct efi_boot_services efi_boot_services = { .hdr = { .signature = EFI_BOOT_SERVICES_SIGNATURE, .revision = EFI_SPECIFICATION_VERSION, - .headersize = sizeof(struct efi_table_hdr), + .headersize = sizeof(struct efi_boot_services), }, .raise_tpl = efi_raise_tpl, .restore_tpl = efi_restore_tpl, @@ -3048,7 +3048,7 @@ struct efi_system_table __efi_runtime_data systab = { .hdr = { .signature = EFI_SYSTEM_TABLE_SIGNATURE, .revision = EFI_SPECIFICATION_VERSION, - .headersize = sizeof(struct efi_table_hdr), + .headersize = sizeof(struct efi_system_table), }, .fw_vendor = (long)firmware_vendor, .con_in = (void *)&efi_con_in, diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index cfa60b8ff7..1acb06a206 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -460,7 +460,7 @@ struct efi_runtime_services __efi_runtime_data efi_runtime_services = { .hdr = { .signature = EFI_RUNTIME_SERVICES_SIGNATURE, .revision = EFI_SPECIFICATION_VERSION, - .headersize = sizeof(struct efi_table_hdr), + .headersize = sizeof(struct efi_runtime_services), }, .get_time = &efi_get_time_boottime, .set_time = (void *)&efi_device_error,

Provide a firmware revision in the system table using the Makefile variables VERSION and PATCHLEVEL, e.g. 0x20180700 for v2018.07.
Correct the type of the firmware vendor. It is a u16* pointer.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de Reviewed-by: Bin Meng bmeng.cn@gmail.com --- v2 No need to prefix VERSION, PATCHLEVEL by 0x0, 0x is sufficient. --- include/efi_api.h | 2 +- lib/efi_loader/Makefile | 3 +++ lib/efi_loader/efi_boottime.c | 5 +++-- 3 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/include/efi_api.h b/include/efi_api.h index c409fc0bd0..cd502c2eb2 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -299,7 +299,7 @@ struct efi_configuration_table
struct efi_system_table { struct efi_table_hdr hdr; - unsigned long fw_vendor; /* physical addr of wchar_t vendor string */ + u16 *fw_vendor; /* physical addr of wchar_t vendor string */ u32 fw_revision; efi_handle_t con_in_handle; struct efi_simple_input_interface *con_in; diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index c6046e36d2..4b22c237d5 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -6,6 +6,9 @@ # This file only gets included with CONFIG_EFI_LOADER set, so all # object inclusion implicitly depends on it
+CFLAGS_efi_boottime.o += \ + -DFW_VERSION="0x$(VERSION)" \ + -DFW_PATCHLEVEL="0x$(PATCHLEVEL)" CFLAGS_helloworld.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_helloworld.o := $(CFLAGS_NON_EFI) -Os
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index fe9a86b44b..7c619c652c 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -3042,7 +3042,7 @@ static const struct efi_boot_services efi_boot_services = { .create_event_ex = efi_create_event_ex, };
-static uint16_t __efi_runtime_data firmware_vendor[] = L"Das U-Boot"; +static u16 __efi_runtime_data firmware_vendor[] = L"Das U-Boot";
struct efi_system_table __efi_runtime_data systab = { .hdr = { @@ -3050,7 +3050,8 @@ struct efi_system_table __efi_runtime_data systab = { .revision = EFI_SPECIFICATION_VERSION, .headersize = sizeof(struct efi_system_table), }, - .fw_vendor = (long)firmware_vendor, + .fw_vendor = firmware_vendor, + .fw_revision = FW_VERSION << 16 | FW_PATCHLEVEL << 8, .con_in = (void *)&efi_con_in, .con_out = (void *)&efi_con_out, .std_err = (void *)&efi_con_out,

For the boot and runtime services tables and for the system table the crc32 has to be set in the header.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de Reviewed-by: Bin Meng bmeng.cn@gmail.com --- v2 no change --- cmd/bootefi.c | 5 +++++ include/efi_loader.h | 2 ++ lib/efi_loader/efi_boottime.c | 32 ++++++++++++++++++++++++++++---- 3 files changed, 35 insertions(+), 4 deletions(-)
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 91277106a2..07c61ac542 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -44,6 +44,11 @@ efi_status_t efi_init_obj_list(void) if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED) return efi_obj_list_initialized;
+ /* Initialize system table */ + ret = efi_initialize_system_table(); + if (ret != EFI_SUCCESS) + goto out; + /* Initialize EFI driver uclass */ ret = efi_driver_init(); if (ret != EFI_SUCCESS) diff --git a/include/efi_loader.h b/include/efi_loader.h index d6e1f50e22..8c9c36556b 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -199,6 +199,8 @@ extern struct list_head efi_obj_list; /* List of all events */ extern struct list_head efi_events;
+/* Called by bootefi to initialize runtime */ +efi_status_t efi_initialize_system_table(void); /* Called by bootefi to make console interface available */ int efi_console_register(void); /* Called by bootefi to make all disk storage accessible as EFI objects */ diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 7c619c652c..904056dbfd 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -163,6 +163,18 @@ const char *__efi_nesting_dec(void) return indent_string(--nesting_level); }
+/** + * efi_update_table_header_crc32() - Update CRC32 in table header + * + * @table: EFI table + */ +static void efi_update_table_header_crc32(struct efi_table_hdr *table) +{ + table->crc32 = 0; + table->crc32 = crc32(0, (const unsigned char *)table, + table->headersize); +} + /** * efi_queue_event - queue an EFI event * @@ -1848,9 +1860,7 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, systab.boottime = NULL;
/* Recalculate CRC32 */ - systab.hdr.crc32 = 0; - systab.hdr.crc32 = crc32(0, (const unsigned char *)&systab, - sizeof(struct efi_system_table)); + efi_update_table_header_crc32(&systab.hdr);
/* Give the payload some time to boot */ efi_set_watchdog(0); @@ -2988,7 +2998,7 @@ out: return EFI_EXIT(r); }
-static const struct efi_boot_services efi_boot_services = { +static struct efi_boot_services efi_boot_services = { .hdr = { .signature = EFI_BOOT_SERVICES_SIGNATURE, .revision = EFI_SPECIFICATION_VERSION, @@ -3060,3 +3070,17 @@ struct efi_system_table __efi_runtime_data systab = { .nr_tables = 0, .tables = (void *)efi_conf_table, }; + +/** + * efi_initialize_system_table() - Initialize system table + * + * Return Value: status code + */ +efi_status_t efi_initialize_system_table(void) +{ + /* Set crc32 field in table headers */ + efi_update_table_header_crc32(&systab.hdr); + efi_update_table_header_crc32(&efi_runtime_services.hdr); + efi_update_table_header_crc32(&efi_boot_services.hdr); + return EFI_SUCCESS; +}

On 06/28/2018 12:45 PM, Heinrich Schuchardt wrote:
For the boot and runtime services tables and for the system table the crc32 has to be set in the header.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de Reviewed-by: Bin Meng bmeng.cn@gmail.com
v2 no change
cmd/bootefi.c | 5 +++++ include/efi_loader.h | 2 ++ lib/efi_loader/efi_boottime.c | 32 ++++++++++++++++++++++++++++---- 3 files changed, 35 insertions(+), 4 deletions(-)
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 91277106a2..07c61ac542 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -44,6 +44,11 @@ efi_status_t efi_init_obj_list(void) if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED) return efi_obj_list_initialized;
- /* Initialize system table */
- ret = efi_initialize_system_table();
- if (ret != EFI_SUCCESS)
goto out;
- /* Initialize EFI driver uclass */ ret = efi_driver_init(); if (ret != EFI_SUCCESS)
diff --git a/include/efi_loader.h b/include/efi_loader.h index d6e1f50e22..8c9c36556b 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -199,6 +199,8 @@ extern struct list_head efi_obj_list; /* List of all events */ extern struct list_head efi_events;
+/* Called by bootefi to initialize runtime */ +efi_status_t efi_initialize_system_table(void); /* Called by bootefi to make console interface available */ int efi_console_register(void); /* Called by bootefi to make all disk storage accessible as EFI objects */ diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 7c619c652c..904056dbfd 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -163,6 +163,18 @@ const char *__efi_nesting_dec(void) return indent_string(--nesting_level); }
+/**
- efi_update_table_header_crc32() - Update CRC32 in table header
- @table: EFI table
- */
+static void efi_update_table_header_crc32(struct efi_table_hdr *table) +{
- table->crc32 = 0;
- table->crc32 = crc32(0, (const unsigned char *)table,
table->headersize);
+}
- /**
- efi_queue_event - queue an EFI event
@@ -1848,9 +1860,7 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, systab.boottime = NULL;
/* Recalculate CRC32 */
- systab.hdr.crc32 = 0;
- systab.hdr.crc32 = crc32(0, (const unsigned char *)&systab,
sizeof(struct efi_system_table));
efi_update_table_header_crc32(&systab.hdr);
/* Give the payload some time to boot */ efi_set_watchdog(0);
@@ -2988,7 +2998,7 @@ out: return EFI_EXIT(r); }
-static const struct efi_boot_services efi_boot_services = { +static struct efi_boot_services efi_boot_services = { .hdr = { .signature = EFI_BOOT_SERVICES_SIGNATURE, .revision = EFI_SPECIFICATION_VERSION, @@ -3060,3 +3070,17 @@ struct efi_system_table __efi_runtime_data systab = { .nr_tables = 0, .tables = (void *)efi_conf_table, };
+/**
- efi_initialize_system_table() - Initialize system table
- Return Value: status code
- */
+efi_status_t efi_initialize_system_table(void) +{
- /* Set crc32 field in table headers */
- efi_update_table_header_crc32(&systab.hdr);
Systab gets modified when tables get added.
- efi_update_table_header_crc32(&efi_runtime_services.hdr);
The RTS table gets modified on exit_boot_services.
Can you please send a follow-up patch to recalculate the crc32 on those 2 events as well?
Alex

The system table contains a link to the list of configurations tables. These include the device tree, SMBIOS table, and the ACPI table.
This array is currently statically linked. With the patch it is allocated as EFI_RUNTIME_SERVICES_DATA. Due to the structure of the system table we cannot work with a linked list here.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de Reviewed-by: Bin Meng bmeng.cn@gmail.com --- v2 no change --- include/efi_loader.h | 3 +++ lib/efi_loader/efi_boottime.c | 39 +++++++++++++++++------------------ 2 files changed, 22 insertions(+), 20 deletions(-)
diff --git a/include/efi_loader.h b/include/efi_loader.h index 8c9c36556b..c4ddb26e48 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -17,6 +17,9 @@
#include <linux/list.h>
+/* Maximum number of configuration tables */ +#define EFI_MAX_CONFIGURATION_TABLES 16 + int __efi_entry_check(void); int __efi_exit_check(void); const char *__efi_nesting(void); diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 904056dbfd..298e6c3bbb 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -35,16 +35,6 @@ LIST_HEAD(efi_events); */ static bool efi_is_direct_boot = true;
-/* - * EFI can pass arbitrary additional "tables" containing vendor specific - * information to the payload. One such table is the FDT table which contains - * a pointer to a flattened device tree blob. - * - * In most cases we want to pass an FDT to the payload, so reserve one slot of - * config table space for it. The pointer gets populated by do_bootefi_exec(). - */ -static struct efi_configuration_table __efi_runtime_data efi_conf_table[16]; - #ifdef CONFIG_ARM /* * The "gd" pointer lives in a register on ARM and AArch64 that we declare @@ -1358,9 +1348,9 @@ static efi_status_t EFIAPI efi_locate_handle_ext( */ static void efi_remove_configuration_table(int i) { - struct efi_configuration_table *this = &efi_conf_table[i]; - struct efi_configuration_table *next = &efi_conf_table[i + 1]; - struct efi_configuration_table *end = &efi_conf_table[systab.nr_tables]; + struct efi_configuration_table *this = &systab.tables[i]; + struct efi_configuration_table *next = &systab.tables[i + 1]; + struct efi_configuration_table *end = &systab.tables[systab.nr_tables];
memmove(this, next, (ulong)end - (ulong)next); systab.nr_tables--; @@ -1388,9 +1378,9 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid,
/* Check for guid override */ for (i = 0; i < systab.nr_tables; i++) { - if (!guidcmp(guid, &efi_conf_table[i].guid)) { + if (!guidcmp(guid, &systab.tables[i].guid)) { if (table) - efi_conf_table[i].table = table; + systab.tables[i].table = table; else efi_remove_configuration_table(i); goto out; @@ -1401,12 +1391,12 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, return EFI_NOT_FOUND;
/* No override, check for overflow */ - if (i >= ARRAY_SIZE(efi_conf_table)) + if (i >= EFI_MAX_CONFIGURATION_TABLES) return EFI_OUT_OF_RESOURCES;
/* Add a new entry */ - memcpy(&efi_conf_table[i].guid, guid, sizeof(*guid)); - efi_conf_table[i].table = table; + memcpy(&systab.tables[i].guid, guid, sizeof(*guid)); + systab.tables[i].table = table; systab.nr_tables = i + 1;
out: @@ -3068,7 +3058,7 @@ struct efi_system_table __efi_runtime_data systab = { .runtime = (void *)&efi_runtime_services, .boottime = (void *)&efi_boot_services, .nr_tables = 0, - .tables = (void *)efi_conf_table, + .tables = NULL, };
/** @@ -3078,9 +3068,18 @@ struct efi_system_table __efi_runtime_data systab = { */ efi_status_t efi_initialize_system_table(void) { + efi_status_t ret; + + /* Allocate configuration table array */ + ret = efi_allocate_pool(EFI_RUNTIME_SERVICES_DATA, + EFI_MAX_CONFIGURATION_TABLES * + sizeof(struct efi_configuration_table), + (void **)&systab.tables); + /* Set crc32 field in table headers */ efi_update_table_header_crc32(&systab.hdr); efi_update_table_header_crc32(&efi_runtime_services.hdr); efi_update_table_header_crc32(&efi_boot_services.hdr); - return EFI_SUCCESS; + + return ret; }

Provide a unit test for InstallConfigurationTable().
A table is installed, updated, removed. The table entry and the triggering of events is checked.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- v2 no change --- lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_config_table.c | 223 +++++++++++++++++++ 2 files changed, 224 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_config_table.c
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index bf5c8199cb..c0fd490d2e 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -13,6 +13,7 @@ CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI) -Os obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += \ efi_selftest.o \ efi_selftest_bitblt.o \ +efi_selftest_config_table.o \ efi_selftest_controllers.o \ efi_selftest_console.o \ efi_selftest_devicepath.o \ diff --git a/lib/efi_selftest/efi_selftest_config_table.c b/lib/efi_selftest/efi_selftest_config_table.c new file mode 100644 index 0000000000..627b73cdf8 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_config_table.c @@ -0,0 +1,223 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_config_tables + * + * Copyright (c) 2018 Heinrich Schuchardt xypron.glpk@gmx.de + * + * This test checks the following service: + * InstallConfigurationTable. + */ + +#include <efi_selftest.h> + +static const struct efi_system_table *sys_table; +static struct efi_boot_services *boottime; + +static efi_guid_t table_guid = + EFI_GUID(0xff1c3f9e, 0x795b, 0x1529, 0xf1, 0x55, + 0x17, 0x2e, 0x51, 0x6b, 0x49, 0x75); + +/* + * Notification function, increments the notfication count if parameter + * context is provided. + * + * @event notified event + * @context pointer to the notification count + */ +static void EFIAPI notify(struct efi_event *event, void *context) +{ + unsigned int *count = context; + + if (count) + ++*count; +} + +/* + * Setup unit test. + * + * @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) +{ + sys_table = systable; + boottime = systable->boottime; + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * A table is installed, updated, removed. The table entry and the + * triggering of events is checked. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + unsigned int counter = 0; + struct efi_event *event; + void *table; + const unsigned int tables[2]; + efi_uintn_t i; + efi_uintn_t tabcnt; + efi_uintn_t table_count = sys_table->nr_tables; + + ret = boottime->create_event_ex(0, TPL_NOTIFY, + notify, (void *)&counter, + &table_guid, &event); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to create event\n"); + return EFI_ST_FAILURE; + } + + /* Try to delete non-existent table */ + ret = boottime->install_configuration_table(&table_guid, NULL); + if (ret != EFI_NOT_FOUND) { + efi_st_error("Failed to detect missing table\n"); + return EFI_ST_FAILURE; + } + if (counter) { + efi_st_error("Notification function was called.\n"); + return EFI_ST_FAILURE; + } + /* Check if the event was signaled */ + ret = boottime->check_event(event); + if (ret == EFI_SUCCESS) { + efi_st_error("Event was signaled on EFI_NOT_FOUND\n"); + return EFI_ST_FAILURE; + } + if (counter != 1) { + efi_st_error("Notification function was not called.\n"); + return EFI_ST_FAILURE; + } + if (table_count != sys_table->nr_tables) { + efi_st_error("Incorrect table count %u, expected %u\n", + (unsigned int)sys_table->nr_tables, + (unsigned int)table_count); + return EFI_ST_FAILURE; + } + + /* Install table */ + ret = boottime->install_configuration_table(&table_guid, + (void *)&tables[0]); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to install table\n"); + return EFI_ST_FAILURE; + } + /* Check signaled state */ + ret = boottime->check_event(event); + if (ret != EFI_SUCCESS) { + efi_st_error("Event was not signaled on insert\n"); + return EFI_ST_FAILURE; + } + if (++table_count != sys_table->nr_tables) { + efi_st_error("Incorrect table count %u, expected %u\n", + (unsigned int)sys_table->nr_tables, + (unsigned int)table_count); + return EFI_ST_FAILURE; + } + table = NULL; + for (i = 0; i < sys_table->nr_tables; ++i) { + if (!efi_st_memcmp(&sys_table->tables[i].guid, &table_guid, + sizeof(efi_guid_t))) + table = sys_table->tables[i].table; + } + if (!table) { + efi_st_error("Installed table not found\n"); + return EFI_ST_FAILURE; + } + if (table != &tables[0]) { + efi_st_error("Incorrect table address\n"); + return EFI_ST_FAILURE; + } + /* Update table */ + ret = boottime->install_configuration_table(&table_guid, + (void *)&tables[1]); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to update table\n"); + return EFI_ST_FAILURE; + } + /* Check signaled state */ + ret = boottime->check_event(event); + if (ret != EFI_SUCCESS) { + efi_st_error("Event was not signaled on update\n"); + return EFI_ST_FAILURE; + } + if (table_count != sys_table->nr_tables) { + efi_st_error("Incorrect table count %u, expected %u\n", + (unsigned int)sys_table->nr_tables, + (unsigned int)table_count); + return EFI_ST_FAILURE; + } + table = NULL; + tabcnt = 0; + for (i = 0; i < sys_table->nr_tables; ++i) { + if (!efi_st_memcmp(&sys_table->tables[i].guid, &table_guid, + sizeof(efi_guid_t))) { + table = sys_table->tables[i].table; + ++tabcnt; + } + } + if (!table) { + efi_st_error("Installed table not found\n"); + return EFI_ST_FAILURE; + } + if (tabcnt > 1) { + efi_st_error("Duplicate table guid\n"); + return EFI_ST_FAILURE; + } + if (table != &tables[1]) { + efi_st_error("Incorrect table address\n"); + return EFI_ST_FAILURE; + } + + /* Delete table */ + ret = boottime->install_configuration_table(&table_guid, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to delete table\n"); + return EFI_ST_FAILURE; + } + /* Check signaled state */ + ret = boottime->check_event(event); + if (ret != EFI_SUCCESS) { + efi_st_error("Event was not signaled on delete\n"); + return EFI_ST_FAILURE; + } + if (--table_count != sys_table->nr_tables) { + efi_st_error("Incorrect table count %u, expected %u\n", + (unsigned int)sys_table->nr_tables, + (unsigned int)table_count); + return EFI_ST_FAILURE; + } + table = NULL; + for (i = 0; i < sys_table->nr_tables; ++i) { + if (!efi_st_memcmp(&sys_table->tables[i].guid, &table_guid, + sizeof(efi_guid_t))) { + table = sys_table->tables[i].table; + } + } + if (table) { + efi_st_error("Wrong table deleted\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->close_event(event); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close event\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(configtables) = { + .name = "configuration tables", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +};

On 06/28/2018 12:45 PM, Heinrich Schuchardt wrote:
Provide a unit test for InstallConfigurationTable().
A table is installed, updated, removed. The table entry and the triggering of events is checked.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de
Could you please do a crc test run that checks the crc32 header values of the systab/BTS/RTS structs at some early stage and again towards the end of your tests?
Alex
participants (2)
-
Alexander Graf
-
Heinrich Schuchardt