]>
Commit | Line | Data |
---|---|---|
34841303 HS |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * efi_selftest_memory | |
4 | * | |
5 | * Copyright (c) 2018 Heinrich Schuchardt <[email protected]> | |
6 | * | |
8688b753 | 7 | * This unit test checks the following boottime services: |
34841303 | 8 | * AllocatePages, FreePages, GetMemoryMap |
34c96659 HS |
9 | * |
10 | * The memory type used for the device tree is checked. | |
34841303 HS |
11 | */ |
12 | ||
13 | #include <efi_selftest.h> | |
14 | ||
15 | #define EFI_ST_NUM_PAGES 8 | |
16 | ||
34c96659 | 17 | static const efi_guid_t fdt_guid = EFI_FDT_GUID; |
34841303 | 18 | static struct efi_boot_services *boottime; |
34c96659 | 19 | static u64 fdt_addr; |
34841303 HS |
20 | |
21 | /** | |
22 | * setup() - setup unit test | |
23 | * | |
24 | * @handle: handle of the loaded image | |
25 | * @systable: system table | |
26 | * Return: EFI_ST_SUCCESS for success | |
27 | */ | |
28 | static int setup(const efi_handle_t handle, | |
29 | const struct efi_system_table *systable) | |
30 | { | |
34c96659 HS |
31 | size_t i; |
32 | ||
34841303 HS |
33 | boottime = systable->boottime; |
34 | ||
34c96659 | 35 | for (i = 0; i < systable->nr_tables; ++i) { |
8101dd3d HS |
36 | if (!memcmp(&systable->tables[i].guid, &fdt_guid, |
37 | sizeof(efi_guid_t))) { | |
34c96659 HS |
38 | if (fdt_addr) { |
39 | efi_st_error("Duplicate device tree\n"); | |
40 | return EFI_ST_FAILURE; | |
41 | } | |
42 | fdt_addr = (uintptr_t)systable->tables[i].table; | |
43 | } | |
44 | } | |
34841303 HS |
45 | return EFI_ST_SUCCESS; |
46 | } | |
47 | ||
48 | /** | |
49 | * find_in_memory_map() - check matching memory map entry exists | |
50 | * | |
51 | * @memory_map: memory map | |
52 | * @desc_size: number of memory map entries | |
53 | * @addr: physical address to find in the map | |
54 | * @type: expected memory type | |
55 | * Return: EFI_ST_SUCCESS for success | |
56 | */ | |
57 | static int find_in_memory_map(efi_uintn_t map_size, | |
58 | struct efi_mem_desc *memory_map, | |
59 | efi_uintn_t desc_size, | |
60 | u64 addr, int memory_type) | |
61 | { | |
62 | efi_uintn_t i; | |
63 | bool found = false; | |
64 | ||
65 | for (i = 0; map_size; ++i, map_size -= desc_size) { | |
66 | struct efi_mem_desc *entry = &memory_map[i]; | |
67 | ||
207c5bcc HS |
68 | if (entry->physical_start != entry->virtual_start) { |
69 | efi_st_error("Physical and virtual addresses do not match\n"); | |
70 | return EFI_ST_FAILURE; | |
71 | } | |
72 | ||
34841303 HS |
73 | if (addr >= entry->physical_start && |
74 | addr < entry->physical_start + | |
75 | (entry->num_pages << EFI_PAGE_SHIFT)) { | |
76 | if (found) { | |
77 | efi_st_error("Duplicate memory map entry\n"); | |
78 | return EFI_ST_FAILURE; | |
79 | } | |
80 | found = true; | |
81 | if (memory_type != entry->type) { | |
82 | efi_st_error | |
83 | ("Wrong memory type %d, expected %d\n", | |
84 | entry->type, memory_type); | |
85 | return EFI_ST_FAILURE; | |
86 | } | |
87 | } | |
88 | } | |
89 | if (!found) { | |
90 | efi_st_error("Missing memory map entry\n"); | |
91 | return EFI_ST_FAILURE; | |
92 | } | |
93 | return EFI_ST_SUCCESS; | |
94 | } | |
95 | ||
96 | /* | |
97 | * execute() - execute unit test | |
98 | * | |
99 | * Return: EFI_ST_SUCCESS for success | |
100 | */ | |
101 | static int execute(void) | |
102 | { | |
103 | u64 p1; | |
104 | u64 p2; | |
105 | efi_uintn_t map_size = 0; | |
106 | efi_uintn_t map_key; | |
107 | efi_uintn_t desc_size; | |
108 | u32 desc_version; | |
109 | struct efi_mem_desc *memory_map; | |
110 | efi_status_t ret; | |
111 | ||
112 | /* Allocate two page ranges with different memory type */ | |
113 | ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES, | |
114 | EFI_RUNTIME_SERVICES_CODE, | |
115 | EFI_ST_NUM_PAGES, &p1); | |
116 | if (ret != EFI_SUCCESS) { | |
117 | efi_st_error("AllocatePages did not return EFI_SUCCESS\n"); | |
118 | return EFI_ST_FAILURE; | |
119 | } | |
120 | ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES, | |
121 | EFI_RUNTIME_SERVICES_DATA, | |
122 | EFI_ST_NUM_PAGES, &p2); | |
123 | if (ret != EFI_SUCCESS) { | |
124 | efi_st_error("AllocatePages did not return EFI_SUCCESS\n"); | |
125 | return EFI_ST_FAILURE; | |
126 | } | |
127 | ||
128 | /* Load memory map */ | |
129 | ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size, | |
130 | &desc_version); | |
131 | if (ret != EFI_BUFFER_TOO_SMALL) { | |
132 | efi_st_error | |
133 | ("GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n"); | |
134 | return EFI_ST_FAILURE; | |
135 | } | |
136 | /* Allocate extra space for newly allocated memory */ | |
137 | map_size += sizeof(struct efi_mem_desc); | |
138 | ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size, | |
139 | (void **)&memory_map); | |
140 | if (ret != EFI_SUCCESS) { | |
141 | efi_st_error("AllocatePool did not return EFI_SUCCESS\n"); | |
142 | return EFI_ST_FAILURE; | |
143 | } | |
144 | ret = boottime->get_memory_map(&map_size, memory_map, &map_key, | |
145 | &desc_size, &desc_version); | |
146 | if (ret != EFI_SUCCESS) { | |
147 | efi_st_error("GetMemoryMap did not return EFI_SUCCESS\n"); | |
148 | return EFI_ST_FAILURE; | |
149 | } | |
150 | ||
151 | /* Check memory map entries */ | |
152 | if (find_in_memory_map(map_size, memory_map, desc_size, p1, | |
153 | EFI_RUNTIME_SERVICES_CODE) != EFI_ST_SUCCESS) | |
154 | return EFI_ST_FAILURE; | |
155 | if (find_in_memory_map(map_size, memory_map, desc_size, p2, | |
156 | EFI_RUNTIME_SERVICES_DATA) != EFI_ST_SUCCESS) | |
157 | return EFI_ST_FAILURE; | |
158 | ||
159 | /* Free memory */ | |
160 | ret = boottime->free_pages(p1, EFI_ST_NUM_PAGES); | |
161 | if (ret != EFI_SUCCESS) { | |
162 | efi_st_error("FreePages did not return EFI_SUCCESS\n"); | |
163 | return EFI_ST_FAILURE; | |
164 | } | |
165 | ret = boottime->free_pages(p2, EFI_ST_NUM_PAGES); | |
166 | if (ret != EFI_SUCCESS) { | |
167 | efi_st_error("FreePages did not return EFI_SUCCESS\n"); | |
168 | return EFI_ST_FAILURE; | |
169 | } | |
170 | ret = boottime->free_pool(memory_map); | |
171 | if (ret != EFI_SUCCESS) { | |
172 | efi_st_error("FreePool did not return EFI_SUCCESS\n"); | |
173 | return EFI_ST_FAILURE; | |
174 | } | |
175 | ||
34c96659 HS |
176 | /* Check memory reservation for the device tree */ |
177 | if (fdt_addr && | |
178 | find_in_memory_map(map_size, memory_map, desc_size, fdt_addr, | |
42a426e0 | 179 | EFI_ACPI_RECLAIM_MEMORY) != EFI_ST_SUCCESS) { |
34c96659 | 180 | efi_st_error |
42a426e0 | 181 | ("Device tree not marked as ACPI reclaim memory\n"); |
34c96659 HS |
182 | return EFI_ST_FAILURE; |
183 | } | |
34841303 HS |
184 | return EFI_ST_SUCCESS; |
185 | } | |
186 | ||
187 | EFI_UNIT_TEST(memory) = { | |
188 | .name = "memory", | |
189 | .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, | |
190 | .setup = setup, | |
191 | .execute = execute, | |
192 | }; |