blob: 24b4438ce4f51b9be75d02df6766c53f09f08ab9 [file] [log] [blame]
Heinrich Schuchardt88b95192018-11-18 17:58:47 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * efi_selftest_memory
4 *
5 * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
6 *
7 * This unit test checks the following runtime services:
8 * AllocatePages, FreePages, GetMemoryMap
Heinrich Schuchardt48161e12018-11-18 17:58:54 +01009 *
10 * The memory type used for the device tree is checked.
Heinrich Schuchardt88b95192018-11-18 17:58:47 +010011 */
12
13#include <efi_selftest.h>
14
15#define EFI_ST_NUM_PAGES 8
16
Heinrich Schuchardt48161e12018-11-18 17:58:54 +010017static const efi_guid_t fdt_guid = EFI_FDT_GUID;
Heinrich Schuchardt88b95192018-11-18 17:58:47 +010018static struct efi_boot_services *boottime;
Heinrich Schuchardt48161e12018-11-18 17:58:54 +010019static u64 fdt_addr;
Heinrich Schuchardt88b95192018-11-18 17:58:47 +010020
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 */
28static int setup(const efi_handle_t handle,
29 const struct efi_system_table *systable)
30{
Heinrich Schuchardt48161e12018-11-18 17:58:54 +010031 size_t i;
32
Heinrich Schuchardt88b95192018-11-18 17:58:47 +010033 boottime = systable->boottime;
34
Heinrich Schuchardt48161e12018-11-18 17:58:54 +010035 for (i = 0; i < systable->nr_tables; ++i) {
36 if (!efi_st_memcmp(&systable->tables[i].guid, &fdt_guid,
37 sizeof(efi_guid_t))) {
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 }
Heinrich Schuchardt88b95192018-11-18 17:58:47 +010045 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 */
57static 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
68 if (addr >= entry->physical_start &&
69 addr < entry->physical_start +
70 (entry->num_pages << EFI_PAGE_SHIFT)) {
71 if (found) {
72 efi_st_error("Duplicate memory map entry\n");
73 return EFI_ST_FAILURE;
74 }
75 found = true;
76 if (memory_type != entry->type) {
77 efi_st_error
78 ("Wrong memory type %d, expected %d\n",
79 entry->type, memory_type);
80 return EFI_ST_FAILURE;
81 }
82 }
83 }
84 if (!found) {
85 efi_st_error("Missing memory map entry\n");
86 return EFI_ST_FAILURE;
87 }
88 return EFI_ST_SUCCESS;
89}
90
91/*
92 * execute() - execute unit test
93 *
94 * Return: EFI_ST_SUCCESS for success
95 */
96static int execute(void)
97{
98 u64 p1;
99 u64 p2;
100 efi_uintn_t map_size = 0;
101 efi_uintn_t map_key;
102 efi_uintn_t desc_size;
103 u32 desc_version;
104 struct efi_mem_desc *memory_map;
105 efi_status_t ret;
106
107 /* Allocate two page ranges with different memory type */
108 ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
109 EFI_RUNTIME_SERVICES_CODE,
110 EFI_ST_NUM_PAGES, &p1);
111 if (ret != EFI_SUCCESS) {
112 efi_st_error("AllocatePages did not return EFI_SUCCESS\n");
113 return EFI_ST_FAILURE;
114 }
115 ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
116 EFI_RUNTIME_SERVICES_DATA,
117 EFI_ST_NUM_PAGES, &p2);
118 if (ret != EFI_SUCCESS) {
119 efi_st_error("AllocatePages did not return EFI_SUCCESS\n");
120 return EFI_ST_FAILURE;
121 }
122
123 /* Load memory map */
124 ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size,
125 &desc_version);
126 if (ret != EFI_BUFFER_TOO_SMALL) {
127 efi_st_error
128 ("GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n");
129 return EFI_ST_FAILURE;
130 }
131 /* Allocate extra space for newly allocated memory */
132 map_size += sizeof(struct efi_mem_desc);
133 ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size,
134 (void **)&memory_map);
135 if (ret != EFI_SUCCESS) {
136 efi_st_error("AllocatePool did not return EFI_SUCCESS\n");
137 return EFI_ST_FAILURE;
138 }
139 ret = boottime->get_memory_map(&map_size, memory_map, &map_key,
140 &desc_size, &desc_version);
141 if (ret != EFI_SUCCESS) {
142 efi_st_error("GetMemoryMap did not return EFI_SUCCESS\n");
143 return EFI_ST_FAILURE;
144 }
145
146 /* Check memory map entries */
147 if (find_in_memory_map(map_size, memory_map, desc_size, p1,
148 EFI_RUNTIME_SERVICES_CODE) != EFI_ST_SUCCESS)
149 return EFI_ST_FAILURE;
150 if (find_in_memory_map(map_size, memory_map, desc_size, p2,
151 EFI_RUNTIME_SERVICES_DATA) != EFI_ST_SUCCESS)
152 return EFI_ST_FAILURE;
153
154 /* Free memory */
155 ret = boottime->free_pages(p1, EFI_ST_NUM_PAGES);
156 if (ret != EFI_SUCCESS) {
157 efi_st_error("FreePages did not return EFI_SUCCESS\n");
158 return EFI_ST_FAILURE;
159 }
160 ret = boottime->free_pages(p2, 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_pool(memory_map);
166 if (ret != EFI_SUCCESS) {
167 efi_st_error("FreePool did not return EFI_SUCCESS\n");
168 return EFI_ST_FAILURE;
169 }
170
Heinrich Schuchardt48161e12018-11-18 17:58:54 +0100171 /* Check memory reservation for the device tree */
172 if (fdt_addr &&
173 find_in_memory_map(map_size, memory_map, desc_size, fdt_addr,
174 EFI_RUNTIME_SERVICES_DATA) != EFI_ST_SUCCESS) {
175 efi_st_error
176 ("Device tree not marked as runtime services data\n");
177 return EFI_ST_FAILURE;
178 }
Heinrich Schuchardt88b95192018-11-18 17:58:47 +0100179 return EFI_ST_SUCCESS;
180}
181
182EFI_UNIT_TEST(memory) = {
183 .name = "memory",
184 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
185 .setup = setup,
186 .execute = execute,
187};