[PATCH 1/2] qemu: Allow SMBIOS entries to be loaded and provided to the VM BIOS

Alex Williamson
2009-03-23T19:11:21Z

Create a new -smbios options that takes binary SMBIOS entries
to provide to the VM BIOS. The binary can be easily generated
using something like:

dmidecode -t 1 -u | grep $'^\t\t[^"]' | xargs -n1 | \
perl -lne 'printf "%c", hex($_)' > smbios_type_1.bin

For some inventory tools, this makes the VM report the system
information for the host. One entry per binary file, multiple
files can be chained together as:

-smbios file1,file2,...

or specified independently:

-smbios file1 -smbios file2

Signed-off-by: Alex Williamson <alex.williamson@hp.com>
--

diff --git a/hw/acpi.c b/hw/acpi.c
index 52f50a0..0bd93bf 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -915,3 +915,69 @@ out:
}
return -1;
}
+
+char *smbios_entries;
+size_t smbios_entries_len;
+
+int smbios_entry_add(const char *t)
+{
+ struct stat s;
+ char file[1024], *p, *f, *n;
+ int fd, r;
+ size_t len, off;
+
+ f = (char *)t;
+ do {
+ n = strchr(f, ',');
+ if (n) {
+ strncpy(file, f, (n - f));
+ file[n - f] = '\0';
+ f = n + 1;
+ } else {
+ strcpy(file, f);
+ f += strlen(file);
+ }
+
+ fd = open(file, O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ if (fstat(fd, &s) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ if (!smbios_entries) {
+ smbios_entries_len = sizeof(uint16_t);
+ smbios_entries = qemu_mallocz(smbios_entries_len);
+ }
+
+ len = s.st_size;
+ smbios_entries = qemu_realloc(smbios_entries, smbios_entries_len +
+ len + sizeof(uint16_t));
+ p = smbios_entries + smbios_entries_len;
+
+ *(uint16_t *)p = cpu_to_le32(len);
+ p += sizeof(uint16_t);
+
+ off = 0;
+ do {
+ r = read(fd, p + off, len);
+ if (r > 0) {
+ off += r;
+ len -= r;
+ } else if ((r < 0 && errno != EINTR) || r == 0) {
+ close(fd);
+ return -1;
+ }
+ } while (len);
+
+ close(fd);
+
+ smbios_entries_len += s.st_size + sizeof(uint16_t);
+ (*(uint16_t *)smbios_entries) =
+ cpu_to_le32(le32_to_cpu(*(uint16_t *)smbios_entries) + 1);
+ } while (*f);
+
+ return 0;
+}
diff --git a/hw/pc.c b/hw/pc.c
index 69f25f3..ec65e33 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -51,6 +51,7 @@
#define ACPI_DATA_SIZE 0x10000
#define BIOS_CFG_IOPORT 0x510
#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
+#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)

#define MAX_IDE_BUS 2

@@ -442,6 +443,8 @@ static void bochs_bios_init(void)
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, (uint8_t *)acpi_tables,
acpi_tables_len);
+ fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES, (uint8_t *)smbios_entries,
+ smbios_entries_len);
}

/* Generate an initial boot sector which sets state and jump to
diff --git a/hw/pc.h b/hw/pc.h
index 5b378d4..6c200b3 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -106,12 +106,15 @@ int ioport_get_a20(void);
extern int acpi_enabled;
extern char *acpi_tables;
extern size_t acpi_tables_len;
+extern char *smbios_entries;
+extern size_t smbios_entries_len;

i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
qemu_irq sci_irq);
void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
void acpi_bios_init(void);
int acpi_table_add(const char *table_desc);
+int smbios_entry_add(const char *smbios_entry);

/* hpet.c */
extern int no_hpet;
diff --git a/vl.c b/vl.c
index b62a2d4..372b83c 100644
--- a/vl.c
+++ b/vl.c
@@ -4061,6 +4061,7 @@ static void help(int exitcode)
"-no-hpet disable HPET\n"
"-acpitable [sig=str][,rev=n][,oem_id=str][,oem_table_id=str][,oem_rev=n][,asl_compiler_id=str][,asl_compiler_rev=n][,data=file1[:file2]...]\n"
" ACPI table description\n"
+ "-smbios file1[,file2] SMBIOS entry\n"
#endif
"Linux boot specific:\n"
"-kernel bzImage use 'bzImage' as kernel image\n"
@@ -4201,6 +4202,7 @@ enum {
QEMU_OPTION_no_acpi,
QEMU_OPTION_no_hpet,
QEMU_OPTION_acpitable,
+ QEMU_OPTION_smbios,

/* Linux boot specific: */
QEMU_OPTION_kernel,
@@ -4322,6 +4324,7 @@ static const QEMUOption qemu_options[] = {
{ "no-acpi", 0, QEMU_OPTION_no_acpi },
{ "no-hpet", 0, QEMU_OPTION_no_hpet },
{ "acpitable", HAS_ARG, QEMU_OPTION_acpitable },
+ { "smbios", HAS_ARG, QEMU_OPTION_smbios },
#endif

/* Linux boot specific: */
@@ -5152,6 +5155,12 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
break;
+ case QEMU_OPTION_smbios:
+ if(smbios_entry_add(optarg) < 0) {
+ fprintf(stderr, "Wrong smbios provided\n");
+ exit(1);
+ }
+ break;
#endif
#ifdef USE_KQEMU