[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