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();