qemu: 2.1+ smbios tables support

Starting with version 2.1 qemu provides a full set of smbios tables
for the virtual hardware emulated, except type 0 (bios information).

This patch adds support for loading those tables to coreboot.
The code is used by both i440fx and q35.

Change-Id: Id034f0c214e8890194145a92f06354201dee7963
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-on: http://review.coreboot.org/8608
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
This commit is contained in:
Gerd Hoffmann 2014-08-27 11:25:13 +02:00
parent f14bd79ae1
commit db9d169ddb
3 changed files with 89 additions and 0 deletions

View File

@ -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) const char *smbios_mainboard_manufacturer(void)
{ {
fw_cfg_smbios_init(); fw_cfg_smbios_init();

View File

@ -19,3 +19,4 @@ void fw_cfg_get(int entry, void *dst, int dstlen);
int fw_cfg_check_file(const char *name); int fw_cfg_check_file(const char *name);
void fw_cfg_load_file(const char *name, void *dst); void fw_cfg_load_file(const char *name, void *dst);
int fw_cfg_max_cpus(void); int fw_cfg_max_cpus(void);
unsigned long fw_cfg_smbios_tables(int *handle, unsigned long *current);

View File

@ -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) static int qemu_get_smbios_data(device_t dev, int *handle, unsigned long *current)
{ {
int len; 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_data16(*handle, current);
len += qemu_get_smbios_data17(*handle+1, *handle, current); len += qemu_get_smbios_data17(*handle+1, *handle, current);
*handle += 2; *handle += 2;