2018-11-18 16:58:47 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
|
|
|
/*
|
|
|
|
* efi_selftest_memory
|
|
|
|
*
|
|
|
|
* Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
|
|
|
|
*
|
2019-04-12 20:09:09 +00:00
|
|
|
* This unit test checks the following boottime services:
|
2018-11-18 16:58:47 +00:00
|
|
|
* AllocatePages, FreePages, GetMemoryMap
|
2018-11-18 16:58:54 +00:00
|
|
|
*
|
|
|
|
* The memory type used for the device tree is checked.
|
2018-11-18 16:58:47 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <efi_selftest.h>
|
|
|
|
|
|
|
|
#define EFI_ST_NUM_PAGES 8
|
|
|
|
|
2018-11-18 16:58:54 +00:00
|
|
|
static const efi_guid_t fdt_guid = EFI_FDT_GUID;
|
2018-11-18 16:58:47 +00:00
|
|
|
static struct efi_boot_services *boottime;
|
2018-11-18 16:58:54 +00:00
|
|
|
static u64 fdt_addr;
|
2018-11-18 16:58:47 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* setup() - setup unit test
|
|
|
|
*
|
|
|
|
* @handle: handle of the loaded image
|
|
|
|
* @systable: system table
|
|
|
|
* Return: EFI_ST_SUCCESS for success
|
|
|
|
*/
|
|
|
|
static int setup(const efi_handle_t handle,
|
|
|
|
const struct efi_system_table *systable)
|
|
|
|
{
|
2018-11-18 16:58:54 +00:00
|
|
|
size_t i;
|
|
|
|
|
2018-11-18 16:58:47 +00:00
|
|
|
boottime = systable->boottime;
|
|
|
|
|
2018-11-18 16:58:54 +00:00
|
|
|
for (i = 0; i < systable->nr_tables; ++i) {
|
|
|
|
if (!efi_st_memcmp(&systable->tables[i].guid, &fdt_guid,
|
|
|
|
sizeof(efi_guid_t))) {
|
|
|
|
if (fdt_addr) {
|
|
|
|
efi_st_error("Duplicate device tree\n");
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
fdt_addr = (uintptr_t)systable->tables[i].table;
|
|
|
|
}
|
|
|
|
}
|
2018-11-18 16:58:47 +00:00
|
|
|
return EFI_ST_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* find_in_memory_map() - check matching memory map entry exists
|
|
|
|
*
|
|
|
|
* @memory_map: memory map
|
|
|
|
* @desc_size: number of memory map entries
|
|
|
|
* @addr: physical address to find in the map
|
|
|
|
* @type: expected memory type
|
|
|
|
* Return: EFI_ST_SUCCESS for success
|
|
|
|
*/
|
|
|
|
static int 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)
|
|
|
|
{
|
|
|
|
efi_uintn_t i;
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
for (i = 0; map_size; ++i, map_size -= desc_size) {
|
|
|
|
struct efi_mem_desc *entry = &memory_map[i];
|
|
|
|
|
2019-04-11 17:59:31 +00:00
|
|
|
if (entry->physical_start != entry->virtual_start) {
|
|
|
|
efi_st_error("Physical and virtual addresses do not match\n");
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
|
2018-11-18 16:58:47 +00:00
|
|
|
if (addr >= entry->physical_start &&
|
|
|
|
addr < entry->physical_start +
|
|
|
|
(entry->num_pages << EFI_PAGE_SHIFT)) {
|
|
|
|
if (found) {
|
|
|
|
efi_st_error("Duplicate memory map entry\n");
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
found = true;
|
|
|
|
if (memory_type != entry->type) {
|
|
|
|
efi_st_error
|
|
|
|
("Wrong memory type %d, expected %d\n",
|
|
|
|
entry->type, memory_type);
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!found) {
|
|
|
|
efi_st_error("Missing memory map entry\n");
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
return EFI_ST_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* execute() - execute unit test
|
|
|
|
*
|
|
|
|
* Return: EFI_ST_SUCCESS for success
|
|
|
|
*/
|
|
|
|
static int execute(void)
|
|
|
|
{
|
|
|
|
u64 p1;
|
|
|
|
u64 p2;
|
|
|
|
efi_uintn_t map_size = 0;
|
|
|
|
efi_uintn_t map_key;
|
|
|
|
efi_uintn_t desc_size;
|
|
|
|
u32 desc_version;
|
|
|
|
struct efi_mem_desc *memory_map;
|
|
|
|
efi_status_t ret;
|
|
|
|
|
|
|
|
/* Allocate two page ranges with different memory type */
|
|
|
|
ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
|
|
|
|
EFI_RUNTIME_SERVICES_CODE,
|
|
|
|
EFI_ST_NUM_PAGES, &p1);
|
|
|
|
if (ret != EFI_SUCCESS) {
|
|
|
|
efi_st_error("AllocatePages did not return EFI_SUCCESS\n");
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
|
|
|
|
EFI_RUNTIME_SERVICES_DATA,
|
|
|
|
EFI_ST_NUM_PAGES, &p2);
|
|
|
|
if (ret != EFI_SUCCESS) {
|
|
|
|
efi_st_error("AllocatePages did not return EFI_SUCCESS\n");
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Load memory map */
|
|
|
|
ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size,
|
|
|
|
&desc_version);
|
|
|
|
if (ret != EFI_BUFFER_TOO_SMALL) {
|
|
|
|
efi_st_error
|
|
|
|
("GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n");
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
/* Allocate extra space for newly allocated memory */
|
|
|
|
map_size += sizeof(struct efi_mem_desc);
|
|
|
|
ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size,
|
|
|
|
(void **)&memory_map);
|
|
|
|
if (ret != EFI_SUCCESS) {
|
|
|
|
efi_st_error("AllocatePool did not return EFI_SUCCESS\n");
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
ret = boottime->get_memory_map(&map_size, memory_map, &map_key,
|
|
|
|
&desc_size, &desc_version);
|
|
|
|
if (ret != EFI_SUCCESS) {
|
|
|
|
efi_st_error("GetMemoryMap did not return EFI_SUCCESS\n");
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check memory map entries */
|
|
|
|
if (find_in_memory_map(map_size, memory_map, desc_size, p1,
|
|
|
|
EFI_RUNTIME_SERVICES_CODE) != EFI_ST_SUCCESS)
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
if (find_in_memory_map(map_size, memory_map, desc_size, p2,
|
|
|
|
EFI_RUNTIME_SERVICES_DATA) != EFI_ST_SUCCESS)
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
|
|
|
|
/* Free memory */
|
|
|
|
ret = boottime->free_pages(p1, EFI_ST_NUM_PAGES);
|
|
|
|
if (ret != EFI_SUCCESS) {
|
|
|
|
efi_st_error("FreePages did not return EFI_SUCCESS\n");
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
ret = boottime->free_pages(p2, EFI_ST_NUM_PAGES);
|
|
|
|
if (ret != EFI_SUCCESS) {
|
|
|
|
efi_st_error("FreePages did not return EFI_SUCCESS\n");
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
ret = boottime->free_pool(memory_map);
|
|
|
|
if (ret != EFI_SUCCESS) {
|
|
|
|
efi_st_error("FreePool did not return EFI_SUCCESS\n");
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
|
2018-11-18 16:58:54 +00:00
|
|
|
/* Check memory reservation for the device tree */
|
|
|
|
if (fdt_addr &&
|
|
|
|
find_in_memory_map(map_size, memory_map, desc_size, fdt_addr,
|
2019-04-12 20:09:09 +00:00
|
|
|
EFI_BOOT_SERVICES_DATA) != EFI_ST_SUCCESS) {
|
2018-11-18 16:58:54 +00:00
|
|
|
efi_st_error
|
2019-04-12 20:09:09 +00:00
|
|
|
("Device tree not marked as boot services data\n");
|
2018-11-18 16:58:54 +00:00
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
2018-11-18 16:58:47 +00:00
|
|
|
return EFI_ST_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_UNIT_TEST(memory) = {
|
|
|
|
.name = "memory",
|
|
|
|
.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
|
|
|
|
.setup = setup,
|
|
|
|
.execute = execute,
|
|
|
|
};
|