[U-Boot] [PATCH 0/3] fix GetMemoryMap()

The sandbox uses two different address rooms - one used internally by the sandbox and one usable for EFI.
In efi_get_memory_map() we have to map the returned physical start addresses to EFI usable addresses.
Add a unit test.
Enable building the sandbox with CONFIG_EFI_SELFTEST=y.
Heinrich Schuchardt (3): efi_loader: fix GetMemoryMap() efi_selftest: add test for memory allocation efi_selftest: building sandbox with EFI_SELFTEST
configs/sandbox_defconfig | 1 - lib/efi_loader/efi_memory.c | 5 + lib/efi_selftest/Kconfig | 2 +- lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_memory.c | 163 +++++++++++++++++++++++++ 5 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 lib/efi_selftest/efi_selftest_memory.c

The sandbox uses two different address rooms - one used internally by the sandbox and one usable for EFI.
Very unfortunately this has spilled into the EFI coding.
In efi_get_memory_map() we have to map the returned physical start addresses to EFI usable addresses.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- lib/efi_loader/efi_memory.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 5bd4f4d7fc4..bbf174c7ef7 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -531,9 +531,14 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size, memory_map = &memory_map[map_entries - 1]; list_for_each(lhandle, &efi_mem) { struct efi_mem_list *lmem; + unsigned long len; + efi_physical_addr_t addr;
lmem = list_entry(lhandle, struct efi_mem_list, link); *memory_map = lmem->desc; + len = memory_map->num_pages << EFI_PAGE_SHIFT; + addr = (uintptr_t)map_sysmem(memory_map->physical_start, len); + memory_map->physical_start = addr; memory_map--; }

This unit test checks the following runtime services: AllocatePages, FreePages, GetMemoryMap
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_memory.c | 163 +++++++++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_memory.c
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 4b1c0bb84b1..743b4820449 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -27,6 +27,7 @@ efi_selftest_fdt.o \ efi_selftest_gop.o \ efi_selftest_loaded_image.o \ efi_selftest_manageprotocols.o \ +efi_selftest_memory.o \ efi_selftest_rtc.o \ efi_selftest_snp.o \ efi_selftest_textinput.o \ diff --git a/lib/efi_selftest/efi_selftest_memory.c b/lib/efi_selftest/efi_selftest_memory.c new file mode 100644 index 00000000000..0623e8e62da --- /dev/null +++ b/lib/efi_selftest/efi_selftest_memory.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_memory + * + * Copyright (c) 2018 Heinrich Schuchardt xypron.glpk@gmx.de + * + * This unit test checks the following runtime services: + * AllocatePages, FreePages, GetMemoryMap + */ + +#include <efi_selftest.h> + +#define EFI_ST_NUM_PAGES 8 + +static struct efi_boot_services *boottime; + +/** + * setup() - 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) +{ + boottime = systable->boottime; + + return EFI_ST_SUCCESS; +} + +/** + * find_in_memory_map() - check matching memory map entry exists + * + * @memory_map: memory map + * @desc_size: number of memory map entries + * @addr: physical address to find in the map + * @type: expected memory type + * Return: EFI_ST_SUCCESS for success + */ +static int find_in_memory_map(efi_uintn_t map_size, + struct efi_mem_desc *memory_map, + efi_uintn_t desc_size, + u64 addr, int memory_type) +{ + efi_uintn_t i; + bool found = false; + + for (i = 0; map_size; ++i, map_size -= desc_size) { + struct efi_mem_desc *entry = &memory_map[i]; + + if (addr >= entry->physical_start && + addr < entry->physical_start + + (entry->num_pages << EFI_PAGE_SHIFT)) { + if (found) { + efi_st_error("Duplicate memory map entry\n"); + return EFI_ST_FAILURE; + } + found = true; + if (memory_type != entry->type) { + efi_st_error + ("Wrong memory type %d, expected %d\n", + entry->type, memory_type); + return EFI_ST_FAILURE; + } + } + } + if (!found) { + efi_st_error("Missing memory map entry\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * execute() - execute unit test + * + * Return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + u64 p1; + u64 p2; + efi_uintn_t map_size = 0; + efi_uintn_t map_key; + efi_uintn_t desc_size; + u32 desc_version; + struct efi_mem_desc *memory_map; + efi_status_t ret; + + /* Allocate two page ranges with different memory type */ + ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES, + EFI_RUNTIME_SERVICES_CODE, + EFI_ST_NUM_PAGES, &p1); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePages did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES, + EFI_RUNTIME_SERVICES_DATA, + EFI_ST_NUM_PAGES, &p2); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePages did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + + /* Load memory map */ + ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size, + &desc_version); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error + ("GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n"); + return EFI_ST_FAILURE; + } + /* Allocate extra space for newly allocated memory */ + map_size += sizeof(struct efi_mem_desc); + ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size, + (void **)&memory_map); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePool did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + ret = boottime->get_memory_map(&map_size, memory_map, &map_key, + &desc_size, &desc_version); + if (ret != EFI_SUCCESS) { + efi_st_error("GetMemoryMap did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + + /* Check memory map entries */ + if (find_in_memory_map(map_size, memory_map, desc_size, p1, + EFI_RUNTIME_SERVICES_CODE) != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + if (find_in_memory_map(map_size, memory_map, desc_size, p2, + EFI_RUNTIME_SERVICES_DATA) != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + /* Free memory */ + ret = boottime->free_pages(p1, EFI_ST_NUM_PAGES); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePages did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pages(p2, EFI_ST_NUM_PAGES); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePages did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(memory_map); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(memory) = { + .name = "memory", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +};

Enable building the sandbox with CONFIG_EFI_SELFTEST.
But do not select it by default as the network unit test may fail.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- configs/sandbox_defconfig | 1 - lib/efi_selftest/Kconfig | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 2ce336fc81c..7edc27f2cde 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -24,7 +24,6 @@ CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_CMD_CPU=y CONFIG_CMD_LICENSE=y CONFIG_CMD_BOOTZ=y -CONFIG_CMD_BOOTEFI_SELFTEST=y # CONFIG_CMD_ELF is not set CONFIG_CMD_ASKENV=y CONFIG_CMD_GREPENV=y diff --git a/lib/efi_selftest/Kconfig b/lib/efi_selftest/Kconfig index b52696778dd..59f9f36801c 100644 --- a/lib/efi_selftest/Kconfig +++ b/lib/efi_selftest/Kconfig @@ -1,6 +1,6 @@ config CMD_BOOTEFI_SELFTEST bool "Allow booting an EFI efi_selftest" - depends on CMD_BOOTEFI && !SANDBOX + depends on CMD_BOOTEFI imply FAT imply FAT_WRITE help
participants (1)
-
Heinrich Schuchardt