blob: 3c2883fb6b7e76b51038eca2793f59270fb310f1 [file] [log] [blame]
Martin Roth61ea5412016-03-07 20:58:18 -07001#include "coreboot_tables.h"
Martin Roth9b1b3352016-02-24 12:27:06 -08002#include "test.h"
3
4static unsigned long ip_compute_csum(void *addr, unsigned long length)
5{
6 uint16_t *ptr;
7 unsigned long sum;
8 unsigned long len;
9 unsigned long laddr;
10 /* compute an ip style checksum */
11 laddr = (unsigned long )addr;
12 sum = 0;
13 if (laddr & 1) {
14 uint16_t buffer;
Martin Roth11248a02016-03-27 21:08:32 -060015 unsigned char *tmp_ptr;
Martin Roth9b1b3352016-02-24 12:27:06 -080016 /* copy the first byte into a 2 byte buffer.
17 * This way automatically handles the endian question
18 * of which byte (low or high) the last byte goes in.
19 */
20 buffer = 0;
Martin Roth11248a02016-03-27 21:08:32 -060021 tmp_ptr = addr;
22 memmove(&buffer, tmp_ptr, 1);
Martin Roth9b1b3352016-02-24 12:27:06 -080023 sum += buffer;
24 if (sum > 0xFFFF)
25 sum -= 0xFFFF;
26 length -= 1;
Martin Roth11248a02016-03-27 21:08:32 -060027 addr = tmp_ptr + 1;
Martin Roth9b1b3352016-02-24 12:27:06 -080028 }
29 len = length >> 1;
30 ptr = addr;
31 while (len--) {
32 sum += *(ptr++);
33 if (sum > 0xFFFF)
34 sum -= 0xFFFF;
35 }
36 addr = ptr;
37 if (length & 1) {
38 uint16_t buffer;
Martin Roth11248a02016-03-27 21:08:32 -060039 unsigned char *tmp_ptr;
Martin Roth9b1b3352016-02-24 12:27:06 -080040 /* copy the last byte into a 2 byte buffer.
41 * This way automatically handles the endian question
42 * of which byte (low or high) the last byte goes in.
43 */
44 buffer = 0;
Martin Roth11248a02016-03-27 21:08:32 -060045 tmp_ptr = addr;
46 memmove(&buffer, tmp_ptr, 1);
Martin Roth9b1b3352016-02-24 12:27:06 -080047 sum += buffer;
48 if (sum > 0xFFFF)
49 sum -= 0xFFFF;
50 }
51 return (~sum) & 0xFFFF;
Martin Roth9b1b3352016-02-24 12:27:06 -080052}
53
54#define for_each_lbrec(head, rec) \
Ben Gardner90f7d112016-03-15 15:25:22 -050055 for (rec = (struct lb_record *)(((char *)head) + sizeof(*head)); \
56 (((char *)rec) < (((char *)head) + sizeof(*head) + head->table_bytes)) && \
57 (rec->size >= 1) && \
58 ((((char *)rec) + rec->size) <= (((char *)head) + sizeof(*head) + head->table_bytes)); \
59 rec = (struct lb_record *)(((char *)rec) + rec->size))
Martin Roth4dcd13d2016-02-24 13:53:07 -080060
Martin Roth9b1b3352016-02-24 12:27:06 -080061
62static int count_lb_records(struct lb_header *head)
63{
64 struct lb_record *rec;
65 int count;
66 count = 0;
67 for_each_lbrec(head, rec) {
68 count++;
69 }
70 return count;
71}
72
73static struct lb_header * __find_lb_table(unsigned long start, unsigned long end)
74{
75 unsigned long addr;
76 /* For now be stupid.... */
Ben Gardner90f7d112016-03-15 15:25:22 -050077 for (addr = start; addr < end; addr += 16) {
Martin Roth9b1b3352016-02-24 12:27:06 -080078 struct lb_header *head = (struct lb_header *)addr;
79 struct lb_record *recs = (struct lb_record *)(addr + sizeof(*head));
80 if (memcmp(head->signature, "LBIO", 4) != 0)
81 continue;
82 if (head->header_bytes != sizeof(*head))
83 continue;
84 if (ip_compute_csum((unsigned char *)head, sizeof(*head)) != 0)
85 continue;
Martin Roth4dcd13d2016-02-24 13:53:07 -080086 if (ip_compute_csum((unsigned char *)recs, head->table_bytes)
Ben Gardner90f7d112016-03-15 15:25:22 -050087 != head->table_checksum)
Martin Roth9b1b3352016-02-24 12:27:06 -080088 continue;
89 if (count_lb_records(head) != head->table_entries)
90 continue;
91 return head;
Ben Gardner90f7d112016-03-15 15:25:22 -050092 }
Martin Roth9b1b3352016-02-24 12:27:06 -080093 return 0;
94}
95
96static struct lb_header * find_lb_table(void)
97{
98 struct lb_header *head;
Martin Roth2cd42532016-03-07 21:32:54 -070099 struct lb_record *rec;
100 struct lb_forward *forward;
101
Martin Roth9b1b3352016-02-24 12:27:06 -0800102 head = 0;
103 if (!head) {
104 /* First try at address 0 */
105 head = __find_lb_table(0x00000, 0x1000);
106 }
107 if (!head) {
108 /* Then try at address 0xf0000 */
109 head = __find_lb_table(0xf0000, 0x100000);
110 }
Martin Roth2cd42532016-03-07 21:32:54 -0700111
112 forward = 0;
113 if (head) {
114 /* Check whether there is a forward header */
115 for_each_lbrec(head, rec) {
116 if (rec->tag == LB_TAG_FORWARD) {
117 forward = (struct lb_forward *)rec;
118 break;
119 }
120 }
121 }
122 if (forward) {
123 /* if there is, all valid information is in the
124 * referenced coreboot table
125 */
Tristan Corrick0704ab32018-07-31 00:34:42 +1200126 head = __find_lb_table(forward->forward,
127 forward->forward + 0x1000);
Martin Roth2cd42532016-03-07 21:32:54 -0700128 }
129
Martin Roth9b1b3352016-02-24 12:27:06 -0800130 return head;
131}
132
Martin Roth61ea5412016-03-07 20:58:18 -0700133int query_coreboot(void)
Martin Roth9b1b3352016-02-24 12:27:06 -0800134{
Alexandru Gagniucfb075982019-07-24 14:51:40 -0500135 const struct lb_serial *serial = 0;
Martin Roth9b1b3352016-02-24 12:27:06 -0800136 struct lb_header *head;
137 struct lb_record *rec;
138 struct lb_memory *mem;
139 struct lb_forward *forward;
140 int i, entries;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800141
Martin Roth9b1b3352016-02-24 12:27:06 -0800142 head = find_lb_table();
143 if (!head) {
144 return 0;
145 }
146
Ben Gardner90f7d112016-03-15 15:25:22 -0500147 /* coreboot also can forward the table to the high tables area. */
148 rec = (struct lb_record *)(((char *)head) + sizeof(*head));
149 if (rec->tag == LB_TAG_FORWARD) {
150 forward = (struct lb_forward *)rec;
151 head = (struct lb_header *)(unsigned long)(forward->forward);
152 if (!head) { return 0; }
153 }
Martin Roth9b1b3352016-02-24 12:27:06 -0800154
155 mem = 0;
156 for_each_lbrec(head, rec) {
Alexandru Gagniucfb075982019-07-24 14:51:40 -0500157 switch (rec->tag) {
158 case LB_TAG_MEMORY:
Martin Roth9b1b3352016-02-24 12:27:06 -0800159 mem = (struct lb_memory *)rec;
160 break;
Alexandru Gagniucfb075982019-07-24 14:51:40 -0500161 case LB_TAG_SERIAL:
162 serial = (const void *)rec;
163 break;
164 default:
165 break;
Martin Roth9b1b3352016-02-24 12:27:06 -0800166 }
167 }
Alexandru Gagniucfb075982019-07-24 14:51:40 -0500168
169 if (serial)
170 serial_console_setup_from_lb_serial(serial);
171
Martin Roth9b1b3352016-02-24 12:27:06 -0800172 if (!mem) {
173 return 1;
174 }
175 entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
176 if (entries == 0)
177 return 1;
178 mem_info.e820_nr = 0;
Ben Gardner90f7d112016-03-15 15:25:22 -0500179 for (i = 0; i < entries; i++) {
Martin Roth9b1b3352016-02-24 12:27:06 -0800180 unsigned long long start;
181 unsigned long long size;
182 unsigned long type;
183 if (i >= E820MAX) {
184 break;
185 }
186 start = mem->map[i].start;
187 size = mem->map[i].size;
Ben Gardner90f7d112016-03-15 15:25:22 -0500188 type = (mem->map[i].type == LB_MEM_RAM) ? E820_RAM : E820_RESERVED;
Martin Roth9b1b3352016-02-24 12:27:06 -0800189 mem_info.e820[mem_info.e820_nr].addr = start;
190 mem_info.e820[mem_info.e820_nr].size = size;
191 mem_info.e820[mem_info.e820_nr].type = type;
192 mem_info.e820_nr++;
193 }
194 return 1;
195}