diff options
-rw-r--r-- | src/mainboard/emulation/qemu-i440fx/fw_cfg.c | 83 | ||||
-rw-r--r-- | src/mainboard/emulation/qemu-i440fx/fw_cfg.h | 1 | ||||
-rw-r--r-- | src/mainboard/emulation/qemu-i440fx/northbridge.c | 5 |
3 files changed, 89 insertions, 0 deletions
diff --git a/src/mainboard/emulation/qemu-i440fx/fw_cfg.c b/src/mainboard/emulation/qemu-i440fx/fw_cfg.c index 44256be442..242f218692 100644 --- a/src/mainboard/emulation/qemu-i440fx/fw_cfg.c +++ b/src/mainboard/emulation/qemu-i440fx/fw_cfg.c @@ -362,6 +362,89 @@ static void fw_cfg_smbios_init(void) } } +static unsigned long smbios_next(unsigned long current) +{ + struct smbios_type0 *t0; + int l, count = 0; + char *s; + + t0 = (void*)current; + current += t0->length; + for (;;) { + s = (void*)current; + l = strlen(s); + if (!l) + return current + (count ? 1 : 2); + current += l + 1; + count++; + } +} + +/* + * Starting with version 2.1 qemu provides a full set of smbios tables + * for the virtual hardware emulated, except type 0 (bios information). + * + * What we are going to do here is find the type0 table, keep it, and + * override everything else generated by coreboot with the qemu smbios + * tables. + * + * It's a bit hackish, but qemu is a special case (compared to real + * hardware) and this way we don't need special qemu support in the + * generic smbios code. + */ +unsigned long fw_cfg_smbios_tables(int *handle, unsigned long *current) +{ + struct smbios_type0 *t0; + unsigned long start, end; + int len, ret, i, count = 1; + char *str; + + len = fw_cfg_check_file("etc/smbios/smbios-tables"); + if (len < 0) + return 0; + printk(BIOS_DEBUG, "QEMU: found smbios tables in fw_cfg (len %d).\n", len); + + /* + * Search backwards for "coreboot" (first string in type0 table, + * see src/arch/x86/boot/smbios.c), then find type0 table. + */ + for (i = 0; i < 16384; i++) { + str = (char*)(*current - i); + if (strcmp(str, "coreboot") == 0) + break; + } + if (i == 16384) + return 0; + i += sizeof(struct smbios_type0) - 2; + t0 = (struct smbios_type0*)(*current - i); + if (t0->type != SMBIOS_BIOS_INFORMATION || t0->handle != 0) + return 0; + printk(BIOS_DEBUG, "QEMU: coreboot type0 table found at 0x%lx.\n", + *current - i); + start = smbios_next(*current - i); + + /* + * Fetch smbios tables from qemu, go find the end marker. + * We'll exclude the end marker as coreboot will add one. + */ + printk(BIOS_DEBUG, "QEMU: loading smbios tables to 0x%lx\n", start); + fw_cfg_load_file("etc/smbios/smbios-tables", (void*)start); + end = start; + do { + t0 = (struct smbios_type0*)end; + if (t0->type == SMBIOS_END_OF_TABLE) + break; + end = smbios_next(end); + count++; + } while (end < start + len); + + /* final fixups. */ + ret = end - *current; + *current = end; + *handle = count; + return ret; +} + const char *smbios_mainboard_manufacturer(void) { fw_cfg_smbios_init(); diff --git a/src/mainboard/emulation/qemu-i440fx/fw_cfg.h b/src/mainboard/emulation/qemu-i440fx/fw_cfg.h index 2a10d8bce9..51ecaa8acd 100644 --- a/src/mainboard/emulation/qemu-i440fx/fw_cfg.h +++ b/src/mainboard/emulation/qemu-i440fx/fw_cfg.h @@ -19,3 +19,4 @@ void fw_cfg_get(int entry, void *dst, int dstlen); int fw_cfg_check_file(const char *name); void fw_cfg_load_file(const char *name, void *dst); int fw_cfg_max_cpus(void); +unsigned long fw_cfg_smbios_tables(int *handle, unsigned long *current); diff --git a/src/mainboard/emulation/qemu-i440fx/northbridge.c b/src/mainboard/emulation/qemu-i440fx/northbridge.c index 08d563fbe5..f12a272f89 100644 --- a/src/mainboard/emulation/qemu-i440fx/northbridge.c +++ b/src/mainboard/emulation/qemu-i440fx/northbridge.c @@ -213,6 +213,11 @@ static int qemu_get_smbios_data17(int handle, int parent_handle, unsigned long * static int qemu_get_smbios_data(device_t dev, int *handle, unsigned long *current) { int len; + + len = fw_cfg_smbios_tables(handle, current); + if (len != 0) + return len; + len = qemu_get_smbios_data16(*handle, current); len += qemu_get_smbios_data17(*handle+1, *handle, current); *handle += 2; |