doc: Add top-level description about U-Boot documentation
[oweals/u-boot.git] / lib / efi_selftest / efi_selftest_memory.c
1 // 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 boottime services:
8  * AllocatePages, FreePages, GetMemoryMap
9  *
10  * The memory type used for the device tree is checked.
11  */
12
13 #include <efi_selftest.h>
14
15 #define EFI_ST_NUM_PAGES 8
16
17 static const efi_guid_t fdt_guid = EFI_FDT_GUID;
18 static struct efi_boot_services *boottime;
19 static u64 fdt_addr;
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 {
31         size_t i;
32
33         boottime = systable->boottime;
34
35         for (i = 0; i < systable->nr_tables; ++i) {
36                 if (!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         }
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
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
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
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,
179                                EFI_BOOT_SERVICES_DATA) != EFI_ST_SUCCESS) {
180                 efi_st_error
181                         ("Device tree not marked as boot services data\n");
182                 return EFI_ST_FAILURE;
183         }
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 };