Initial support for finding option roms in coreboot flash layout.

Add code to search for roms in the "coreboot file system".
Change hardcode option rom detection to use vendor/deviceid instead of
    bus/device/fn.
Move streq() function to generic place so cbfs functions can use it.
diff --git a/src/cdrom.c b/src/cdrom.c
index f518a37..71a8b84 100644
--- a/src/cdrom.c
+++ b/src/cdrom.c
@@ -192,7 +192,7 @@
     regs->al = 0x00;
     regs->bl = 0x00;
     regs->ch = nlc & 0xff;
-    regs->cl = ((nlc >> 2) & 0xc0) | (nlspt  & 0x3f);
+    regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f);
     regs->dh = nlh;
     // FIXME ElTorito Various. should send the real count of drives 1 or 2
     // FIXME ElTorito Harddisk. should send the HD count
@@ -389,21 +389,6 @@
     return 0;
 }
 
-// Compare a string on the stack to one in the code segment.
-static int
-streq_cs(u8 *s1, char *cs_s2)
-{
-    u8 *s2 = (u8*)cs_s2;
-    for (;;) {
-        if (*s1 != GET_GLOBAL(*s2))
-            return 0;
-        if (! *s1)
-            return 1;
-        s1++;
-        s2++;
-    }
-}
-
 int
 cdrom_boot(int cdid)
 {
@@ -432,7 +417,7 @@
     // Validity checks
     if (buffer[0])
         return 4;
-    if (!streq_cs(&buffer[1], "CD001\001EL TORITO SPECIFICATION"))
+    if (!streq((char*)&buffer[1], "CD001\001EL TORITO SPECIFICATION"))
         return 5;
 
     // ok, now we calculate the Boot catalog address
diff --git a/src/config.h b/src/config.h
index a882afc..70a9051 100644
--- a/src/config.h
+++ b/src/config.h
@@ -59,11 +59,13 @@
 #define CONFIG_OPTIONROMS 1
 // Set if option roms are already copied to 0xc0000-0xf0000
 #define CONFIG_OPTIONROMS_DEPLOYED 1
+// Support searching coreboot flash format.
+#define CONFIG_COREBOOT_FLASH 0
 // When option roms are not pre-deployed, SeaBIOS can copy an optionrom
 // from flash for up to 2 devices.
-#define OPTIONROM_BDF_1 0x0000
+#define OPTIONROM_VENDEV_1 0x00000000
 #define OPTIONROM_MEM_1 0x00000000
-#define OPTIONROM_BDF_2 0x0000
+#define OPTIONROM_VENDEV_2 0x00000000
 #define OPTIONROM_MEM_2 0x00000000
 // Support an interactive boot menu at end of post.
 #define CONFIG_BOOTMENU 1
diff --git a/src/coreboot.c b/src/coreboot.c
index 5f0190f..9fd5e0f 100644
--- a/src/coreboot.c
+++ b/src/coreboot.c
@@ -204,7 +204,7 @@
 }
 
 // Populate max ram and e820 map info by scanning for a coreboot table.
-void
+static void
 coreboot_fill_map()
 {
     dprintf(3, "Attempting to find coreboot table\n");
@@ -270,3 +270,129 @@
     add_e820(0, 16*1024*1024, E820_RAM);
     return;
 }
