xref: /arm-trusted-firmware/lib/coreboot/coreboot_table.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2017-2020, Arm Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu #include <string.h>
9*91f16700Schasinglulu 
10*91f16700Schasinglulu #include <drivers/coreboot/cbmem_console.h>
11*91f16700Schasinglulu #include <common/debug.h>
12*91f16700Schasinglulu #include <lib/coreboot.h>
13*91f16700Schasinglulu #include <lib/mmio.h>
14*91f16700Schasinglulu #include <lib/xlat_tables/xlat_tables_v2.h>
15*91f16700Schasinglulu 
16*91f16700Schasinglulu /*
17*91f16700Schasinglulu  * Structures describing coreboot's in-memory descriptor tables. See
18*91f16700Schasinglulu  * <coreboot>/src/commonlib/include/commonlib/coreboot_tables.h for
19*91f16700Schasinglulu  * canonical implementation.
20*91f16700Schasinglulu  */
21*91f16700Schasinglulu 
22*91f16700Schasinglulu typedef struct {
23*91f16700Schasinglulu 	char signature[4];
24*91f16700Schasinglulu 	uint32_t header_bytes;
25*91f16700Schasinglulu 	uint32_t header_checksum;
26*91f16700Schasinglulu 	uint32_t table_bytes;
27*91f16700Schasinglulu 	uint32_t table_checksum;
28*91f16700Schasinglulu 	uint32_t table_entries;
29*91f16700Schasinglulu } cb_header_t;
30*91f16700Schasinglulu 
31*91f16700Schasinglulu typedef enum {
32*91f16700Schasinglulu 	CB_TAG_MEMORY = 0x1,
33*91f16700Schasinglulu 	CB_TAG_SERIAL = 0xf,
34*91f16700Schasinglulu 	CB_TAG_CBMEM_CONSOLE = 0x17,
35*91f16700Schasinglulu } cb_tag_t;
36*91f16700Schasinglulu 
37*91f16700Schasinglulu typedef struct {
38*91f16700Schasinglulu 	uint32_t tag;
39*91f16700Schasinglulu 	uint32_t size;
40*91f16700Schasinglulu 	union {
41*91f16700Schasinglulu 		coreboot_memrange_t memranges[COREBOOT_MAX_MEMRANGES];
42*91f16700Schasinglulu 		coreboot_serial_t serial;
43*91f16700Schasinglulu 		uint64_t uint64;
44*91f16700Schasinglulu 	};
45*91f16700Schasinglulu } cb_entry_t;
46*91f16700Schasinglulu 
47*91f16700Schasinglulu coreboot_memrange_t coreboot_memranges[COREBOOT_MAX_MEMRANGES];
48*91f16700Schasinglulu coreboot_serial_t coreboot_serial;
49*91f16700Schasinglulu uint64_t coreboot_table_addr;
50*91f16700Schasinglulu uint32_t coreboot_table_size;
51*91f16700Schasinglulu 
52*91f16700Schasinglulu /*
53*91f16700Schasinglulu  * The coreboot table is parsed before the MMU is enabled (i.e. with strongly
54*91f16700Schasinglulu  * ordered memory), so we cannot make unaligned accesses. The table entries
55*91f16700Schasinglulu  * immediately follow one another without padding, so nothing after the header
56*91f16700Schasinglulu  * is guaranteed to be naturally aligned. Therefore, we need to define safety
57*91f16700Schasinglulu  * functions that can read unaligned integers.
58*91f16700Schasinglulu  */
59*91f16700Schasinglulu static uint32_t read_le32(uint32_t *p)
60*91f16700Schasinglulu {
61*91f16700Schasinglulu 	uintptr_t addr = (uintptr_t)p;
62*91f16700Schasinglulu 	return mmio_read_8(addr)		|
63*91f16700Schasinglulu 	       mmio_read_8(addr + 1) << 8	|
64*91f16700Schasinglulu 	       mmio_read_8(addr + 2) << 16	|
65*91f16700Schasinglulu 	       mmio_read_8(addr + 3) << 24;
66*91f16700Schasinglulu }
67*91f16700Schasinglulu static uint64_t read_le64(uint64_t *p)
68*91f16700Schasinglulu {
69*91f16700Schasinglulu 	return read_le32((void *)p) | (uint64_t)read_le32((void *)p + 4) << 32;
70*91f16700Schasinglulu }
71*91f16700Schasinglulu 
72*91f16700Schasinglulu static void expand_and_mmap(uintptr_t baseaddr, size_t size)
73*91f16700Schasinglulu {
74*91f16700Schasinglulu 	uintptr_t pageaddr = round_down(baseaddr, PAGE_SIZE);
75*91f16700Schasinglulu 	size_t expanded = round_up(baseaddr - pageaddr + size, PAGE_SIZE);
76*91f16700Schasinglulu 	mmap_add_region(pageaddr, pageaddr, expanded,
77*91f16700Schasinglulu 			MT_MEMORY | MT_RW | MT_NS | MT_EXECUTE_NEVER);
78*91f16700Schasinglulu }
79*91f16700Schasinglulu 
80*91f16700Schasinglulu static void setup_cbmem_console(uintptr_t baseaddr)
81*91f16700Schasinglulu {
82*91f16700Schasinglulu 	static console_cbmc_t console;
83*91f16700Schasinglulu 	assert(!console.console.base);	/* should only have one CBMEM console */
84*91f16700Schasinglulu 
85*91f16700Schasinglulu 	/* CBMEM console structure stores its size in first header field. */
86*91f16700Schasinglulu 	uint32_t size = *(uint32_t *)baseaddr;
87*91f16700Schasinglulu 	expand_and_mmap(baseaddr, size);
88*91f16700Schasinglulu 	console_cbmc_register(baseaddr, &console);
89*91f16700Schasinglulu 	console_set_scope(&console.console, CONSOLE_FLAG_BOOT |
90*91f16700Schasinglulu 					    CONSOLE_FLAG_RUNTIME |
91*91f16700Schasinglulu 					    CONSOLE_FLAG_CRASH);
92*91f16700Schasinglulu }
93*91f16700Schasinglulu 
94*91f16700Schasinglulu coreboot_memory_t coreboot_get_memory_type(uintptr_t start, size_t size)
95*91f16700Schasinglulu {
96*91f16700Schasinglulu 	int i;
97*91f16700Schasinglulu 
98*91f16700Schasinglulu 	for (i = 0; i < COREBOOT_MAX_MEMRANGES; i++) {
99*91f16700Schasinglulu 		coreboot_memrange_t *range = &coreboot_memranges[i];
100*91f16700Schasinglulu 
101*91f16700Schasinglulu 		if (range->type == CB_MEM_NONE)
102*91f16700Schasinglulu 			break;	/* end of table reached */
103*91f16700Schasinglulu 		if ((start >= range->start) &&
104*91f16700Schasinglulu 		    (start - range->start < range->size) &&
105*91f16700Schasinglulu 		    (size <= range->size - (start - range->start))) {
106*91f16700Schasinglulu 			return range->type;
107*91f16700Schasinglulu 		}
108*91f16700Schasinglulu 	}
109*91f16700Schasinglulu 
110*91f16700Schasinglulu 	return CB_MEM_NONE;
111*91f16700Schasinglulu }
112*91f16700Schasinglulu 
113*91f16700Schasinglulu void coreboot_get_table_location(uint64_t *address, uint32_t *size)
114*91f16700Schasinglulu {
115*91f16700Schasinglulu 	*address = coreboot_table_addr;
116*91f16700Schasinglulu 	*size = coreboot_table_size;
117*91f16700Schasinglulu }
118*91f16700Schasinglulu 
119*91f16700Schasinglulu void coreboot_table_setup(void *base)
120*91f16700Schasinglulu {
121*91f16700Schasinglulu 	cb_header_t *header = base;
122*91f16700Schasinglulu 	void *ptr;
123*91f16700Schasinglulu 	int i;
124*91f16700Schasinglulu 
125*91f16700Schasinglulu 	if (strncmp(header->signature, "LBIO", 4)) {
126*91f16700Schasinglulu 		ERROR("coreboot table signature corrupt!\n");
127*91f16700Schasinglulu 		return;
128*91f16700Schasinglulu 	}
129*91f16700Schasinglulu 	coreboot_table_addr = (uint64_t) base;
130*91f16700Schasinglulu 	coreboot_table_size = header->header_bytes + header->table_bytes;
131*91f16700Schasinglulu 
132*91f16700Schasinglulu 	ptr = base + header->header_bytes;
133*91f16700Schasinglulu 	for (i = 0; i < header->table_entries; i++) {
134*91f16700Schasinglulu 		size_t size;
135*91f16700Schasinglulu 		cb_entry_t *entry = ptr;
136*91f16700Schasinglulu 
137*91f16700Schasinglulu 		if (ptr - base >= header->header_bytes + header->table_bytes) {
138*91f16700Schasinglulu 			ERROR("coreboot table exceeds its bounds!\n");
139*91f16700Schasinglulu 			break;
140*91f16700Schasinglulu 		}
141*91f16700Schasinglulu 
142*91f16700Schasinglulu 		switch (read_le32(&entry->tag)) {
143*91f16700Schasinglulu 		case CB_TAG_MEMORY:
144*91f16700Schasinglulu 			size = read_le32(&entry->size) -
145*91f16700Schasinglulu 			       offsetof(cb_entry_t, memranges);
146*91f16700Schasinglulu 			if (size > sizeof(coreboot_memranges)) {
147*91f16700Schasinglulu 				ERROR("Need to truncate coreboot memranges!\n");
148*91f16700Schasinglulu 				size = sizeof(coreboot_memranges);
149*91f16700Schasinglulu 			}
150*91f16700Schasinglulu 			memcpy(&coreboot_memranges, &entry->memranges, size);
151*91f16700Schasinglulu 			break;
152*91f16700Schasinglulu 		case CB_TAG_SERIAL:
153*91f16700Schasinglulu 			memcpy(&coreboot_serial, &entry->serial,
154*91f16700Schasinglulu 			       sizeof(coreboot_serial));
155*91f16700Schasinglulu 			break;
156*91f16700Schasinglulu 		case CB_TAG_CBMEM_CONSOLE:
157*91f16700Schasinglulu 			setup_cbmem_console(read_le64(&entry->uint64));
158*91f16700Schasinglulu 			break;
159*91f16700Schasinglulu 		default:
160*91f16700Schasinglulu 			/* There are many tags TF doesn't need to care about. */
161*91f16700Schasinglulu 			break;
162*91f16700Schasinglulu 		}
163*91f16700Schasinglulu 
164*91f16700Schasinglulu 		ptr += read_le32(&entry->size);
165*91f16700Schasinglulu 	}
166*91f16700Schasinglulu }
167