summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mainboard/emulation/qemu-i440fx/fw_cfg.c83
-rw-r--r--src/mainboard/emulation/qemu-i440fx/fw_cfg.h1
-rw-r--r--src/mainboard/emulation/qemu-i440fx/northbridge.c5
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;