+
+
+/****************************************************************
+ * Coreboot flash format
+ ****************************************************************/
+
+// XXX - optimize
+#define ntohl(x) ((((x)&0xff)<<24) | (((x)&0xff00)<<8) | \
+                  (((x)&0xff0000) >> 8) | (((x)&0xff000000) >> 24))
+#define htonl(x) ntohl(x)
+
+#define CBFS_HEADER_MAGIC 0x4F524243
+#define CBFS_HEADPTR_ADDR 0xFFFFFFFc
+#define CBFS_VERSION1 0x31313131
+
+struct cbfs_header {
+    u32 magic;
+    u32 version;
+    u32 romsize;
+    u32 bootblocksize;
+    u32 align;
+    u32 offset;
+    u32 pad[2];
+} PACKED;
+
+static struct cbfs_header *CBHDR;
+
+static void
+cbfs_setup()
+{
+    if (! CONFIG_COREBOOT_FLASH)
+        return;
+
+    CBHDR = *(void **)CBFS_HEADPTR_ADDR;
+    if (CBHDR->magic != htonl(CBFS_HEADER_MAGIC)) {
+        dprintf(1, "Unable to find CBFS (got %x not %x)\n"
+                , CBHDR->magic, htonl(CBFS_HEADER_MAGIC));
+        CBHDR = NULL;
+        return;
+    }
+
+    dprintf(1, "Found CBFS header at %p\n", CBHDR);
+}
+
+#define CBFS_FILE_MAGIC 0x455649484352414cLL // LARCHIVE
+
+struct cbfs_file {
+    u64 magic;
+    u32 len;
+    u32 type;
+    u32 checksum;
+    u32 offset;
+} PACKED;
+
+static struct cbfs_file *
+cbfs_find(char *fname)
+{
+    if (! CONFIG_COREBOOT_FLASH)
+        return NULL;
+    if (! CBHDR)
+        return NULL;
+
+    dprintf(3, "Searching CBFS for %s\n", fname);
+
+    struct cbfs_file *file = (void *)(0 - ntohl(CBHDR->romsize) + ntohl(CBHDR->offset));
+    for (;;) {
+        if (file < (struct cbfs_file *)(0xFFFFFFFF - ntohl(CBHDR->romsize)))
+            return NULL;
+        if (file->magic != CBFS_FILE_MAGIC) {
+            file = (void*)file + ntohl(CBHDR->align);
+            continue;
+        }
+
+        dprintf(3, "Found CBFS file %s\n", (char*)file + sizeof(*file));
+        if (streq(fname, (char*)file + sizeof(*file)))
+            return file;
+        file = (void*)file + ALIGN(ntohl(file->len) + ntohl(file->offset), ntohl(CBHDR->align));
+    }
+}
+
+static char
+getHex(u8 x)
+{
+    if (x <= 9)
+        return '0' + x;
+    return 'a' + x - 10;
+}
+
+static u32
+hexify4(u16 x)
+{
+    return ((getHex(x&0xf) << 24)
+            | (getHex((x>>4)&0xf) << 16)
+            | (getHex((x>>8)&0xf) << 8)
+            | (getHex(x>>12)));
+}
+
+void *
+cb_find_optionrom(u32 vendev)
+{
+    if (! CONFIG_COREBOOT_FLASH)
+        return NULL;
+
+    char fname[17];
+    // Ughh - poor man's sprintf of "pci%04x,%04x.rom"
+    *(u32*)fname = 0x20696370; // "pci"
+    *(u32*)&fname[3] = hexify4(vendev);
+    fname[7] = ',';
+    *(u32*)&fname[8] = hexify4(vendev >> 16);
+    *(u32*)&fname[12] = 0x6d6f722e; // ".rom"
+    fname[16] = '\0';
+
+    struct cbfs_file *file = cbfs_find(fname);
+    if (!file)
+        return NULL;
+    // Found it.
+    dprintf(3, "Found rom at %p\n", (void*)file + ntohl(file->offset));
+    return (void*)file + ntohl(file->offset);
+}
+
+void
+coreboot_setup(void)
+{
+    coreboot_fill_map();
+    cbfs_setup();
+}
diff --git a/src/optionroms.c b/src/optionroms.c
index e750bbb..6bc28fa 100644
--- a/src/optionroms.c
+++ b/src/optionroms.c
@@ -172,19 +172,25 @@
 
 // Check if an option rom is at a hardcoded location for a device.
 static struct rom_header *
-lookup_hardcode(u16 bdf)
+lookup_hardcode(u32 vendev)
 {
-    if (OPTIONROM_BDF_1 && OPTIONROM_BDF_1 == bdf)
+    if (OPTIONROM_VENDEV_1
+        && ((OPTIONROM_VENDEV_1 >> 16)
+            | ((OPTIONROM_VENDEV_1 & 0xffff)) << 16) == vendev)
         return copy_rom((struct rom_header *)OPTIONROM_MEM_1);
-    else if (OPTIONROM_BDF_2 && OPTIONROM_BDF_2 == bdf)
+    if (OPTIONROM_VENDEV_2
+        && ((OPTIONROM_VENDEV_2 >> 16)
+            | ((OPTIONROM_VENDEV_2 & 0xffff)) << 16) == vendev)
         return copy_rom((struct rom_header *)OPTIONROM_MEM_2);
-    // XXX - check LAR when in coreboot?
+    struct rom_header *rom = cb_find_optionrom(vendev);
+    if (rom)
+        return copy_rom(rom);
     return NULL;
 }
 
 // Map the option rom of a given PCI device.
 static struct rom_header *
