[U-Boot] [PATCH v2 0/4] efi_loader: implement ConvertPointer()

Correct the signature of efi_virtual_address_map(). Implement the ConvertPointer() runtime service. Adjust the unit test for ConvertPointer().
v2 replace || by | when setting RuntimeServicesSupported variable
Heinrich Schuchardt (4): efi_selftest: fix SetVirtualAddressMap unit test efi_loader: definition of efi_virtual_address_map() efi_loader: implement ConvertPointer() efi_selftest: sharpen ConvertPointer() test
include/efi_api.h | 4 +- lib/efi_loader/efi_runtime.c | 89 ++++++++++++++++--- .../efi_selftest_set_virtual_address_map.c | 31 +++++-- 3 files changed, 103 insertions(+), 21 deletions(-)
-- 2.20.1

We read the address map before assigning the memory for the pages that will be mapped to virtual addresses. So these pages will overlap with the entry for EFI_CONVENTIONAL_MEMORY. We have to ensure that every page is described at most once in the map.
Remove EFI_CONVENTIONAL_MEMORY from the map that we pass to SetVirtualAddressMap().
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- v2 no change --- lib/efi_selftest/efi_selftest_set_virtual_address_map.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/lib/efi_selftest/efi_selftest_set_virtual_address_map.c b/lib/efi_selftest/efi_selftest_set_virtual_address_map.c index 6ee7bbeb01..3ffb61b7e8 100644 --- a/lib/efi_selftest/efi_selftest_set_virtual_address_map.c +++ b/lib/efi_selftest/efi_selftest_set_virtual_address_map.c @@ -123,6 +123,7 @@ static int setup(const efi_handle_t handle, case EFI_LOADER_DATA: case EFI_BOOT_SERVICES_CODE: case EFI_BOOT_SERVICES_DATA: + case EFI_CONVENTIONAL_MEMORY: continue; } memcpy(pos1, pos2, desc_size); -- 2.20.1

