[SeaBIOS] [PATCH] coreboot: Add support for FMAP and multiple CBFS
Ben Gardner
gardner.ben at gmail.com
Wed Mar 9 19:19:43 CET 2016
ROM images with a FMAP may have multiple CBFS.
Scan all available CBFS so that, say, a SeaBIOS bootable image doesn't
have to be in the main CBFS.
Coreboot puts the FMAP location in the BOOT_MEDIA_PARAMS entry in the
coreboot table. We can grab that and can all regions for CBFS files.
Signed-off-by: Ben Gardner <gardner.ben at gmail.com>
---
src/fw/coreboot.c | 148 +++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 124 insertions(+), 24 deletions(-)
diff --git a/src/fw/coreboot.c b/src/fw/coreboot.c
index 4957b80..0309832 100644
--- a/src/fw/coreboot.c
+++ b/src/fw/coreboot.c
@@ -86,6 +86,41 @@ struct cbmem_console {
} PACKED;
static struct cbmem_console *cbcon = NULL;
+#define CB_TAG_BOOT_MEDIA_PARAMS 0x0030
+struct cb_boot_media_params {
+ u32 tag;
+ u32 size;
+ /* offsets are relative to start of boot media */
+ u64 fmap_offset;
+ u64 cbfs_offset;
+ u64 cbfs_size;
+ u64 boot_media_size;
+};
+
+#define FMAP_SIGNATURE "__FMAP__"
+#define FMAP_VER_MAJOR 1 /* this header's FMAP minor version */
+#define FMAP_VER_MINOR 1 /* this header's FMAP minor version */
+#define FMAP_STRLEN 32 /* maximum length for strings, */
+
+/* Mapping of volatile and static regions in firmware binary */
+struct fmap_area {
+ u32 offset; /* offset relative to base */
+ u32 size; /* size in bytes */
+ u8 name[FMAP_STRLEN]; /* descriptive name */
+ u16 flags; /* flags for this area */
+} PACKED;
+
+struct fmap {
+ u8 signature[8]; /* "__FMAP__" (0x5F5F464D41505F5F) */
+ u8 ver_major; /* major version */
+ u8 ver_minor; /* minor version */
+ u64 base; /* address of the firmware binary */
+ u32 size; /* size of firmware binary in bytes */
+ u8 name[FMAP_STRLEN]; /* name of this firmware binary */
+ u16 nareas; /* number of areas described by fmap_areas[] below */
+ struct fmap_area areas[];
+} PACKED;
+
static u16
ipchksum(char *buf, int count)
{
@@ -159,6 +194,39 @@ find_cb_table(void)
static struct cb_memory *CBMemTable;
const char *CBvendor = "", *CBpart = "";
+struct fmap *CBfmap;
+
+static void
+fmap_init(struct fmap *fm)
+{
+ if (memcmp(fm->signature, FMAP_SIGNATURE, sizeof(fm->signature)) != 0) {
+ dprintf(1, "FMAP: bad signature\n");
+ return;
+ }
+ if ((fm->ver_major != FMAP_VER_MAJOR) ||
+ (fm->ver_minor != FMAP_VER_MINOR)) {
+ dprintf(1, "FMAP: bad version %d.%d\n", fm->ver_major, fm->ver_minor);
+ return;
+ }
+
+ /* print out the FMAP contents */
+ void *base = (void *)(uintptr_t)fm->base;
+ dprintf(1, "FMAP: %p 0x%08x 0x%04x %s\n",
+ base, fm->size, fm->nareas, fm->name);
+
+ int idx;
+ for (idx = 0; idx < fm->nareas; idx++) {
+ struct fmap_area *fa = &fm->areas[idx];
+ const u8 *ptr = base + fa->offset;
+ int is_cbfs = (fa->size > 4096) && (memcmp(ptr, "LARCHIVE", 8) == 0);
+ dprintf(is_cbfs ? 1 : 3,
+ " [%d] %p 0x%08x 0x%04x %s%s\n",
+ idx, ptr, fa->size, fa->flags, fa->name,
+ is_cbfs ? "(CBFS)" : "");
+ }
+ /* looks good -- save the FMAP pointer for later */
+ CBfmap = fm;
+}
// Populate max ram and e820 map info by scanning for a coreboot table.
void
@@ -205,6 +273,17 @@ coreboot_preinit(void)
dprintf(1, "Found mainboard %s %s\n", CBvendor, CBpart);
}
+ struct cb_boot_media_params *cbbmb = find_cb_subtable(cbh, CB_TAG_BOOT_MEDIA_PARAMS);
+ if (cbbmb) {
+ /* ~0 is used to indicate 'not present' */
+ if ((cbbmb->fmap_offset + 1) != 0) {
+ /* Assuming the ROM map ends at 4 GB */
+ u8 *base = (u8 *)(u32)~(cbbmb->boot_media_size - 1);
+ struct fmap *fm = (void *)(base + cbbmb->fmap_offset);
+ fmap_init(fm);
+ }
+ }
+
return;
fail:
@@ -414,30 +493,11 @@ process_links_file(void)
free(links);
}
-void
-coreboot_cbfs_init(void)
+static void
+coreboot_cbfs_scan(struct cbfs_file *fhdr, u32 romsize, u32 align)
{
- if (!CONFIG_COREBOOT_FLASH)
- return;
-
- struct cbfs_header *hdr = *(void **)(CONFIG_CBFS_LOCATION - 4);
- if ((u32)hdr & 0x03) {
- dprintf(1, "Invalid CBFS pointer %p\n", hdr);
- return;
- }
- if (CONFIG_CBFS_LOCATION && (u32)hdr > CONFIG_CBFS_LOCATION)
- // Looks like the pointer is relative to CONFIG_CBFS_LOCATION
- hdr = (void*)hdr + CONFIG_CBFS_LOCATION;
- if (hdr->magic != cpu_to_be32(CBFS_HEADER_MAGIC)) {
- dprintf(1, "Unable to find CBFS (ptr=%p; got %x not %x)\n"
- , hdr, hdr->magic, cpu_to_be32(CBFS_HEADER_MAGIC));
- return;
- }
- dprintf(1, "Found CBFS header at %p\n", hdr);
+ u32 romstart = (u32)fhdr;
- u32 romsize = be32_to_cpu(hdr->romsize);
- u32 romstart = CONFIG_CBFS_LOCATION - romsize;
- struct cbfs_file *fhdr = (void*)romstart + be32_to_cpu(hdr->offset);
for (;;) {
if ((u32)fhdr - romstart > romsize)
break;
@@ -464,8 +524,48 @@ coreboot_cbfs_init(void)
}
romfile_add(&cfile->file);
- fhdr = (void*)ALIGN((u32)cfile->data + cfile->rawsize
- , be32_to_cpu(hdr->align));
+ fhdr = (void*)ALIGN((u32)cfile->data + cfile->rawsize, align);
+ }
+}
+
+void
+coreboot_cbfs_init(void)
+{
+ if (!CONFIG_COREBOOT_FLASH)
+ return;
+
+ if (CBfmap) {
+ void *base = (void *)(uintptr_t)CBfmap->base;
+ int idx;
+
+ for (idx = 0; idx < CBfmap->nareas; idx++) {
+ struct fmap_area *fa = &CBfmap->areas[idx];
+ struct cbfs_file *cf = (struct cbfs_file *)(base + fa->offset);
+ if (fa->size > 4096) {
+ coreboot_cbfs_scan(cf, fa->size, 64);
+ }
+ }
+ } else {
+ /* no FMAP - read CBFS header location from last 4 bytes of ROM */
+ struct cbfs_header *hdr = *(void **)(CONFIG_CBFS_LOCATION - 4);
+ if ((u32)hdr & 0x03) {
+ dprintf(1, "Invalid CBFS pointer %p\n", hdr);
+ return;
+ }
+ if (CONFIG_CBFS_LOCATION && (u32)hdr > CONFIG_CBFS_LOCATION)
+ // Looks like the pointer is relative to CONFIG_CBFS_LOCATION
+ hdr = (void*)hdr + CONFIG_CBFS_LOCATION;
+ if (hdr->magic != cpu_to_be32(CBFS_HEADER_MAGIC)) {
+ dprintf(1, "Unable to find CBFS (ptr=%p; got %x not %x)\n",
+ hdr, hdr->magic, cpu_to_be32(CBFS_HEADER_MAGIC));
+ return;
+ }
+ dprintf(1, "Found CBFS header at %p\n", hdr);
+
+ u32 romsize = be32_to_cpu(hdr->romsize);
+ u32 romstart = CONFIG_CBFS_LOCATION - romsize;
+ struct cbfs_file *fhdr = (void*)romstart + be32_to_cpu(hdr->offset);
+ coreboot_cbfs_scan(fhdr, romsize, be32_to_cpu(hdr->align));
}
process_links_file();
--
1.9.1
More information about the SeaBIOS
mailing list