coreboot: Add memory range parsing

This patch adds code to parse memory range information passed by
coreboot, and a simple helper to test whether a specific address belongs
to a range. This may be useful for coreboot-using platforms that need to
know information about the system's memory layout (e.g. to check whether
an address passed in via SMC targets valid DRAM).

Signed-off-by: Julius Werner <jwerner@chromium.org>
Change-Id: I3bea326c426db27d1a8b7d6e17418e4850e884b4
This commit is contained in:
Julius Werner 2020-03-26 18:06:21 -07:00 committed by Sandrine Bailleux
parent 9dfe46c21b
commit 579d1e90d4
2 changed files with 53 additions and 2 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -19,6 +19,27 @@ typedef struct {
} coreboot_serial_t;
extern coreboot_serial_t coreboot_serial;
#define COREBOOT_MAX_MEMRANGES 32 /* libpayload also uses this limit */
typedef struct __packed {
uint64_t start;
uint64_t size;
uint32_t type;
} coreboot_memrange_t;
extern coreboot_memrange_t coreboot_memranges[COREBOOT_MAX_MEMRANGES];
typedef enum {
CB_MEM_NONE = 0, /* coreboot will never report this */
CB_MEM_RAM = 1,
CB_MEM_RESERVED = 2,
CB_MEM_ACPI = 3,
CB_MEM_NVS = 4,
CB_MEM_UNUSABLE = 5,
CB_MEM_VENDOR_RSVD = 6,
CB_MEM_TABLE = 16,
} coreboot_memory_t;
coreboot_memory_t coreboot_get_memory_type(uintptr_t address);
void coreboot_table_setup(void *base);
#endif /* COREBOOT_H */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -29,6 +29,7 @@ typedef struct {
} cb_header_t;
typedef enum {
CB_TAG_MEMORY = 0x1,
CB_TAG_SERIAL = 0xf,
CB_TAG_CBMEM_CONSOLE = 0x17,
} cb_tag_t;
@ -37,11 +38,13 @@ typedef struct {
uint32_t tag;
uint32_t size;
union {
coreboot_memrange_t memranges[COREBOOT_MAX_MEMRANGES];
coreboot_serial_t serial;
uint64_t uint64;
};
} cb_entry_t;
coreboot_memrange_t coreboot_memranges[COREBOOT_MAX_MEMRANGES];
coreboot_serial_t coreboot_serial;
/*
@ -86,6 +89,23 @@ static void setup_cbmem_console(uintptr_t baseaddr)
CONSOLE_FLAG_CRASH);
}
coreboot_memory_t coreboot_get_memory_type(uintptr_t address)
{
int i;
for (i = 0; i < COREBOOT_MAX_MEMRANGES; i++) {
coreboot_memrange_t *range = &coreboot_memranges[i];
if (range->type == CB_MEM_NONE)
break; /* end of table reached */
if (address >= range->start &&
address - range->start < range->size)
return range->type;
}
return CB_MEM_NONE;
}
void coreboot_table_setup(void *base)
{
cb_header_t *header = base;
@ -99,6 +119,7 @@ void coreboot_table_setup(void *base)
ptr = base + header->header_bytes;
for (i = 0; i < header->table_entries; i++) {
size_t size;
cb_entry_t *entry = ptr;
if (ptr - base >= header->header_bytes + header->table_bytes) {
@ -107,6 +128,15 @@ void coreboot_table_setup(void *base)
}
switch (read_le32(&entry->tag)) {
case CB_TAG_MEMORY:
size = read_le32(&entry->size) -
offsetof(cb_entry_t, memranges);
if (size > sizeof(coreboot_memranges)) {
ERROR("Need to truncate coreboot memranges!\n");
size = sizeof(coreboot_memranges);
}
memcpy(&coreboot_memranges, &entry->memranges, size);
break;
case CB_TAG_SERIAL:
memcpy(&coreboot_serial, &entry->serial,
sizeof(coreboot_serial));