Add parlib/common.h
[akaros.git] / user / vmm / coreboot_table.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2003-2004 Eric Biederman
5  * Copyright (C) 2005-2010 coresystems GmbH
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; version 2 of
10  * the License.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
20  * MA 02110-1301 USA
21  */
22 #include <parlib/common.h>
23
24 #include <stdio.h>
25 #include <stdarg.h>
26 #include <string.h>
27 #include <vmm/coreboot_tables.h>
28
29 static struct lb_header *lb_table_init(void *addr)
30 {
31         struct lb_header *header;
32
33         /* 16 byte align the address */
34         header = (void *)(((unsigned long)addr + 15) & ~15);
35         header->signature[0] = 'L';
36         header->signature[1] = 'B';
37         header->signature[2] = 'I';
38         header->signature[3] = 'O';
39         header->header_bytes = sizeof(*header);
40         header->header_checksum = 0;
41         header->table_bytes = 0;
42         header->table_checksum = 0;
43         header->table_entries = 0;
44         return header;
45 }
46
47 static struct lb_record *lb_first_record(struct lb_header *header)
48 {
49         struct lb_record *rec;
50         rec = (void *)(((char *)header) + sizeof(*header));
51         return rec;
52 }
53
54 static struct lb_record *lb_last_record(struct lb_header *header)
55 {
56         struct lb_record *rec;
57         rec = (void *)(((char *)header) + sizeof(*header) + header->table_bytes);
58         return rec;
59 }
60
61 struct lb_record *lb_new_record(struct lb_header *header)
62 {
63         struct lb_record *rec;
64         rec = lb_last_record(header);
65         if (header->table_entries) {
66                 header->table_bytes += rec->size;
67         }
68         rec = lb_last_record(header);
69         header->table_entries++;
70         rec->tag = LB_TAG_UNUSED;
71         rec->size = sizeof(*rec);
72         return rec;
73 }
74
75 static struct lb_memory *lb_memory(struct lb_header *header)
76 {
77         struct lb_record *rec;
78         struct lb_memory *mem;
79         rec = lb_new_record(header);
80         mem = (struct lb_memory *)rec;
81         mem->tag = LB_TAG_MEMORY;
82         mem->size = sizeof(*mem);
83         return mem;
84 }
85
86 void lb_add_serial(struct lb_serial *new_serial, void *data)
87 {
88         struct lb_header *header = (struct lb_header *)data;
89         struct lb_serial *serial;
90
91         serial = (struct lb_serial *)lb_new_record(header);
92         serial->tag = LB_TAG_SERIAL;
93         serial->size = sizeof(*serial);
94         serial->type = new_serial->type;
95         serial->baseaddr = new_serial->baseaddr;
96         serial->baud = new_serial->baud;
97         serial->regwidth = new_serial->regwidth;
98 }
99
100 void lb_add_console(uint16_t consoletype, void *data)
101 {
102         struct lb_header *header = (struct lb_header *)data;
103         struct lb_console *console;
104
105         console = (struct lb_console *)lb_new_record(header);
106         console->tag = LB_TAG_CONSOLE;
107         console->size = sizeof(*console);
108         console->type = consoletype;
109 }
110
111 static void lb_framebuffer(struct lb_header *header)
112 {
113 #if 0 //CONFIG_FRAMEBUFFER_KEEP_VESA_MODE || CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT
114         void fill_lb_framebuffer(struct lb_framebuffer *framebuffer);
115         int vbe_mode_info_valid(void);
116
117         // If there isn't any mode info to put in the table, don't ask for it
118         // to be filled with junk.
119         if (!vbe_mode_info_valid())
120                 return;
121         struct lb_framebuffer *framebuffer;
122         framebuffer = (struct lb_framebuffer *)lb_new_record(header);
123         fill_lb_framebuffer(framebuffer);
124         framebuffer->tag = LB_TAG_FRAMEBUFFER;
125         framebuffer->size = sizeof(*framebuffer);
126 #endif
127 }
128
129 void fill_lb_gpio(struct lb_gpio *gpio, int num,
130                          int polarity, const char *name, int value)
131 {
132         memset(gpio, 0, sizeof(*gpio));
133         gpio->port = num;
134         gpio->polarity = polarity;
135         if (value >= 0)
136                 gpio->value = value;
137         strncpy((char *)gpio->name, name, GPIO_MAX_NAME_LENGTH);
138 }
139
140 #if CONFIG_CHROMEOS
141 static void lb_gpios(struct lb_header *header)
142 {
143         struct lb_gpios *gpios;
144
145         gpios = (struct lb_gpios *)lb_new_record(header);
146         gpios->tag = LB_TAG_GPIO;
147         gpios->size = sizeof(*gpios);
148         gpios->count = 0;
149         fill_lb_gpios(gpios);
150 }
151
152 static void lb_vdat(struct lb_header *header)
153 {
154 #if CONFIG_HAVE_ACPI_TABLES
155         struct lb_range *vdat;
156
157         vdat = (struct lb_range *)lb_new_record(header);
158         vdat->tag = LB_TAG_VDAT;
159         vdat->size = sizeof(*vdat);
160         acpi_get_vdat_info(&vdat->range_start, &vdat->range_size);
161 #endif
162 }
163
164 static void lb_vbnv(struct lb_header *header)
165 {
166 #if CONFIG_PC80_SYSTEM
167         struct lb_range *vbnv;
168
169         vbnv = (struct lb_range *)lb_new_record(header);
170         vbnv->tag = LB_TAG_VBNV;
171         vbnv->size = sizeof(*vbnv);
172         vbnv->range_start = CONFIG_VBNV_OFFSET + 14;
173         vbnv->range_size = CONFIG_VBNV_SIZE;
174 #endif
175 }
176
177 #if CONFIG_VBOOT_VERIFY_FIRMWARE
178 static void lb_vboot_handoff(struct lb_header *header)
179 {
180         void *addr;
181         uint32_t size;
182         struct lb_range *vbho;
183
184         if (vboot_get_handoff_info(&addr, &size))
185                 return;
186
187         vbho = (struct lb_range *)lb_new_record(header);
188         vbho->tag = LB_TAB_VBOOT_HANDOFF;
189         vbho->size = sizeof(*vbho);
190         vbho->range_start = (intptr_t)addr;
191         vbho->range_size = size;
192 }
193 #else
194 static inline void lb_vboot_handoff(struct lb_header *header) {}
195 #endif /* CONFIG_VBOOT_VERIFY_FIRMWARE */
196 #endif /* CONFIG_CHROMEOS */
197
198 static void lb_board_id(struct lb_header *header)
199 {
200 #if 0 // CONFIG_BOARD_ID_AUTO || CONFIG_BOARD_ID_MANUAL
201         struct lb_board_id  *bid;
202
203         bid = (struct lb_board_id *)lb_new_record(header);
204
205         bid->tag = LB_TAG_BOARD_ID;
206         bid->size = sizeof(*bid);
207         bid->board_id = board_id();
208 #endif
209 }
210
211 static void lb_strings(struct lb_header *header)
212 {
213         static const struct {
214                 uint32_t tag;
215                 const char *string;
216         } strings[] = {
217                 // we may want this at some point.
218         };
219         unsigned int i;
220         for(i = 0; i < sizeof(strings)/sizeof(strings[0]); i++) {
221                 struct lb_string *rec;
222                 size_t len;
223                 rec = (struct lb_string *)lb_new_record(header);
224                 len = strlen(strings[i].string);
225                 rec->tag = strings[i].tag;
226                 rec->size = (sizeof(*rec) + len + 1 + 3) & ~3;
227                 memcpy(rec->string, strings[i].string, len+1);
228         }
229
230 }
231
232 static void lb_record_version_timestamp(struct lb_header *header)
233 {
234         struct lb_timestamp *rec;
235         rec = (struct lb_timestamp *)lb_new_record(header);
236         rec->tag = LB_TAG_VERSION_TIMESTAMP;
237         rec->size = sizeof(*rec);
238         // TODO
239         //rec->timestamp = coreboot_version_timestamp;
240 }
241
242 void __attribute__((weak)) lb_board(struct lb_header *header) { /* NOOP */ }
243
244 static struct lb_forward *lb_forward(struct lb_header *header, struct lb_header *next_header)
245 {
246         struct lb_record *rec;
247         struct lb_forward *forward;
248         rec = lb_new_record(header);
249         forward = (struct lb_forward *)rec;
250         forward->tag = LB_TAG_FORWARD;
251         forward->size = sizeof(*forward);
252         forward->forward = (uint64_t)(unsigned long)next_header;
253         return forward;
254 }
255
256 /* enough with the ip dependency already. This is a trivial checksum. */
257 static inline uint16_t cb_checksum(const void *ptr, unsigned len)
258 {
259         uint32_t sum;
260         const uint8_t *addr = ptr;
261
262         sum = 0;
263
264         while(len > 0) {
265                 sum += addr[0]<<8 | addr[1] ;
266                 len -= 2;
267                 addr += 2;
268         }
269
270         sum = (sum & 0xffff) + (sum >> 16);
271         sum = (sum & 0xffff) + (sum >> 16);
272
273         return (sum^0xffff);
274 }
275
276 static void *lb_table_fini(struct lb_header *head)
277 {
278         struct lb_record *rec, *first_rec;
279         rec = lb_last_record(head);
280         if (head->table_entries) {
281                 head->table_bytes += rec->size;
282         }
283
284         first_rec = lb_first_record(head);
285         head->table_checksum = cb_checksum((void *)first_rec, head->table_bytes);
286         head->header_checksum = 0;
287         head->header_checksum = cb_checksum((void *)head, sizeof(*head));
288         printf("Wrote coreboot table at: %p, 0x%x bytes, checksum %x\n",
289                head, head->table_bytes, head->table_checksum);
290         printf("header checksum (not worth using in a kernel) 0x%x\n", head->header_checksum);
291         return rec + rec->size;
292 }
293
294 void * write_coreboot_table(void *where, void *base, uint64_t len)
295 {
296         struct lb_header *head;
297         struct lb_memory *m;
298         struct lb_memory_range *mem;
299
300         printf("Writing coreboot table at %p with mem %p len 0x%lx\n", where, base, len);
301
302         head = lb_table_init(where);
303         m = lb_memory(head);
304         mem = (void *)(&m[1]);
305         mem->start = pack_lb64((uint64_t) 0);
306         mem->size = pack_lb64((uint64_t) base-1);
307         mem->type = LB_MEM_RESERVED;
308         m->size += sizeof(*mem);
309         mem = (void *)(&mem[1]);
310         mem->start = pack_lb64((uint64_t) base);
311         mem->size = pack_lb64((uint64_t) len);
312         mem->type = LB_MEM_RAM;
313         m->size += sizeof(*mem);
314         printf("Head is %p, mem is %p, m is %p, m->size is %d, mem->size is %d\n",
315                 head, mem, m, m->size, mem->size);
316         return lb_table_fini(head);
317 }