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