blob: c66e6e317604fe0a23ebad29c36bffe3c4ebf60d [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'Connora2a86e22013-02-13 19:35:12 -050016#include "pci.h" // pci_probe_devices
Gerd Hoffmann1f209822013-06-03 08:06:27 +020017#include "paravirt.h" // PlatformRunningOn
Kevin O'Connora2a86e22013-02-13 19:35:12 -050018
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040019
20/****************************************************************
Kevin O'Connor93479e42008-06-12 22:22:43 -040021 * Memory map
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040022 ****************************************************************/
23
24struct cb_header {
25 u32 signature;
26 u32 header_bytes;
27 u32 header_checksum;
28 u32 table_bytes;
29 u32 table_checksum;
30 u32 table_entries;
31};
32
33#define CB_SIGNATURE 0x4f49424C // "LBIO"
34
35struct cb_memory_range {
36 u64 start;
37 u64 size;
38 u32 type;
39};
40
41#define CB_MEM_TABLE 16
42
43struct cb_memory {
44 u32 tag;
45 u32 size;
46 struct cb_memory_range map[0];
47};
48
49#define CB_TAG_MEMORY 0x01
50
51#define MEM_RANGE_COUNT(_rec) \
52 (((_rec)->size - sizeof(*(_rec))) / sizeof((_rec)->map[0]))
53
Kevin O'Connor22e1b912009-07-19 18:52:46 -040054struct cb_mainboard {
55 u32 tag;
56 u32 size;
57 u8 vendor_idx;
58 u8 part_idx;
59 char strings[0];
60};
61
62#define CB_TAG_MAINBOARD 0x0003
63
Kevin O'Connor071f1542009-03-21 13:17:21 -040064struct cb_forward {
65 u32 tag;
66 u32 size;
67 u64 forward;
68};
69
70#define CB_TAG_FORWARD 0x11
71
Gerd Hoffmannebf03f72013-06-24 11:24:57 +020072struct cb_cbmem_ref {
73 u32 tag;
74 u32 size;
75 u64 cbmem_addr;
76};
77
78#define CB_TAG_CBMEM_CONSOLE 0x17
79
80struct cbmem_console {
81 u32 buffer_size;
82 u32 buffer_cursor;
83 u8 buffer_body[0];
84} PACKED;
85static struct cbmem_console *cbcon = NULL;
86
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040087static u16
88ipchksum(char *buf, int count)
89{
90 u16 *p = (u16*)buf;
91 u32 sum = 0;
92 while (count > 1) {
93 sum += *p++;
94 count -= 2;
95 }
96 if (count)
97 sum += *(u8*)p;
98 sum = (sum >> 16) + (sum & 0xffff);
99 sum += (sum >> 16);
100 return ~sum;
101}
102
103// Try to locate the coreboot header in a given address range.
104static struct cb_header *
105find_cb_header(char *addr, int len)
106{
107 char *end = addr + len;
108 for (; addr < end; addr += 16) {
109 struct cb_header *cbh = (struct cb_header *)addr;
110 if (cbh->signature != CB_SIGNATURE)
111 continue;
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400112 if (! cbh->table_bytes)
113 continue;
114 if (ipchksum(addr, sizeof(*cbh)) != 0)
115 continue;
116 if (ipchksum(addr + sizeof(*cbh), cbh->table_bytes)
117 != cbh->table_checksum)
118 continue;
119 return cbh;
120 }
121 return NULL;
122}
123
124// Try to find the coreboot memory table in the given coreboot table.
Kevin O'Connor93479e42008-06-12 22:22:43 -0400125static void *
126find_cb_subtable(struct cb_header *cbh, u32 tag)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400127{
128 char *tbl = (char *)cbh + sizeof(*cbh);
129 int i;
130 for (i=0; i<cbh->table_entries; i++) {
131 struct cb_memory *cbm = (struct cb_memory *)tbl;
132 tbl += cbm->size;
Kevin O'Connor93479e42008-06-12 22:22:43 -0400133 if (cbm->tag == tag)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400134 return cbm;
135 }
136 return NULL;
137}
138
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400139static struct cb_memory *CBMemTable;
Julian Pidancet02145152012-02-05 04:51:06 +0000140const char *CBvendor = "", *CBpart = "";
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400141
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400142// Populate max ram and e820 map info by scanning for a coreboot table.
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400143void
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500144coreboot_preinit(void)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400145{
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500146 if (!CONFIG_COREBOOT)
147 return;
148
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400149 dprintf(3, "Attempting to find coreboot table\n");
Kevin O'Connoref3d8822009-02-05 19:51:12 -0500150
Kevin O'Connoref3d8822009-02-05 19:51:12 -0500151 // Find coreboot table.
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400152 struct cb_header *cbh = find_cb_header(0, 0x1000);
153 if (!cbh)
154 goto fail;
Kevin O'Connor071f1542009-03-21 13:17:21 -0400155 struct cb_forward *cbf = find_cb_subtable(cbh, CB_TAG_FORWARD);
156 if (cbf) {
157 dprintf(3, "Found coreboot table forwarder.\n");
158 cbh = find_cb_header((char *)((u32)cbf->forward), 0x100);
159 if (!cbh)
160 goto fail;
161 }
162 dprintf(3, "Now attempting to find coreboot memory map\n");
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400163 struct cb_memory *cbm = CBMemTable = find_cb_subtable(cbh, CB_TAG_MEMORY);
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400164 if (!cbm)
165 goto fail;
166
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400167 int i, count = MEM_RANGE_COUNT(cbm);
168 for (i=0; i<count; i++) {
169 struct cb_memory_range *m = &cbm->map[i];
170 u32 type = m->type;
Kevin O'Connorf85e4bc2013-02-19 01:33:45 -0500171 if (type == CB_MEM_TABLE)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400172 type = E820_RESERVED;
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400173 add_e820(m->start, m->size, type);
174 }
175
176 // Ughh - coreboot likes to set a map at 0x0000-0x1000, but this
177 // confuses grub. So, override it.
178 add_e820(0, 16*1024, E820_RAM);
179
Gerd Hoffmannebf03f72013-06-24 11:24:57 +0200180 struct cb_cbmem_ref *cbref = find_cb_subtable(cbh, CB_TAG_CBMEM_CONSOLE);
181 if (cbref) {
182 cbcon = (void*)(u32)cbref->cbmem_addr;
183 dprintf(1, "----- [ seabios log starts here ] -----\n");
184 dprintf(1, "Found coreboot cbmem console @ %llx\n", cbref->cbmem_addr);
185 }
186
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400187 struct cb_mainboard *cbmb = find_cb_subtable(cbh, CB_TAG_MAINBOARD);
188 if (cbmb) {
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400189 CBvendor = &cbmb->strings[cbmb->vendor_idx];
190 CBpart = &cbmb->strings[cbmb->part_idx];
Gerd Hoffmann1f209822013-06-03 08:06:27 +0200191 if (strcmp(CBvendor, "Emulation") == 0 &&
Gerd Hoffmann95983862013-06-13 07:42:58 +0200192 memcmp(CBpart, "QEMU", 4) == 0) {
Gerd Hoffmann1f209822013-06-03 08:06:27 +0200193 PlatformRunningOn |= PF_QEMU;
194 }
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400195 dprintf(1, "Found mainboard %s %s\n", CBvendor, CBpart);
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400196 }
197
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400198 return;
199
200fail:
201 // No table found.. Use 16Megs as a dummy value.
202 dprintf(1, "Unable to find coreboot table!\n");
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400203 add_e820(0, 16*1024*1024, E820_RAM);
204 return;
205}
Kevin O'Connor4c0c85a2009-04-11 23:31:29 -0400206
Gerd Hoffmannebf03f72013-06-24 11:24:57 +0200207void debug_cbmem(char c)
208{
209 if (!CONFIG_COREBOOT)
210 return;
211 if (!cbcon)
212 return;
213 if (cbcon->buffer_cursor == cbcon->buffer_size)
214 return;
215 cbcon->buffer_body[cbcon->buffer_cursor++] = c;
216}
Kevin O'Connor4c0c85a2009-04-11 23:31:29 -0400217
218/****************************************************************
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400219 * BIOS table copying
220 ****************************************************************/
221
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400222// Attempt to find (and relocate) any standard bios tables found in a
223// given address range.
224static void
225scan_tables(u32 start, u32 size)
226{
227 void *p = (void*)ALIGN(start, 16);
228 void *end = (void*)start + size;
Kevin O'Connor4d053eb2012-06-09 13:08:02 -0400229 for (; p<end; p += 16)
230 copy_table(p);
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400231}
232
233void
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500234coreboot_platform_setup(void)
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400235{
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500236 if (!CONFIG_COREBOOT)
237 return;
238 pci_probe_devices();
239
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400240 struct cb_memory *cbm = CBMemTable;
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500241 if (!cbm)
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400242 return;
243
244 dprintf(3, "Relocating coreboot bios tables\n");
245
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400246 // Scan CB_MEM_TABLE areas for bios tables.
247 int i, count = MEM_RANGE_COUNT(cbm);
248 for (i=0; i<count; i++) {
249 struct cb_memory_range *m = &cbm->map[i];
250 if (m->type == CB_MEM_TABLE)
251 scan_tables(m->start, m->size);
252 }
David Woodhousedbdb7732013-02-05 16:14:20 +0000253
David Woodhoused304fe42013-02-23 00:24:48 +0000254 find_acpi_features();
Kevin O'Connordf5a5fd2009-07-28 20:46:03 -0400255}
256
257
258/****************************************************************
Kevin O'Connor592323f2009-04-26 23:17:49 -0400259 * ulzma
260 ****************************************************************/
261
Kevin O'Connor1f836252009-08-16 20:17:35 -0400262// Uncompress data in flash to an area of memory.
Kevin O'Connor592323f2009-04-26 23:17:49 -0400263static int
Kevin O'Connorcbd6ca02009-04-27 21:51:13 -0400264ulzma(u8 *dst, u32 maxlen, const u8 *src, u32 srclen)
Kevin O'Connor592323f2009-04-26 23:17:49 -0400265{
Kevin O'Connor1edc89d2009-04-30 21:50:35 -0400266 dprintf(3, "Uncompressing data %d@%p to %d@%p\n", srclen, src, maxlen, dst);
Kevin O'Connor592323f2009-04-26 23:17:49 -0400267 CLzmaDecoderState state;
268 int ret = LzmaDecodeProperties(&state.Properties, src, LZMA_PROPERTIES_SIZE);
269 if (ret != LZMA_RESULT_OK) {
270 dprintf(1, "LzmaDecodeProperties error - %d\n", ret);
271 return -1;
272 }
273 u8 scratch[15980];
274 int need = (LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
275 if (need > sizeof(scratch)) {
Kevin O'Connor311f8872010-12-26 14:16:22 -0500276 dprintf(1, "LzmaDecode need %d have %d\n", need, (unsigned int)sizeof(scratch));
Kevin O'Connor592323f2009-04-26 23:17:49 -0400277 return -1;
278 }
279 state.Probs = (CProb *)scratch;
280
281 u32 dstlen = *(u32*)(src + LZMA_PROPERTIES_SIZE);
Kevin O'Connorcbd6ca02009-04-27 21:51:13 -0400282 if (dstlen > maxlen) {
283 dprintf(1, "LzmaDecode too large (max %d need %d)\n", maxlen, dstlen);
284 return -1;
285 }
Kevin O'Connor592323f2009-04-26 23:17:49 -0400286 u32 inProcessed, outProcessed;
Kevin O'Connorcbd6ca02009-04-27 21:51:13 -0400287 ret = LzmaDecode(&state, src + LZMA_PROPERTIES_SIZE + 8, srclen
Kevin O'Connor592323f2009-04-26 23:17:49 -0400288 , &inProcessed, dst, dstlen, &outProcessed);
289 if (ret) {
290 dprintf(1, "LzmaDecode returned %d\n", ret);
291 return -1;
292 }
293 return dstlen;
294}
295
296
297/****************************************************************
Kevin O'Connor4c0c85a2009-04-11 23:31:29 -0400298 * Coreboot flash format
299 ****************************************************************/
300
Kevin O'Connor4c0c85a2009-04-11 23:31:29 -0400301#define CBFS_HEADER_MAGIC 0x4F524243
302#define CBFS_HEADPTR_ADDR 0xFFFFFFFc
303#define CBFS_VERSION1 0x31313131
304
305struct cbfs_header {
306 u32 magic;
307 u32 version;
308 u32 romsize;
309 u32 bootblocksize;
310 u32 align;
311 u32 offset;
312 u32 pad[2];
313} PACKED;
314
Kevin O'Connor4c0c85a2009-04-11 23:31:29 -0400315#define CBFS_FILE_MAGIC 0x455649484352414cLL // LARCHIVE
316
317struct cbfs_file {
318 u64 magic;
319 u32 len;
320 u32 type;
321 u32 checksum;
322 u32 offset;
Kevin O'Connor67823442009-04-13 14:14:51 -0400323 char filename[0];
Kevin O'Connor4c0c85a2009-04-11 23:31:29 -0400324} PACKED;
325
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400326struct cbfs_romfile_s {
327 struct romfile_s file;
328 struct cbfs_file *fhdr;
329 void *data;
330 u32 rawsize, flags;
331};
332
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400333// Copy a file to memory (uncompressing if necessary)
334static int
335cbfs_copyfile(struct romfile_s *file, void *dst, u32 maxlen)
Kevin O'Connor67823442009-04-13 14:14:51 -0400336{
Kevin O'Connor897fb112013-02-07 23:32:48 -0500337 if (!CONFIG_COREBOOT_FLASH)
Kevin O'Connor1f836252009-08-16 20:17:35 -0400338 return -1;
339
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400340 struct cbfs_romfile_s *cfile;
341 cfile = container_of(file, struct cbfs_romfile_s, file);
342 u32 size = cfile->rawsize;
343 void *src = cfile->data;
344 if (cfile->flags) {
Kevin O'Connor34036962009-12-05 18:51:53 -0500345 // Compressed - copy to temp ram and uncompress it.
Kevin O'Connorb4525a02010-07-27 01:14:11 -0400346 void *temp = malloc_tmphigh(size);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400347 if (!temp) {
348 warn_noalloc();
Kevin O'Connor34036962009-12-05 18:51:53 -0500349 return -1;
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400350 }
Kevin O'Connorb4525a02010-07-27 01:14:11 -0400351 iomemcpy(temp, src, size);
Kevin O'Connor34036962009-12-05 18:51:53 -0500352 int ret = ulzma(dst, maxlen, temp, size);
353 yield();
354 free(temp);
355 return ret;
356 }
Kevin O'Connor1f836252009-08-16 20:17:35 -0400357
358 // Not compressed.
359 dprintf(3, "Copying data %d@%p to %d@%p\n", size, src, maxlen, dst);
360 if (size > maxlen) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500361 warn_noalloc();
Kevin O'Connor1f836252009-08-16 20:17:35 -0400362 return -1;
363 }
Kevin O'Connor34036962009-12-05 18:51:53 -0500364 iomemcpy(dst, src, size);
Kevin O'Connor1f836252009-08-16 20:17:35 -0400365 return size;
Kevin O'Connor67823442009-04-13 14:14:51 -0400366}
367
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400368void
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500369coreboot_cbfs_init(void)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400370{
Kevin O'Connor897fb112013-02-07 23:32:48 -0500371 if (!CONFIG_COREBOOT_FLASH)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400372 return;
373
374 struct cbfs_header *hdr = *(void **)CBFS_HEADPTR_ADDR;
Kevin O'Connorb3064592012-08-14 21:20:10 -0400375 if (hdr->magic != cpu_to_be32(CBFS_HEADER_MAGIC)) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400376 dprintf(1, "Unable to find CBFS (ptr=%p; got %x not %x)\n"
Kevin O'Connorb3064592012-08-14 21:20:10 -0400377 , hdr, hdr->magic, cpu_to_be32(CBFS_HEADER_MAGIC));
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400378 return;
379 }
380 dprintf(1, "Found CBFS header at %p\n", hdr);
381
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400382 struct cbfs_file *fhdr = (void *)(0 - be32_to_cpu(hdr->romsize)
383 + be32_to_cpu(hdr->offset));
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400384 for (;;) {
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400385 if (fhdr < (struct cbfs_file *)(0xFFFFFFFF - be32_to_cpu(hdr->romsize)))
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400386 break;
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400387 u64 magic = fhdr->magic;
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400388 if (magic != CBFS_FILE_MAGIC)
389 break;
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400390 struct cbfs_romfile_s *cfile = malloc_tmp(sizeof(*cfile));
391 if (!cfile) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400392 warn_noalloc();
393 break;
394 }
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400395 memset(cfile, 0, sizeof(*cfile));
396 strtcpy(cfile->file.name, fhdr->filename, sizeof(cfile->file.name));
397 cfile->file.size = cfile->rawsize = be32_to_cpu(fhdr->len);
398 cfile->fhdr = fhdr;
399 cfile->file.copy = cbfs_copyfile;
400 cfile->data = (void*)fhdr + be32_to_cpu(fhdr->offset);
401 int len = strlen(cfile->file.name);
402 if (len > 5 && strcmp(&cfile->file.name[len-5], ".lzma") == 0) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400403 // Using compression.
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400404 cfile->flags = 1;
405 cfile->file.name[len-5] = '\0';
406 cfile->file.size = *(u32*)(cfile->data + LZMA_PROPERTIES_SIZE);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400407 }
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400408 romfile_add(&cfile->file);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400409
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400410 fhdr = (void*)ALIGN((u32)cfile->data + cfile->file.size
411 , be32_to_cpu(hdr->align));
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400412 }
413}
414
Kevin O'Connor67823442009-04-13 14:14:51 -0400415struct cbfs_payload_segment {
416 u32 type;
417 u32 compression;
418 u32 offset;
419 u64 load_addr;
420 u32 len;
421 u32 mem_len;
422} PACKED;
423
424#define PAYLOAD_SEGMENT_BSS 0x20535342
425#define PAYLOAD_SEGMENT_ENTRY 0x52544E45
426
427#define CBFS_COMPRESS_NONE 0
Kevin O'Connor592323f2009-04-26 23:17:49 -0400428#define CBFS_COMPRESS_LZMA 1
Kevin O'Connor67823442009-04-13 14:14:51 -0400429
430struct cbfs_payload {
431 struct cbfs_payload_segment segments[1];
432};
433
434void
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400435cbfs_run_payload(struct cbfs_file *fhdr)
Kevin O'Connor67823442009-04-13 14:14:51 -0400436{
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400437 if (!CONFIG_COREBOOT_FLASH || !fhdr)
Kevin O'Connorcbd6ca02009-04-27 21:51:13 -0400438 return;
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400439 dprintf(1, "Run %s\n", fhdr->filename);
440 struct cbfs_payload *pay = (void*)fhdr + be32_to_cpu(fhdr->offset);
Kevin O'Connor67823442009-04-13 14:14:51 -0400441 struct cbfs_payload_segment *seg = pay->segments;
442 for (;;) {
Kevin O'Connorb3064592012-08-14 21:20:10 -0400443 void *src = (void*)pay + be32_to_cpu(seg->offset);
444 void *dest = (void*)(u32)be64_to_cpu(seg->load_addr);
445 u32 src_len = be32_to_cpu(seg->len);
446 u32 dest_len = be32_to_cpu(seg->mem_len);
Kevin O'Connor67823442009-04-13 14:14:51 -0400447 switch (seg->type) {
448 case PAYLOAD_SEGMENT_BSS:
449 dprintf(3, "BSS segment %d@%p\n", dest_len, dest);
450 memset(dest, 0, dest_len);
451 break;
452 case PAYLOAD_SEGMENT_ENTRY: {
453 dprintf(1, "Calling addr %p\n", dest);
454 void (*func)() = dest;
455 func();
456 return;
457 }
458 default:
459 dprintf(3, "Segment %x %d@%p -> %d@%p\n"
460 , seg->type, src_len, src, dest_len, dest);
Kevin O'Connorb3064592012-08-14 21:20:10 -0400461 if (seg->compression == cpu_to_be32(CBFS_COMPRESS_NONE)) {
Kevin O'Connorcbd6ca02009-04-27 21:51:13 -0400462 if (src_len > dest_len)
463 src_len = dest_len;
Kevin O'Connor592323f2009-04-26 23:17:49 -0400464 memcpy(dest, src, src_len);
465 } else if (CONFIG_LZMA
Kevin O'Connorb3064592012-08-14 21:20:10 -0400466 && seg->compression == cpu_to_be32(CBFS_COMPRESS_LZMA)) {
Kevin O'Connorcbd6ca02009-04-27 21:51:13 -0400467 int ret = ulzma(dest, dest_len, src, src_len);
Kevin O'Connor592323f2009-04-26 23:17:49 -0400468 if (ret < 0)
469 return;
470 src_len = ret;
471 } else {
472 dprintf(1, "No support for compression type %x\n"
473 , seg->compression);
474 return;
475 }
Kevin O'Connor67823442009-04-13 14:14:51 -0400476 if (dest_len > src_len)
477 memset(dest + src_len, 0, dest_len - src_len);
478 break;
479 }
480 seg++;
481 }
482}
483
Kevin O'Connor72eee3e2010-12-27 19:07:49 -0500484// Register payloads in "img/" directory with boot system.
Kevin O'Connor89a1efd2011-01-08 12:24:39 -0500485void
486cbfs_payload_setup(void)
Kevin O'Connor72eee3e2010-12-27 19:07:49 -0500487{
Kevin O'Connor897fb112013-02-07 23:32:48 -0500488 if (!CONFIG_COREBOOT_FLASH)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400489 return;
490 struct romfile_s *file = NULL;
Kevin O'Connor72eee3e2010-12-27 19:07:49 -0500491 for (;;) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400492 file = romfile_findprefix("img/", file);
Kevin O'Connor72eee3e2010-12-27 19:07:49 -0500493 if (!file)
494 break;
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400495 struct cbfs_romfile_s *cfile;
496 cfile = container_of(file, struct cbfs_romfile_s, file);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400497 const char *filename = file->name;
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500498 char *desc = znprintf(MAXDESCSIZE, "Payload [%s]", &filename[4]);
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400499 boot_add_cbfs(cfile->fhdr, desc, bootprio_find_named_rom(filename, 0));
Kevin O'Connor72eee3e2010-12-27 19:07:49 -0500500 }
501}