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