uboot/lib/efi_selftest/efi_selftest_memory.c
<<
>>
Prefs
   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
  17static const efi_guid_t fdt_guid = EFI_FDT_GUID;
  18static struct efi_boot_services *boottime;
  19static 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 */
  28static 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 */
  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 (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 */
 101static 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_ACPI_RECLAIM_MEMORY) != EFI_ST_SUCCESS) {
 180                efi_st_error
 181                        ("Device tree not marked as ACPI reclaim memory\n");
 182                return EFI_ST_FAILURE;
 183        }
 184        return EFI_ST_SUCCESS;
 185}
 186
 187EFI_UNIT_TEST(memory) = {
 188        .name = "memory",
 189        .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
 190        .setup = setup,
 191        .execute = execute,
 192};
 193