blob: bcc51f8b5e9846c240191389e4671816ce047414 [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{
135 struct lb_header *head;
136 struct lb_record *rec;
137 struct lb_memory *mem;
138 struct lb_forward *forward;
139 int i, entries;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800140
Martin Roth9b1b3352016-02-24 12:27:06 -0800141 head = find_lb_table();
142 if (!head) {
143 return 0;
144 }
145
Ben Gardner90f7d112016-03-15 15:25:22 -0500146 /* coreboot also can forward the table to the high tables area. */
147 rec = (struct lb_record *)(((char *)head) + sizeof(*head));
148 if (rec->tag == LB_TAG_FORWARD) {
149 forward = (struct lb_forward *)rec;
150 head = (struct lb_header *)(unsigned long)(forward->forward);
151 if (!head) { return 0; }
152 }
Martin Roth9b1b3352016-02-24 12:27:06 -0800153
154 mem = 0;
155 for_each_lbrec(head, rec) {
156 if (rec->tag == LB_TAG_MEMORY) {
157 mem = (struct lb_memory *)rec;
158 break;
159 }
160 }
161 if (!mem) {
162 return 1;
163 }
164 entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
165 if (entries == 0)
166 return 1;
167 mem_info.e820_nr = 0;
Ben Gardner90f7d112016-03-15 15:25:22 -0500168 for (i = 0; i < entries; i++) {
Martin Roth9b1b3352016-02-24 12:27:06 -0800169 unsigned long long start;
170 unsigned long long size;
171 unsigned long type;
172 if (i >= E820MAX) {
173 break;
174 }
175 start = mem->map[i].start;
176 size = mem->map[i].size;
Ben Gardner90f7d112016-03-15 15:25:22 -0500177 type = (mem->map[i].type == LB_MEM_RAM) ? E820_RAM : E820_RESERVED;
Martin Roth9b1b3352016-02-24 12:27:06 -0800178 mem_info.e820[mem_info.e820_nr].addr = start;
179 mem_info.e820[mem_info.e820_nr].size = size;
180 mem_info.e820[mem_info.e820_nr].type = type;
181 mem_info.e820_nr++;
182 }
183 return 1;
184}