1 // SPDX-License-Identifier: GPL-2.0+
3 * efi_selftest_set_virtual_address_map.c
7 * This test checks the notification of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
8 * and the following services: SetVirtualAddressMap, ConvertPointer.
11 #include <efi_selftest.h>
13 static const struct efi_boot_services *boottime;
14 static const struct efi_runtime_services *runtime;
15 static struct efi_event *event;
16 static struct efi_mem_desc *memory_map;
17 static efi_uintn_t map_size;
18 static efi_uintn_t desc_size;
19 static u32 desc_version;
22 static u32 notify_call_count;
25 * notify () - notification function
27 * This function is called when the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event
28 * occurs. The correct output of ConvertPointer() is checked.
30 * @event notified event
31 * @context pointer to the notification count
33 static void EFIAPI notify(struct efi_event *event, void *context)
40 addr = (void *)(uintptr_t)page1;
41 ret = runtime->convert_pointer(0, &addr);
42 if (ret != EFI_SUCCESS)
43 efi_st_todo("ConvertPointer failed\n");
44 if ((uintptr_t)addr != page1 + EFI_PAGE_SIZE)
45 efi_st_todo("ConvertPointer wrong address\n");
47 addr = (void *)(uintptr_t)page2;
48 ret = runtime->convert_pointer(0, &addr);
49 if (ret != EFI_SUCCESS)
50 efi_st_todo("ConvertPointer failed\n");
51 if ((uintptr_t)addr != page2 + 2 * EFI_PAGE_SIZE)
52 efi_st_todo("ConvertPointer wrong address\n");
56 * setup() - setup unit test
58 * The memory map is read. Boottime only entries are deleted. Two entries for
59 * newly allocated pages are added. For these virtual addresses deviating from
60 * the physical addresses are set.
62 * @handle: handle of the loaded image
63 * @systable: system table
64 * @return: EFI_ST_SUCCESS for success
66 static int setup(const efi_handle_t handle,
67 const struct efi_system_table *systable)
71 struct efi_mem_desc *end, *pos1, *pos2;
73 boottime = systable->boottime;
74 runtime = systable->runtime;
76 ret = boottime->create_event(EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
77 TPL_CALLBACK, notify, NULL,
79 if (ret != EFI_SUCCESS) {
80 efi_st_error("could not create event\n");
81 return EFI_ST_FAILURE;
84 ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size,
86 if (ret != EFI_BUFFER_TOO_SMALL) {
88 "GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n");
89 return EFI_ST_FAILURE;
91 /* Allocate extra space for newly allocated memory */
92 map_size += 3 * sizeof(struct efi_mem_desc);
93 ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size,
94 (void **)&memory_map);
95 if (ret != EFI_SUCCESS) {
96 efi_st_error("AllocatePool failed\n");
97 return EFI_ST_FAILURE;
99 ret = boottime->get_memory_map(&map_size, memory_map, &map_key,
100 &desc_size, &desc_version);
101 if (ret != EFI_SUCCESS) {
102 efi_st_error("GetMemoryMap failed\n");
103 return EFI_ST_FAILURE;
105 ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
106 EFI_BOOT_SERVICES_DATA, 2, &page1);
107 if (ret != EFI_SUCCESS) {
108 efi_st_error("AllocatePages failed\n");
109 return EFI_ST_FAILURE;
111 ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
112 EFI_BOOT_SERVICES_DATA, 3, &page2);
113 if (ret != EFI_SUCCESS) {
114 efi_st_error("AllocatePages failed\n");
115 return EFI_ST_FAILURE;
117 /* Remove entries not relevant for runtime from map */
118 end = (struct efi_mem_desc *)((u8 *)memory_map + map_size);
119 for (pos1 = memory_map, pos2 = memory_map;
120 pos2 < end; ++pos2) {
121 switch (pos2->type) {
122 case EFI_LOADER_CODE:
123 case EFI_LOADER_DATA:
124 case EFI_BOOT_SERVICES_CODE:
125 case EFI_BOOT_SERVICES_DATA:
128 memcpy(pos1, pos2, desc_size);
133 * Add entries with virtual addresses deviating from the physical
134 * addresses. By choosing virtual address ranges within the allocated
135 * physical pages address space collisions are avoided.
137 pos1->type = EFI_RUNTIME_SERVICES_DATA;
139 pos1->physical_start = page1;
140 pos1->virtual_start = page1 + EFI_PAGE_SIZE;
142 pos1->attribute = EFI_MEMORY_RUNTIME;
145 pos1->type = EFI_RUNTIME_SERVICES_DATA;
147 pos1->physical_start = page2;
148 pos1->virtual_start = page2 + 2 * EFI_PAGE_SIZE;
150 pos1->attribute = EFI_MEMORY_RUNTIME;
153 map_size = (u8 *)pos1 - (u8 *)memory_map;
155 return EFI_ST_SUCCESS;
159 * execute() - execute unit test
161 * SetVirtualAddressMap() is called with the memory map prepared in setup().
163 * The triggering of the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event is checked via
164 * the call count of the notification function.
166 * @return: EFI_ST_SUCCESS for success
168 static int execute(void)
172 ret = runtime->set_virtual_address_map(map_size, desc_size,
173 desc_version, memory_map);
174 if (ret != EFI_SUCCESS) {
175 efi_st_error("SetVirtualAddressMap failed\n");
176 return EFI_ST_FAILURE;
178 if (notify_call_count != 1) {
179 efi_st_error("EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE triggered %d times\n",
181 return EFI_ST_FAILURE;
184 return EFI_ST_SUCCESS;
187 EFI_UNIT_TEST(virtaddrmap) = {
188 .name = "virtual address map",
189 .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,