1 // SPDX-License-Identifier: GPL-2.0+
3 * efi_selftest_set_virtual_address_map.c
5 * Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de>
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
;
23 static bool convert_pointer_failed
;
26 * notify() - notification function
28 * This function is called when the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event
29 * occurs. The correct output of ConvertPointer() is checked.
31 * @event notified event
32 * @context pointer to the notification count
34 static void EFIAPI
notify(struct efi_event
*event
, void *context
)
41 addr
= (void *)(uintptr_t)page1
;
42 ret
= runtime
->convert_pointer(0, &addr
);
43 if (ret
!= EFI_SUCCESS
) {
44 efi_st_error("ConvertPointer failed\n");
45 convert_pointer_failed
= true;
48 if ((uintptr_t)addr
!= page1
+ EFI_PAGE_SIZE
) {
49 efi_st_error("ConvertPointer wrong address\n");
50 convert_pointer_failed
= true;
54 addr
= (void *)(uintptr_t)page2
;
55 ret
= runtime
->convert_pointer(0, &addr
);
56 if (ret
!= EFI_SUCCESS
) {
57 efi_st_error("ConvertPointer failed\n");
58 convert_pointer_failed
= true;
61 if ((uintptr_t)addr
!= page2
+ 2 * EFI_PAGE_SIZE
) {
62 efi_st_error("ConvertPointer wrong address\n");
63 convert_pointer_failed
= true;
68 * setup() - setup unit test
70 * The memory map is read. Boottime only entries are deleted. Two entries for
71 * newly allocated pages are added. For these virtual addresses deviating from
72 * the physical addresses are set.
74 * @handle: handle of the loaded image
75 * @systable: system table
76 * Return: EFI_ST_SUCCESS for success
78 static int setup(const efi_handle_t handle
,
79 const struct efi_system_table
*systable
)
83 struct efi_mem_desc
*end
, *pos1
, *pos2
;
85 boottime
= systable
->boottime
;
86 runtime
= systable
->runtime
;
88 ret
= boottime
->create_event(EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
,
89 TPL_CALLBACK
, notify
, NULL
,
91 if (ret
!= EFI_SUCCESS
) {
92 efi_st_error("could not create event\n");
93 return EFI_ST_FAILURE
;
96 ret
= boottime
->get_memory_map(&map_size
, NULL
, &map_key
, &desc_size
,
98 if (ret
!= EFI_BUFFER_TOO_SMALL
) {
100 "GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n");
101 return EFI_ST_FAILURE
;
103 /* Allocate extra space for newly allocated memory */
104 map_size
+= 3 * sizeof(struct efi_mem_desc
);
105 ret
= boottime
->allocate_pool(EFI_BOOT_SERVICES_DATA
, map_size
,
106 (void **)&memory_map
);
107 if (ret
!= EFI_SUCCESS
) {
108 efi_st_error("AllocatePool failed\n");
109 return EFI_ST_FAILURE
;
111 ret
= boottime
->get_memory_map(&map_size
, memory_map
, &map_key
,
112 &desc_size
, &desc_version
);
113 if (ret
!= EFI_SUCCESS
) {
114 efi_st_error("GetMemoryMap failed\n");
115 return EFI_ST_FAILURE
;
117 ret
= boottime
->allocate_pages(EFI_ALLOCATE_ANY_PAGES
,
118 EFI_BOOT_SERVICES_DATA
, 2, &page1
);
119 if (ret
!= EFI_SUCCESS
) {
120 efi_st_error("AllocatePages failed\n");
121 return EFI_ST_FAILURE
;
123 ret
= boottime
->allocate_pages(EFI_ALLOCATE_ANY_PAGES
,
124 EFI_BOOT_SERVICES_DATA
, 3, &page2
);
125 if (ret
!= EFI_SUCCESS
) {
126 efi_st_error("AllocatePages failed\n");
127 return EFI_ST_FAILURE
;
129 /* Remove entries not relevant for runtime from map */
130 end
= (struct efi_mem_desc
*)((u8
*)memory_map
+ map_size
);
131 for (pos1
= memory_map
, pos2
= memory_map
;
132 pos2
< end
; ++pos2
) {
133 switch (pos2
->type
) {
134 case EFI_LOADER_CODE
:
135 case EFI_LOADER_DATA
:
136 case EFI_BOOT_SERVICES_CODE
:
137 case EFI_BOOT_SERVICES_DATA
:
138 case EFI_CONVENTIONAL_MEMORY
:
141 memcpy(pos1
, pos2
, desc_size
);
146 * Add entries with virtual addresses deviating from the physical
147 * addresses. By choosing virtual address ranges within the allocated
148 * physical pages address space collisions are avoided.
150 pos1
->type
= EFI_RUNTIME_SERVICES_DATA
;
152 pos1
->physical_start
= page1
;
153 pos1
->virtual_start
= page1
+ EFI_PAGE_SIZE
;
155 pos1
->attribute
= EFI_MEMORY_RUNTIME
;
158 pos1
->type
= EFI_RUNTIME_SERVICES_DATA
;
160 pos1
->physical_start
= page2
;
161 pos1
->virtual_start
= page2
+ 2 * EFI_PAGE_SIZE
;
163 pos1
->attribute
= EFI_MEMORY_RUNTIME
;
166 map_size
= (u8
*)pos1
- (u8
*)memory_map
;
168 return EFI_ST_SUCCESS
;
172 * execute() - execute unit test
174 * SetVirtualAddressMap() is called with the memory map prepared in setup().
176 * The triggering of the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event is checked via
177 * the call count of the notification function.
179 * Return: EFI_ST_SUCCESS for success
181 static int execute(void)
185 ret
= runtime
->set_virtual_address_map(map_size
, desc_size
,
186 desc_version
, memory_map
);
187 if (ret
!= EFI_SUCCESS
) {
188 efi_st_error("SetVirtualAddressMap failed\n");
189 return EFI_ST_FAILURE
;
191 if (notify_call_count
!= 1) {
192 efi_st_error("EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE triggered %d times\n",
194 return EFI_ST_FAILURE
;
196 if (convert_pointer_failed
)
197 return EFI_ST_FAILURE
;
199 return EFI_ST_SUCCESS
;
202 EFI_UNIT_TEST(virtaddrmap
) = {
203 .name
= "virtual address map",
204 .phase
= EFI_SETTING_VIRTUAL_ADDRESS_MAP
,