blob: ba65dc603354e0dfdbad11f5091d092bce08bc05 [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
7#include "memmap.h" // add_e820
8#include "util.h" // dprintf
Kevin O'Connorb3064592012-08-14 21:20:10 -04009#include "byteorder.h" // be32_to_cpu
Kevin O'Connor592323f2009-04-26 23:17:49 -040010#include "lzmadecode.h" // LzmaDecode
Kevin O'Connor01a85202009-10-18 09:49:59 -040011#include "smbios.h" // smbios_init
Kevin O'Connor72eee3e2010-12-27 19:07:49 -050012#include "boot.h" // boot_add_cbfs
Kevin O'Connord3140832012-05-13 22:46:12 -040013#include "disk.h" // MAXDESCSIZE
14#include "config.h" // CONFIG_*
David Woodhoused304fe42013-02-23 00:24:48 +000015#include "acpi.h" // find_acpi_features
Kevin O'Connor5d369d82013-09-02 20:48:46 -040016#include "hw/pci.h" // pci_probe_devices
Gerd Hoffmann1f209822013-06-03 08:06:27 +020017#include "paravirt.h" // PlatformRunningOn
Kevin O'Connor41639f82013-09-14 19:37:36 -040018#include "romfile.h" // romfile_findprefix
Kevin O'Connor3df600b2013-09-14 19:28:55 -040019#include "stacks.h" // yield
Kevin O'Connorfa9c66a2013-09-14 19:10:40 -040020#include "string.h" // memset
Kevin O'Connora2a86e22013-02-13 19:35:12 -050021
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040022
23/****************************************************************
Kevin O'Connor93479e42008-06-12 22:22:43 -040024 * Memory map
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040025 ****************************************************************/
26
27struct cb_header {
28 u32 signature;
29 u32 header_bytes;
30 u32 header_checksum;
31 u32 table_bytes;
32 u32 table_checksum;
33 u32 table_entries;
34};
35
36#define CB_SIGNATURE 0x4f49424C // "LBIO"
37
38struct cb_memory_range {
39 u64 start;
40 u64 size;
41 u32 type;
42};
43
44#define CB_MEM_TABLE 16
45
46struct cb_memory {
47 u32 tag;
48 u32 size;
49 struct cb_memory_range map[0];
50};
51
52#define CB_TAG_MEMORY 0x01
53
54#define MEM_RANGE_COUNT(_rec) \
55 (((_rec)->size - sizeof(*(_rec))) / sizeof((_rec)->map[0]))
56
Kevin O'Connor22e1b912009-07-19 18:52:46 -040057struct cb_mainboard {
58 u32 tag;
59 u32 size;
60 u8 vendor_idx;
61 u8 part_idx;
62 char strings[0];
63};
64
65#define CB_TAG_MAINBOARD 0x0003
66
Kevin O'Connor071f1542009-03-21 13:17:21 -040067struct cb_forward {
68 u32 tag;
69 u32 size;
70 u64 forward;
71};
72
73#define CB_TAG_FORWARD 0x11
74
Gerd Hoffmannebf03f72013-06-24 11:24:57 +020075struct cb_cbmem_ref {
76 u32 tag;
77 u32 size;
78 u64 cbmem_addr;
79};
80
81#define CB_TAG_CBMEM_CONSOLE 0x17
82
83struct cbmem_console {
84 u32 buffer_size;
85 u32 buffer_cursor;
86 u8 buffer_body[0];
87} PACKED;
88static struct cbmem_console *cbcon = NULL;
89
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040090static u16
91ipchksum(char *buf, int count)
92{
93 u16 *p = (u16*)buf;
94 u32 sum = 0;
95 while (count > 1) {
96 sum += *p++;
97 count -= 2;
98 }
99 if (count)
100 sum += *(u8*)p;
101 sum = (sum >> 16) + (sum & 0xffff);
102 sum += (sum >> 16);
103 return ~sum;
104}
105
106// Try to locate the coreboot header in a given address range.
107static struct cb_header *
108find_cb_header(char *addr, int len)
109{
110 char *end = addr + len;
111 for (; addr < end; addr += 16) {
112 struct cb_header *cbh = (struct cb_header *)addr;
113 if (cbh->signature != CB_SIGNATURE)
114 continue;
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400115 if (! cbh->table_bytes)
116 continue;
117 if (ipchksum(addr, sizeof(*cbh)) != 0)
118 continue;
119 if (ipchksum(addr + sizeof(*cbh), cbh->table_bytes)
120 != cbh->table_checksum)
121 continue;
122 return cbh;
123 }
124 return NULL;
125}
126
127// Try to find the coreboot memory table in the given coreboot table.
Kevin O'Connor93479e42008-06-12 22:22:43 -0400128static void *
129find_cb_subtable(struct cb_header *cbh, u32 tag)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400130{
131 char *tbl = (char *)cbh + sizeof(*cbh);
132 int i;
133 for (i=0; i<cbh->table_entries; i++) {
134 struct cb_memory *cbm = (struct cb_memory *)tbl;
135 tbl += cbm->size;
Kevin O'Connor93479e42008-06-12 22:22:43 -0400136 if (cbm->tag == tag)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400137 return cbm;
138 }
139 return NULL;
140}
141
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400142static struct cb_memory *CBMemTable;
Julian Pidancet02145152012-02-05 04:51:06 +0000143const char *CBvendor = "", *CBpart = "";
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400144
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400145// Populate max ram and e820 map info by scanning for a coreboot table.
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400146void
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500147coreboot_preinit(void)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400148{
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500149 if (!CONFIG_COREBOOT)
150 return;
151
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400152 dprintf(3, "Attempting to find coreboot table\n");
Kevin O'Connoref3d8822009-02-05 19:51:12 -0500153
Kevin O'Connoref3d8822009-02-05 19:51:12 -0500154 // Find coreboot table.
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400155 struct cb_header *cbh = find_cb_header(0, 0x1000);
156 if (!cbh)
157 goto fail;
Kevin O'Connor071f1542009-03-21 13:17:21 -0400158 struct cb_forward *cbf = find_cb_subtable(cbh, CB_TAG_FORWARD);
159 if (cbf) {
160 dprintf(3, "Found coreboot table forwarder.\n");
161 cbh = find_cb_header((char *)((u32)cbf->forward), 0x100);
162 if (!cbh)
163 goto fail;
164 }
165 dprintf(3, "Now attempting to find coreboot memory map\n");
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400166 struct cb_memory *cbm = CBMemTable = find_cb_subtable(cbh, CB_TAG_MEMORY);
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400167 if (!cbm)
168 goto fail;
169
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400170 int i, count = MEM_RANGE_COUNT(cbm);
171 for (i=0; i<count; i++) {
172 struct cb_memory_range *m = &cbm->map[i];
173 u32 type = m->type;
Kevin O'Connorf85e4bc2013-02-19 01:33:45 -0500174 if (type == CB_MEM_TABLE)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400175 type = E820_RESERVED;
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400176 add_e820(m->start, m->size, type);
177 }
178
179 // Ughh - coreboot likes to set a map at 0x0000-0x1000, but this
180 // confuses grub. So, override it.
181 add_e820(0, 16*1024, E820_RAM);
182
Gerd Hoffmannebf03f72013-06-24 11:24:57 +0200183 struct cb_cbmem_ref *cbref = find_cb_subtable(cbh, CB_TAG_CBMEM_CONSOLE);
184 if (cbref) {
185 cbcon = (void*)(u32)cbref->cbmem_addr;
186 dprintf(1, "----- [ seabios log starts here ] -----\n");
187 dprintf(1, "Found coreboot cbmem console @ %llx\n", cbref->cbmem_addr);
188 }
189
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400190 struct cb_mainboard *cbmb = find_cb_subtable(cbh, CB_TAG_MAINBOARD);
191 if (cbmb) {
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400192 CBvendor = &cbmb->strings[cbmb->vendor_idx];
193 CBpart = &cbmb->strings[cbmb->part_idx];
Gerd Hoffmann1f209822013-06-03 08:06:27 +0200194 if (strcmp(CBvendor, "Emulation") == 0 &&
Gerd Hoffmann95983862013-06-13 07:42:58 +0200195 memcmp(CBpart, "QEMU", 4) == 0) {
Gerd Hoffmann1f209822013-06-03 08:06:27 +0200196 PlatformRunningOn |= PF_QEMU;
197 }
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400198 dprintf(1, "Found mainboard %s %s\n", CBvendor, CBpart);
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400199 }
200
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400201 return;
202
203fail:
204 // No table found.. Use 16Megs as a dummy value.
205 dprintf(1, "Unable to find coreboot table!\n");
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400206 add_e820(0, 16*1024*1024, E820_RAM);
207 return;
208}
Kevin O'Connor4c0c85a2009-04-11 23:31:29 -0400209
Gerd Hoffmannebf03f72013-06-24 11:24:57 +0200210void debug_cbmem(char c)
211{
Gerd Hoffmannc83e7c22013-06-25 15:45:30 +0200212 if (!CONFIG_DEBUG_COREBOOT)
Gerd Hoffmannebf03f72013-06-24 11:24:57 +0200213 return;
214 if (!cbcon)
215 return;
216 if (cbcon->buffer_cursor == cbcon->buffer_size)
217 return;
218 cbcon->buffer_body[cbcon->buffer_cursor++] = c;
219}
Kevin O'Connor4c0c85a2009-04-11 23:31:29 -0400220
221/****************************************************************
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400222 * BIOS table copying
223 ****************************************************************/
224
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400225// Attempt to find (and relocate) any standard bios tables found in a
226// given address range.
227static void
228scan_tables(u32 start, u32 size)
229{
230 void *p = (void*)ALIGN(start, 16);
231 void *end = (void*)start + size;
Kevin O'Connor4d053eb2012-06-09 13:08:02 -0400232 for (; p<end; p += 16)
233 copy_table(p);
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400234}
235
236void
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500237coreboot_platform_setup(void)
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400238{
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500239 if (!CONFIG_COREBOOT)
240 return;
241 pci_probe_devices();
242
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400243 struct cb_memory *cbm = CBMemTable;
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500244 if (!cbm)
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400245 return;
246
247 dprintf(3, "Relocating coreboot bios tables\n");
248
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400249 // Scan CB_MEM_TABLE areas for bios tables.
250 int i, count = MEM_RANGE_COUNT(cbm);
251 for (i=0; i<count; i++) {
252 struct cb_memory_range *m = &cbm->map[i];
253 if (m->type == CB_MEM_TABLE)
254 scan_tables(m->start, m->size);
255 }
David Woodhousedbdb7732013-02-05 16:14:20 +0000256
David Woodhoused304fe42013-02-23 00:24:48 +0000257 find_acpi_features();
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400258}
259
260
261/****************************************************************
Kevin O'Connor592323f2009-04-26 23:17:49 -0400262 * ulzma
263 ****************************************************************/
264
Kevin O'Connor1f836252009-08-16 20:17:35 -0400265// Uncompress data in flash to an area of memory.
Kevin O'Connor592323f2009-04-26 23:17:49 -0400266static int
Kevin O'Connorcbd6ca02009-04-27 21:51:13 -0400267ulzma(u8 *dst, u32 maxlen, const u8 *src, u32 srclen)
Kevin O'Connor592323f2009-04-26 23:17:49 -0400268{
Kevin O'Connor1edc89d2009-04-30 21:50:35 -0400269 dprintf(3, "Uncompressing data %d@%p to %d@%p\n", srclen, src, maxlen, dst);
Kevin O'Connor592323f2009-04-26 23:17:49 -0400270 CLzmaDecoderState state;
271 int ret = LzmaDecodeProperties(&state.Properties, src, LZMA_PROPERTIES_SIZE);
272 if (ret != LZMA_RESULT_OK) {
273 dprintf(1, "LzmaDecodeProperties error - %d\n", ret);
274 return -1;
275 }
276 u8 scratch[15980];
277 int need = (LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
278 if (need > sizeof(scratch)) {
Kevin O'Connor311f8872010-12-26 14:16:22 -0500279 dprintf(1, "LzmaDecode need %d have %d\n", need, (unsigned int)sizeof(scratch));
Kevin O'Connor592323f2009-04-26 23:17:49 -0400280 return -1;
281 }
282 state.Probs = (CProb *)scratch;
283
284 u32 dstlen = *(u32*)(src + LZMA_PROPERTIES_SIZE);
Kevin O'Connorcbd6ca02009-04-27 21:51:13 -0400285 if (dstlen > maxlen) {
286 dprintf(1, "LzmaDecode too large (max %d need %d)\n", maxlen, dstlen);
287 return -1;
288 }
Kevin O'Connor592323f2009-04-26 23:17:49 -0400289 u32 inProcessed, outProcessed;
Kevin O'Connorcbd6ca02009-04-27 21:51:13 -0400290 ret = LzmaDecode(&state, src + LZMA_PROPERTIES_SIZE + 8, srclen
Kevin O'Connor592323f2009-04-26 23:17:49 -0400291 , &inProcessed, dst, dstlen, &outProcessed);
292 if (ret) {
293 dprintf(1, "LzmaDecode returned %d\n", ret);
294 return -1;
295 }
296 return dstlen;
297}
298
299
300/****************************************************************
Kevin O'Connor4c0c85a2009-04-11 23:31:29 -0400301 * Coreboot flash format
302 ****************************************************************/
303
Kevin O'Connor4c0c85a2009-04-11 23:31:29 -0400304#define CBFS_HEADER_MAGIC 0x4F524243
305#define CBFS_HEADPTR_ADDR 0xFFFFFFFc
306#define CBFS_VERSION1 0x31313131
307
308struct cbfs_header {
309 u32 magic;
310 u32 version;
311 u32 romsize;
312 u32 bootblocksize;
313 u32 align;
314 u32 offset;
315 u32 pad[2];
316} PACKED;
317
Kevin O'Connor4c0c85a2009-04-11 23:31:29 -0400318#define CBFS_FILE_MAGIC 0x455649484352414cLL // LARCHIVE
319
320struct cbfs_file {
321 u64 magic;
322 u32 len;
323 u32 type;
324 u32 checksum;
325 u32 offset;
Kevin O'Connor67823442009-04-13 14:14:51 -0400326 char filename[0];
Kevin O'Connor4c0c85a2009-04-11 23:31:29 -0400327} PACKED;
328
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400329struct cbfs_romfile_s {
330 struct romfile_s file;
331 struct cbfs_file *fhdr;
332 void *data;
333 u32 rawsize, flags;
334};
335
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400336// Copy a file to memory (uncompressing if necessary)
337static int
338cbfs_copyfile(struct romfile_s *file, void *dst, u32 maxlen)
Kevin O'Connor67823442009-04-13 14:14:51 -0400339{
Kevin O'Connor897fb112013-02-07 23:32:48 -0500340 if (!CONFIG_COREBOOT_FLASH)
Kevin O'Connor1f836252009-08-16 20:17:35 -0400341 return -1;
342
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400343 struct cbfs_romfile_s *cfile;
344 cfile = container_of(file, struct cbfs_romfile_s, file);
345 u32 size = cfile->rawsize;
346 void *src = cfile->data;
347 if (cfile->flags) {
Kevin O'Connor34036962009-12-05 18:51:53 -0500348 // Compressed - copy to temp ram and uncompress it.
Kevin O'Connorb4525a02010-07-27 01:14:11 -0400349 void *temp = malloc_tmphigh(size);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400350 if (!temp) {
351 warn_noalloc();
Kevin O'Connor34036962009-12-05 18:51:53 -0500352 return -1;
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400353 }
Kevin O'Connorb4525a02010-07-27 01:14:11 -0400354 iomemcpy(temp, src, size);
Kevin O'Connor34036962009-12-05 18:51:53 -0500355 int ret = ulzma(dst, maxlen, temp, size);
356 yield();
357 free(temp);
358 return ret;
359 }
Kevin O'Connor1f836252009-08-16 20:17:35 -0400360
361 // Not compressed.
362 dprintf(3, "Copying data %d@%p to %d@%p\n", size, src, maxlen, dst);
363 if (size > maxlen) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500364 warn_noalloc();
Kevin O'Connor1f836252009-08-16 20:17:35 -0400365 return -1;
366 }
Kevin O'Connor34036962009-12-05 18:51:53 -0500367 iomemcpy(dst, src, size);
Kevin O'Connor1f836252009-08-16 20:17:35 -0400368 return size;
Kevin O'Connor67823442009-04-13 14:14:51 -0400369}
370
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400371void
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500372coreboot_cbfs_init(void)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400373{
Kevin O'Connor897fb112013-02-07 23:32:48 -0500374 if (!CONFIG_COREBOOT_FLASH)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400375 return;
376
377 struct cbfs_header *hdr = *(void **)CBFS_HEADPTR_ADDR;
Kevin O'Connorb3064592012-08-14 21:20:10 -0400378 if (hdr->magic != cpu_to_be32(CBFS_HEADER_MAGIC)) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400379 dprintf(1, "Unable to find CBFS (ptr=%p; got %x not %x)\n"
Kevin O'Connorb3064592012-08-14 21:20:10 -0400380 , hdr, hdr->magic, cpu_to_be32(CBFS_HEADER_MAGIC));
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400381 return;
382 }
383 dprintf(1, "Found CBFS header at %p\n", hdr);
384
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400385 struct cbfs_file *fhdr = (void *)(0 - be32_to_cpu(hdr->romsize)
386 + be32_to_cpu(hdr->offset));
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400387 for (;;) {
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400388 if (fhdr < (struct cbfs_file *)(0xFFFFFFFF - be32_to_cpu(hdr->romsize)))
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400389 break;
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400390 u64 magic = fhdr->magic;
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400391 if (magic != CBFS_FILE_MAGIC)
392 break;
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400393 struct cbfs_romfile_s *cfile = malloc_tmp(sizeof(*cfile));
394 if (!cfile) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400395 warn_noalloc();
396 break;
397 }
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400398 memset(cfile, 0, sizeof(*cfile));
399 strtcpy(cfile->file.name, fhdr->filename, sizeof(cfile->file.name));
400 cfile->file.size = cfile->rawsize = be32_to_cpu(fhdr->len);
401 cfile->fhdr = fhdr;
402 cfile->file.copy = cbfs_copyfile;
403 cfile->data = (void*)fhdr + be32_to_cpu(fhdr->offset);
404 int len = strlen(cfile->file.name);
405 if (len > 5 && strcmp(&cfile->file.name[len-5], ".lzma") == 0) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400406 // Using compression.
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400407 cfile->flags = 1;
408 cfile->file.name[len-5] = '\0';
409 cfile->file.size = *(u32*)(cfile->data + LZMA_PROPERTIES_SIZE);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400410 }
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400411 romfile_add(&cfile->file);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400412
Kevin O'Connor1a113e12013-08-02 14:12:09 -0400413 fhdr = (void*)ALIGN((u32)cfile->data + cfile->rawsize
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400414 , be32_to_cpu(hdr->align));
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400415 }
416}
417
Kevin O'Connor67823442009-04-13 14:14:51 -0400418struct cbfs_payload_segment {
419 u32 type;
420 u32 compression;
421 u32 offset;
422 u64 load_addr;
423 u32 len;
424 u32 mem_len;
425} PACKED;
426
427#define PAYLOAD_SEGMENT_BSS 0x20535342
428#define PAYLOAD_SEGMENT_ENTRY 0x52544E45
429
430#define CBFS_COMPRESS_NONE 0
Kevin O'Connor592323f2009-04-26 23:17:49 -0400431#define CBFS_COMPRESS_LZMA 1
Kevin O'Connor67823442009-04-13 14:14:51 -0400432
433struct cbfs_payload {
434 struct cbfs_payload_segment segments[1];
435};
436
437void
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400438cbfs_run_payload(struct cbfs_file *fhdr)
Kevin O'Connor67823442009-04-13 14:14:51 -0400439{
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400440 if (!CONFIG_COREBOOT_FLASH || !fhdr)
Kevin O'Connorcbd6ca02009-04-27 21:51:13 -0400441 return;
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400442 dprintf(1, "Run %s\n", fhdr->filename);
443 struct cbfs_payload *pay = (void*)fhdr + be32_to_cpu(fhdr->offset);
Kevin O'Connor67823442009-04-13 14:14:51 -0400444 struct cbfs_payload_segment *seg = pay->segments;
445 for (;;) {
Kevin O'Connorb3064592012-08-14 21:20:10 -0400446 void *src = (void*)pay + be32_to_cpu(seg->offset);
447 void *dest = (void*)(u32)be64_to_cpu(seg->load_addr);
448 u32 src_len = be32_to_cpu(seg->len);
449 u32 dest_len = be32_to_cpu(seg->mem_len);
Kevin O'Connor67823442009-04-13 14:14:51 -0400450 switch (seg->type) {
451 case PAYLOAD_SEGMENT_BSS:
452 dprintf(3, "BSS segment %d@%p\n", dest_len, dest);
453 memset(dest, 0, dest_len);
454 break;
455 case PAYLOAD_SEGMENT_ENTRY: {
456 dprintf(1, "Calling addr %p\n", dest);
457 void (*func)() = dest;
458 func();
459 return;
460 }
461 default:
462 dprintf(3, "Segment %x %d@%p -> %d@%p\n"
463 , seg->type, src_len, src, dest_len, dest);
Kevin O'Connorb3064592012-08-14 21:20:10 -0400464 if (seg->compression == cpu_to_be32(CBFS_COMPRESS_NONE)) {
Kevin O'Connorcbd6ca02009-04-27 21:51:13 -0400465 if (src_len > dest_len)
466 src_len = dest_len;
Kevin O'Connor592323f2009-04-26 23:17:49 -0400467 memcpy(dest, src, src_len);
468 } else if (CONFIG_LZMA
Kevin O'Connorb3064592012-08-14 21:20:10 -0400469 && seg->compression == cpu_to_be32(CBFS_COMPRESS_LZMA)) {
Kevin O'Connorcbd6ca02009-04-27 21:51:13 -0400470 int ret = ulzma(dest, dest_len, src, src_len);
Kevin O'Connor592323f2009-04-26 23:17:49 -0400471 if (ret < 0)
472 return;
473 src_len = ret;
474 } else {
475 dprintf(1, "No support for compression type %x\n"
476 , seg->compression);
477 return;
478 }
Kevin O'Connor67823442009-04-13 14:14:51 -0400479 if (dest_len > src_len)
480 memset(dest + src_len, 0, dest_len - src_len);
481 break;
482 }
483 seg++;
484 }
485}
486
Kevin O'Connor72eee3e2010-12-27 19:07:49 -0500487// Register payloads in "img/" directory with boot system.
Kevin O'Connor89a1efd2011-01-08 12:24:39 -0500488void
489cbfs_payload_setup(void)
Kevin O'Connor72eee3e2010-12-27 19:07:49 -0500490{
Kevin O'Connor897fb112013-02-07 23:32:48 -0500491 if (!CONFIG_COREBOOT_FLASH)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400492 return;
493 struct romfile_s *file = NULL;
Kevin O'Connor72eee3e2010-12-27 19:07:49 -0500494 for (;;) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400495 file = romfile_findprefix("img/", file);
Kevin O'Connor72eee3e2010-12-27 19:07:49 -0500496 if (!file)
497 break;
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400498 struct cbfs_romfile_s *cfile;
499 cfile = container_of(file, struct cbfs_romfile_s, file);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400500 const char *filename = file->name;
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500501 char *desc = znprintf(MAXDESCSIZE, "Payload [%s]", &filename[4]);
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400502 boot_add_cbfs(cfile->fhdr, desc, bootprio_find_named_rom(filename, 0));
Kevin O'Connor72eee3e2010-12-27 19:07:49 -0500503 }
504}