blob: f1f92b81335843b3dbc1cdf5ac4531b41ab652e1 [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;
15 unsigned char *ptr;
16 /* 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;
21 ptr = addr;
22 memmove(&buffer, ptr, 1);
23 sum += buffer;
24 if (sum > 0xFFFF)
25 sum -= 0xFFFF;
26 length -= 1;
27 addr = ptr +1;
Martin Roth4dcd13d2016-02-24 13:53:07 -080028
Martin Roth9b1b3352016-02-24 12:27:06 -080029 }
30 len = length >> 1;
31 ptr = addr;
32 while (len--) {
33 sum += *(ptr++);
34 if (sum > 0xFFFF)
35 sum -= 0xFFFF;
36 }
37 addr = ptr;
38 if (length & 1) {
39 uint16_t buffer;
40 unsigned char *ptr;
41 /* copy the last byte into a 2 byte buffer.
42 * This way automatically handles the endian question
43 * of which byte (low or high) the last byte goes in.
44 */
45 buffer = 0;
46 ptr = addr;
47 memmove(&buffer, ptr, 1);
48 sum += buffer;
49 if (sum > 0xFFFF)
50 sum -= 0xFFFF;
51 }
52 return (~sum) & 0xFFFF;
Martin Roth4dcd13d2016-02-24 13:53:07 -080053
Martin Roth9b1b3352016-02-24 12:27:06 -080054}
55
56#define for_each_lbrec(head, rec) \
57 for(rec = (struct lb_record *)(((char *)head) + sizeof(*head)); \
58 (((char *)rec) < (((char *)head) + sizeof(*head) + head->table_bytes)) && \
59 (rec->size >= 1) && \
60 ((((char *)rec) + rec->size) <= (((char *)head) + sizeof(*head) + head->table_bytes)); \
Martin Roth4dcd13d2016-02-24 13:53:07 -080061 rec = (struct lb_record *)(((char *)rec) + rec->size))
62
Martin Roth9b1b3352016-02-24 12:27:06 -080063
64static int count_lb_records(struct lb_header *head)
65{
66 struct lb_record *rec;
67 int count;
68 count = 0;
69 for_each_lbrec(head, rec) {
70 count++;
71 }
72 return count;
73}
74
75static struct lb_header * __find_lb_table(unsigned long start, unsigned long end)
76{
77 unsigned long addr;
78 /* For now be stupid.... */
79 for(addr = start; addr < end; addr += 16) {
80 struct lb_header *head = (struct lb_header *)addr;
81 struct lb_record *recs = (struct lb_record *)(addr + sizeof(*head));
82 if (memcmp(head->signature, "LBIO", 4) != 0)
83 continue;
84 if (head->header_bytes != sizeof(*head))
85 continue;
86 if (ip_compute_csum((unsigned char *)head, sizeof(*head)) != 0)
87 continue;
Martin Roth4dcd13d2016-02-24 13:53:07 -080088 if (ip_compute_csum((unsigned char *)recs, head->table_bytes)
Martin Roth9b1b3352016-02-24 12:27:06 -080089 != head->table_checksum)
90 continue;
91 if (count_lb_records(head) != head->table_entries)
92 continue;
93 return head;
94 };
95 return 0;
96}
97
98static struct lb_header * find_lb_table(void)
99{
100 struct lb_header *head;
Martin Roth2cd42532016-03-07 21:32:54 -0700101 struct lb_record *rec;
102 struct lb_forward *forward;
103
Martin Roth9b1b3352016-02-24 12:27:06 -0800104 head = 0;
105 if (!head) {
106 /* First try at address 0 */
107 head = __find_lb_table(0x00000, 0x1000);
108 }
109 if (!head) {
110 /* Then try at address 0xf0000 */
111 head = __find_lb_table(0xf0000, 0x100000);
112 }
Martin Roth2cd42532016-03-07 21:32:54 -0700113
114 forward = 0;
115 if (head) {
116 /* Check whether there is a forward header */
117 for_each_lbrec(head, rec) {
118 if (rec->tag == LB_TAG_FORWARD) {
119 forward = (struct lb_forward *)rec;
120 break;
121 }
122 }
123 }
124 if (forward) {
125 /* if there is, all valid information is in the
126 * referenced coreboot table
127 */
128 head = __find_lb_table(forward->forward, 0x1000);
129 }
130
Martin Roth9b1b3352016-02-24 12:27:06 -0800131 return head;
132}
133
Martin Roth61ea5412016-03-07 20:58:18 -0700134int query_coreboot(void)
Martin Roth9b1b3352016-02-24 12:27:06 -0800135{
136 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
147 /* 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 }
154
155 mem = 0;
156 for_each_lbrec(head, rec) {
157 if (rec->tag == LB_TAG_MEMORY) {
158 mem = (struct lb_memory *)rec;
159 break;
160 }
161 }
162 if (!mem) {
163 return 1;
164 }
165 entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
166 if (entries == 0)
167 return 1;
168 mem_info.e820_nr = 0;
169 for(i = 0; i < entries; i++) {
170 unsigned long long start;
171 unsigned long long size;
172 unsigned long type;
173 if (i >= E820MAX) {
174 break;
175 }
176 start = mem->map[i].start;
177 size = mem->map[i].size;
178 type = (mem->map[i].type == LB_MEM_RAM)?E820_RAM: E820_RESERVED;
179 mem_info.e820[mem_info.e820_nr].addr = start;
180 mem_info.e820[mem_info.e820_nr].size = size;
181 mem_info.e820[mem_info.e820_nr].type = type;
182 mem_info.e820_nr++;
183 }
184 return 1;
185}