blob: a234e97f68de92cb79e2f74bf07255fa78cc6594 [file] [log] [blame]
Kevin O'Connor59a23bb2008-06-08 23:09:42 -04001// Coreboot interface support.
2//
Kevin O'Connor2929c352009-07-25 13:48:27 -04003// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
Kevin O'Connor59a23bb2008-06-08 23:09:42 -04004//
Kevin O'Connorb1b7c2a2009-01-15 20:52:58 -05005// This file may be distributed under the terms of the GNU LGPLv3 license.
Kevin O'Connor59a23bb2008-06-08 23:09:42 -04006
Kevin O'Connor135f3f62013-09-14 23:57:26 -04007#include "block.h" // MAXDESCSIZE
Kevin O'Connor2d2fa312013-09-14 21:55:26 -04008#include "byteorder.h" // be32_to_cpu
9#include "config.h" // CONFIG_*
Kevin O'Connor5d369d82013-09-02 20:48:46 -040010#include "hw/pci.h" // pci_probe_devices
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040011#include "lzmadecode.h" // LzmaDecode
Kevin O'Connor9dea5902013-09-14 20:23:54 -040012#include "malloc.h" // free
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040013#include "memmap.h" // add_e820
14#include "output.h" // dprintf
Gerd Hoffmann1f209822013-06-03 08:06:27 +020015#include "paravirt.h" // PlatformRunningOn
Kevin O'Connor41639f82013-09-14 19:37:36 -040016#include "romfile.h" // romfile_findprefix
Kevin O'Connor3df600b2013-09-14 19:28:55 -040017#include "stacks.h" // yield
Kevin O'Connorfa9c66a2013-09-14 19:10:40 -040018#include "string.h" // memset
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040019#include "util.h" // coreboot_preinit
Kevin O'Connora2a86e22013-02-13 19:35:12 -050020
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040021
22/****************************************************************
Kevin O'Connor93479e42008-06-12 22:22:43 -040023 * Memory map
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040024 ****************************************************************/
25
26struct cb_header {
27 u32 signature;
28 u32 header_bytes;
29 u32 header_checksum;
30 u32 table_bytes;
31 u32 table_checksum;
32 u32 table_entries;
33};
34
35#define CB_SIGNATURE 0x4f49424C // "LBIO"
36
37struct cb_memory_range {
38 u64 start;
39 u64 size;
40 u32 type;
41};
42
43#define CB_MEM_TABLE 16
44
45struct cb_memory {
46 u32 tag;
47 u32 size;
48 struct cb_memory_range map[0];
49};
50
51#define CB_TAG_MEMORY 0x01
52
53#define MEM_RANGE_COUNT(_rec) \
54 (((_rec)->size - sizeof(*(_rec))) / sizeof((_rec)->map[0]))
55
Kevin O'Connor22e1b912009-07-19 18:52:46 -040056struct cb_mainboard {
57 u32 tag;
58 u32 size;
59 u8 vendor_idx;
60 u8 part_idx;
61 char strings[0];
62};
63
64#define CB_TAG_MAINBOARD 0x0003
65
Kevin O'Connor071f1542009-03-21 13:17:21 -040066struct cb_forward {
67 u32 tag;
68 u32 size;
69 u64 forward;
70};
71
72#define CB_TAG_FORWARD 0x11
73
Gerd Hoffmannebf03f72013-06-24 11:24:57 +020074struct cb_cbmem_ref {
75 u32 tag;
76 u32 size;
77 u64 cbmem_addr;
78};
79
80#define CB_TAG_CBMEM_CONSOLE 0x17
81
82struct cbmem_console {
83 u32 buffer_size;
84 u32 buffer_cursor;
85 u8 buffer_body[0];
86} PACKED;
87static struct cbmem_console *cbcon = NULL;
88
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040089static u16
90ipchksum(char *buf, int count)
91{
92 u16 *p = (u16*)buf;
93 u32 sum = 0;
94 while (count > 1) {
95 sum += *p++;
96 count -= 2;
97 }
98 if (count)
99 sum += *(u8*)p;
100 sum = (sum >> 16) + (sum & 0xffff);
101 sum += (sum >> 16);
102 return ~sum;
103}
104
105// Try to locate the coreboot header in a given address range.
106static struct cb_header *
107find_cb_header(char *addr, int len)
108{
109 char *end = addr + len;
110 for (; addr < end; addr += 16) {
111 struct cb_header *cbh = (struct cb_header *)addr;
112 if (cbh->signature != CB_SIGNATURE)
113 continue;
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400114 if (! cbh->table_bytes)
115 continue;
116 if (ipchksum(addr, sizeof(*cbh)) != 0)
117 continue;
118 if (ipchksum(addr + sizeof(*cbh), cbh->table_bytes)
119 != cbh->table_checksum)
120 continue;
121 return cbh;
122 }
123 return NULL;
124}
125
126// Try to find the coreboot memory table in the given coreboot table.
Kevin O'Connor93479e42008-06-12 22:22:43 -0400127static void *
128find_cb_subtable(struct cb_header *cbh, u32 tag)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400129{
130 char *tbl = (char *)cbh + sizeof(*cbh);
131 int i;
132 for (i=0; i<cbh->table_entries; i++) {
133 struct cb_memory *cbm = (struct cb_memory *)tbl;
134 tbl += cbm->size;
Kevin O'Connor93479e42008-06-12 22:22:43 -0400135 if (cbm->tag == tag)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400136 return cbm;
137 }
138 return NULL;
139}
140
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400141static struct cb_memory *CBMemTable;
Julian Pidancet02145152012-02-05 04:51:06 +0000142const char *CBvendor = "", *CBpart = "";
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400143
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400144// Populate max ram and e820 map info by scanning for a coreboot table.
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400145void
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500146coreboot_preinit(void)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400147{
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500148 if (!CONFIG_COREBOOT)
149 return;
150
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400151 dprintf(3, "Attempting to find coreboot table\n");
Kevin O'Connoref3d8822009-02-05 19:51:12 -0500152
Kevin O'Connoref3d8822009-02-05 19:51:12 -0500153 // Find coreboot table.
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400154 struct cb_header *cbh = find_cb_header(0, 0x1000);
155 if (!cbh)
156 goto fail;
Kevin O'Connor071f1542009-03-21 13:17:21 -0400157 struct cb_forward *cbf = find_cb_subtable(cbh, CB_TAG_FORWARD);
158 if (cbf) {
159 dprintf(3, "Found coreboot table forwarder.\n");
160 cbh = find_cb_header((char *)((u32)cbf->forward), 0x100);
161 if (!cbh)
162 goto fail;
163 }
164 dprintf(3, "Now attempting to find coreboot memory map\n");
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400165 struct cb_memory *cbm = CBMemTable = find_cb_subtable(cbh, CB_TAG_MEMORY);
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400166 if (!cbm)
167 goto fail;
168
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400169 int i, count = MEM_RANGE_COUNT(cbm);
170 for (i=0; i<count; i++) {
171 struct cb_memory_range *m = &cbm->map[i];
172 u32 type = m->type;
Kevin O'Connorf85e4bc2013-02-19 01:33:45 -0500173 if (type == CB_MEM_TABLE)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400174 type = E820_RESERVED;
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400175 add_e820(m->start, m->size, type);
176 }
177
178 // Ughh - coreboot likes to set a map at 0x0000-0x1000, but this
179 // confuses grub. So, override it.
180 add_e820(0, 16*1024, E820_RAM);
181
Gerd Hoffmannebf03f72013-06-24 11:24:57 +0200182 struct cb_cbmem_ref *cbref = find_cb_subtable(cbh, CB_TAG_CBMEM_CONSOLE);
183 if (cbref) {
184 cbcon = (void*)(u32)cbref->cbmem_addr;
185 dprintf(1, "----- [ seabios log starts here ] -----\n");
186 dprintf(1, "Found coreboot cbmem console @ %llx\n", cbref->cbmem_addr);
187 }
188
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400189 struct cb_mainboard *cbmb = find_cb_subtable(cbh, CB_TAG_MAINBOARD);
190 if (cbmb) {
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400191 CBvendor = &cbmb->strings[cbmb->vendor_idx];
192 CBpart = &cbmb->strings[cbmb->part_idx];
Gerd Hoffmann1f209822013-06-03 08:06:27 +0200193 if (strcmp(CBvendor, "Emulation") == 0 &&
Gerd Hoffmann95983862013-06-13 07:42:58 +0200194 memcmp(CBpart, "QEMU", 4) == 0) {
Gerd Hoffmann1f209822013-06-03 08:06:27 +0200195 PlatformRunningOn |= PF_QEMU;
196 }
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400197 dprintf(1, "Found mainboard %s %s\n", CBvendor, CBpart);
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400198 }
199
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400200 return;
201
202fail:
203 // No table found.. Use 16Megs as a dummy value.
204 dprintf(1, "Unable to find coreboot table!\n");
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400205 add_e820(0, 16*1024*1024, E820_RAM);
206 return;
207}
Kevin O'Connor4c0c85a2009-04-11 23:31:29 -0400208
Gerd Hoffmannebf03f72013-06-24 11:24:57 +0200209void debug_cbmem(char c)
210{
Gerd Hoffmannc83e7c22013-06-25 15:45:30 +0200211 if (!CONFIG_DEBUG_COREBOOT)
Gerd Hoffmannebf03f72013-06-24 11:24:57 +0200212 return;
213 if (!cbcon)
214 return;
215 if (cbcon->buffer_cursor == cbcon->buffer_size)
216 return;
217 cbcon->buffer_body[cbcon->buffer_cursor++] = c;
218}
Kevin O'Connor4c0c85a2009-04-11 23:31:29 -0400219
220/****************************************************************
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400221 * BIOS table copying
222 ****************************************************************/
223
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400224// Attempt to find (and relocate) any standard bios tables found in a
225// given address range.
226static void
227scan_tables(u32 start, u32 size)
228{
229 void *p = (void*)ALIGN(start, 16);
230 void *end = (void*)start + size;
Kevin O'Connor4d053eb2012-06-09 13:08:02 -0400231 for (; p<end; p += 16)
232 copy_table(p);
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400233}
234
235void
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500236coreboot_platform_setup(void)
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400237{
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500238 if (!CONFIG_COREBOOT)
239 return;
240 pci_probe_devices();
241
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400242 struct cb_memory *cbm = CBMemTable;
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500243 if (!cbm)
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400244 return;
245
246 dprintf(3, "Relocating coreboot bios tables\n");
247
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400248 // Scan CB_MEM_TABLE areas for bios tables.
249 int i, count = MEM_RANGE_COUNT(cbm);
250 for (i=0; i<count; i++) {
251 struct cb_memory_range *m = &cbm->map[i];
252 if (m->type == CB_MEM_TABLE)
253 scan_tables(m->start, m->size);
254 }
David Woodhousedbdb7732013-02-05 16:14:20 +0000255
David Woodhoused304fe42013-02-23 00:24:48 +0000256 find_acpi_features();
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400257}
258
259
260/****************************************************************
Kevin O'Connor592323f2009-04-26 23:17:49 -0400261 * ulzma
262 ****************************************************************/
263
Kevin O'Connor1f836252009-08-16 20:17:35 -0400264// Uncompress data in flash to an area of memory.
Kevin O'Connor592323f2009-04-26 23:17:49 -0400265static int
Kevin O'Connorcbd6ca02009-04-27 21:51:13 -0400266ulzma(u8 *dst, u32 maxlen, const u8 *src, u32 srclen)
Kevin O'Connor592323f2009-04-26 23:17:49 -0400267{
Kevin O'Connor1edc89d2009-04-30 21:50:35 -0400268 dprintf(3, "Uncompressing data %d@%p to %d@%p\n", srclen, src, maxlen, dst);
Kevin O'Connor592323f2009-04-26 23:17:49 -0400269 CLzmaDecoderState state;
270 int ret = LzmaDecodeProperties(&state.Properties, src, LZMA_PROPERTIES_SIZE);
271 if (ret != LZMA_RESULT_OK) {
272 dprintf(1, "LzmaDecodeProperties error - %d\n", ret);
273 return -1;
274 }
275 u8 scratch[15980];
276 int need = (LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
277 if (need > sizeof(scratch)) {
Kevin O'Connor311f8872010-12-26 14:16:22 -0500278 dprintf(1, "LzmaDecode need %d have %d\n", need, (unsigned int)sizeof(scratch));
Kevin O'Connor592323f2009-04-26 23:17:49 -0400279 return -1;
280 }
281 state.Probs = (CProb *)scratch;
282
283 u32 dstlen = *(u32*)(src + LZMA_PROPERTIES_SIZE);
Kevin O'Connorcbd6ca02009-04-27 21:51:13 -0400284 if (dstlen > maxlen) {
285 dprintf(1, "LzmaDecode too large (max %d need %d)\n", maxlen, dstlen);
286 return -1;
287 }
Kevin O'Connor592323f2009-04-26 23:17:49 -0400288 u32 inProcessed, outProcessed;
Kevin O'Connorcbd6ca02009-04-27 21:51:13 -0400289 ret = LzmaDecode(&state, src + LZMA_PROPERTIES_SIZE + 8, srclen
Kevin O'Connor592323f2009-04-26 23:17:49 -0400290 , &inProcessed, dst, dstlen, &outProcessed);
291 if (ret) {
292 dprintf(1, "LzmaDecode returned %d\n", ret);
293 return -1;
294 }
295 return dstlen;
296}
297
298
299/****************************************************************
Kevin O'Connor4c0c85a2009-04-11 23:31:29 -0400300 * Coreboot flash format
301 ****************************************************************/
302
Kevin O'Connor4c0c85a2009-04-11 23:31:29 -0400303#define CBFS_HEADER_MAGIC 0x4F524243
304#define CBFS_HEADPTR_ADDR 0xFFFFFFFc
305#define CBFS_VERSION1 0x31313131
306
307struct cbfs_header {
308 u32 magic;
309 u32 version;
310 u32 romsize;
311 u32 bootblocksize;
312 u32 align;
313 u32 offset;
314 u32 pad[2];
315} PACKED;
316
Kevin O'Connor4c0c85a2009-04-11 23:31:29 -0400317#define CBFS_FILE_MAGIC 0x455649484352414cLL // LARCHIVE
318
319struct cbfs_file {
320 u64 magic;
321 u32 len;
322 u32 type;
323 u32 checksum;
324 u32 offset;
Kevin O'Connor67823442009-04-13 14:14:51 -0400325 char filename[0];
Kevin O'Connor4c0c85a2009-04-11 23:31:29 -0400326} PACKED;
327
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400328struct cbfs_romfile_s {
329 struct romfile_s file;
330 struct cbfs_file *fhdr;
331 void *data;
332 u32 rawsize, flags;
333};
334
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400335// Copy a file to memory (uncompressing if necessary)
336static int
337cbfs_copyfile(struct romfile_s *file, void *dst, u32 maxlen)
Kevin O'Connor67823442009-04-13 14:14:51 -0400338{
Kevin O'Connor897fb112013-02-07 23:32:48 -0500339 if (!CONFIG_COREBOOT_FLASH)
Kevin O'Connor1f836252009-08-16 20:17:35 -0400340 return -1;
341
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400342 struct cbfs_romfile_s *cfile;
343 cfile = container_of(file, struct cbfs_romfile_s, file);
344 u32 size = cfile->rawsize;
345 void *src = cfile->data;
346 if (cfile->flags) {
Kevin O'Connor34036962009-12-05 18:51:53 -0500347 // Compressed - copy to temp ram and uncompress it.
Kevin O'Connorb4525a02010-07-27 01:14:11 -0400348 void *temp = malloc_tmphigh(size);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400349 if (!temp) {
350 warn_noalloc();
Kevin O'Connor34036962009-12-05 18:51:53 -0500351 return -1;
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400352 }
Kevin O'Connorb4525a02010-07-27 01:14:11 -0400353 iomemcpy(temp, src, size);
Kevin O'Connor34036962009-12-05 18:51:53 -0500354 int ret = ulzma(dst, maxlen, temp, size);
355 yield();
356 free(temp);
357 return ret;
358 }
Kevin O'Connor1f836252009-08-16 20:17:35 -0400359
360 // Not compressed.
361 dprintf(3, "Copying data %d@%p to %d@%p\n", size, src, maxlen, dst);
362 if (size > maxlen) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500363 warn_noalloc();
Kevin O'Connor1f836252009-08-16 20:17:35 -0400364 return -1;
365 }
Kevin O'Connor34036962009-12-05 18:51:53 -0500366 iomemcpy(dst, src, size);
Kevin O'Connor1f836252009-08-16 20:17:35 -0400367 return size;
Kevin O'Connor67823442009-04-13 14:14:51 -0400368}
369
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400370void
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500371coreboot_cbfs_init(void)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400372{
Kevin O'Connor897fb112013-02-07 23:32:48 -0500373 if (!CONFIG_COREBOOT_FLASH)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400374 return;
375
376 struct cbfs_header *hdr = *(void **)CBFS_HEADPTR_ADDR;
Kevin O'Connorb3064592012-08-14 21:20:10 -0400377 if (hdr->magic != cpu_to_be32(CBFS_HEADER_MAGIC)) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400378 dprintf(1, "Unable to find CBFS (ptr=%p; got %x not %x)\n"
Kevin O'Connorb3064592012-08-14 21:20:10 -0400379 , hdr, hdr->magic, cpu_to_be32(CBFS_HEADER_MAGIC));
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400380 return;
381 }
382 dprintf(1, "Found CBFS header at %p\n", hdr);
383
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400384 struct cbfs_file *fhdr = (void *)(0 - be32_to_cpu(hdr->romsize)
385 + be32_to_cpu(hdr->offset));
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400386 for (;;) {
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400387 if (fhdr < (struct cbfs_file *)(0xFFFFFFFF - be32_to_cpu(hdr->romsize)))
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400388 break;
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400389 u64 magic = fhdr->magic;
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400390 if (magic != CBFS_FILE_MAGIC)
391 break;
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400392 struct cbfs_romfile_s *cfile = malloc_tmp(sizeof(*cfile));
393 if (!cfile) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400394 warn_noalloc();
395 break;
396 }
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400397 memset(cfile, 0, sizeof(*cfile));
398 strtcpy(cfile->file.name, fhdr->filename, sizeof(cfile->file.name));
399 cfile->file.size = cfile->rawsize = be32_to_cpu(fhdr->len);
400 cfile->fhdr = fhdr;
401 cfile->file.copy = cbfs_copyfile;
402 cfile->data = (void*)fhdr + be32_to_cpu(fhdr->offset);
403 int len = strlen(cfile->file.name);
404 if (len > 5 && strcmp(&cfile->file.name[len-5], ".lzma") == 0) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400405 // Using compression.
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400406 cfile->flags = 1;
407 cfile->file.name[len-5] = '\0';
408 cfile->file.size = *(u32*)(cfile->data + LZMA_PROPERTIES_SIZE);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400409 }
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400410 romfile_add(&cfile->file);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400411
Kevin O'Connor1a113e12013-08-02 14:12:09 -0400412 fhdr = (void*)ALIGN((u32)cfile->data + cfile->rawsize
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400413 , be32_to_cpu(hdr->align));
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400414 }
415}
416
Kevin O'Connor67823442009-04-13 14:14:51 -0400417struct cbfs_payload_segment {
418 u32 type;
419 u32 compression;
420 u32 offset;
421 u64 load_addr;
422 u32 len;
423 u32 mem_len;
424} PACKED;
425
426#define PAYLOAD_SEGMENT_BSS 0x20535342
427#define PAYLOAD_SEGMENT_ENTRY 0x52544E45
428
429#define CBFS_COMPRESS_NONE 0
Kevin O'Connor592323f2009-04-26 23:17:49 -0400430#define CBFS_COMPRESS_LZMA 1
Kevin O'Connor67823442009-04-13 14:14:51 -0400431
432struct cbfs_payload {
433 struct cbfs_payload_segment segments[1];
434};
435
436void
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400437cbfs_run_payload(struct cbfs_file *fhdr)
Kevin O'Connor67823442009-04-13 14:14:51 -0400438{
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400439 if (!CONFIG_COREBOOT_FLASH || !fhdr)
Kevin O'Connorcbd6ca02009-04-27 21:51:13 -0400440 return;
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400441 dprintf(1, "Run %s\n", fhdr->filename);
442 struct cbfs_payload *pay = (void*)fhdr + be32_to_cpu(fhdr->offset);
Kevin O'Connor67823442009-04-13 14:14:51 -0400443 struct cbfs_payload_segment *seg = pay->segments;
444 for (;;) {
Kevin O'Connorb3064592012-08-14 21:20:10 -0400445 void *src = (void*)pay + be32_to_cpu(seg->offset);
446 void *dest = (void*)(u32)be64_to_cpu(seg->load_addr);
447 u32 src_len = be32_to_cpu(seg->len);
448 u32 dest_len = be32_to_cpu(seg->mem_len);
Kevin O'Connor67823442009-04-13 14:14:51 -0400449 switch (seg->type) {
450 case PAYLOAD_SEGMENT_BSS:
451 dprintf(3, "BSS segment %d@%p\n", dest_len, dest);
452 memset(dest, 0, dest_len);
453 break;
454 case PAYLOAD_SEGMENT_ENTRY: {
455 dprintf(1, "Calling addr %p\n", dest);
456 void (*func)() = dest;
457 func();
458 return;
459 }
460 default:
461 dprintf(3, "Segment %x %d@%p -> %d@%p\n"
462 , seg->type, src_len, src, dest_len, dest);
Kevin O'Connorb3064592012-08-14 21:20:10 -0400463 if (seg->compression == cpu_to_be32(CBFS_COMPRESS_NONE)) {
Kevin O'Connorcbd6ca02009-04-27 21:51:13 -0400464 if (src_len > dest_len)
465 src_len = dest_len;
Kevin O'Connor592323f2009-04-26 23:17:49 -0400466 memcpy(dest, src, src_len);
467 } else if (CONFIG_LZMA
Kevin O'Connorb3064592012-08-14 21:20:10 -0400468 && seg->compression == cpu_to_be32(CBFS_COMPRESS_LZMA)) {
Kevin O'Connorcbd6ca02009-04-27 21:51:13 -0400469 int ret = ulzma(dest, dest_len, src, src_len);
Kevin O'Connor592323f2009-04-26 23:17:49 -0400470 if (ret < 0)
471 return;
472 src_len = ret;
473 } else {
474 dprintf(1, "No support for compression type %x\n"
475 , seg->compression);
476 return;
477 }
Kevin O'Connor67823442009-04-13 14:14:51 -0400478 if (dest_len > src_len)
479 memset(dest + src_len, 0, dest_len - src_len);
480 break;
481 }
482 seg++;
483 }
484}
485
Kevin O'Connor72eee3e2010-12-27 19:07:49 -0500486// Register payloads in "img/" directory with boot system.
Kevin O'Connor89a1efd2011-01-08 12:24:39 -0500487void
488cbfs_payload_setup(void)
Kevin O'Connor72eee3e2010-12-27 19:07:49 -0500489{
Kevin O'Connor897fb112013-02-07 23:32:48 -0500490 if (!CONFIG_COREBOOT_FLASH)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400491 return;
492 struct romfile_s *file = NULL;
Kevin O'Connor72eee3e2010-12-27 19:07:49 -0500493 for (;;) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400494 file = romfile_findprefix("img/", file);
Kevin O'Connor72eee3e2010-12-27 19:07:49 -0500495 if (!file)
496 break;
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400497 struct cbfs_romfile_s *cfile;
498 cfile = container_of(file, struct cbfs_romfile_s, file);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400499 const char *filename = file->name;
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500500 char *desc = znprintf(MAXDESCSIZE, "Payload [%s]", &filename[4]);
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400501 boot_add_cbfs(cfile->fhdr, desc, bootprio_find_named_rom(filename, 0));
Kevin O'Connor72eee3e2010-12-27 19:07:49 -0500502 }
503}