mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 10:26:10 +01:00 
			
		
		
		
	Setup will always occur before ExitBootServices(). So eliminate EFI_SETUP_AFTER_BOOTTIME_EXIT. Put the SetVirtualAddressMap() test into a separate class so that we can execute it last. Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
		
			
				
	
	
		
			208 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			208 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // 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_SETTING_VIRTUAL_ADDRESS_MAP,
 | |
| 	.setup = setup,
 | |
| 	.execute = execute,
 | |
| };
 |