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@xxxxxx> -- 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 case QEMU_OPTION_no_kqemu: -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html