123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * efi_selftest_set_virtual_address_map.c
- *
- * Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de>
- *
- * This test checks the notification of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
- * and the following services: SetVirtualAddressMap, ConvertPointer.
- */
- #include <efi_selftest.h>
- 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;
- static bool convert_pointer_failed;
- /**
- * 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_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_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;
- }
- }
- /**
- * 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:
- case EFI_CONVENTIONAL_MEMORY:
- 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;
- }
- if (convert_pointer_failed)
- 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,
- };
|