-map_optionrom(u16 bdf)
+map_optionrom(u16 bdf, u32 vendev)
 {
     dprintf(6, "Attempting to map option rom on dev %x\n", bdf);
 
@@ -211,10 +217,9 @@
     // Looks like a rom - enable it.
     pci_config_writel(bdf, PCI_ROM_ADDRESS, orig | PCI_ROM_ADDRESS_ENABLE);
 
-    u32 vendev = pci_config_readl(bdf, PCI_VENDOR_ID);
     struct rom_header *rom = (struct rom_header *)orig;
     for (;;) {
-        dprintf(5, "Inspecting possible rom at %p (vd=%x bdf=%x)\n"
+        dprintf(5, "Inspecting possible rom at %p (dv=%x bdf=%x)\n"
                 , rom, vendev, bdf);
         if (rom->signature != OPTION_ROM_SIGNATURE) {
             dprintf(6, "No option rom signature (got %x)\n", rom->signature);
@@ -230,7 +235,7 @@
         if (vd == vendev && pci->type == PCIROM_CODETYPE_X86)
             // A match
             break;
-        dprintf(6, "Didn't match vendev (got %x) or type (got %d)\n"
+        dprintf(6, "Didn't match dev/ven (got %x) or type (got %d)\n"
                 , vd, pci->type);
         if (pci->indicator & 0x80) {
             dprintf(6, "No more images left\n");
@@ -252,10 +257,11 @@
 static struct rom_header *
 init_optionrom(u16 bdf)
 {
-    dprintf(4, "Attempting to init PCI bdf %x\n", bdf);
-    struct rom_header *rom = lookup_hardcode(bdf);
+    u32 vendev = pci_config_readl(bdf, PCI_VENDOR_ID);
+    dprintf(4, "Attempting to init PCI bdf %x (dev/ven %x)\n", bdf, vendev);
+    struct rom_header *rom = lookup_hardcode(vendev);
     if (! rom)
-        rom = map_optionrom(bdf);
+        rom = map_optionrom(bdf, vendev);
     if (! rom)
         // No ROM present.
         return NULL;
diff --git a/src/post.c b/src/post.c
index 73cd798..f961cd8 100644
--- a/src/post.c
+++ b/src/post.c
@@ -93,7 +93,7 @@
 {
     dprintf(3, "Find memory size\n");
     if (CONFIG_COREBOOT) {
-        coreboot_fill_map();
+        coreboot_setup();
     } else {
         // On emulators, get memory size from nvram.
         u32 rs = ((inb_cmos(CMOS_MEM_EXTMEM2_LOW) << 16)
diff --git a/src/util.c b/src/util.c
index ae00d6c..2b46ea2 100644
--- a/src/util.c
+++ b/src/util.c
@@ -117,6 +117,20 @@
     return checksum_far(GET_SEG(SS), buf, len);
 }
 
+// Compare two strings.
+int
+streq(char *s1, char *s2)
+{
+    for (;;) {
+        if (*s1 != *s2)
+            return 0;
+        if (! *s1)
+            return 1;
+        s1++;
+        s2++;
+    }
+}
+
 void *
 memset(void *s, int c, size_t n)
 {
diff --git a/src/util.h b/src/util.h
index f96d61c..9ce220a 100644
--- a/src/util.h
+++ b/src/util.h
@@ -69,6 +69,7 @@
 inline u32 stack_hop(u32 eax, u32 edx, u32 ecx, void *func);
 u8 checksum_far(u16 buf_seg, void *buf_far, u32 len);
 u8 checksum(void *buf, u32 len);
+int streq(char *s1, char *s2);
 void *memset(void *s, int c, size_t n);
 void *memcpy(void *d1, const void *s1, size_t len);
 inline void memcpy_far(u16 d_seg, void *d_far
@@ -164,7 +165,8 @@
 void smbios_init(void);
 
 // coreboot.c
-void coreboot_fill_map();
+void *cb_find_optionrom(u32 vendev);
+void coreboot_setup();
 
 // vgahooks.c
 void handle_155f();