Use efi_uintn_t where the UEFI spec uses UINTN. Use efi_uintn_t also for the result of the division of two efi_uintn_t.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- v2 no change --- include/efi_api.h | 4 ++-- lib/efi_loader/efi_runtime.c | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/include/efi_api.h b/include/efi_api.h index d4f32dbdc8..e5634dc6a0 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -238,8 +238,8 @@ struct efi_runtime_services { efi_status_t (EFIAPI *set_wakeup_time)(char enabled, struct efi_time *time); efi_status_t (EFIAPI *set_virtual_address_map)( - unsigned long memory_map_size, - unsigned long descriptor_size, + efi_uintn_t memory_map_size, + efi_uintn_t descriptor_size, uint32_t descriptor_version, struct efi_mem_desc *virtmap); efi_status_t (EFIAPI *convert_pointer)( diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 8b56ab0207..a8f0b5eae3 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -427,8 +427,8 @@ void efi_runtime_detach(void) * Return: status code EFI_UNSUPPORTED */ static __efi_runtime efi_status_t EFIAPI efi_set_virtual_address_map_runtime( - unsigned long memory_map_size, - unsigned long descriptor_size, + efi_uintn_t memory_map_size, + efi_uintn_t descriptor_size, uint32_t descriptor_version, struct efi_mem_desc *virtmap) { @@ -571,17 +571,17 @@ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map) * Return: status code */ static efi_status_t EFIAPI efi_set_virtual_address_map( - unsigned long memory_map_size, - unsigned long descriptor_size, + efi_uintn_t memory_map_size, + efi_uintn_t descriptor_size, uint32_t descriptor_version, struct efi_mem_desc *virtmap) { - int n = memory_map_size / descriptor_size; - int i; + efi_uintn_t n = memory_map_size / descriptor_size; + efi_uintn_t i; int rt_code_sections = 0; struct efi_event *event;
- EFI_ENTRY("%lx %lx %x %p", memory_map_size, descriptor_size, + EFI_ENTRY("%zx %zx %x %p", memory_map_size, descriptor_size, descriptor_version, virtmap);
/* -- 2.20.1

Implement the ConvertPointer() runtime service.
Suggested-by: AKASHI Takahiro takahiro.akashi@linaro.org Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- v2 replace || by | when setting RuntimeServicesSupported variable --- lib/efi_loader/efi_runtime.c | 75 ++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 4 deletions(-)
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index a8f0b5eae3..2286e847a7 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -81,6 +81,10 @@ struct elf_rela { long addend; };
+static __efi_runtime_data struct efi_mem_desc *efi_virtmap; +static __efi_runtime_data efi_uintn_t efi_descriptor_count; +static __efi_runtime_data efi_uintn_t efi_descriptor_size; + /* * EFI runtime code lives in two stages. In the first stage, U-Boot and an EFI * payload are running concurrently at the same time. In this mode, we can @@ -89,7 +93,9 @@ struct elf_rela {
efi_status_t efi_init_runtime_supported(void) { - u16 efi_runtime_services_supported = 0; + u16 efi_runtime_services_supported = + EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP | + EFI_RT_SUPPORTED_CONVERT_POINTER;
/* * This value must be synced with efi_runtime_detach_list @@ -98,8 +104,7 @@ efi_status_t efi_init_runtime_supported(void) #ifdef CONFIG_EFI_HAVE_RUNTIME_RESET efi_runtime_services_supported |= EFI_RT_SUPPORTED_RESET_SYSTEM; #endif - efi_runtime_services_supported |= - EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP; + return EFI_CALL(efi_set_variable(L"RuntimeServicesSupported", &efi_global_variable_guid, EFI_VARIABLE_BOOTSERVICE_ACCESS | @@ -454,6 +459,58 @@ static __efi_runtime efi_status_t EFIAPI efi_convert_pointer_runtime( return EFI_UNSUPPORTED; }
+/** + * efi_convert_pointer_runtime() - convert from physical to virtual pointer + * + * This function implements the ConvertPointer() runtime service until + * 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( + efi_uintn_t debug_disposition, void **address) +{ + efi_physical_addr_t addr = (uintptr_t)*address; + efi_uintn_t i; + efi_status_t ret = EFI_NOT_FOUND; + + EFI_ENTRY("%zu %p", debug_disposition, address); + + if (!efi_virtmap) { + ret = EFI_UNSUPPORTED; + goto out; + } + + if (!address) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + for (i = 0; i < efi_descriptor_count; i++) { + struct efi_mem_desc *map = (void *)efi_virtmap + + (efi_descriptor_size * i); + + if (addr >= map->physical_start && + (addr < map->physical_start + + (map->num_pages << EFI_PAGE_SHIFT))) { + *address = (void *)(uintptr_t) + (addr + map->virtual_start - + map->physical_start); + + ret = EFI_SUCCESS; + break; + } + } + +out: + return EFI_EXIT(ret); +} + static __efi_runtime void efi_relocate_runtime_table(ulong offset) { ulong patchoff; @@ -480,6 +537,12 @@ static __efi_runtime void efi_relocate_runtime_table(ulong offset) */ efi_runtime_services.convert_pointer = &efi_convert_pointer_runtime;
+ /* + * TODO: Update UEFI variable RuntimeServicesSupported removing flags + * EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP and + * EFI_RT_SUPPORTED_CONVERT_POINTER as required by the UEFI spec 2.8. + */ + /* Update CRC32 */ efi_update_table_header_crc32(&efi_runtime_services.hdr); } @@ -584,6 +647,10 @@ static efi_status_t EFIAPI efi_set_virtual_address_map( EFI_ENTRY("%zx %zx %x %p", memory_map_size, descriptor_size, descriptor_version, virtmap);
+ efi_virtmap = virtmap; + efi_descriptor_size = descriptor_size; + efi_descriptor_count = n; + /* * TODO: * Further down we are cheating. While really we should implement @@ -800,7 +867,7 @@ 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_unimplemented, + .convert_pointer = efi_convert_pointer, .get_variable = efi_get_variable, .get_next_variable_name = efi_get_next_variable_name, .set_variable = efi_set_variable, -- 2.20.1

Now that ConvertPointer() is implemented throw an error if the result is incorrect.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- v2 no change --- .../efi_selftest_set_virtual_address_map.c | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-)
diff --git a/lib/efi_selftest/efi_selftest_set_virtual_address_map.c b/lib/efi_selftest/efi_selftest_set_virtual_address_map.c index 3ffb61b7e8..a4e5a50f63 100644 --- a/lib/efi_selftest/efi_selftest_set_virtual_address_map.c +++ b/lib/efi_selftest/efi_selftest_set_virtual_address_map.c @@ -20,6 +20,7 @@ static u32 desc_version; static u64 page1; static u64 page2; static u32 notify_call_count; +static bool convert_pointer_failed;
/** * notify () - notification function @@ -39,17 +40,28 @@ static void EFIAPI notify(struct efi_event *event, void *context)
addr = (void *)(uintptr_t)page1; ret = runtime->convert_pointer(0, &addr); - if (ret != EFI_SUCCESS) - efi_st_todo("ConvertPointer failed\n"); - if ((uintptr_t)addr != page1 + EFI_PAGE_SIZE) - efi_st_todo("ConvertPointer wrong address\n"); + if (ret != EFI_SUCCESS) { + efi_st_error("ConvertPointer failed\n"); + convert_pointer_failed = true; + return; + } + if ((uintptr_t)addr != page1 + EFI_PAGE_SIZE) { + efi_st_error("ConvertPointer wrong address\n"); + convert_pointer_failed = true; + return; + }
addr = (void *)(uintptr_t)page2; ret = runtime->convert_pointer(0, &addr); - if (ret != EFI_SUCCESS) - efi_st_todo("ConvertPointer failed\n"); - if ((uintptr_t)addr != page2 + 2 * EFI_PAGE_SIZE) - efi_st_todo("ConvertPointer wrong address\n"); + if (ret != EFI_SUCCESS) { + efi_st_error("ConvertPointer failed\n"); + convert_pointer_failed = true; + return; + } + if ((uintptr_t)addr != page2 + 2 * EFI_PAGE_SIZE) { + efi_st_error("ConvertPointer wrong address\n"); + convert_pointer_failed = true; + } }
/** @@ -181,6 +193,8 @@ static int execute(void) notify_call_count); return EFI_ST_FAILURE; } + if (convert_pointer_failed) + return EFI_ST_FAILURE;
return EFI_ST_SUCCESS; } -- 2.20.1
participants (1)
-
Heinrich Schuchardt