134841303SHeinrich Schuchardt // SPDX-License-Identifier: GPL-2.0+
234841303SHeinrich Schuchardt /*
334841303SHeinrich Schuchardt * efi_selftest_memory
434841303SHeinrich Schuchardt *
534841303SHeinrich Schuchardt * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
634841303SHeinrich Schuchardt *
734841303SHeinrich Schuchardt * This unit test checks the following runtime services:
834841303SHeinrich Schuchardt * AllocatePages, FreePages, GetMemoryMap
9*34c96659SHeinrich Schuchardt *
10*34c96659SHeinrich Schuchardt * The memory type used for the device tree is checked.
1134841303SHeinrich Schuchardt */
1234841303SHeinrich Schuchardt
1334841303SHeinrich Schuchardt #include <efi_selftest.h>
1434841303SHeinrich Schuchardt
1534841303SHeinrich Schuchardt #define EFI_ST_NUM_PAGES 8
1634841303SHeinrich Schuchardt
17*34c96659SHeinrich Schuchardt static const efi_guid_t fdt_guid = EFI_FDT_GUID;
1834841303SHeinrich Schuchardt static struct efi_boot_services *boottime;
19*34c96659SHeinrich Schuchardt static u64 fdt_addr;
2034841303SHeinrich Schuchardt
2134841303SHeinrich Schuchardt /**
2234841303SHeinrich Schuchardt * setup() - setup unit test
2334841303SHeinrich Schuchardt *
2434841303SHeinrich Schuchardt * @handle: handle of the loaded image
2534841303SHeinrich Schuchardt * @systable: system table
2634841303SHeinrich Schuchardt * Return: EFI_ST_SUCCESS for success
2734841303SHeinrich Schuchardt */
setup(const efi_handle_t handle,const struct efi_system_table * systable)2834841303SHeinrich Schuchardt static int setup(const efi_handle_t handle,
2934841303SHeinrich Schuchardt const struct efi_system_table *systable)
3034841303SHeinrich Schuchardt {
31*34c96659SHeinrich Schuchardt size_t i;
32*34c96659SHeinrich Schuchardt
3334841303SHeinrich Schuchardt boottime = systable->boottime;
3434841303SHeinrich Schuchardt
35*34c96659SHeinrich Schuchardt for (i = 0; i < systable->nr_tables; ++i) {
36*34c96659SHeinrich Schuchardt if (!efi_st_memcmp(&systable->tables[i].guid, &fdt_guid,
37*34c96659SHeinrich Schuchardt sizeof(efi_guid_t))) {
38*34c96659SHeinrich Schuchardt if (fdt_addr) {
39*34c96659SHeinrich Schuchardt efi_st_error("Duplicate device tree\n");
40*34c96659SHeinrich Schuchardt return EFI_ST_FAILURE;
41*34c96659SHeinrich Schuchardt }
42*34c96659SHeinrich Schuchardt fdt_addr = (uintptr_t)systable->tables[i].table;
43*34c96659SHeinrich Schuchardt }
44*34c96659SHeinrich Schuchardt }
4534841303SHeinrich Schuchardt return EFI_ST_SUCCESS;
4634841303SHeinrich Schuchardt }
4734841303SHeinrich Schuchardt
4834841303SHeinrich Schuchardt /**
4934841303SHeinrich Schuchardt * find_in_memory_map() - check matching memory map entry exists
5034841303SHeinrich Schuchardt *
5134841303SHeinrich Schuchardt * @memory_map: memory map
5234841303SHeinrich Schuchardt * @desc_size: number of memory map entries
5334841303SHeinrich Schuchardt * @addr: physical address to find in the map
5434841303SHeinrich Schuchardt * @type: expected memory type
5534841303SHeinrich Schuchardt * Return: EFI_ST_SUCCESS for success
5634841303SHeinrich Schuchardt */
find_in_memory_map(efi_uintn_t map_size,struct efi_mem_desc * memory_map,efi_uintn_t desc_size,u64 addr,int memory_type)5734841303SHeinrich Schuchardt static int find_in_memory_map(efi_uintn_t map_size,
5834841303SHeinrich Schuchardt struct efi_mem_desc *memory_map,
5934841303SHeinrich Schuchardt efi_uintn_t desc_size,
6034841303SHeinrich Schuchardt u64 addr, int memory_type)
6134841303SHeinrich Schuchardt {
6234841303SHeinrich Schuchardt efi_uintn_t i;
6334841303SHeinrich Schuchardt bool found = false;
6434841303SHeinrich Schuchardt
6534841303SHeinrich Schuchardt for (i = 0; map_size; ++i, map_size -= desc_size) {
6634841303SHeinrich Schuchardt struct efi_mem_desc *entry = &memory_map[i];
6734841303SHeinrich Schuchardt
6834841303SHeinrich Schuchardt if (addr >= entry->physical_start &&
6934841303SHeinrich Schuchardt addr < entry->physical_start +
7034841303SHeinrich Schuchardt (entry->num_pages << EFI_PAGE_SHIFT)) {
7134841303SHeinrich Schuchardt if (found) {
7234841303SHeinrich Schuchardt efi_st_error("Duplicate memory map entry\n");
7334841303SHeinrich Schuchardt return EFI_ST_FAILURE;
7434841303SHeinrich Schuchardt }
7534841303SHeinrich Schuchardt found = true;
7634841303SHeinrich Schuchardt if (memory_type != entry->type) {
7734841303SHeinrich Schuchardt efi_st_error
7834841303SHeinrich Schuchardt ("Wrong memory type %d, expected %d\n",
7934841303SHeinrich Schuchardt entry->type, memory_type);
8034841303SHeinrich Schuchardt return EFI_ST_FAILURE;
8134841303SHeinrich Schuchardt }
8234841303SHeinrich Schuchardt }
8334841303SHeinrich Schuchardt }
8434841303SHeinrich Schuchardt if (!found) {
8534841303SHeinrich Schuchardt efi_st_error("Missing memory map entry\n");
8634841303SHeinrich Schuchardt return EFI_ST_FAILURE;
8734841303SHeinrich Schuchardt }
8834841303SHeinrich Schuchardt return EFI_ST_SUCCESS;
8934841303SHeinrich Schuchardt }
9034841303SHeinrich Schuchardt
9134841303SHeinrich Schuchardt /*
9234841303SHeinrich Schuchardt * execute() - execute unit test
9334841303SHeinrich Schuchardt *
9434841303SHeinrich Schuchardt * Return: EFI_ST_SUCCESS for success
9534841303SHeinrich Schuchardt */
execute(void)9634841303SHeinrich Schuchardt static int execute(void)
9734841303SHeinrich Schuchardt {
9834841303SHeinrich Schuchardt u64 p1;
9934841303SHeinrich Schuchardt u64 p2;
10034841303SHeinrich Schuchardt efi_uintn_t map_size = 0;
10134841303SHeinrich Schuchardt efi_uintn_t map_key;
10234841303SHeinrich Schuchardt efi_uintn_t desc_size;
10334841303SHeinrich Schuchardt u32 desc_version;
10434841303SHeinrich Schuchardt struct efi_mem_desc *memory_map;
10534841303SHeinrich Schuchardt efi_status_t ret;
10634841303SHeinrich Schuchardt
10734841303SHeinrich Schuchardt /* Allocate two page ranges with different memory type */
10834841303SHeinrich Schuchardt ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
10934841303SHeinrich Schuchardt EFI_RUNTIME_SERVICES_CODE,
11034841303SHeinrich Schuchardt EFI_ST_NUM_PAGES, &p1);
11134841303SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
11234841303SHeinrich Schuchardt efi_st_error("AllocatePages did not return EFI_SUCCESS\n");
11334841303SHeinrich Schuchardt return EFI_ST_FAILURE;
11434841303SHeinrich Schuchardt }
11534841303SHeinrich Schuchardt ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
11634841303SHeinrich Schuchardt EFI_RUNTIME_SERVICES_DATA,
11734841303SHeinrich Schuchardt EFI_ST_NUM_PAGES, &p2);
11834841303SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
11934841303SHeinrich Schuchardt efi_st_error("AllocatePages did not return EFI_SUCCESS\n");
12034841303SHeinrich Schuchardt return EFI_ST_FAILURE;
12134841303SHeinrich Schuchardt }
12234841303SHeinrich Schuchardt
12334841303SHeinrich Schuchardt /* Load memory map */
12434841303SHeinrich Schuchardt ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size,
12534841303SHeinrich Schuchardt &desc_version);
12634841303SHeinrich Schuchardt if (ret != EFI_BUFFER_TOO_SMALL) {
12734841303SHeinrich Schuchardt efi_st_error
12834841303SHeinrich Schuchardt ("GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n");
12934841303SHeinrich Schuchardt return EFI_ST_FAILURE;
13034841303SHeinrich Schuchardt }
13134841303SHeinrich Schuchardt /* Allocate extra space for newly allocated memory */
13234841303SHeinrich Schuchardt map_size += sizeof(struct efi_mem_desc);
13334841303SHeinrich Schuchardt ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size,
13434841303SHeinrich Schuchardt (void **)&memory_map);
13534841303SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
13634841303SHeinrich Schuchardt efi_st_error("AllocatePool did not return EFI_SUCCESS\n");
13734841303SHeinrich Schuchardt return EFI_ST_FAILURE;
13834841303SHeinrich Schuchardt }
13934841303SHeinrich Schuchardt ret = boottime->get_memory_map(&map_size, memory_map, &map_key,
14034841303SHeinrich Schuchardt &desc_size, &desc_version);
14134841303SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
14234841303SHeinrich Schuchardt efi_st_error("GetMemoryMap did not return EFI_SUCCESS\n");
14334841303SHeinrich Schuchardt return EFI_ST_FAILURE;
14434841303SHeinrich Schuchardt }
14534841303SHeinrich Schuchardt
14634841303SHeinrich Schuchardt /* Check memory map entries */
14734841303SHeinrich Schuchardt if (find_in_memory_map(map_size, memory_map, desc_size, p1,
14834841303SHeinrich Schuchardt EFI_RUNTIME_SERVICES_CODE) != EFI_ST_SUCCESS)
14934841303SHeinrich Schuchardt return EFI_ST_FAILURE;
15034841303SHeinrich Schuchardt if (find_in_memory_map(map_size, memory_map, desc_size, p2,
15134841303SHeinrich Schuchardt EFI_RUNTIME_SERVICES_DATA) != EFI_ST_SUCCESS)
15234841303SHeinrich Schuchardt return EFI_ST_FAILURE;
15334841303SHeinrich Schuchardt
15434841303SHeinrich Schuchardt /* Free memory */
15534841303SHeinrich Schuchardt ret = boottime->free_pages(p1, EFI_ST_NUM_PAGES);
15634841303SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
15734841303SHeinrich Schuchardt efi_st_error("FreePages did not return EFI_SUCCESS\n");
15834841303SHeinrich Schuchardt return EFI_ST_FAILURE;
15934841303SHeinrich Schuchardt }
16034841303SHeinrich Schuchardt ret = boottime->free_pages(p2, EFI_ST_NUM_PAGES);
16134841303SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
16234841303SHeinrich Schuchardt efi_st_error("FreePages did not return EFI_SUCCESS\n");
16334841303SHeinrich Schuchardt return EFI_ST_FAILURE;
16434841303SHeinrich Schuchardt }
16534841303SHeinrich Schuchardt ret = boottime->free_pool(memory_map);
16634841303SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
16734841303SHeinrich Schuchardt efi_st_error("FreePool did not return EFI_SUCCESS\n");
16834841303SHeinrich Schuchardt return EFI_ST_FAILURE;
16934841303SHeinrich Schuchardt }
17034841303SHeinrich Schuchardt
171*34c96659SHeinrich Schuchardt /* Check memory reservation for the device tree */
172*34c96659SHeinrich Schuchardt if (fdt_addr &&
173*34c96659SHeinrich Schuchardt find_in_memory_map(map_size, memory_map, desc_size, fdt_addr,
174*34c96659SHeinrich Schuchardt EFI_RUNTIME_SERVICES_DATA) != EFI_ST_SUCCESS) {
175*34c96659SHeinrich Schuchardt efi_st_error
176*34c96659SHeinrich Schuchardt ("Device tree not marked as runtime services data\n");
177*34c96659SHeinrich Schuchardt return EFI_ST_FAILURE;
178*34c96659SHeinrich Schuchardt }
17934841303SHeinrich Schuchardt return EFI_ST_SUCCESS;
18034841303SHeinrich Schuchardt }
18134841303SHeinrich Schuchardt
18234841303SHeinrich Schuchardt EFI_UNIT_TEST(memory) = {
18334841303SHeinrich Schuchardt .name = "memory",
18434841303SHeinrich Schuchardt .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
18534841303SHeinrich Schuchardt .setup = setup,
18634841303SHeinrich Schuchardt .execute = execute,
18734841303SHeinrich Schuchardt };
188