From 5375ee508fead38c733a56b394db7bae86435390 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 5 Jul 2019 21:27:13 +0200 Subject: [PATCH 01/17] disk: efi: buffer overflow in part_get_info_efi() In part_get_info_efi() we use the output of print_efiname() to set info->name[]. The size of info->name is PART_NAME_LEN = 32 but print_efiname() returns a string with a maximum length of PARTNAME_SZ + 1 = 37. Use snprintf() instead of sprintf() to avoid buffer overflow. Signed-off-by: Heinrich Schuchardt --- disk/part_efi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/disk/part_efi.c b/disk/part_efi.c index c0fa753339..3e026697db 100644 --- a/disk/part_efi.c +++ b/disk/part_efi.c @@ -313,8 +313,8 @@ int part_get_info_efi(struct blk_desc *dev_desc, int part, - info->start; info->blksz = dev_desc->blksz; - sprintf((char *)info->name, "%s", - print_efiname(&gpt_pte[part - 1])); + snprintf((char *)info->name, sizeof(info->name), "%s", + print_efiname(&gpt_pte[part - 1])); strcpy((char *)info->type, "U-Boot"); info->bootable = is_bootable(&gpt_pte[part - 1]); #if CONFIG_IS_ENABLED(PARTITION_UUIDS) From fb083801d5d0f196fa6b93442da1874baefb938c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 30 Jun 2019 07:27:09 +0200 Subject: [PATCH 02/17] efi_selftest: description of CMD_BOOTEFI_SELFTEST The current short description has a typo. Let it stand out clear that we provide unit tests. Improve the description of the CMD_BOOTEFI_SELFTEST configuration option. Signed-off-by: Heinrich Schuchardt Reviewed-by: Alexander Graf --- lib/efi_selftest/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/efi_selftest/Kconfig b/lib/efi_selftest/Kconfig index 59f9f36801..d20f5899af 100644 --- a/lib/efi_selftest/Kconfig +++ b/lib/efi_selftest/Kconfig @@ -1,9 +1,9 @@ config CMD_BOOTEFI_SELFTEST - bool "Allow booting an EFI efi_selftest" + bool "UEFI unit tests" depends on CMD_BOOTEFI imply FAT imply FAT_WRITE help - This adds an EFI test application to U-Boot that can be executed - with the 'bootefi selftest' command. It provides extended tests of - the EFI API implementation. + This adds a UEFI test application to U-Boot that can be executed + via the 'bootefi selftest' command. It provides extended tests of + the UEFI API implementation. From 983142dff8fdccfc6a063b2ffe9af14d432f6634 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 5 Jul 2019 17:43:13 +0200 Subject: [PATCH 03/17] test/py: error message test_efi_selftest_device_tree Correct the error message in test_efi_selftest_device_tree(). Signed-off-by: Heinrich Schuchardt --- test/py/tests/test_efi_selftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/py/tests/test_efi_selftest.py b/test/py/tests/test_efi_selftest.py index 07e4db0452..516e41cf51 100644 --- a/test/py/tests/test_efi_selftest.py +++ b/test/py/tests/test_efi_selftest.py @@ -37,7 +37,7 @@ def test_efi_selftest_device_tree(u_boot_console): u_boot_console.run_command(cmd='bootefi selftest ${fdtcontroladdr}', wait_for_prompt=False) m = u_boot_console.p.expect(['serial-number: Testing DT', 'U-Boot']) if m != 0: - raise Exception('Reset failed in \'device tree\' test') + raise Exception('serial-number missing in device tree') u_boot_console.restart_uboot(); @pytest.mark.buildconfigspec('cmd_bootefi_selftest') From 359a699a12bac28cf6b3b0ce7af06bd72bb3b638 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 3 Jul 2019 20:27:24 +0200 Subject: [PATCH 04/17] efi_loader: remove superfluous spaces in comments Leave only a single space after * if not aligning. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index d104cc6b31..e62410c57f 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * EFI application boot time services + * EFI application boot time services * - * Copyright (c) 2016 Alexander Graf + * Copyright (c) 2016 Alexander Graf */ #include @@ -3234,7 +3234,7 @@ static efi_status_t efi_connect_single_controller( if (r != EFI_SUCCESS) return r; - /* Context Override */ + /* Context Override */ if (driver_image_handle) { for (; *driver_image_handle; ++driver_image_handle) { for (i = 0; i < count; ++i) { @@ -3341,7 +3341,7 @@ static efi_status_t EFIAPI efi_connect_controller( } } } - /* Check for child controller specified by end node */ + /* Check for child controller specified by end node */ if (ret != EFI_SUCCESS && remain_device_path && remain_device_path->type == DEVICE_PATH_TYPE_END) ret = EFI_SUCCESS; From ce43528d6a9ff3d1099a6bc194f0cccc8f0df44d Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 20 Jun 2019 12:13:05 +0200 Subject: [PATCH 05/17] efi_loader: move efi_query_variable_info() Let's keep similar things together. Move efi_query_variable_info() to lib/efi_loader/efi_variable.c Signed-off-by: Heinrich Schuchardt --- include/efi_loader.h | 5 +++++ lib/efi_loader/efi_runtime.c | 27 --------------------------- lib/efi_loader/efi_variable.c | 27 +++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index b07155cecb..de1e67fd40 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -618,6 +618,11 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name, const efi_guid_t *vendor, u32 attributes, efi_uintn_t data_size, const void *data); +efi_status_t EFIAPI efi_query_variable_info( + u32 attributes, u64 *maximum_variable_storage_size, + u64 *remaining_variable_storage_size, + u64 *maximum_variable_size); + /* * See section 3.1.3 in the v2.7 UEFI spec for more details on * the layout of EFI_LOAD_OPTION. In short it is: diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 40fdc0ea92..dd91880ad6 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -782,33 +782,6 @@ efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps( return EFI_UNSUPPORTED; } -/** - * efi_query_variable_info() - get information about EFI variables - * - * This function implements the QueryVariableInfo() runtime service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. - * - * @attributes: bitmask to select variables to be - * queried - * @maximum_variable_storage_size: maximum size of storage area for the - * selected variable types - * @remaining_variable_storage_size: remaining size of storage are for the - * selected variable types - * @maximum_variable_size: maximum size of a variable of the - * selected type - * Returns: status code - */ -efi_status_t __efi_runtime EFIAPI efi_query_variable_info( - u32 attributes, - u64 *maximum_variable_storage_size, - u64 *remaining_variable_storage_size, - u64 *maximum_variable_size) -{ - return EFI_UNSUPPORTED; -} - struct efi_runtime_services __efi_runtime_data efi_runtime_services = { .hdr = { .signature = EFI_RUNTIME_SERVICES_SIGNATURE, diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index d6b75ca02e..f71dc29ee9 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -520,3 +520,30 @@ out: return EFI_EXIT(ret); } + +/** + * efi_query_variable_info() - get information about EFI variables + * + * This function implements the QueryVariableInfo() runtime service. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * @attributes: bitmask to select variables to be + * queried + * @maximum_variable_storage_size: maximum size of storage area for the + * selected variable types + * @remaining_variable_storage_size: remaining size of storage are for the + * selected variable types + * @maximum_variable_size: maximum size of a variable of the + * selected type + * Returns: status code + */ +efi_status_t __efi_runtime EFIAPI efi_query_variable_info( + u32 attributes, + u64 *maximum_variable_storage_size, + u64 *remaining_variable_storage_size, + u64 *maximum_variable_size) +{ + return EFI_UNSUPPORTED; +} From 88192098d160aff42c08a9e4edc746a55d199232 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 20 Jun 2019 13:52:16 +0200 Subject: [PATCH 06/17] efi_loader: initialization of variable services Provide an initialization routine for variable services. Signed-off-by: Heinrich Schuchardt --- include/efi_loader.h | 2 ++ lib/efi_loader/efi_setup.c | 5 +++++ lib/efi_loader/efi_variable.c | 10 ++++++++++ 3 files changed, 17 insertions(+) diff --git a/include/efi_loader.h b/include/efi_loader.h index de1e67fd40..d30c4e8ef3 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -325,6 +325,8 @@ extern struct list_head efi_register_notify_events; /* Initialize efi execution environment */ efi_status_t efi_init_obj_list(void); +/* Initialize variable services */ +efi_status_t efi_init_variables(void); /* Called by bootefi to initialize root node */ efi_status_t efi_root_node_register(void); /* Called by bootefi to initialize runtime */ diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index bfb57836fa..de7b616c6d 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -102,6 +102,11 @@ efi_status_t efi_init_obj_list(void) /* On ARM switch from EL3 or secure mode to EL2 or non-secure mode */ switch_to_non_secure_mode(); + /* Initialize variable services */ + ret = efi_init_variables(); + if (ret != EFI_SUCCESS) + goto out; + /* Define supported languages */ ret = efi_init_platform_lang(); if (ret != EFI_SUCCESS) diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index f71dc29ee9..6210425f5e 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -547,3 +547,13 @@ efi_status_t __efi_runtime EFIAPI efi_query_variable_info( { return EFI_UNSUPPORTED; } + +/** + * efi_init_variables() - initialize variable services + * + * Return: status code + */ +efi_status_t efi_init_variables(void) +{ + return EFI_SUCCESS; +} From 93148eba77dcab583ca2a28b7f837afe056a56a6 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 29 Jun 2019 02:00:16 +0200 Subject: [PATCH 07/17] efi_loader: remove NULL entries from runtime detach list Some entries in the system table are set to NULL in ExitBootServices(). We had them in the runtime detach list to avoid relocation of NULL. Let's instead assign the pointers dynamically in efi_initialize_system_table() to avoid the relocation entry. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 13 +++++++++---- lib/efi_loader/efi_runtime.c | 16 ---------------- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index e62410c57f..bf2df80c83 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -3620,11 +3620,7 @@ struct efi_system_table __efi_runtime_data systab = { }, .fw_vendor = firmware_vendor, .fw_revision = FW_VERSION << 16 | FW_PATCHLEVEL << 8, - .con_in = &efi_con_in, - .con_out = &efi_con_out, - .std_err = &efi_con_out, .runtime = &efi_runtime_services, - .boottime = &efi_boot_services, .nr_tables = 0, .tables = NULL, }; @@ -3644,6 +3640,15 @@ efi_status_t efi_initialize_system_table(void) sizeof(struct efi_configuration_table), (void **)&systab.tables); + /* + * These entries will be set to NULL in ExitBootServices(). To avoid + * relocation in SetVirtualAddressMap(), set them dynamically. + */ + systab.con_in = &efi_con_in; + systab.con_out = &efi_con_out; + systab.std_err = &efi_con_out; + systab.boottime = &efi_boot_services; + /* Set CRC32 field in table headers */ efi_update_table_header_crc32(&systab.hdr); efi_update_table_header_crc32(&efi_runtime_services.hdr); diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index dd91880ad6..c56230cad3 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -408,22 +408,6 @@ static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = { }, { .ptr = &efi_runtime_services.set_time, .patchto = &efi_set_time, - }, { - /* Clean up system table */ - .ptr = &systab.con_in, - .patchto = NULL, - }, { - /* Clean up system table */ - .ptr = &systab.con_out, - .patchto = NULL, - }, { - /* Clean up system table */ - .ptr = &systab.std_err, - .patchto = NULL, - }, { - /* Clean up system table */ - .ptr = &systab.boottime, - .patchto = NULL, }, { .ptr = &efi_runtime_services.get_variable, .patchto = &efi_device_error, From 24a238f7633cbebcc00b810d0ac1608233a81fbf Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 20 Jun 2019 22:00:02 +0000 Subject: [PATCH 08/17] efi_loader: clean up runtime detaching The detaching of the runtime will have to move to ExitBootServices() to encompass operating system that do not call SetVirtualAddressMap(). This patch changes the logic for the relocation of the pointers in the runtime table such that the relocation becomes independent of the entries in the detach list. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_runtime.c | 78 +++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 23 deletions(-) diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index c56230cad3..702136ae0e 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -420,29 +420,53 @@ static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = { } }; -static bool efi_runtime_tobedetached(void *p) +/** + * efi_is_runtime_service_pointer() - check if pointer points to runtime table + * + * @p: pointer to check + * Return: true if the pointer points to a service function pointer in the + * runtime table + */ +static bool efi_is_runtime_service_pointer(void *p) { - int i; - - for (i = 0; i < ARRAY_SIZE(efi_runtime_detach_list); i++) - if (efi_runtime_detach_list[i].ptr == p) - return true; - - return false; + return p >= (void *)&efi_runtime_services.get_time && + p <= (void *)&efi_runtime_services.query_variable_info; } -static void efi_runtime_detach(ulong offset) +static __efi_runtime void efi_runtime_detach(void) { int i; - ulong patchoff = offset - (ulong)gd->relocaddr; + /* + * Replace boottime functions by runtime functions + * TODO: move this step to ExitBootServices() + */ for (i = 0; i < ARRAY_SIZE(efi_runtime_detach_list); i++) { ulong patchto = (ulong)efi_runtime_detach_list[i].patchto; ulong *p = efi_runtime_detach_list[i].ptr; - ulong newaddr = patchto ? (patchto + patchoff) : 0; - debug("%s: Setting %p to %lx\n", __func__, p, newaddr); - *p = newaddr; + debug("%s: Setting %p to %lx\n", __func__, p, patchto); + *p = patchto; + } +} + +static __efi_runtime void efi_relocate_runtime_table(ulong offset) +{ + ulong patchoff; + void **pos; + + /* Relocate the runtime services pointers */ + patchoff = offset - gd->relocaddr; + for (pos = (void **)&efi_runtime_services.get_time; + pos <= (void **)&efi_runtime_services.query_variable_info; ++pos) { + /* + * The UEFI spec requires not to update VirtualAddressMap() + * and ConvertPointer(). + */ + if (*pos && pos != + (void **)&efi_runtime_services.set_virtual_address_map && + pos != (void **)&efi_runtime_services.convert_pointer) + *pos += patchoff; } /* Update CRC32 */ @@ -467,6 +491,10 @@ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map) p = (void*)((ulong)rel->offset - base) + gd->relocaddr; + /* The runtime services are updated in efi_runtime_detach() */ + if (map && efi_is_runtime_service_pointer(p)) + continue; + debug("%s: rel->info=%#lx *p=%#lx rel->offset=%p\n", __func__, rel->info, *p, rel->offset); @@ -490,9 +518,8 @@ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map) } #endif default: - if (!efi_runtime_tobedetached(p)) - printf("%s: Unknown relocation type %llx\n", - __func__, rel->info & R_MASK); + printf("%s: Unknown relocation type %llx\n", + __func__, rel->info & R_MASK); continue; } @@ -500,9 +527,8 @@ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map) if (map && ((newaddr < map->virtual_start) || newaddr > (map->virtual_start + (map->num_pages << EFI_PAGE_SHIFT)))) { - if (!efi_runtime_tobedetached(p)) - printf("%s: Relocation at %p is out of " - "range (%lx)\n", __func__, p, newaddr); + printf("%s: Relocation at %p is out of range (%lx)\n", + __func__, p, newaddr); continue; } @@ -607,7 +633,15 @@ static efi_status_t EFIAPI efi_set_virtual_address_map( } } - /* Move the actual runtime code over */ + /* + * Some runtime services are implemented in a way that we can only offer + * them at boottime. Replace those function pointers. + * + * TODO: move this call to ExitBootServices(). + */ + efi_runtime_detach(); + + /* Relocate the runtime. See TODO above */ for (i = 0; i < n; i++) { struct efi_mem_desc *map; @@ -616,10 +650,8 @@ static efi_status_t EFIAPI efi_set_virtual_address_map( ulong new_offset = map->virtual_start - map->physical_start + gd->relocaddr; + efi_relocate_runtime_table(new_offset); efi_runtime_relocate(new_offset, map); - /* Once we're virtual, we can no longer handle - complex callbacks */ - efi_runtime_detach(new_offset); return EFI_EXIT(EFI_SUCCESS); } } From 29018abb09a6ad638df38d6df5ab089ef1115e3c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 20 Jun 2019 15:25:48 +0200 Subject: [PATCH 09/17] efi_loader: let the variable driver patch out the runtime Our variable services are only provided at boottime. Therefore when leaving boottime the variable function are replaced by dummy functions returning EFI_UNSUPPORTED. Move this patching of the runtime table to the variable services implementation. Executed it in ExitBootServices(). Signed-off-by: Heinrich Schuchardt --- include/efi_loader.h | 2 ++ lib/efi_loader/efi_boottime.c | 3 ++- lib/efi_loader/efi_runtime.c | 9 ------- lib/efi_loader/efi_variable.c | 44 +++++++++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 10 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index d30c4e8ef3..8d75dde569 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -327,6 +327,8 @@ extern struct list_head efi_register_notify_events; efi_status_t efi_init_obj_list(void); /* Initialize variable services */ efi_status_t efi_init_variables(void); +/* Notify ExitBootServices() is called */ +void efi_variables_boot_exit_notify(void); /* Called by bootefi to initialize root node */ efi_status_t efi_root_node_register(void); /* Called by bootefi to initialize runtime */ diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index bf2df80c83..ba4c1e5765 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1968,7 +1968,8 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, /* Make sure that notification functions are not called anymore */ efi_tpl = TPL_HIGH_LEVEL; - /* TODO: Should persist EFI variables here */ + /* Notify variable services */ + efi_variables_boot_exit_notify(); board_quiesce_devices(); diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 702136ae0e..bc2a23afbb 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -408,15 +408,6 @@ static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = { }, { .ptr = &efi_runtime_services.set_time, .patchto = &efi_set_time, - }, { - .ptr = &efi_runtime_services.get_variable, - .patchto = &efi_device_error, - }, { - .ptr = &efi_runtime_services.get_next_variable_name, - .patchto = &efi_device_error, - }, { - .ptr = &efi_runtime_services.set_variable, - .patchto = &efi_device_error, } }; diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 6210425f5e..bc8ed678c9 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -548,6 +548,50 @@ efi_status_t __efi_runtime EFIAPI efi_query_variable_info( return EFI_UNSUPPORTED; } +/** + * efi_get_variable_runtime() - runtime implementation of GetVariable() + */ +static efi_status_t __efi_runtime EFIAPI +efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *vendor, + u32 *attributes, efi_uintn_t *data_size, void *data) +{ + return EFI_UNSUPPORTED; +} + +/** + * efi_get_next_variable_name_runtime() - runtime implementation of + * GetNextVariable() + */ +static efi_status_t __efi_runtime EFIAPI +efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size, + u16 *variable_name, const efi_guid_t *vendor) +{ + return EFI_UNSUPPORTED; +} + +/** + * efi_set_variable_runtime() - runtime implementation of SetVariable() + */ +static efi_status_t __efi_runtime EFIAPI +efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor, + u32 attributes, efi_uintn_t data_size, + const void *data) +{ + return EFI_UNSUPPORTED; +} + +/** + * efi_variables_boot_exit_notify() - notify ExitBootServices() is called + */ +void efi_variables_boot_exit_notify(void) +{ + efi_runtime_services.get_variable = efi_get_variable_runtime; + efi_runtime_services.get_next_variable_name = + efi_get_next_variable_name_runtime; + efi_runtime_services.set_variable = efi_set_variable_runtime; + efi_update_table_header_crc32(&efi_runtime_services.hdr); +} + /** * efi_init_variables() - initialize variable services * From b94461c224ac65714a5f50861e8f660665ed559f Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 20 Jun 2019 15:40:49 +0200 Subject: [PATCH 10/17] efi_loader: unimplemented runtime services Unimplemented runtime services should always return EFI_UNSUPPORTED as described in the UEFI 2.8 spec. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_runtime.c | 34 ++-------------------------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index bc2a23afbb..7e0526f485 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -26,8 +26,6 @@ struct efi_runtime_mmio_list { LIST_HEAD(efi_runtime_mmio); static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void); -static efi_status_t __efi_runtime EFIAPI efi_device_error(void); -static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void); /* * TODO(sjg@chromium.org): These defines and structures should come from the ELF @@ -717,34 +715,6 @@ static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void) return EFI_UNSUPPORTED; } -/** - * efi_device_error() - replacement function, returns EFI_DEVICE_ERROR - * - * This function is used after SetVirtualAddressMap() is called as replacement - * for services that are not available anymore due to constraints of the U-Boot - * implementation. - * - * Return: EFI_DEVICE_ERROR - */ -static efi_status_t __efi_runtime EFIAPI efi_device_error(void) -{ - return EFI_DEVICE_ERROR; -} - -/** - * efi_invalid_parameter() - replacement function, returns EFI_INVALID_PARAMETER - * - * This function is used after SetVirtualAddressMap() is called as replacement - * for services that are not available anymore due to constraints of the U-Boot - * implementation. - * - * Return: EFI_INVALID_PARAMETER - */ -static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void) -{ - return EFI_INVALID_PARAMETER; -} - /** * efi_update_capsule() - process information from operating system * @@ -800,11 +770,11 @@ struct efi_runtime_services __efi_runtime_data efi_runtime_services = { .get_wakeup_time = (void *)&efi_unimplemented, .set_wakeup_time = (void *)&efi_unimplemented, .set_virtual_address_map = &efi_set_virtual_address_map, - .convert_pointer = (void *)&efi_invalid_parameter, + .convert_pointer = (void *)&efi_unimplemented, .get_variable = efi_get_variable, .get_next_variable_name = efi_get_next_variable_name, .set_variable = efi_set_variable, - .get_next_high_mono_count = (void *)&efi_device_error, + .get_next_high_mono_count = (void *)&efi_unimplemented, .reset_system = &efi_reset_system_boottime, .update_capsule = efi_update_capsule, .query_capsule_caps = efi_query_capsule_caps, From 1bb52fc2d20da0502c0514109e102bdcf3a25b6e Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 20 Jun 2019 16:18:48 +0200 Subject: [PATCH 11/17] efi_selftest: test variable services at runtime Provide a unit test for the variable services at runtime. Currently we expect EFI_UNSUPPORTED to be returned as the runtime implementation is still missing. Signed-off-by: Heinrich Schuchardt --- lib/efi_selftest/Makefile | 1 + .../efi_selftest_variables_runtime.c | 94 +++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_variables_runtime.c diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 3bebd0f573..88678755cc 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -35,6 +35,7 @@ efi_selftest_textoutput.o \ efi_selftest_tpl.o \ efi_selftest_util.o \ efi_selftest_variables.o \ +efi_selftest_variables_runtime.o \ efi_selftest_watchdog.o obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_selftest_devicepath.o diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c new file mode 100644 index 0000000000..b3b40ad2cf --- /dev/null +++ b/lib/efi_selftest/efi_selftest_variables_runtime.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_variables_runtime + * + * Copyright (c) 2019 Heinrich Schuchardt + * + * This unit test checks the runtime services for variables after + * ExitBootServices(): + * GetVariable, GetNextVariableName, SetVariable, QueryVariableInfo. + */ + +#include + +#define EFI_ST_MAX_DATA_SIZE 16 +#define EFI_ST_MAX_VARNAME_SIZE 40 + +static struct efi_boot_services *boottime; +static struct efi_runtime_services *runtime; +static const efi_guid_t guid_vendor0 = + EFI_GUID(0x67029eb5, 0x0af2, 0xf6b1, + 0xda, 0x53, 0xfc, 0xb5, 0x66, 0xdd, 0x1c, 0xe6); + +/* + * Setup unit test. + * + * @handle handle of the loaded image + * @systable system table + */ +static int setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + boottime = systable->boottime; + runtime = systable->runtime; + + return EFI_ST_SUCCESS; +} + +/** + * execute() - execute unit test + * + * As runtime support is not implmented expect EFI_UNSUPPORTED to be returned. + */ +static int execute(void) +{ + efi_status_t ret; + efi_uintn_t len; + u32 attr; + u8 v[16] = {0x5d, 0xd1, 0x5e, 0x51, 0x5a, 0x05, 0xc7, 0x0c, + 0x35, 0x4a, 0xae, 0x87, 0xa5, 0xdf, 0x0f, 0x65,}; + u8 data[EFI_ST_MAX_DATA_SIZE]; + u16 varname[EFI_ST_MAX_VARNAME_SIZE]; + efi_guid_t guid; + u64 max_storage, rem_storage, max_size; + + ret = runtime->query_variable_info(EFI_VARIABLE_BOOTSERVICE_ACCESS, + &max_storage, &rem_storage, + &max_size); + if (ret != EFI_UNSUPPORTED) { + efi_st_error("QueryVariableInfo failed\n"); + return EFI_ST_FAILURE; + } + + ret = runtime->set_variable(L"efi_st_var0", &guid_vendor0, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + 3, v + 4); + if (ret != EFI_UNSUPPORTED) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + len = 3; + ret = runtime->get_variable(L"efi_st_var0", &guid_vendor0, + &attr, &len, data); + if (ret != EFI_UNSUPPORTED) { + efi_st_error("GetVariable failed\n"); + return EFI_ST_FAILURE; + } + memset(&guid, 0, 16); + *varname = 0; + ret = runtime->get_next_variable_name(&len, varname, &guid); + if (ret != EFI_UNSUPPORTED) { + efi_st_error("GetNextVariableName failed\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(variables_run) = { + .name = "variables at runtime", + .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; From ee8ebaaaaedc21e06bf3c11c8589c2f201afb88c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 29 Jun 2019 03:32:52 +0200 Subject: [PATCH 12/17] efi_loader: split off detaching SetVirtualAddress() The runtime services SetVirtualAddress() and ConvertPointer() become unavailable after SetVirtualAddress(). Other runtime services become unavailable after ExitBootServices. Move the update of SetVirtualAddress() and ConvertPointer() to efi_relocate_runtime_table(). Use functions with the correct signature when detaching. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_runtime.c | 69 ++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 7e0526f485..63d8a29146 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -395,10 +395,6 @@ static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = { /* do_reset is gone */ .ptr = &efi_runtime_services.reset_system, .patchto = efi_reset_system, - }, { - /* invalidate_*cache_all are gone */ - .ptr = &efi_runtime_services.set_virtual_address_map, - .patchto = &efi_unimplemented, }, { /* RTC accessors are gone */ .ptr = &efi_runtime_services.get_time, @@ -439,6 +435,50 @@ static __efi_runtime void efi_runtime_detach(void) } } +/** + * efi_set_virtual_address_map_runtime() - change from physical to virtual + * mapping + * + * This function implements the SetVirtualAddressMap() runtime service after + * it is first called. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * @memory_map_size: size of the virtual map + * @descriptor_size: size of an entry in the map + * @descriptor_version: version of the map entries + * @virtmap: virtual address mapping information + * Return: status code EFI_UNSUPPORTED + */ +static efi_status_t EFIAPI efi_set_virtual_address_map_runtime( + unsigned long memory_map_size, + unsigned long descriptor_size, + uint32_t descriptor_version, + struct efi_mem_desc *virtmap) +{ + return EFI_UNSUPPORTED; +} + +/** + * efi_convert_pointer_runtime() - convert from physical to virtual pointer + * + * This function implements the ConvertPointer() runtime service after + * the first call to SetVirtualAddressMap(). + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * @debug_disposition: indicates if pointer may be converted to NULL + * @address: pointer to be converted + * Return: status code EFI_UNSUPPORTED + */ +static __efi_runtime efi_status_t EFIAPI efi_convert_pointer_runtime( + efi_uintn_t debug_disposition, void **address) +{ + return EFI_UNSUPPORTED; +} + static __efi_runtime void efi_relocate_runtime_table(ulong offset) { ulong patchoff; @@ -448,16 +488,23 @@ static __efi_runtime void efi_relocate_runtime_table(ulong offset) patchoff = offset - gd->relocaddr; for (pos = (void **)&efi_runtime_services.get_time; pos <= (void **)&efi_runtime_services.query_variable_info; ++pos) { - /* - * The UEFI spec requires not to update VirtualAddressMap() - * and ConvertPointer(). - */ - if (*pos && pos != - (void **)&efi_runtime_services.set_virtual_address_map && - pos != (void **)&efi_runtime_services.convert_pointer) + if (*pos) *pos += patchoff; } + /* + * The entry for SetVirtualAddress() must point to a physical address. + * After the first execution the service must return EFI_UNSUPPORTED. + */ + efi_runtime_services.set_virtual_address_map = + &efi_set_virtual_address_map_runtime; + + /* + * The entry for ConvertPointer() must point to a physical address. + * The service is not usable after SetVirtualAddress(). + */ + efi_runtime_services.convert_pointer = &efi_convert_pointer_runtime; + /* Update CRC32 */ efi_update_table_header_crc32(&efi_runtime_services.hdr); } From c7308d6e2307c763f0006f4933da3bfbb875bed7 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 28 Jun 2019 19:31:55 +0200 Subject: [PATCH 13/17] efi_loader: bump UEFI specification number to 2.8 We are implementing UEFI variable RuntimeServicesSupported and set the unimplemented runtime functions return EFI_UNSUPPORTED as described in UEFI specification 2.8. So let's also advertise this specification version in our system table. Signed-off-by: Heinrich Schuchardt Reviewed-by: Alexander Graf --- include/efi_api.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/efi_api.h b/include/efi_api.h index a36ececc81..d4f32dbdc8 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -23,8 +23,8 @@ #include #endif -/* UEFI spec version 2.7 */ -#define EFI_SPECIFICATION_VERSION (2 << 16 | 70) +/* UEFI spec version 2.8 */ +#define EFI_SPECIFICATION_VERSION (2 << 16 | 80) /* Types and defines for EFI CreateEvent */ enum efi_timer_delay { From 0b1da53e534a89afc2f5ddcbe2bdbde83cf37523 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 5 Jul 2019 18:16:51 +0200 Subject: [PATCH 14/17] test/py: not all boards support UEFI runtime reset As not all boards support resets at runtime do not test for it in the Python tests. Signed-off-by: Heinrich Schuchardt --- test/py/tests/test_efi_selftest.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/py/tests/test_efi_selftest.py b/test/py/tests/test_efi_selftest.py index 516e41cf51..d5430f9c12 100644 --- a/test/py/tests/test_efi_selftest.py +++ b/test/py/tests/test_efi_selftest.py @@ -19,10 +19,6 @@ def test_efi_selftest(u_boot_console): m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key']) if m != 0: raise Exception('Failures occurred during the EFI selftest') - u_boot_console.run_command(cmd='', wait_for_echo=False, wait_for_prompt=False); - m = u_boot_console.p.expect(['resetting', 'U-Boot']) - if m != 0: - raise Exception('Reset failed during the EFI selftest') u_boot_console.restart_uboot(); @pytest.mark.buildconfigspec('cmd_bootefi_selftest') From 953661a9124ec38a51963608773e2f1a0c041a1a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 5 Jul 2019 18:12:16 +0200 Subject: [PATCH 15/17] efi_loader: decision on EFI_RT_SUPPORTED_RESET_SYSTEM Move the logic determining which board supports reset at runtime to Kconfig. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/Kconfig | 6 ++++++ lib/efi_loader/efi_runtime.c | 5 +---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index cd5436c576..a7f2c68fa9 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -101,4 +101,10 @@ config EFI_PLATFORM_LANG_CODES RFC 4646 format, e.g. "en-US;de-DE". The first language code is used to initialize the PlatformLang variable. +config EFI_HAVE_RUNTIME_RESET + # bool "Reset runtime service is available" + bool + default y + depends on ARCH_BCM283X || FSL_LAYERSCAPE || PSCI_RESET || SYSRESET_X86 + endif diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 63d8a29146..59dde8a27d 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -95,10 +95,7 @@ efi_status_t efi_init_runtime_supported(void) * This value must be synced with efi_runtime_detach_list * as well as efi_runtime_services. */ -#if CONFIG_IS_ENABLED(ARCH_BCM283X) || \ - CONFIG_IS_ENABLED(FSL_LAYERSCAPE) || \ - CONFIG_IS_ENABLED(SYSRESET_X86) || \ - CONFIG_IS_ENABLED(PSCI_RESET) +#ifdef CONFIG_EFI_HAVE_RUNTIME_RESET efi_runtime_services_supported |= EFI_RT_SUPPORTED_RESET_SYSTEM; #endif efi_runtime_services_supported |= From b23ffcbe02dc7182d910ab081bd6d33a5b540777 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 5 Jul 2019 18:12:21 +0200 Subject: [PATCH 16/17] efi_loader: simplify detaching We do not need any array typed detach list. Let's simply update the pointers directly. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_runtime.c | 40 ++++++++---------------------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 59dde8a27d..dcbe824451 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -382,26 +382,6 @@ efi_status_t __weak __efi_runtime EFIAPI efi_set_time(struct efi_time *time) return EFI_UNSUPPORTED; } -struct efi_runtime_detach_list_struct { - void *ptr; - void *patchto; -}; - -static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = { - { - /* do_reset is gone */ - .ptr = &efi_runtime_services.reset_system, - .patchto = efi_reset_system, - }, { - /* RTC accessors are gone */ - .ptr = &efi_runtime_services.get_time, - .patchto = &efi_get_time, - }, { - .ptr = &efi_runtime_services.set_time, - .patchto = &efi_set_time, - } -}; - /** * efi_is_runtime_service_pointer() - check if pointer points to runtime table * @@ -415,21 +395,17 @@ static bool efi_is_runtime_service_pointer(void *p) p <= (void *)&efi_runtime_services.query_variable_info; } +/** + * efi_runtime_detach() - detach unimplemented runtime functions + */ static __efi_runtime void efi_runtime_detach(void) { - int i; + efi_runtime_services.reset_system = efi_reset_system; + efi_runtime_services.get_time = efi_get_time; + efi_runtime_services.set_time = efi_set_time; - /* - * Replace boottime functions by runtime functions - * TODO: move this step to ExitBootServices() - */ - for (i = 0; i < ARRAY_SIZE(efi_runtime_detach_list); i++) { - ulong patchto = (ulong)efi_runtime_detach_list[i].patchto; - ulong *p = efi_runtime_detach_list[i].ptr; - - debug("%s: Setting %p to %lx\n", __func__, p, patchto); - *p = patchto; - } + /* Update CRC32 */ + efi_update_table_header_crc32(&efi_runtime_services.hdr); } /** From 7f95104d91ccfb26f802feb5300838b41bc5fbb1 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 5 Jul 2019 17:42:16 +0200 Subject: [PATCH 17/17] efi_loader: detach runtime in ExitBootServices() Linux can be called with a command line parameter efi=novamap, cf. commit 4e46c2a95621 ("efi/arm/arm64: Allow SetVirtualAddressMap() to be omitted"). In this case SetVirtualAddressMap() is not called after ExitBootServices(). OpenBSD 32bit does not call SetVirtualAddressMap() either. Runtime services must be set to an implementation supported at runtime in ExitBootServices(). Reported-by: Ard Biesheuvel Suggested-by: Alexander Graf Signed-off-by: Heinrich Schuchardt --- include/efi_loader.h | 2 ++ lib/efi_loader/efi_boottime.c | 3 +++ lib/efi_loader/efi_runtime.c | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index 8d75dde569..db4763fc9b 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -333,6 +333,8 @@ void efi_variables_boot_exit_notify(void); efi_status_t efi_root_node_register(void); /* Called by bootefi to initialize runtime */ efi_status_t efi_initialize_system_table(void); +/* efi_runtime_detach() - detach unimplemented runtime functions */ +void efi_runtime_detach(void); /* Called by bootefi to make console interface available */ efi_status_t 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 ba4c1e5765..c2f89805c7 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1973,6 +1973,9 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, board_quiesce_devices(); + /* Patch out unsupported runtime function */ + efi_runtime_detach(); + /* Fix up caches for EFI payloads if necessary */ efi_exit_caches(); diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index dcbe824451..7a64dd42ca 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -398,7 +398,7 @@ static bool efi_is_runtime_service_pointer(void *p) /** * efi_runtime_detach() - detach unimplemented runtime functions */ -static __efi_runtime void efi_runtime_detach(void) +void efi_runtime_detach(void) { efi_runtime_services.reset_system = efi_reset_system; efi_runtime_services.get_time = efi_get_time;