From 112464f3253c740a1b834849743cb7c543f39e92 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 12 Jul 2019 12:58:48 +0200 Subject: efi_selftest: EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE Provide a unit test for SetVirtualAddressMap() and ConvertPointer(). As ConvertPointer() is not implemented yet this will spit out some warnings. Signed-off-by: Heinrich Schuchardt --- lib/efi_selftest/Makefile | 1 + .../efi_selftest_set_virtual_address_map.c | 192 +++++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_set_virtual_address_map.c (limited to 'lib') diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 8867875..5d7a164 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -28,6 +28,7 @@ efi_selftest_manageprotocols.o \ efi_selftest_memory.o \ efi_selftest_open_protocol.o \ efi_selftest_register_notify.o \ +efi_selftest_set_virtual_address_map.o \ efi_selftest_snp.o \ efi_selftest_textinput.o \ efi_selftest_textinputex.o \ diff --git a/lib/efi_selftest/efi_selftest_set_virtual_address_map.c b/lib/efi_selftest/efi_selftest_set_virtual_address_map.c new file mode 100644 index 0000000..6ee7bbe --- /dev/null +++ b/lib/efi_selftest/efi_selftest_set_virtual_address_map.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_set_virtual_address_map.c + * + * Copyright (c) 2019 Heinrich Schuchardt + * + * This test checks the notification of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE + * and the following services: SetVirtualAddressMap, ConvertPointer. + */ + +#include + +static const struct efi_boot_services *boottime; +static const struct efi_runtime_services *runtime; +static struct efi_event *event; +static struct efi_mem_desc *memory_map; +static efi_uintn_t map_size; +static efi_uintn_t desc_size; +static u32 desc_version; +static u64 page1; +static u64 page2; +static u32 notify_call_count; + +/** + * notify () - notification function + * + * This function is called when the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event + * occurs. The correct output of ConvertPointer() is checked. + * + * @event notified event + * @context pointer to the notification count + */ +static void EFIAPI notify(struct efi_event *event, void *context) +{ + void *addr; + efi_status_t ret; + + ++notify_call_count; + + 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"); + + 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"); +} + +/** + * setup() - setup unit test + * + * The memory map is read. Boottime only entries are deleted. Two entries for + * newly allocated pages are added. For these virtual addresses deviating from + * the physical addresses are set. + * + * @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_uintn_t map_key; + efi_status_t ret; + struct efi_mem_desc *end, *pos1, *pos2; + + boottime = systable->boottime; + runtime = systable->runtime; + + ret = boottime->create_event(EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, + TPL_CALLBACK, notify, NULL, + &event); + if (ret != EFI_SUCCESS) { + efi_st_error("could not create event\n"); + return EFI_ST_FAILURE; + } + + 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 += 3 * 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 failed\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 failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES, + EFI_BOOT_SERVICES_DATA, 2, &page1); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePages failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES, + EFI_BOOT_SERVICES_DATA, 3, &page2); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePages failed\n"); + return EFI_ST_FAILURE; + } + /* Remove entries not relevant for runtime from map */ + end = (struct efi_mem_desc *)((u8 *)memory_map + map_size); + for (pos1 = memory_map, pos2 = memory_map; + pos2 < end; ++pos2) { + switch (pos2->type) { + case EFI_LOADER_CODE: + case EFI_LOADER_DATA: + case EFI_BOOT_SERVICES_CODE: + case EFI_BOOT_SERVICES_DATA: + continue; + } + memcpy(pos1, pos2, desc_size); + ++pos1; + } + + /* + * Add entries with virtual addresses deviating from the physical + * addresses. By choosing virtual address ranges within the allocated + * physical pages address space collisions are avoided. + */ + pos1->type = EFI_RUNTIME_SERVICES_DATA; + pos1->reserved = 0; + pos1->physical_start = page1; + pos1->virtual_start = page1 + EFI_PAGE_SIZE; + pos1->num_pages = 1; + pos1->attribute = EFI_MEMORY_RUNTIME; + ++pos1; + + pos1->type = EFI_RUNTIME_SERVICES_DATA; + pos1->reserved = 0; + pos1->physical_start = page2; + pos1->virtual_start = page2 + 2 * EFI_PAGE_SIZE; + pos1->num_pages = 1; + pos1->attribute = EFI_MEMORY_RUNTIME; + ++pos1; + + map_size = (u8 *)pos1 - (u8 *)memory_map; + + return EFI_ST_SUCCESS; +} + +/** + * execute() - execute unit test + * + * SetVirtualAddressMap() is called with the memory map prepared in setup(). + * + * The triggering of the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event is checked via + * the call count of the notification function. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + + ret = runtime->set_virtual_address_map(map_size, desc_size, + desc_version, memory_map); + if (ret != EFI_SUCCESS) { + efi_st_error("SetVirtualAddressMap failed\n"); + return EFI_ST_FAILURE; + } + if (notify_call_count != 1) { + efi_st_error("EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE triggered %d times\n", + notify_call_count); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(virtaddrmap) = { + .name = "virtual address map", + .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; -- cgit v1.1