All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [ARM SMBIOS RFC PATCH 0/5] SMBIOS Support for ARM
@ 2015-07-14 20:23 Wei Huang
  2015-07-14 20:23 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 1/5] smbios: extract x86 smbios building code into a function Wei Huang
                   ` (7 more replies)
  0 siblings, 8 replies; 11+ messages in thread
From: Wei Huang @ 2015-07-14 20:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Wei Huang, peter.maydell, drjones, ehabkost, mst, zhaoshenglong,
	pbonzini, imammedo, lersek, rth

SMBIOS tables present userful system hardware info to management
applications, such as DMI tools. Even though SMBIOS was originally
developed for Intel x86, it has been extended to both Itanium and 
ARM (32bit & 64bit). More and more ARM server releases, such as 
RHEL Server for ARM, start to integrate support for SMBIOS.

This patchset is intendted to provid SMBIOS tables for ARM mach-virt
machine. The SMBIOS tables are created and stored in fw_cfg, awaiting
OVMF (AAVMF) to parse/present SMBIOS entry.

NOTE: This is RFC and the patches haven't been fully tested yet.
Laszlo is kind enough to offer help on fixing AAVMF to enable support
for SMBIOS. Any comments are welcomed for next release.

Thanks,
-Wei

Wei Huang (5):
  smbios: extract x86 smbios building code into a function
  smbios: remove dependency on x86 e820 tables
  smbios: pass ram size as a parameter to build smbios tables
  smbios: move smbios code into a common folder
  smbios: implement smbios support for mach-virt

 arch_init.c                        |    2 +-
 default-configs/arm-softmmu.mak    |    1 +
 default-configs/i386-softmmu.mak   |    1 +
 default-configs/x86_64-softmmu.mak |    1 +
 hw/Makefile.objs                   |    1 +
 hw/arm/virt.c                      |   24 +
 hw/i386/Makefile.objs              |    2 +-
 hw/i386/pc.c                       |   56 +-
 hw/i386/pc_piix.c                  |    2 +-
 hw/i386/pc_q35.c                   |    2 +-
 hw/i386/smbios.c                   | 1102 ------------------------------------
 hw/smbios/Makefile.objs            |    1 +
 hw/smbios/smbios.c                 | 1102 ++++++++++++++++++++++++++++++++++++
 include/hw/arm/virt-acpi-build.h   |    1 +
 include/hw/i386/smbios.h           |  227 --------
 include/hw/smbios/smbios.h         |  237 ++++++++
 tests/bios-tables-test.c           |    2 +-
 vl.c                               |    2 +-
 18 files changed, 1414 insertions(+), 1352 deletions(-)
 delete mode 100644 hw/i386/smbios.c
 create mode 100644 hw/smbios/Makefile.objs
 create mode 100644 hw/smbios/smbios.c
 delete mode 100644 include/hw/i386/smbios.h
 create mode 100644 include/hw/smbios/smbios.h

-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [Qemu-devel] [ARM SMBIOS RFC PATCH 1/5] smbios: extract x86 smbios building code into a function
  2015-07-14 20:23 [Qemu-devel] [ARM SMBIOS RFC PATCH 0/5] SMBIOS Support for ARM Wei Huang
@ 2015-07-14 20:23 ` Wei Huang
  2015-07-14 20:23 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 2/5] smbios: remove dependency on x86 e820 tables Wei Huang
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Wei Huang @ 2015-07-14 20:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Wei Huang, peter.maydell, drjones, ehabkost, mst, zhaoshenglong,
	pbonzini, imammedo, lersek, rth

This patch extracts out the procedure of buidling x86 SMBIOS tables
into a dedicated function.

Signed-off-by: Wei Huang <wei@redhat.com>
---
 hw/i386/pc.c | 38 ++++++++++++++++++++++----------------
 1 file changed, 22 insertions(+), 16 deletions(-)

diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 7661ea9..00e45f3 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -718,11 +718,30 @@ static unsigned int pc_apic_id_limit(unsigned int max_cpus)
     return x86_cpu_apic_id_from_index(max_cpus - 1) + 1;
 }
 
-static FWCfgState *bochs_bios_init(void)
+static void pc_build_smbios(FWCfgState *fw_cfg)
 {
-    FWCfgState *fw_cfg;
     uint8_t *smbios_tables, *smbios_anchor;
     size_t smbios_tables_len, smbios_anchor_len;
+
+    smbios_tables = smbios_get_table_legacy(&smbios_tables_len);
+    if (smbios_tables) {
+        fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
+                         smbios_tables, smbios_tables_len);
+    }
+
+    smbios_get_tables(&smbios_tables, &smbios_tables_len,
+                      &smbios_anchor, &smbios_anchor_len);
+    if (smbios_anchor) {
+        fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables",
+                        smbios_tables, smbios_tables_len);
+        fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor",
+                        smbios_anchor, smbios_anchor_len);
+    }
+}
+
+static FWCfgState *bochs_bios_init(void)
+{
+    FWCfgState *fw_cfg;
     uint64_t *numa_fw_cfg;
     int i, j;
     unsigned int apic_id_limit = pc_apic_id_limit(max_cpus);
@@ -748,20 +767,7 @@ static FWCfgState *bochs_bios_init(void)
                      acpi_tables, acpi_tables_len);
     fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override());
 
-    smbios_tables = smbios_get_table_legacy(&smbios_tables_len);
-    if (smbios_tables) {
-        fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
-                         smbios_tables, smbios_tables_len);
-    }
-
-    smbios_get_tables(&smbios_tables, &smbios_tables_len,
-                      &smbios_anchor, &smbios_anchor_len);
-    if (smbios_anchor) {
-        fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables",
-                        smbios_tables, smbios_tables_len);
-        fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor",
-                        smbios_anchor, smbios_anchor_len);
-    }
+    pc_build_smbios(fw_cfg);
 
     fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE,
                      &e820_reserve, sizeof(e820_reserve));
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [Qemu-devel] [ARM SMBIOS RFC PATCH 2/5] smbios: remove dependency on x86 e820 tables
  2015-07-14 20:23 [Qemu-devel] [ARM SMBIOS RFC PATCH 0/5] SMBIOS Support for ARM Wei Huang
  2015-07-14 20:23 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 1/5] smbios: extract x86 smbios building code into a function Wei Huang
@ 2015-07-14 20:23 ` Wei Huang
  2015-07-14 20:23 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 3/5] smbios: pass ram size as a parameter to build smbios tables Wei Huang
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Wei Huang @ 2015-07-14 20:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Wei Huang, peter.maydell, drjones, ehabkost, mst, zhaoshenglong,
	pbonzini, imammedo, lersek, rth

Current smbios builds type 19 table from e820, which is x86 specific.
This patch removes smbios' dependency on e820 by passing an array
of memory area to smbios_get_tables().

Signed-off-by: Wei Huang <wei@redhat.com>
---
 hw/i386/pc.c             | 18 +++++++++++++++++-
 hw/i386/smbios.c         | 14 +++++++-------
 include/hw/i386/smbios.h | 10 +++++++++-
 3 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 00e45f3..34e9133 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -722,6 +722,8 @@ static void pc_build_smbios(FWCfgState *fw_cfg)
 {
     uint8_t *smbios_tables, *smbios_anchor;
     size_t smbios_tables_len, smbios_anchor_len;
+    struct smbios_phys_mem_area *mem_array;
+    unsigned i, array_count;
 
     smbios_tables = smbios_get_table_legacy(&smbios_tables_len);
     if (smbios_tables) {
@@ -729,8 +731,22 @@ static void pc_build_smbios(FWCfgState *fw_cfg)
                          smbios_tables, smbios_tables_len);
     }
 
-    smbios_get_tables(&smbios_tables, &smbios_tables_len,
+    /* build the array of physical mem area from e820 table */
+    mem_array = g_malloc0(sizeof(*mem_array) * e820_get_num_entries());
+    for (i = 0, array_count = 0; i < e820_get_num_entries(); i++) {
+        uint64_t addr, len;
+
+        if (e820_get_entry(i, E820_RAM, &addr, &len)) {
+            mem_array[array_count].address = addr;
+            mem_array[array_count].length = len;
+            array_count++;
+        }
+    }
+    smbios_get_tables(mem_array, array_count,
+                      &smbios_tables, &smbios_tables_len,
                       &smbios_anchor, &smbios_anchor_len);
+    g_free(mem_array);
+
     if (smbios_anchor) {
         fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables",
                         smbios_tables, smbios_tables_len);
diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c
index 1341e02..6f715c6 100644
--- a/hw/i386/smbios.c
+++ b/hw/i386/smbios.c
@@ -831,10 +831,12 @@ static void smbios_entry_point_setup(void)
     ep.structure_table_address = cpu_to_le32(0);
 }
 
-void smbios_get_tables(uint8_t **tables, size_t *tables_len,
+void smbios_get_tables(const struct smbios_phys_mem_area *mem_array,
+                       const unsigned int mem_array_size,
+                       uint8_t **tables, size_t *tables_len,
                        uint8_t **anchor, size_t *anchor_len)
 {
-    unsigned i, dimm_cnt, instance;
+    unsigned i, dimm_cnt;
 
     if (smbios_legacy) {
         *tables = *anchor = NULL;
@@ -867,11 +869,9 @@ void smbios_get_tables(uint8_t **tables, size_t *tables_len,
             smbios_build_type_17_table(i, GET_DIMM_SZ);
         }
 
-        for (i = 0, instance = 0; i < e820_get_num_entries(); i++) {
-            uint64_t address, length;
-            if (e820_get_entry(i, E820_RAM, &address, &length)) {
-                smbios_build_type_19_table(instance++, address, length);
-            }
+        for (i = 0; i < mem_array_size; i++) {
+            smbios_build_type_19_table(i, mem_array[i].address,
+                                       mem_array[i].length);
         }
 
         smbios_build_type_32_table();
diff --git a/include/hw/i386/smbios.h b/include/hw/i386/smbios.h
index d2850be..4269aab 100644
--- a/include/hw/i386/smbios.h
+++ b/include/hw/i386/smbios.h
@@ -17,13 +17,21 @@
 
 #define SMBIOS_MAX_TYPE 127
 
+/* memory area description, used by type 19 table */
+struct smbios_phys_mem_area {
+    uint64_t address;
+    uint64_t length;
+};
+
 void smbios_entry_add(QemuOpts *opts);
 void smbios_set_cpuid(uint32_t version, uint32_t features);
 void smbios_set_defaults(const char *manufacturer, const char *product,
                          const char *version, bool legacy_mode,
                          bool uuid_encoded);
 uint8_t *smbios_get_table_legacy(size_t *length);
-void smbios_get_tables(uint8_t **tables, size_t *tables_len,
+void smbios_get_tables(const struct smbios_phys_mem_area *mem_array,
+                       const unsigned int mem_array_size,
+                       uint8_t **tables, size_t *tables_len,
                        uint8_t **anchor, size_t *anchor_len);
 
 /*
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [Qemu-devel] [ARM SMBIOS RFC PATCH 3/5] smbios: pass ram size as a parameter to build smbios tables
  2015-07-14 20:23 [Qemu-devel] [ARM SMBIOS RFC PATCH 0/5] SMBIOS Support for ARM Wei Huang
  2015-07-14 20:23 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 1/5] smbios: extract x86 smbios building code into a function Wei Huang
  2015-07-14 20:23 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 2/5] smbios: remove dependency on x86 e820 tables Wei Huang
@ 2015-07-14 20:23 ` Wei Huang
  2015-07-14 20:23 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 4/5] smbios: move smbios code into a common folder Wei Huang
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Wei Huang @ 2015-07-14 20:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Wei Huang, peter.maydell, drjones, ehabkost, mst, zhaoshenglong,
	pbonzini, imammedo, lersek, rth

This patch adds a new parameter, mem_size, to smbios_get_tables()
function. This step is required to make smbios code
architect-independent.

Signed-off-by: Wei Huang <wei@redhat.com>
---
 hw/i386/pc.c             | 2 +-
 hw/i386/smbios.c         | 8 ++++----
 include/hw/i386/smbios.h | 2 ++
 3 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 34e9133..944d5b1 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -742,7 +742,7 @@ static void pc_build_smbios(FWCfgState *fw_cfg)
             array_count++;
         }
     }
-    smbios_get_tables(mem_array, array_count,
+    smbios_get_tables(mem_array, array_count, ram_size,
                       &smbios_tables, &smbios_tables_len,
                       &smbios_anchor, &smbios_anchor_len);
     g_free(mem_array);
diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c
index 6f715c6..12aee90 100644
--- a/hw/i386/smbios.c
+++ b/hw/i386/smbios.c
@@ -19,10 +19,9 @@
 #include "qemu/error-report.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/cpus.h"
-#include "hw/i386/pc.h"
 #include "hw/i386/smbios.h"
 #include "hw/loader.h"
-
+#include "exec/cpu-common.h"
 
 /* legacy structures and constants for <= 2.0 machines */
 struct smbios_header {
@@ -649,7 +648,7 @@ static void smbios_build_type_4_table(unsigned instance)
 
 #define MAX_T16_STD_SZ 0x80000000 /* 2T in Kilobytes */
 
-static void smbios_build_type_16_table(unsigned dimm_cnt)
+static void smbios_build_type_16_table(unsigned dimm_cnt, ram_addr_t ram_size)
 {
     uint64_t size_kb;
 
@@ -833,6 +832,7 @@ static void smbios_entry_point_setup(void)
 
 void smbios_get_tables(const struct smbios_phys_mem_area *mem_array,
                        const unsigned int mem_array_size,
+                       const ram_addr_t ram_size,
                        uint8_t **tables, size_t *tables_len,
                        uint8_t **anchor, size_t *anchor_len)
 {
@@ -863,7 +863,7 @@ void smbios_get_tables(const struct smbios_phys_mem_area *mem_array,
 
         dimm_cnt = QEMU_ALIGN_UP(ram_size, MAX_DIMM_SZ) / MAX_DIMM_SZ;
 
-        smbios_build_type_16_table(dimm_cnt);
+        smbios_build_type_16_table(dimm_cnt, ram_size);
 
         for (i = 0; i < dimm_cnt; i++) {
             smbios_build_type_17_table(i, GET_DIMM_SZ);
diff --git a/include/hw/i386/smbios.h b/include/hw/i386/smbios.h
index 4269aab..e727233 100644
--- a/include/hw/i386/smbios.h
+++ b/include/hw/i386/smbios.h
@@ -14,6 +14,7 @@
  */
 
 #include "qemu/option.h"
+#include "exec/cpu-common.h"
 
 #define SMBIOS_MAX_TYPE 127
 
@@ -31,6 +32,7 @@ void smbios_set_defaults(const char *manufacturer, const char *product,
 uint8_t *smbios_get_table_legacy(size_t *length);
 void smbios_get_tables(const struct smbios_phys_mem_area *mem_array,
                        const unsigned int mem_array_size,
+                       const ram_addr_t ram_size,
                        uint8_t **tables, size_t *tables_len,
                        uint8_t **anchor, size_t *anchor_len);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [Qemu-devel] [ARM SMBIOS RFC PATCH 4/5] smbios: move smbios code into a common folder
  2015-07-14 20:23 [Qemu-devel] [ARM SMBIOS RFC PATCH 0/5] SMBIOS Support for ARM Wei Huang
                   ` (2 preceding siblings ...)
  2015-07-14 20:23 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 3/5] smbios: pass ram size as a parameter to build smbios tables Wei Huang
@ 2015-07-14 20:23 ` Wei Huang
  2015-07-15 12:08   ` Laszlo Ersek
  2015-07-14 20:23 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 5/5] smbios: implement smbios support for mach-virt Wei Huang
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 11+ messages in thread
From: Wei Huang @ 2015-07-14 20:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Wei Huang, peter.maydell, drjones, ehabkost, mst, zhaoshenglong,
	pbonzini, imammedo, lersek, rth

To share smbios among different architectures, this patch moves SMBIOS
code (smbios.c and smbios.h) from x86 specific folders into new
hw/smbios directories. As a result, CONFIG_SMBIOS=y is defined in
x86 default config files.

Signed-off-by: Wei Huang <wei@redhat.com>
---
 arch_init.c                        |    2 +-
 default-configs/i386-softmmu.mak   |    1 +
 default-configs/x86_64-softmmu.mak |    1 +
 hw/Makefile.objs                   |    1 +
 hw/i386/Makefile.objs              |    2 +-
 hw/i386/pc.c                       |    2 +-
 hw/i386/pc_piix.c                  |    2 +-
 hw/i386/pc_q35.c                   |    2 +-
 hw/i386/smbios.c                   | 1102 ------------------------------------
 hw/smbios/Makefile.objs            |    1 +
 hw/smbios/smbios.c                 | 1102 ++++++++++++++++++++++++++++++++++++
 include/hw/i386/smbios.h           |  237 --------
 include/hw/smbios/smbios.h         |  237 ++++++++
 tests/bios-tables-test.c           |    2 +-
 vl.c                               |    2 +-
 15 files changed, 1350 insertions(+), 1346 deletions(-)
 delete mode 100644 hw/i386/smbios.c
 create mode 100644 hw/smbios/Makefile.objs
 create mode 100644 hw/smbios/smbios.c
 delete mode 100644 include/hw/i386/smbios.h
 create mode 100644 include/hw/smbios/smbios.h

diff --git a/arch_init.c b/arch_init.c
index 725c638..38f5fb9 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -26,7 +26,7 @@
 #include "sysemu/arch_init.h"
 #include "hw/pci/pci.h"
 #include "hw/audio/audio.h"
-#include "hw/i386/smbios.h"
+#include "hw/smbios/smbios.h"
 #include "qemu/config-file.h"
 #include "qemu/error-report.h"
 #include "qmp-commands.h"
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index 48b5762..5eaafa1 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -49,3 +49,4 @@ CONFIG_MEM_HOTPLUG=y
 CONFIG_XIO3130=y
 CONFIG_IOH3420=y
 CONFIG_I82801B11=y
+CONFIG_SMBIOS=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index 4962ed7..28e2099 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -50,3 +50,4 @@ CONFIG_MEM_HOTPLUG=y
 CONFIG_XIO3130=y
 CONFIG_IOH3420=y
 CONFIG_I82801B11=y
+CONFIG_SMBIOS=y
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 73afa41..7e7c241 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -31,6 +31,7 @@ devices-dirs-$(CONFIG_VIRTIO) += virtio/
 devices-dirs-$(CONFIG_SOFTMMU) += watchdog/
 devices-dirs-$(CONFIG_SOFTMMU) += xen/
 devices-dirs-$(CONFIG_MEM_HOTPLUG) += mem/
+devices-dirs-$(CONFIG_SMBIOS) += smbios/
 devices-dirs-y += core/
 common-obj-y += $(devices-dirs-y)
 obj-y += $(devices-dirs-y)
diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
index bd4f147..723a4d8 100644
--- a/hw/i386/Makefile.objs
+++ b/hw/i386/Makefile.objs
@@ -1,5 +1,5 @@
 obj-$(CONFIG_KVM) += kvm/
-obj-y += multiboot.o smbios.o
+obj-y += multiboot.o
 obj-y += pc.o pc_piix.o pc_q35.o
 obj-y += pc_sysfw.o
 obj-y += intel_iommu.o
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 944d5b1..80291fe 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -33,7 +33,7 @@
 #include "hw/pci/pci_bus.h"
 #include "hw/nvram/fw_cfg.h"
 #include "hw/timer/hpet.h"
-#include "hw/i386/smbios.h"
+#include "hw/smbios/smbios.h"
 #include "hw/loader.h"
 #include "elf.h"
 #include "multiboot.h"
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 8167b12..4ee4c28 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -28,7 +28,7 @@
 #include "hw/loader.h"
 #include "hw/i386/pc.h"
 #include "hw/i386/apic.h"
-#include "hw/i386/smbios.h"
+#include "hw/smbios/smbios.h"
 #include "hw/pci/pci.h"
 #include "hw/pci/pci_ids.h"
 #include "hw/usb.h"
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 974aead..d83df14 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -39,7 +39,7 @@
 #include "hw/pci-host/q35.h"
 #include "exec/address-spaces.h"
 #include "hw/i386/ich9.h"
-#include "hw/i386/smbios.h"
+#include "hw/smbios/smbios.h"
 #include "hw/ide/pci.h"
 #include "hw/ide/ahci.h"
 #include "hw/usb.h"
diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c
deleted file mode 100644
index 12aee90..0000000
--- a/hw/i386/smbios.c
+++ /dev/null
@@ -1,1102 +0,0 @@
-/*
- * SMBIOS Support
- *
- * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
- * Copyright (C) 2013 Red Hat, Inc.
- *
- * Authors:
- *  Alex Williamson <alex.williamson@hp.com>
- *  Markus Armbruster <armbru@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/config-file.h"
-#include "qemu/error-report.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/cpus.h"
-#include "hw/i386/smbios.h"
-#include "hw/loader.h"
-#include "exec/cpu-common.h"
-
-/* legacy structures and constants for <= 2.0 machines */
-struct smbios_header {
-    uint16_t length;
-    uint8_t type;
-} QEMU_PACKED;
-
-struct smbios_field {
-    struct smbios_header header;
-    uint8_t type;
-    uint16_t offset;
-    uint8_t data[];
-} QEMU_PACKED;
-
-struct smbios_table {
-    struct smbios_header header;
-    uint8_t data[];
-} QEMU_PACKED;
-
-#define SMBIOS_FIELD_ENTRY 0
-#define SMBIOS_TABLE_ENTRY 1
-
-static uint8_t *smbios_entries;
-static size_t smbios_entries_len;
-static bool smbios_legacy = true;
-static bool smbios_uuid_encoded = true;
-/* end: legacy structures & constants for <= 2.0 machines */
-
-
-static uint8_t *smbios_tables;
-static size_t smbios_tables_len;
-static unsigned smbios_table_max;
-static unsigned smbios_table_cnt;
-static struct smbios_entry_point ep;
-
-static int smbios_type4_count = 0;
-static bool smbios_immutable;
-static bool smbios_have_defaults;
-static uint32_t smbios_cpuid_version, smbios_cpuid_features, smbios_smp_sockets;
-
-static DECLARE_BITMAP(have_binfile_bitmap, SMBIOS_MAX_TYPE+1);
-static DECLARE_BITMAP(have_fields_bitmap, SMBIOS_MAX_TYPE+1);
-
-static struct {
-    const char *vendor, *version, *date;
-    bool have_major_minor, uefi;
-    uint8_t major, minor;
-} type0;
-
-static struct {
-    const char *manufacturer, *product, *version, *serial, *sku, *family;
-    /* uuid is in qemu_uuid[] */
-} type1;
-
-static struct {
-    const char *manufacturer, *product, *version, *serial, *asset, *location;
-} type2;
-
-static struct {
-    const char *manufacturer, *version, *serial, *asset, *sku;
-} type3;
-
-static struct {
-    const char *sock_pfx, *manufacturer, *version, *serial, *asset, *part;
-} type4;
-
-static struct {
-    const char *loc_pfx, *bank, *manufacturer, *serial, *asset, *part;
-    uint16_t speed;
-} type17;
-
-static QemuOptsList qemu_smbios_opts = {
-    .name = "smbios",
-    .head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head),
-    .desc = {
-        /*
-         * no elements => accept any params
-         * validation will happen later
-         */
-        { /* end of list */ }
-    }
-};
-
-static const QemuOptDesc qemu_smbios_file_opts[] = {
-    {
-        .name = "file",
-        .type = QEMU_OPT_STRING,
-        .help = "binary file containing an SMBIOS element",
-    },
-    { /* end of list */ }
-};
-
-static const QemuOptDesc qemu_smbios_type0_opts[] = {
-    {
-        .name = "type",
-        .type = QEMU_OPT_NUMBER,
-        .help = "SMBIOS element type",
-    },{
-        .name = "vendor",
-        .type = QEMU_OPT_STRING,
-        .help = "vendor name",
-    },{
-        .name = "version",
-        .type = QEMU_OPT_STRING,
-        .help = "version number",
-    },{
-        .name = "date",
-        .type = QEMU_OPT_STRING,
-        .help = "release date",
-    },{
-        .name = "release",
-        .type = QEMU_OPT_STRING,
-        .help = "revision number",
-    },{
-        .name = "uefi",
-        .type = QEMU_OPT_BOOL,
-        .help = "uefi support",
-    },
-    { /* end of list */ }
-};
-
-static const QemuOptDesc qemu_smbios_type1_opts[] = {
-    {
-        .name = "type",
-        .type = QEMU_OPT_NUMBER,
-        .help = "SMBIOS element type",
-    },{
-        .name = "manufacturer",
-        .type = QEMU_OPT_STRING,
-        .help = "manufacturer name",
-    },{
-        .name = "product",
-        .type = QEMU_OPT_STRING,
-        .help = "product name",
-    },{
-        .name = "version",
-        .type = QEMU_OPT_STRING,
-        .help = "version number",
-    },{
-        .name = "serial",
-        .type = QEMU_OPT_STRING,
-        .help = "serial number",
-    },{
-        .name = "uuid",
-        .type = QEMU_OPT_STRING,
-        .help = "UUID",
-    },{
-        .name = "sku",
-        .type = QEMU_OPT_STRING,
-        .help = "SKU number",
-    },{
-        .name = "family",
-        .type = QEMU_OPT_STRING,
-        .help = "family name",
-    },
-    { /* end of list */ }
-};
-
-static const QemuOptDesc qemu_smbios_type2_opts[] = {
-    {
-        .name = "type",
-        .type = QEMU_OPT_NUMBER,
-        .help = "SMBIOS element type",
-    },{
-        .name = "manufacturer",
-        .type = QEMU_OPT_STRING,
-        .help = "manufacturer name",
-    },{
-        .name = "product",
-        .type = QEMU_OPT_STRING,
-        .help = "product name",
-    },{
-        .name = "version",
-        .type = QEMU_OPT_STRING,
-        .help = "version number",
-    },{
-        .name = "serial",
-        .type = QEMU_OPT_STRING,
-        .help = "serial number",
-    },{
-        .name = "asset",
-        .type = QEMU_OPT_STRING,
-        .help = "asset tag number",
-    },{
-        .name = "location",
-        .type = QEMU_OPT_STRING,
-        .help = "location in chassis",
-    },
-    { /* end of list */ }
-};
-
-static const QemuOptDesc qemu_smbios_type3_opts[] = {
-    {
-        .name = "type",
-        .type = QEMU_OPT_NUMBER,
-        .help = "SMBIOS element type",
-    },{
-        .name = "manufacturer",
-        .type = QEMU_OPT_STRING,
-        .help = "manufacturer name",
-    },{
-        .name = "version",
-        .type = QEMU_OPT_STRING,
-        .help = "version number",
-    },{
-        .name = "serial",
-        .type = QEMU_OPT_STRING,
-        .help = "serial number",
-    },{
-        .name = "asset",
-        .type = QEMU_OPT_STRING,
-        .help = "asset tag number",
-    },{
-        .name = "sku",
-        .type = QEMU_OPT_STRING,
-        .help = "SKU number",
-    },
-    { /* end of list */ }
-};
-
-static const QemuOptDesc qemu_smbios_type4_opts[] = {
-    {
-        .name = "type",
-        .type = QEMU_OPT_NUMBER,
-        .help = "SMBIOS element type",
-    },{
-        .name = "sock_pfx",
-        .type = QEMU_OPT_STRING,
-        .help = "socket designation string prefix",
-    },{
-        .name = "manufacturer",
-        .type = QEMU_OPT_STRING,
-        .help = "manufacturer name",
-    },{
-        .name = "version",
-        .type = QEMU_OPT_STRING,
-        .help = "version number",
-    },{
-        .name = "serial",
-        .type = QEMU_OPT_STRING,
-        .help = "serial number",
-    },{
-        .name = "asset",
-        .type = QEMU_OPT_STRING,
-        .help = "asset tag number",
-    },{
-        .name = "part",
-        .type = QEMU_OPT_STRING,
-        .help = "part number",
-    },
-    { /* end of list */ }
-};
-
-static const QemuOptDesc qemu_smbios_type17_opts[] = {
-    {
-        .name = "type",
-        .type = QEMU_OPT_NUMBER,
-        .help = "SMBIOS element type",
-    },{
-        .name = "loc_pfx",
-        .type = QEMU_OPT_STRING,
-        .help = "device locator string prefix",
-    },{
-        .name = "bank",
-        .type = QEMU_OPT_STRING,
-        .help = "bank locator string",
-    },{
-        .name = "manufacturer",
-        .type = QEMU_OPT_STRING,
-        .help = "manufacturer name",
-    },{
-        .name = "serial",
-        .type = QEMU_OPT_STRING,
-        .help = "serial number",
-    },{
-        .name = "asset",
-        .type = QEMU_OPT_STRING,
-        .help = "asset tag number",
-    },{
-        .name = "part",
-        .type = QEMU_OPT_STRING,
-        .help = "part number",
-    },{
-        .name = "speed",
-        .type = QEMU_OPT_NUMBER,
-        .help = "maximum capable speed",
-    },
-    { /* end of list */ }
-};
-
-static void smbios_register_config(void)
-{
-    qemu_add_opts(&qemu_smbios_opts);
-}
-
-machine_init(smbios_register_config);
-
-static void smbios_validate_table(void)
-{
-    uint32_t expect_t4_count = smbios_legacy ? smp_cpus : smbios_smp_sockets;
-
-    if (smbios_type4_count && smbios_type4_count != expect_t4_count) {
-        error_report("Expected %d SMBIOS Type 4 tables, got %d instead",
-                     expect_t4_count, smbios_type4_count);
-        exit(1);
-    }
-}
-
-
-/* legacy setup functions for <= 2.0 machines */
-static void smbios_add_field(int type, int offset, const void *data, size_t len)
-{
-    struct smbios_field *field;
-
-    if (!smbios_entries) {
-        smbios_entries_len = sizeof(uint16_t);
-        smbios_entries = g_malloc0(smbios_entries_len);
-    }
-    smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
-                                                  sizeof(*field) + len);
-    field = (struct smbios_field *)(smbios_entries + smbios_entries_len);
-    field->header.type = SMBIOS_FIELD_ENTRY;
-    field->header.length = cpu_to_le16(sizeof(*field) + len);
-
-    field->type = type;
-    field->offset = cpu_to_le16(offset);
-    memcpy(field->data, data, len);
-
-    smbios_entries_len += sizeof(*field) + len;
-    (*(uint16_t *)smbios_entries) =
-            cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
-}
-
-static void smbios_maybe_add_str(int type, int offset, const char *data)
-{
-    if (data) {
-        smbios_add_field(type, offset, data, strlen(data) + 1);
-    }
-}
-
-static void smbios_build_type_0_fields(void)
-{
-    smbios_maybe_add_str(0, offsetof(struct smbios_type_0, vendor_str),
-                         type0.vendor);
-    smbios_maybe_add_str(0, offsetof(struct smbios_type_0, bios_version_str),
-                         type0.version);
-    smbios_maybe_add_str(0, offsetof(struct smbios_type_0,
-                                     bios_release_date_str),
-                         type0.date);
-    if (type0.have_major_minor) {
-        smbios_add_field(0, offsetof(struct smbios_type_0,
-                                     system_bios_major_release),
-                         &type0.major, 1);
-        smbios_add_field(0, offsetof(struct smbios_type_0,
-                                     system_bios_minor_release),
-                         &type0.minor, 1);
-    }
-}
-
-static void smbios_build_type_1_fields(void)
-{
-    smbios_maybe_add_str(1, offsetof(struct smbios_type_1, manufacturer_str),
-                         type1.manufacturer);
-    smbios_maybe_add_str(1, offsetof(struct smbios_type_1, product_name_str),
-                         type1.product);
-    smbios_maybe_add_str(1, offsetof(struct smbios_type_1, version_str),
-                         type1.version);
-    smbios_maybe_add_str(1, offsetof(struct smbios_type_1, serial_number_str),
-                         type1.serial);
-    smbios_maybe_add_str(1, offsetof(struct smbios_type_1, sku_number_str),
-                         type1.sku);
-    smbios_maybe_add_str(1, offsetof(struct smbios_type_1, family_str),
-                         type1.family);
-    if (qemu_uuid_set) {
-        /* We don't encode the UUID in the "wire format" here because this
-         * function is for legacy mode and needs to keep the guest ABI, and
-         * because we don't know what's the SMBIOS version advertised by the
-         * BIOS.
-         */
-        smbios_add_field(1, offsetof(struct smbios_type_1, uuid),
-                         qemu_uuid, 16);
-    }
-}
-
-uint8_t *smbios_get_table_legacy(size_t *length)
-{
-    if (!smbios_legacy) {
-        *length = 0;
-        return NULL;
-    }
-
-    if (!smbios_immutable) {
-        smbios_build_type_0_fields();
-        smbios_build_type_1_fields();
-        smbios_validate_table();
-        smbios_immutable = true;
-    }
-    *length = smbios_entries_len;
-    return smbios_entries;
-}
-/* end: legacy setup functions for <= 2.0 machines */
-
-
-static bool smbios_skip_table(uint8_t type, bool required_table)
-{
-    if (test_bit(type, have_binfile_bitmap)) {
-        return true; /* user provided their own binary blob(s) */
-    }
-    if (test_bit(type, have_fields_bitmap)) {
-        return false; /* user provided fields via command line */
-    }
-    if (smbios_have_defaults && required_table) {
-        return false; /* we're building tables, and this one's required */
-    }
-    return true;
-}
-
-#define SMBIOS_BUILD_TABLE_PRE(tbl_type, tbl_handle, tbl_required)        \
-    struct smbios_type_##tbl_type *t;                                     \
-    size_t t_off; /* table offset into smbios_tables */                   \
-    int str_index = 0;                                                    \
-    do {                                                                  \
-        /* should we skip building this table ? */                        \
-        if (smbios_skip_table(tbl_type, tbl_required)) {                  \
-            return;                                                       \
-        }                                                                 \
-                                                                          \
-        /* use offset of table t within smbios_tables */                  \
-        /* (pointer must be updated after each realloc) */                \
-        t_off = smbios_tables_len;                                        \
-        smbios_tables_len += sizeof(*t);                                  \
-        smbios_tables = g_realloc(smbios_tables, smbios_tables_len);      \
-        t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off);     \
-                                                                          \
-        t->header.type = tbl_type;                                        \
-        t->header.length = sizeof(*t);                                    \
-        t->header.handle = cpu_to_le16(tbl_handle);                       \
-    } while (0)
-
-#define SMBIOS_TABLE_SET_STR(tbl_type, field, value)                      \
-    do {                                                                  \
-        int len = (value != NULL) ? strlen(value) + 1 : 0;                \
-        if (len > 1) {                                                    \
-            smbios_tables = g_realloc(smbios_tables,                      \
-                                      smbios_tables_len + len);           \
-            memcpy(smbios_tables + smbios_tables_len, value, len);        \
-            smbios_tables_len += len;                                     \
-            /* update pointer post-realloc */                             \
-            t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \
-            t->field = ++str_index;                                       \
-        } else {                                                          \
-            t->field = 0;                                                 \
-        }                                                                 \
-    } while (0)
-
-#define SMBIOS_BUILD_TABLE_POST                                           \
-    do {                                                                  \
-        size_t term_cnt, t_size;                                          \
-                                                                          \
-        /* add '\0' terminator (add two if no strings defined) */         \
-        term_cnt = (str_index == 0) ? 2 : 1;                              \
-        smbios_tables = g_realloc(smbios_tables,                          \
-                                  smbios_tables_len + term_cnt);          \
-        memset(smbios_tables + smbios_tables_len, 0, term_cnt);           \
-        smbios_tables_len += term_cnt;                                    \
-                                                                          \
-        /* update smbios max. element size */                             \
-        t_size = smbios_tables_len - t_off;                               \
-        if (t_size > smbios_table_max) {                                  \
-            smbios_table_max = t_size;                                    \
-        }                                                                 \
-                                                                          \
-        /* update smbios element count */                                 \
-        smbios_table_cnt++;                                               \
-    } while (0)
-
-static void smbios_build_type_0_table(void)
-{
-    SMBIOS_BUILD_TABLE_PRE(0, 0x000, false); /* optional, leave up to BIOS */
-
-    SMBIOS_TABLE_SET_STR(0, vendor_str, type0.vendor);
-    SMBIOS_TABLE_SET_STR(0, bios_version_str, type0.version);
-
-    t->bios_starting_address_segment = cpu_to_le16(0xE800); /* from SeaBIOS */
-
-    SMBIOS_TABLE_SET_STR(0, bios_release_date_str, type0.date);
-
-    t->bios_rom_size = 0; /* hardcoded in SeaBIOS with FIXME comment */
-
-    t->bios_characteristics = cpu_to_le64(0x08); /* Not supported */
-    t->bios_characteristics_extension_bytes[0] = 0;
-    t->bios_characteristics_extension_bytes[1] = 0x14; /* TCD/SVVP | VM */
-    if (type0.uefi) {
-        t->bios_characteristics_extension_bytes[1] |= 0x08; /* |= UEFI */
-    }
-
-    if (type0.have_major_minor) {
-        t->system_bios_major_release = type0.major;
-        t->system_bios_minor_release = type0.minor;
-    } else {
-        t->system_bios_major_release = 0;
-        t->system_bios_minor_release = 0;
-    }
-
-    /* hardcoded in SeaBIOS */
-    t->embedded_controller_major_release = 0xFF;
-    t->embedded_controller_minor_release = 0xFF;
-
-    SMBIOS_BUILD_TABLE_POST;
-}
-
-/* Encode UUID from the big endian encoding described on RFC4122 to the wire
- * format specified by SMBIOS version 2.6.
- */
-static void smbios_encode_uuid(struct smbios_uuid *uuid, const uint8_t *buf)
-{
-    memcpy(uuid, buf, 16);
-    if (smbios_uuid_encoded) {
-        uuid->time_low = bswap32(uuid->time_low);
-        uuid->time_mid = bswap16(uuid->time_mid);
-        uuid->time_hi_and_version = bswap16(uuid->time_hi_and_version);
-    }
-}
-
-static void smbios_build_type_1_table(void)
-{
-    SMBIOS_BUILD_TABLE_PRE(1, 0x100, true); /* required */
-
-    SMBIOS_TABLE_SET_STR(1, manufacturer_str, type1.manufacturer);
-    SMBIOS_TABLE_SET_STR(1, product_name_str, type1.product);
-    SMBIOS_TABLE_SET_STR(1, version_str, type1.version);
-    SMBIOS_TABLE_SET_STR(1, serial_number_str, type1.serial);
-    if (qemu_uuid_set) {
-        smbios_encode_uuid(&t->uuid, qemu_uuid);
-    } else {
-        memset(&t->uuid, 0, 16);
-    }
-    t->wake_up_type = 0x06; /* power switch */
-    SMBIOS_TABLE_SET_STR(1, sku_number_str, type1.sku);
-    SMBIOS_TABLE_SET_STR(1, family_str, type1.family);
-
-    SMBIOS_BUILD_TABLE_POST;
-}
-
-static void smbios_build_type_2_table(void)
-{
-    SMBIOS_BUILD_TABLE_PRE(2, 0x200, false); /* optional */
-
-    SMBIOS_TABLE_SET_STR(2, manufacturer_str, type2.manufacturer);
-    SMBIOS_TABLE_SET_STR(2, product_str, type2.product);
-    SMBIOS_TABLE_SET_STR(2, version_str, type2.version);
-    SMBIOS_TABLE_SET_STR(2, serial_number_str, type2.serial);
-    SMBIOS_TABLE_SET_STR(2, asset_tag_number_str, type2.asset);
-    t->feature_flags = 0x01; /* Motherboard */
-    SMBIOS_TABLE_SET_STR(2, location_str, type2.location);
-    t->chassis_handle = cpu_to_le16(0x300); /* Type 3 (System enclosure) */
-    t->board_type = 0x0A; /* Motherboard */
-    t->contained_element_count = 0;
-
-    SMBIOS_BUILD_TABLE_POST;
-}
-
-static void smbios_build_type_3_table(void)
-{
-    SMBIOS_BUILD_TABLE_PRE(3, 0x300, true); /* required */
-
-    SMBIOS_TABLE_SET_STR(3, manufacturer_str, type3.manufacturer);
-    t->type = 0x01; /* Other */
-    SMBIOS_TABLE_SET_STR(3, version_str, type3.version);
-    SMBIOS_TABLE_SET_STR(3, serial_number_str, type3.serial);
-    SMBIOS_TABLE_SET_STR(3, asset_tag_number_str, type3.asset);
-    t->boot_up_state = 0x03; /* Safe */
-    t->power_supply_state = 0x03; /* Safe */
-    t->thermal_state = 0x03; /* Safe */
-    t->security_status = 0x02; /* Unknown */
-    t->oem_defined = cpu_to_le32(0);
-    t->height = 0;
-    t->number_of_power_cords = 0;
-    t->contained_element_count = 0;
-    SMBIOS_TABLE_SET_STR(3, sku_number_str, type3.sku);
-
-    SMBIOS_BUILD_TABLE_POST;
-}
-
-static void smbios_build_type_4_table(unsigned instance)
-{
-    char sock_str[128];
-
-    SMBIOS_BUILD_TABLE_PRE(4, 0x400 + instance, true); /* required */
-
-    snprintf(sock_str, sizeof(sock_str), "%s%2x", type4.sock_pfx, instance);
-    SMBIOS_TABLE_SET_STR(4, socket_designation_str, sock_str);
-    t->processor_type = 0x03; /* CPU */
-    t->processor_family = 0x01; /* Other */
-    SMBIOS_TABLE_SET_STR(4, processor_manufacturer_str, type4.manufacturer);
-    t->processor_id[0] = cpu_to_le32(smbios_cpuid_version);
-    t->processor_id[1] = cpu_to_le32(smbios_cpuid_features);
-    SMBIOS_TABLE_SET_STR(4, processor_version_str, type4.version);
-    t->voltage = 0;
-    t->external_clock = cpu_to_le16(0); /* Unknown */
-    /* SVVP requires max_speed and current_speed to not be unknown. */
-    t->max_speed = cpu_to_le16(2000); /* 2000 MHz */
-    t->current_speed = cpu_to_le16(2000); /* 2000 MHz */
-    t->status = 0x41; /* Socket populated, CPU enabled */
-    t->processor_upgrade = 0x01; /* Other */
-    t->l1_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
-    t->l2_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
-    t->l3_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
-    SMBIOS_TABLE_SET_STR(4, serial_number_str, type4.serial);
-    SMBIOS_TABLE_SET_STR(4, asset_tag_number_str, type4.asset);
-    SMBIOS_TABLE_SET_STR(4, part_number_str, type4.part);
-    t->core_count = t->core_enabled = smp_cores;
-    t->thread_count = smp_threads;
-    t->processor_characteristics = cpu_to_le16(0x02); /* Unknown */
-    t->processor_family2 = cpu_to_le16(0x01); /* Other */
-
-    SMBIOS_BUILD_TABLE_POST;
-    smbios_type4_count++;
-}
-
-#define ONE_KB ((ram_addr_t)1 << 10)
-#define ONE_MB ((ram_addr_t)1 << 20)
-#define ONE_GB ((ram_addr_t)1 << 30)
-
-#define MAX_T16_STD_SZ 0x80000000 /* 2T in Kilobytes */
-
-static void smbios_build_type_16_table(unsigned dimm_cnt, ram_addr_t ram_size)
-{
-    uint64_t size_kb;
-
-    SMBIOS_BUILD_TABLE_PRE(16, 0x1000, true); /* required */
-
-    t->location = 0x01; /* Other */
-    t->use = 0x03; /* System memory */
-    t->error_correction = 0x06; /* Multi-bit ECC (for Microsoft, per SeaBIOS) */
-    size_kb = QEMU_ALIGN_UP(ram_size, ONE_KB) / ONE_KB;
-    if (size_kb < MAX_T16_STD_SZ) {
-        t->maximum_capacity = cpu_to_le32(size_kb);
-        t->extended_maximum_capacity = cpu_to_le64(0);
-    } else {
-        t->maximum_capacity = cpu_to_le32(MAX_T16_STD_SZ);
-        t->extended_maximum_capacity = cpu_to_le64(ram_size);
-    }
-    t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */
-    t->number_of_memory_devices = cpu_to_le16(dimm_cnt);
-
-    SMBIOS_BUILD_TABLE_POST;
-}
-
-#define MAX_T17_STD_SZ 0x7FFF /* (32G - 1M), in Megabytes */
-#define MAX_T17_EXT_SZ 0x80000000 /* 2P, in Megabytes */
-
-static void smbios_build_type_17_table(unsigned instance, uint64_t size)
-{
-    char loc_str[128];
-    uint64_t size_mb;
-
-    SMBIOS_BUILD_TABLE_PRE(17, 0x1100 + instance, true); /* required */
-
-    t->physical_memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */
-    t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */
-    t->total_width = cpu_to_le16(0xFFFF); /* Unknown */
-    t->data_width = cpu_to_le16(0xFFFF); /* Unknown */
-    size_mb = QEMU_ALIGN_UP(size, ONE_MB) / ONE_MB;
-    if (size_mb < MAX_T17_STD_SZ) {
-        t->size = cpu_to_le16(size_mb);
-        t->extended_size = cpu_to_le32(0);
-    } else {
-        assert(size_mb < MAX_T17_EXT_SZ);
-        t->size = cpu_to_le16(MAX_T17_STD_SZ);
-        t->extended_size = cpu_to_le32(size_mb);
-    }
-    t->form_factor = 0x09; /* DIMM */
-    t->device_set = 0; /* Not in a set */
-    snprintf(loc_str, sizeof(loc_str), "%s %d", type17.loc_pfx, instance);
-    SMBIOS_TABLE_SET_STR(17, device_locator_str, loc_str);
-    SMBIOS_TABLE_SET_STR(17, bank_locator_str, type17.bank);
-    t->memory_type = 0x07; /* RAM */
-    t->type_detail = cpu_to_le16(0x02); /* Other */
-    t->speed = cpu_to_le16(type17.speed);
-    SMBIOS_TABLE_SET_STR(17, manufacturer_str, type17.manufacturer);
-    SMBIOS_TABLE_SET_STR(17, serial_number_str, type17.serial);
-    SMBIOS_TABLE_SET_STR(17, asset_tag_number_str, type17.asset);
-    SMBIOS_TABLE_SET_STR(17, part_number_str, type17.part);
-    t->attributes = 0; /* Unknown */
-    t->configured_clock_speed = t->speed; /* reuse value for max speed */
-    t->minimum_voltage = cpu_to_le16(0); /* Unknown */
-    t->maximum_voltage = cpu_to_le16(0); /* Unknown */
-    t->configured_voltage = cpu_to_le16(0); /* Unknown */
-
-    SMBIOS_BUILD_TABLE_POST;
-}
-
-static void smbios_build_type_19_table(unsigned instance,
-                                       uint64_t start, uint64_t size)
-{
-    uint64_t end, start_kb, end_kb;
-
-    SMBIOS_BUILD_TABLE_PRE(19, 0x1300 + instance, true); /* required */
-
-    end = start + size - 1;
-    assert(end > start);
-    start_kb = start / ONE_KB;
-    end_kb = end / ONE_KB;
-    if (start_kb < UINT32_MAX && end_kb < UINT32_MAX) {
-        t->starting_address = cpu_to_le32(start_kb);
-        t->ending_address = cpu_to_le32(end_kb);
-        t->extended_starting_address =
-            t->extended_ending_address = cpu_to_le64(0);
-    } else {
-        t->starting_address = t->ending_address = cpu_to_le32(UINT32_MAX);
-        t->extended_starting_address = cpu_to_le64(start);
-        t->extended_ending_address = cpu_to_le64(end);
-    }
-    t->memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */
-    t->partition_width = 1; /* One device per row */
-
-    SMBIOS_BUILD_TABLE_POST;
-}
-
-static void smbios_build_type_32_table(void)
-{
-    SMBIOS_BUILD_TABLE_PRE(32, 0x2000, true); /* required */
-
-    memset(t->reserved, 0, 6);
-    t->boot_status = 0; /* No errors detected */
-
-    SMBIOS_BUILD_TABLE_POST;
-}
-
-static void smbios_build_type_127_table(void)
-{
-    SMBIOS_BUILD_TABLE_PRE(127, 0x7F00, true); /* required */
-    SMBIOS_BUILD_TABLE_POST;
-}
-
-void smbios_set_cpuid(uint32_t version, uint32_t features)
-{
-    smbios_cpuid_version = version;
-    smbios_cpuid_features = features;
-}
-
-#define SMBIOS_SET_DEFAULT(field, value)                                  \
-    if (!field) {                                                         \
-        field = value;                                                    \
-    }
-
-void smbios_set_defaults(const char *manufacturer, const char *product,
-                         const char *version, bool legacy_mode,
-                         bool uuid_encoded)
-{
-    smbios_have_defaults = true;
-    smbios_legacy = legacy_mode;
-    smbios_uuid_encoded = uuid_encoded;
-
-    /* drop unwanted version of command-line file blob(s) */
-    if (smbios_legacy) {
-        g_free(smbios_tables);
-        /* in legacy mode, also complain if fields were given for types > 1 */
-        if (find_next_bit(have_fields_bitmap,
-                          SMBIOS_MAX_TYPE+1, 2) < SMBIOS_MAX_TYPE+1) {
-            error_report("can't process fields for smbios "
-                         "types > 1 on machine versions < 2.1!");
-            exit(1);
-        }
-    } else {
-        g_free(smbios_entries);
-    }
-
-    SMBIOS_SET_DEFAULT(type1.manufacturer, manufacturer);
-    SMBIOS_SET_DEFAULT(type1.product, product);
-    SMBIOS_SET_DEFAULT(type1.version, version);
-    SMBIOS_SET_DEFAULT(type2.manufacturer, manufacturer);
-    SMBIOS_SET_DEFAULT(type2.product, product);
-    SMBIOS_SET_DEFAULT(type2.version, version);
-    SMBIOS_SET_DEFAULT(type3.manufacturer, manufacturer);
-    SMBIOS_SET_DEFAULT(type3.version, version);
-    SMBIOS_SET_DEFAULT(type4.sock_pfx, "CPU");
-    SMBIOS_SET_DEFAULT(type4.manufacturer, manufacturer);
-    SMBIOS_SET_DEFAULT(type4.version, version);
-    SMBIOS_SET_DEFAULT(type17.loc_pfx, "DIMM");
-    SMBIOS_SET_DEFAULT(type17.manufacturer, manufacturer);
-}
-
-static void smbios_entry_point_setup(void)
-{
-    memcpy(ep.anchor_string, "_SM_", 4);
-    memcpy(ep.intermediate_anchor_string, "_DMI_", 5);
-    ep.length = sizeof(struct smbios_entry_point);
-    ep.entry_point_revision = 0; /* formatted_area reserved, per spec v2.1+ */
-    memset(ep.formatted_area, 0, 5);
-
-    /* compliant with smbios spec v2.8 */
-    ep.smbios_major_version = 2;
-    ep.smbios_minor_version = 8;
-    ep.smbios_bcd_revision = 0x28;
-
-    /* set during table construction, but BIOS may override: */
-    ep.structure_table_length = cpu_to_le16(smbios_tables_len);
-    ep.max_structure_size = cpu_to_le16(smbios_table_max);
-    ep.number_of_structures = cpu_to_le16(smbios_table_cnt);
-
-    /* BIOS must recalculate: */
-    ep.checksum = 0;
-    ep.intermediate_checksum = 0;
-    ep.structure_table_address = cpu_to_le32(0);
-}
-
-void smbios_get_tables(const struct smbios_phys_mem_area *mem_array,
-                       const unsigned int mem_array_size,
-                       const ram_addr_t ram_size,
-                       uint8_t **tables, size_t *tables_len,
-                       uint8_t **anchor, size_t *anchor_len)
-{
-    unsigned i, dimm_cnt;
-
-    if (smbios_legacy) {
-        *tables = *anchor = NULL;
-        *tables_len = *anchor_len = 0;
-        return;
-    }
-
-    if (!smbios_immutable) {
-        smbios_build_type_0_table();
-        smbios_build_type_1_table();
-        smbios_build_type_2_table();
-        smbios_build_type_3_table();
-
-        smbios_smp_sockets = DIV_ROUND_UP(smp_cpus, smp_cores * smp_threads);
-        assert(smbios_smp_sockets >= 1);
-
-        for (i = 0; i < smbios_smp_sockets; i++) {
-            smbios_build_type_4_table(i);
-        }
-
-#define MAX_DIMM_SZ (16ll * ONE_GB)
-#define GET_DIMM_SZ ((i < dimm_cnt - 1) ? MAX_DIMM_SZ \
-                                        : ((ram_size - 1) % MAX_DIMM_SZ) + 1)
-
-        dimm_cnt = QEMU_ALIGN_UP(ram_size, MAX_DIMM_SZ) / MAX_DIMM_SZ;
-
-        smbios_build_type_16_table(dimm_cnt, ram_size);
-
-        for (i = 0; i < dimm_cnt; i++) {
-            smbios_build_type_17_table(i, GET_DIMM_SZ);
-        }
-
-        for (i = 0; i < mem_array_size; i++) {
-            smbios_build_type_19_table(i, mem_array[i].address,
-                                       mem_array[i].length);
-        }
-
-        smbios_build_type_32_table();
-        smbios_build_type_127_table();
-
-        smbios_validate_table();
-        smbios_entry_point_setup();
-        smbios_immutable = true;
-    }
-
-    /* return tables blob and entry point (anchor), and their sizes */
-    *tables = smbios_tables;
-    *tables_len = smbios_tables_len;
-    *anchor = (uint8_t *)&ep;
-    *anchor_len = sizeof(struct smbios_entry_point);
-}
-
-static void save_opt(const char **dest, QemuOpts *opts, const char *name)
-{
-    const char *val = qemu_opt_get(opts, name);
-
-    if (val) {
-        *dest = val;
-    }
-}
-
-void smbios_entry_add(QemuOpts *opts)
-{
-    Error *local_err = NULL;
-    const char *val;
-
-    assert(!smbios_immutable);
-
-    val = qemu_opt_get(opts, "file");
-    if (val) {
-        struct smbios_structure_header *header;
-        int size;
-        struct smbios_table *table; /* legacy mode only */
-
-        qemu_opts_validate(opts, qemu_smbios_file_opts, &local_err);
-        if (local_err) {
-            error_report_err(local_err);
-            exit(1);
-        }
-
-        size = get_image_size(val);
-        if (size == -1 || size < sizeof(struct smbios_structure_header)) {
-            error_report("Cannot read SMBIOS file %s", val);
-            exit(1);
-        }
-
-        /*
-         * NOTE: standard double '\0' terminator expected, per smbios spec.
-         * (except in legacy mode, where the second '\0' is implicit and
-         *  will be inserted by the BIOS).
-         */
-        smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size);
-        header = (struct smbios_structure_header *)(smbios_tables +
-                                                    smbios_tables_len);
-
-        if (load_image(val, (uint8_t *)header) != size) {
-            error_report("Failed to load SMBIOS file %s", val);
-            exit(1);
-        }
-
-        if (test_bit(header->type, have_fields_bitmap)) {
-            error_report("can't load type %d struct, fields already specified!",
-                         header->type);
-            exit(1);
-        }
-        set_bit(header->type, have_binfile_bitmap);
-
-        if (header->type == 4) {
-            smbios_type4_count++;
-        }
-
-        smbios_tables_len += size;
-        if (size > smbios_table_max) {
-            smbios_table_max = size;
-        }
-        smbios_table_cnt++;
-
-        /* add a copy of the newly loaded blob to legacy smbios_entries */
-        /* NOTE: This code runs before smbios_set_defaults(), so we don't
-         *       yet know which mode (legacy vs. aggregate-table) will be
-         *       required. We therefore add the binary blob to both legacy
-         *       (smbios_entries) and aggregate (smbios_tables) tables, and
-         *       delete the one we don't need from smbios_set_defaults(),
-         *       once we know which machine version has been requested.
-         */
-        if (!smbios_entries) {
-            smbios_entries_len = sizeof(uint16_t);
-            smbios_entries = g_malloc0(smbios_entries_len);
-        }
-        smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
-                                                   size + sizeof(*table));
-        table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
-        table->header.type = SMBIOS_TABLE_ENTRY;
-        table->header.length = cpu_to_le16(sizeof(*table) + size);
-        memcpy(table->data, header, size);
-        smbios_entries_len += sizeof(*table) + size;
-        (*(uint16_t *)smbios_entries) =
-                cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
-        /* end: add a copy of the newly loaded blob to legacy smbios_entries */
-
-        return;
-    }
-
-    val = qemu_opt_get(opts, "type");
-    if (val) {
-        unsigned long type = strtoul(val, NULL, 0);
-
-        if (type > SMBIOS_MAX_TYPE) {
-            error_report("out of range!");
-            exit(1);
-        }
-
-        if (test_bit(type, have_binfile_bitmap)) {
-            error_report("can't add fields, binary file already loaded!");
-            exit(1);
-        }
-        set_bit(type, have_fields_bitmap);
-
-        switch (type) {
-        case 0:
-            qemu_opts_validate(opts, qemu_smbios_type0_opts, &local_err);
-            if (local_err) {
-                error_report_err(local_err);
-                exit(1);
-            }
-            save_opt(&type0.vendor, opts, "vendor");
-            save_opt(&type0.version, opts, "version");
-            save_opt(&type0.date, opts, "date");
-            type0.uefi = qemu_opt_get_bool(opts, "uefi", false);
-
-            val = qemu_opt_get(opts, "release");
-            if (val) {
-                if (sscanf(val, "%hhu.%hhu", &type0.major, &type0.minor) != 2) {
-                    error_report("Invalid release");
-                    exit(1);
-                }
-                type0.have_major_minor = true;
-            }
-            return;
-        case 1:
-            qemu_opts_validate(opts, qemu_smbios_type1_opts, &local_err);
-            if (local_err) {
-                error_report_err(local_err);
-                exit(1);
-            }
-            save_opt(&type1.manufacturer, opts, "manufacturer");
-            save_opt(&type1.product, opts, "product");
-            save_opt(&type1.version, opts, "version");
-            save_opt(&type1.serial, opts, "serial");
-            save_opt(&type1.sku, opts, "sku");
-            save_opt(&type1.family, opts, "family");
-
-            val = qemu_opt_get(opts, "uuid");
-            if (val) {
-                if (qemu_uuid_parse(val, qemu_uuid) != 0) {
-                    error_report("Invalid UUID");
-                    exit(1);
-                }
-                qemu_uuid_set = true;
-            }
-            return;
-        case 2:
-            qemu_opts_validate(opts, qemu_smbios_type2_opts, &local_err);
-            if (local_err) {
-                error_report_err(local_err);
-                exit(1);
-            }
-            save_opt(&type2.manufacturer, opts, "manufacturer");
-            save_opt(&type2.product, opts, "product");
-            save_opt(&type2.version, opts, "version");
-            save_opt(&type2.serial, opts, "serial");
-            save_opt(&type2.asset, opts, "asset");
-            save_opt(&type2.location, opts, "location");
-            return;
-        case 3:
-            qemu_opts_validate(opts, qemu_smbios_type3_opts, &local_err);
-            if (local_err) {
-                error_report_err(local_err);
-                exit(1);
-            }
-            save_opt(&type3.manufacturer, opts, "manufacturer");
-            save_opt(&type3.version, opts, "version");
-            save_opt(&type3.serial, opts, "serial");
-            save_opt(&type3.asset, opts, "asset");
-            save_opt(&type3.sku, opts, "sku");
-            return;
-        case 4:
-            qemu_opts_validate(opts, qemu_smbios_type4_opts, &local_err);
-            if (local_err) {
-                error_report_err(local_err);
-                exit(1);
-            }
-            save_opt(&type4.sock_pfx, opts, "sock_pfx");
-            save_opt(&type4.manufacturer, opts, "manufacturer");
-            save_opt(&type4.version, opts, "version");
-            save_opt(&type4.serial, opts, "serial");
-            save_opt(&type4.asset, opts, "asset");
-            save_opt(&type4.part, opts, "part");
-            return;
-        case 17:
-            qemu_opts_validate(opts, qemu_smbios_type17_opts, &local_err);
-            if (local_err) {
-                error_report_err(local_err);
-                exit(1);
-            }
-            save_opt(&type17.loc_pfx, opts, "loc_pfx");
-            save_opt(&type17.bank, opts, "bank");
-            save_opt(&type17.manufacturer, opts, "manufacturer");
-            save_opt(&type17.serial, opts, "serial");
-            save_opt(&type17.asset, opts, "asset");
-            save_opt(&type17.part, opts, "part");
-            type17.speed = qemu_opt_get_number(opts, "speed", 0);
-            return;
-        default:
-            error_report("Don't know how to build fields for SMBIOS type %ld",
-                         type);
-            exit(1);
-        }
-    }
-
-    error_report("Must specify type= or file=");
-    exit(1);
-}
diff --git a/hw/smbios/Makefile.objs b/hw/smbios/Makefile.objs
new file mode 100644
index 0000000..f69a92f
--- /dev/null
+++ b/hw/smbios/Makefile.objs
@@ -0,0 +1 @@
+common-obj-$(CONFIG_SMBIOS) += smbios.o
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
new file mode 100644
index 0000000..08ba62a
--- /dev/null
+++ b/hw/smbios/smbios.c
@@ -0,0 +1,1102 @@
+/*
+ * SMBIOS Support
+ *
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * Authors:
+ *  Alex Williamson <alex.williamson@hp.com>
+ *  Markus Armbruster <armbru@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu/config-file.h"
+#include "qemu/error-report.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/cpus.h"
+#include "hw/smbios/smbios.h"
+#include "hw/loader.h"
+#include "exec/cpu-common.h"
+
+/* legacy structures and constants for <= 2.0 machines */
+struct smbios_header {
+    uint16_t length;
+    uint8_t type;
+} QEMU_PACKED;
+
+struct smbios_field {
+    struct smbios_header header;
+    uint8_t type;
+    uint16_t offset;
+    uint8_t data[];
+} QEMU_PACKED;
+
+struct smbios_table {
+    struct smbios_header header;
+    uint8_t data[];
+} QEMU_PACKED;
+
+#define SMBIOS_FIELD_ENTRY 0
+#define SMBIOS_TABLE_ENTRY 1
+
+static uint8_t *smbios_entries;
+static size_t smbios_entries_len;
+static bool smbios_legacy = true;
+static bool smbios_uuid_encoded = true;
+/* end: legacy structures & constants for <= 2.0 machines */
+
+
+static uint8_t *smbios_tables;
+static size_t smbios_tables_len;
+static unsigned smbios_table_max;
+static unsigned smbios_table_cnt;
+static struct smbios_entry_point ep;
+
+static int smbios_type4_count = 0;
+static bool smbios_immutable;
+static bool smbios_have_defaults;
+static uint32_t smbios_cpuid_version, smbios_cpuid_features, smbios_smp_sockets;
+
+static DECLARE_BITMAP(have_binfile_bitmap, SMBIOS_MAX_TYPE+1);
+static DECLARE_BITMAP(have_fields_bitmap, SMBIOS_MAX_TYPE+1);
+
+static struct {
+    const char *vendor, *version, *date;
+    bool have_major_minor, uefi;
+    uint8_t major, minor;
+} type0;
+
+static struct {
+    const char *manufacturer, *product, *version, *serial, *sku, *family;
+    /* uuid is in qemu_uuid[] */
+} type1;
+
+static struct {
+    const char *manufacturer, *product, *version, *serial, *asset, *location;
+} type2;
+
+static struct {
+    const char *manufacturer, *version, *serial, *asset, *sku;
+} type3;
+
+static struct {
+    const char *sock_pfx, *manufacturer, *version, *serial, *asset, *part;
+} type4;
+
+static struct {
+    const char *loc_pfx, *bank, *manufacturer, *serial, *asset, *part;
+    uint16_t speed;
+} type17;
+
+static QemuOptsList qemu_smbios_opts = {
+    .name = "smbios",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head),
+    .desc = {
+        /*
+         * no elements => accept any params
+         * validation will happen later
+         */
+        { /* end of list */ }
+    }
+};
+
+static const QemuOptDesc qemu_smbios_file_opts[] = {
+    {
+        .name = "file",
+        .type = QEMU_OPT_STRING,
+        .help = "binary file containing an SMBIOS element",
+    },
+    { /* end of list */ }
+};
+
+static const QemuOptDesc qemu_smbios_type0_opts[] = {
+    {
+        .name = "type",
+        .type = QEMU_OPT_NUMBER,
+        .help = "SMBIOS element type",
+    },{
+        .name = "vendor",
+        .type = QEMU_OPT_STRING,
+        .help = "vendor name",
+    },{
+        .name = "version",
+        .type = QEMU_OPT_STRING,
+        .help = "version number",
+    },{
+        .name = "date",
+        .type = QEMU_OPT_STRING,
+        .help = "release date",
+    },{
+        .name = "release",
+        .type = QEMU_OPT_STRING,
+        .help = "revision number",
+    },{
+        .name = "uefi",
+        .type = QEMU_OPT_BOOL,
+        .help = "uefi support",
+    },
+    { /* end of list */ }
+};
+
+static const QemuOptDesc qemu_smbios_type1_opts[] = {
+    {
+        .name = "type",
+        .type = QEMU_OPT_NUMBER,
+        .help = "SMBIOS element type",
+    },{
+        .name = "manufacturer",
+        .type = QEMU_OPT_STRING,
+        .help = "manufacturer name",
+    },{
+        .name = "product",
+        .type = QEMU_OPT_STRING,
+        .help = "product name",
+    },{
+        .name = "version",
+        .type = QEMU_OPT_STRING,
+        .help = "version number",
+    },{
+        .name = "serial",
+        .type = QEMU_OPT_STRING,
+        .help = "serial number",
+    },{
+        .name = "uuid",
+        .type = QEMU_OPT_STRING,
+        .help = "UUID",
+    },{
+        .name = "sku",
+        .type = QEMU_OPT_STRING,
+        .help = "SKU number",
+    },{
+        .name = "family",
+        .type = QEMU_OPT_STRING,
+        .help = "family name",
+    },
+    { /* end of list */ }
+};
+
+static const QemuOptDesc qemu_smbios_type2_opts[] = {
+    {
+        .name = "type",
+        .type = QEMU_OPT_NUMBER,
+        .help = "SMBIOS element type",
+    },{
+        .name = "manufacturer",
+        .type = QEMU_OPT_STRING,
+        .help = "manufacturer name",
+    },{
+        .name = "product",
+        .type = QEMU_OPT_STRING,
+        .help = "product name",
+    },{
+        .name = "version",
+        .type = QEMU_OPT_STRING,
+        .help = "version number",
+    },{
+        .name = "serial",
+        .type = QEMU_OPT_STRING,
+        .help = "serial number",
+    },{
+        .name = "asset",
+        .type = QEMU_OPT_STRING,
+        .help = "asset tag number",
+    },{
+        .name = "location",
+        .type = QEMU_OPT_STRING,
+        .help = "location in chassis",
+    },
+    { /* end of list */ }
+};
+
+static const QemuOptDesc qemu_smbios_type3_opts[] = {
+    {
+        .name = "type",
+        .type = QEMU_OPT_NUMBER,
+        .help = "SMBIOS element type",
+    },{
+        .name = "manufacturer",
+        .type = QEMU_OPT_STRING,
+        .help = "manufacturer name",
+    },{
+        .name = "version",
+        .type = QEMU_OPT_STRING,
+        .help = "version number",
+    },{
+        .name = "serial",
+        .type = QEMU_OPT_STRING,
+        .help = "serial number",
+    },{
+        .name = "asset",
+        .type = QEMU_OPT_STRING,
+        .help = "asset tag number",
+    },{
+        .name = "sku",
+        .type = QEMU_OPT_STRING,
+        .help = "SKU number",
+    },
+    { /* end of list */ }
+};
+
+static const QemuOptDesc qemu_smbios_type4_opts[] = {
+    {
+        .name = "type",
+        .type = QEMU_OPT_NUMBER,
+        .help = "SMBIOS element type",
+    },{
+        .name = "sock_pfx",
+        .type = QEMU_OPT_STRING,
+        .help = "socket designation string prefix",
+    },{
+        .name = "manufacturer",
+        .type = QEMU_OPT_STRING,
+        .help = "manufacturer name",
+    },{
+        .name = "version",
+        .type = QEMU_OPT_STRING,
+        .help = "version number",
+    },{
+        .name = "serial",
+        .type = QEMU_OPT_STRING,
+        .help = "serial number",
+    },{
+        .name = "asset",
+        .type = QEMU_OPT_STRING,
+        .help = "asset tag number",
+    },{
+        .name = "part",
+        .type = QEMU_OPT_STRING,
+        .help = "part number",
+    },
+    { /* end of list */ }
+};
+
+static const QemuOptDesc qemu_smbios_type17_opts[] = {
+    {
+        .name = "type",
+        .type = QEMU_OPT_NUMBER,
+        .help = "SMBIOS element type",
+    },{
+        .name = "loc_pfx",
+        .type = QEMU_OPT_STRING,
+        .help = "device locator string prefix",
+    },{
+        .name = "bank",
+        .type = QEMU_OPT_STRING,
+        .help = "bank locator string",
+    },{
+        .name = "manufacturer",
+        .type = QEMU_OPT_STRING,
+        .help = "manufacturer name",
+    },{
+        .name = "serial",
+        .type = QEMU_OPT_STRING,
+        .help = "serial number",
+    },{
+        .name = "asset",
+        .type = QEMU_OPT_STRING,
+        .help = "asset tag number",
+    },{
+        .name = "part",
+        .type = QEMU_OPT_STRING,
+        .help = "part number",
+    },{
+        .name = "speed",
+        .type = QEMU_OPT_NUMBER,
+        .help = "maximum capable speed",
+    },
+    { /* end of list */ }
+};
+
+static void smbios_register_config(void)
+{
+    qemu_add_opts(&qemu_smbios_opts);
+}
+
+machine_init(smbios_register_config);
+
+static void smbios_validate_table(void)
+{
+    uint32_t expect_t4_count = smbios_legacy ? smp_cpus : smbios_smp_sockets;
+
+    if (smbios_type4_count && smbios_type4_count != expect_t4_count) {
+        error_report("Expected %d SMBIOS Type 4 tables, got %d instead",
+                     expect_t4_count, smbios_type4_count);
+        exit(1);
+    }
+}
+
+
+/* legacy setup functions for <= 2.0 machines */
+static void smbios_add_field(int type, int offset, const void *data, size_t len)
+{
+    struct smbios_field *field;
+
+    if (!smbios_entries) {
+        smbios_entries_len = sizeof(uint16_t);
+        smbios_entries = g_malloc0(smbios_entries_len);
+    }
+    smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
+                                                  sizeof(*field) + len);
+    field = (struct smbios_field *)(smbios_entries + smbios_entries_len);
+    field->header.type = SMBIOS_FIELD_ENTRY;
+    field->header.length = cpu_to_le16(sizeof(*field) + len);
+
+    field->type = type;
+    field->offset = cpu_to_le16(offset);
+    memcpy(field->data, data, len);
+
+    smbios_entries_len += sizeof(*field) + len;
+    (*(uint16_t *)smbios_entries) =
+            cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
+}
+
+static void smbios_maybe_add_str(int type, int offset, const char *data)
+{
+    if (data) {
+        smbios_add_field(type, offset, data, strlen(data) + 1);
+    }
+}
+
+static void smbios_build_type_0_fields(void)
+{
+    smbios_maybe_add_str(0, offsetof(struct smbios_type_0, vendor_str),
+                         type0.vendor);
+    smbios_maybe_add_str(0, offsetof(struct smbios_type_0, bios_version_str),
+                         type0.version);
+    smbios_maybe_add_str(0, offsetof(struct smbios_type_0,
+                                     bios_release_date_str),
+                         type0.date);
+    if (type0.have_major_minor) {
+        smbios_add_field(0, offsetof(struct smbios_type_0,
+                                     system_bios_major_release),
+                         &type0.major, 1);
+        smbios_add_field(0, offsetof(struct smbios_type_0,
+                                     system_bios_minor_release),
+                         &type0.minor, 1);
+    }
+}
+
+static void smbios_build_type_1_fields(void)
+{
+    smbios_maybe_add_str(1, offsetof(struct smbios_type_1, manufacturer_str),
+                         type1.manufacturer);
+    smbios_maybe_add_str(1, offsetof(struct smbios_type_1, product_name_str),
+                         type1.product);
+    smbios_maybe_add_str(1, offsetof(struct smbios_type_1, version_str),
+                         type1.version);
+    smbios_maybe_add_str(1, offsetof(struct smbios_type_1, serial_number_str),
+                         type1.serial);
+    smbios_maybe_add_str(1, offsetof(struct smbios_type_1, sku_number_str),
+                         type1.sku);
+    smbios_maybe_add_str(1, offsetof(struct smbios_type_1, family_str),
+                         type1.family);
+    if (qemu_uuid_set) {
+        /* We don't encode the UUID in the "wire format" here because this
+         * function is for legacy mode and needs to keep the guest ABI, and
+         * because we don't know what's the SMBIOS version advertised by the
+         * BIOS.
+         */
+        smbios_add_field(1, offsetof(struct smbios_type_1, uuid),
+                         qemu_uuid, 16);
+    }
+}
+
+uint8_t *smbios_get_table_legacy(size_t *length)
+{
+    if (!smbios_legacy) {
+        *length = 0;
+        return NULL;
+    }
+
+    if (!smbios_immutable) {
+        smbios_build_type_0_fields();
+        smbios_build_type_1_fields();
+        smbios_validate_table();
+        smbios_immutable = true;
+    }
+    *length = smbios_entries_len;
+    return smbios_entries;
+}
+/* end: legacy setup functions for <= 2.0 machines */
+
+
+static bool smbios_skip_table(uint8_t type, bool required_table)
+{
+    if (test_bit(type, have_binfile_bitmap)) {
+        return true; /* user provided their own binary blob(s) */
+    }
+    if (test_bit(type, have_fields_bitmap)) {
+        return false; /* user provided fields via command line */
+    }
+    if (smbios_have_defaults && required_table) {
+        return false; /* we're building tables, and this one's required */
+    }
+    return true;
+}
+
+#define SMBIOS_BUILD_TABLE_PRE(tbl_type, tbl_handle, tbl_required)        \
+    struct smbios_type_##tbl_type *t;                                     \
+    size_t t_off; /* table offset into smbios_tables */                   \
+    int str_index = 0;                                                    \
+    do {                                                                  \
+        /* should we skip building this table ? */                        \
+        if (smbios_skip_table(tbl_type, tbl_required)) {                  \
+            return;                                                       \
+        }                                                                 \
+                                                                          \
+        /* use offset of table t within smbios_tables */                  \
+        /* (pointer must be updated after each realloc) */                \
+        t_off = smbios_tables_len;                                        \
+        smbios_tables_len += sizeof(*t);                                  \
+        smbios_tables = g_realloc(smbios_tables, smbios_tables_len);      \
+        t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off);     \
+                                                                          \
+        t->header.type = tbl_type;                                        \
+        t->header.length = sizeof(*t);                                    \
+        t->header.handle = cpu_to_le16(tbl_handle);                       \
+    } while (0)
+
+#define SMBIOS_TABLE_SET_STR(tbl_type, field, value)                      \
+    do {                                                                  \
+        int len = (value != NULL) ? strlen(value) + 1 : 0;                \
+        if (len > 1) {                                                    \
+            smbios_tables = g_realloc(smbios_tables,                      \
+                                      smbios_tables_len + len);           \
+            memcpy(smbios_tables + smbios_tables_len, value, len);        \
+            smbios_tables_len += len;                                     \
+            /* update pointer post-realloc */                             \
+            t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \
+            t->field = ++str_index;                                       \
+        } else {                                                          \
+            t->field = 0;                                                 \
+        }                                                                 \
+    } while (0)
+
+#define SMBIOS_BUILD_TABLE_POST                                           \
+    do {                                                                  \
+        size_t term_cnt, t_size;                                          \
+                                                                          \
+        /* add '\0' terminator (add two if no strings defined) */         \
+        term_cnt = (str_index == 0) ? 2 : 1;                              \
+        smbios_tables = g_realloc(smbios_tables,                          \
+                                  smbios_tables_len + term_cnt);          \
+        memset(smbios_tables + smbios_tables_len, 0, term_cnt);           \
+        smbios_tables_len += term_cnt;                                    \
+                                                                          \
+        /* update smbios max. element size */                             \
+        t_size = smbios_tables_len - t_off;                               \
+        if (t_size > smbios_table_max) {                                  \
+            smbios_table_max = t_size;                                    \
+        }                                                                 \
+                                                                          \
+        /* update smbios element count */                                 \
+        smbios_table_cnt++;                                               \
+    } while (0)
+
+static void smbios_build_type_0_table(void)
+{
+    SMBIOS_BUILD_TABLE_PRE(0, 0x000, false); /* optional, leave up to BIOS */
+
+    SMBIOS_TABLE_SET_STR(0, vendor_str, type0.vendor);
+    SMBIOS_TABLE_SET_STR(0, bios_version_str, type0.version);
+
+    t->bios_starting_address_segment = cpu_to_le16(0xE800); /* from SeaBIOS */
+
+    SMBIOS_TABLE_SET_STR(0, bios_release_date_str, type0.date);
+
+    t->bios_rom_size = 0; /* hardcoded in SeaBIOS with FIXME comment */
+
+    t->bios_characteristics = cpu_to_le64(0x08); /* Not supported */
+    t->bios_characteristics_extension_bytes[0] = 0;
+    t->bios_characteristics_extension_bytes[1] = 0x14; /* TCD/SVVP | VM */
+    if (type0.uefi) {
+        t->bios_characteristics_extension_bytes[1] |= 0x08; /* |= UEFI */
+    }
+
+    if (type0.have_major_minor) {
+        t->system_bios_major_release = type0.major;
+        t->system_bios_minor_release = type0.minor;
+    } else {
+        t->system_bios_major_release = 0;
+        t->system_bios_minor_release = 0;
+    }
+
+    /* hardcoded in SeaBIOS */
+    t->embedded_controller_major_release = 0xFF;
+    t->embedded_controller_minor_release = 0xFF;
+
+    SMBIOS_BUILD_TABLE_POST;
+}
+
+/* Encode UUID from the big endian encoding described on RFC4122 to the wire
+ * format specified by SMBIOS version 2.6.
+ */
+static void smbios_encode_uuid(struct smbios_uuid *uuid, const uint8_t *buf)
+{
+    memcpy(uuid, buf, 16);
+    if (smbios_uuid_encoded) {
+        uuid->time_low = bswap32(uuid->time_low);
+        uuid->time_mid = bswap16(uuid->time_mid);
+        uuid->time_hi_and_version = bswap16(uuid->time_hi_and_version);
+    }
+}
+
+static void smbios_build_type_1_table(void)
+{
+    SMBIOS_BUILD_TABLE_PRE(1, 0x100, true); /* required */
+
+    SMBIOS_TABLE_SET_STR(1, manufacturer_str, type1.manufacturer);
+    SMBIOS_TABLE_SET_STR(1, product_name_str, type1.product);
+    SMBIOS_TABLE_SET_STR(1, version_str, type1.version);
+    SMBIOS_TABLE_SET_STR(1, serial_number_str, type1.serial);
+    if (qemu_uuid_set) {
+        smbios_encode_uuid(&t->uuid, qemu_uuid);
+    } else {
+        memset(&t->uuid, 0, 16);
+    }
+    t->wake_up_type = 0x06; /* power switch */
+    SMBIOS_TABLE_SET_STR(1, sku_number_str, type1.sku);
+    SMBIOS_TABLE_SET_STR(1, family_str, type1.family);
+
+    SMBIOS_BUILD_TABLE_POST;
+}
+
+static void smbios_build_type_2_table(void)
+{
+    SMBIOS_BUILD_TABLE_PRE(2, 0x200, false); /* optional */
+
+    SMBIOS_TABLE_SET_STR(2, manufacturer_str, type2.manufacturer);
+    SMBIOS_TABLE_SET_STR(2, product_str, type2.product);
+    SMBIOS_TABLE_SET_STR(2, version_str, type2.version);
+    SMBIOS_TABLE_SET_STR(2, serial_number_str, type2.serial);
+    SMBIOS_TABLE_SET_STR(2, asset_tag_number_str, type2.asset);
+    t->feature_flags = 0x01; /* Motherboard */
+    SMBIOS_TABLE_SET_STR(2, location_str, type2.location);
+    t->chassis_handle = cpu_to_le16(0x300); /* Type 3 (System enclosure) */
+    t->board_type = 0x0A; /* Motherboard */
+    t->contained_element_count = 0;
+
+    SMBIOS_BUILD_TABLE_POST;
+}
+
+static void smbios_build_type_3_table(void)
+{
+    SMBIOS_BUILD_TABLE_PRE(3, 0x300, true); /* required */
+
+    SMBIOS_TABLE_SET_STR(3, manufacturer_str, type3.manufacturer);
+    t->type = 0x01; /* Other */
+    SMBIOS_TABLE_SET_STR(3, version_str, type3.version);
+    SMBIOS_TABLE_SET_STR(3, serial_number_str, type3.serial);
+    SMBIOS_TABLE_SET_STR(3, asset_tag_number_str, type3.asset);
+    t->boot_up_state = 0x03; /* Safe */
+    t->power_supply_state = 0x03; /* Safe */
+    t->thermal_state = 0x03; /* Safe */
+    t->security_status = 0x02; /* Unknown */
+    t->oem_defined = cpu_to_le32(0);
+    t->height = 0;
+    t->number_of_power_cords = 0;
+    t->contained_element_count = 0;
+    SMBIOS_TABLE_SET_STR(3, sku_number_str, type3.sku);
+
+    SMBIOS_BUILD_TABLE_POST;
+}
+
+static void smbios_build_type_4_table(unsigned instance)
+{
+    char sock_str[128];
+
+    SMBIOS_BUILD_TABLE_PRE(4, 0x400 + instance, true); /* required */
+
+    snprintf(sock_str, sizeof(sock_str), "%s%2x", type4.sock_pfx, instance);
+    SMBIOS_TABLE_SET_STR(4, socket_designation_str, sock_str);
+    t->processor_type = 0x03; /* CPU */
+    t->processor_family = 0x01; /* Other */
+    SMBIOS_TABLE_SET_STR(4, processor_manufacturer_str, type4.manufacturer);
+    t->processor_id[0] = cpu_to_le32(smbios_cpuid_version);
+    t->processor_id[1] = cpu_to_le32(smbios_cpuid_features);
+    SMBIOS_TABLE_SET_STR(4, processor_version_str, type4.version);
+    t->voltage = 0;
+    t->external_clock = cpu_to_le16(0); /* Unknown */
+    /* SVVP requires max_speed and current_speed to not be unknown. */
+    t->max_speed = cpu_to_le16(2000); /* 2000 MHz */
+    t->current_speed = cpu_to_le16(2000); /* 2000 MHz */
+    t->status = 0x41; /* Socket populated, CPU enabled */
+    t->processor_upgrade = 0x01; /* Other */
+    t->l1_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
+    t->l2_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
+    t->l3_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
+    SMBIOS_TABLE_SET_STR(4, serial_number_str, type4.serial);
+    SMBIOS_TABLE_SET_STR(4, asset_tag_number_str, type4.asset);
+    SMBIOS_TABLE_SET_STR(4, part_number_str, type4.part);
+    t->core_count = t->core_enabled = smp_cores;
+    t->thread_count = smp_threads;
+    t->processor_characteristics = cpu_to_le16(0x02); /* Unknown */
+    t->processor_family2 = cpu_to_le16(0x01); /* Other */
+
+    SMBIOS_BUILD_TABLE_POST;
+    smbios_type4_count++;
+}
+
+#define ONE_KB ((ram_addr_t)1 << 10)
+#define ONE_MB ((ram_addr_t)1 << 20)
+#define ONE_GB ((ram_addr_t)1 << 30)
+
+#define MAX_T16_STD_SZ 0x80000000 /* 2T in Kilobytes */
+
+static void smbios_build_type_16_table(unsigned dimm_cnt, ram_addr_t ram_size)
+{
+    uint64_t size_kb;
+
+    SMBIOS_BUILD_TABLE_PRE(16, 0x1000, true); /* required */
+
+    t->location = 0x01; /* Other */
+    t->use = 0x03; /* System memory */
+    t->error_correction = 0x06; /* Multi-bit ECC (for Microsoft, per SeaBIOS) */
+    size_kb = QEMU_ALIGN_UP(ram_size, ONE_KB) / ONE_KB;
+    if (size_kb < MAX_T16_STD_SZ) {
+        t->maximum_capacity = cpu_to_le32(size_kb);
+        t->extended_maximum_capacity = cpu_to_le64(0);
+    } else {
+        t->maximum_capacity = cpu_to_le32(MAX_T16_STD_SZ);
+        t->extended_maximum_capacity = cpu_to_le64(ram_size);
+    }
+    t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */
+    t->number_of_memory_devices = cpu_to_le16(dimm_cnt);
+
+    SMBIOS_BUILD_TABLE_POST;
+}
+
+#define MAX_T17_STD_SZ 0x7FFF /* (32G - 1M), in Megabytes */
+#define MAX_T17_EXT_SZ 0x80000000 /* 2P, in Megabytes */
+
+static void smbios_build_type_17_table(unsigned instance, uint64_t size)
+{
+    char loc_str[128];
+    uint64_t size_mb;
+
+    SMBIOS_BUILD_TABLE_PRE(17, 0x1100 + instance, true); /* required */
+
+    t->physical_memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */
+    t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */
+    t->total_width = cpu_to_le16(0xFFFF); /* Unknown */
+    t->data_width = cpu_to_le16(0xFFFF); /* Unknown */
+    size_mb = QEMU_ALIGN_UP(size, ONE_MB) / ONE_MB;
+    if (size_mb < MAX_T17_STD_SZ) {
+        t->size = cpu_to_le16(size_mb);
+        t->extended_size = cpu_to_le32(0);
+    } else {
+        assert(size_mb < MAX_T17_EXT_SZ);
+        t->size = cpu_to_le16(MAX_T17_STD_SZ);
+        t->extended_size = cpu_to_le32(size_mb);
+    }
+    t->form_factor = 0x09; /* DIMM */
+    t->device_set = 0; /* Not in a set */
+    snprintf(loc_str, sizeof(loc_str), "%s %d", type17.loc_pfx, instance);
+    SMBIOS_TABLE_SET_STR(17, device_locator_str, loc_str);
+    SMBIOS_TABLE_SET_STR(17, bank_locator_str, type17.bank);
+    t->memory_type = 0x07; /* RAM */
+    t->type_detail = cpu_to_le16(0x02); /* Other */
+    t->speed = cpu_to_le16(type17.speed);
+    SMBIOS_TABLE_SET_STR(17, manufacturer_str, type17.manufacturer);
+    SMBIOS_TABLE_SET_STR(17, serial_number_str, type17.serial);
+    SMBIOS_TABLE_SET_STR(17, asset_tag_number_str, type17.asset);
+    SMBIOS_TABLE_SET_STR(17, part_number_str, type17.part);
+    t->attributes = 0; /* Unknown */
+    t->configured_clock_speed = t->speed; /* reuse value for max speed */
+    t->minimum_voltage = cpu_to_le16(0); /* Unknown */
+    t->maximum_voltage = cpu_to_le16(0); /* Unknown */
+    t->configured_voltage = cpu_to_le16(0); /* Unknown */
+
+    SMBIOS_BUILD_TABLE_POST;
+}
+
+static void smbios_build_type_19_table(unsigned instance,
+                                       uint64_t start, uint64_t size)
+{
+    uint64_t end, start_kb, end_kb;
+
+    SMBIOS_BUILD_TABLE_PRE(19, 0x1300 + instance, true); /* required */
+
+    end = start + size - 1;
+    assert(end > start);
+    start_kb = start / ONE_KB;
+    end_kb = end / ONE_KB;
+    if (start_kb < UINT32_MAX && end_kb < UINT32_MAX) {
+        t->starting_address = cpu_to_le32(start_kb);
+        t->ending_address = cpu_to_le32(end_kb);
+        t->extended_starting_address =
+            t->extended_ending_address = cpu_to_le64(0);
+    } else {
+        t->starting_address = t->ending_address = cpu_to_le32(UINT32_MAX);
+        t->extended_starting_address = cpu_to_le64(start);
+        t->extended_ending_address = cpu_to_le64(end);
+    }
+    t->memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */
+    t->partition_width = 1; /* One device per row */
+
+    SMBIOS_BUILD_TABLE_POST;
+}
+
+static void smbios_build_type_32_table(void)
+{
+    SMBIOS_BUILD_TABLE_PRE(32, 0x2000, true); /* required */
+
+    memset(t->reserved, 0, 6);
+    t->boot_status = 0; /* No errors detected */
+
+    SMBIOS_BUILD_TABLE_POST;
+}
+
+static void smbios_build_type_127_table(void)
+{
+    SMBIOS_BUILD_TABLE_PRE(127, 0x7F00, true); /* required */
+    SMBIOS_BUILD_TABLE_POST;
+}
+
+void smbios_set_cpuid(uint32_t version, uint32_t features)
+{
+    smbios_cpuid_version = version;
+    smbios_cpuid_features = features;
+}
+
+#define SMBIOS_SET_DEFAULT(field, value)                                  \
+    if (!field) {                                                         \
+        field = value;                                                    \
+    }
+
+void smbios_set_defaults(const char *manufacturer, const char *product,
+                         const char *version, bool legacy_mode,
+                         bool uuid_encoded)
+{
+    smbios_have_defaults = true;
+    smbios_legacy = legacy_mode;
+    smbios_uuid_encoded = uuid_encoded;
+
+    /* drop unwanted version of command-line file blob(s) */
+    if (smbios_legacy) {
+        g_free(smbios_tables);
+        /* in legacy mode, also complain if fields were given for types > 1 */
+        if (find_next_bit(have_fields_bitmap,
+                          SMBIOS_MAX_TYPE+1, 2) < SMBIOS_MAX_TYPE+1) {
+            error_report("can't process fields for smbios "
+                         "types > 1 on machine versions < 2.1!");
+            exit(1);
+        }
+    } else {
+        g_free(smbios_entries);
+    }
+
+    SMBIOS_SET_DEFAULT(type1.manufacturer, manufacturer);
+    SMBIOS_SET_DEFAULT(type1.product, product);
+    SMBIOS_SET_DEFAULT(type1.version, version);
+    SMBIOS_SET_DEFAULT(type2.manufacturer, manufacturer);
+    SMBIOS_SET_DEFAULT(type2.product, product);
+    SMBIOS_SET_DEFAULT(type2.version, version);
+    SMBIOS_SET_DEFAULT(type3.manufacturer, manufacturer);
+    SMBIOS_SET_DEFAULT(type3.version, version);
+    SMBIOS_SET_DEFAULT(type4.sock_pfx, "CPU");
+    SMBIOS_SET_DEFAULT(type4.manufacturer, manufacturer);
+    SMBIOS_SET_DEFAULT(type4.version, version);
+    SMBIOS_SET_DEFAULT(type17.loc_pfx, "DIMM");
+    SMBIOS_SET_DEFAULT(type17.manufacturer, manufacturer);
+}
+
+static void smbios_entry_point_setup(void)
+{
+    memcpy(ep.anchor_string, "_SM_", 4);
+    memcpy(ep.intermediate_anchor_string, "_DMI_", 5);
+    ep.length = sizeof(struct smbios_entry_point);
+    ep.entry_point_revision = 0; /* formatted_area reserved, per spec v2.1+ */
+    memset(ep.formatted_area, 0, 5);
+
+    /* compliant with smbios spec v2.8 */
+    ep.smbios_major_version = 2;
+    ep.smbios_minor_version = 8;
+    ep.smbios_bcd_revision = 0x28;
+
+    /* set during table construction, but BIOS may override: */
+    ep.structure_table_length = cpu_to_le16(smbios_tables_len);
+    ep.max_structure_size = cpu_to_le16(smbios_table_max);
+    ep.number_of_structures = cpu_to_le16(smbios_table_cnt);
+
+    /* BIOS must recalculate: */
+    ep.checksum = 0;
+    ep.intermediate_checksum = 0;
+    ep.structure_table_address = cpu_to_le32(0);
+}
+
+void smbios_get_tables(const struct smbios_phys_mem_area *mem_array,
+                       const unsigned int mem_array_size,
+                       const ram_addr_t ram_size,
+                       uint8_t **tables, size_t *tables_len,
+                       uint8_t **anchor, size_t *anchor_len)
+{
+    unsigned i, dimm_cnt;
+
+    if (smbios_legacy) {
+        *tables = *anchor = NULL;
+        *tables_len = *anchor_len = 0;
+        return;
+    }
+
+    if (!smbios_immutable) {
+        smbios_build_type_0_table();
+        smbios_build_type_1_table();
+        smbios_build_type_2_table();
+        smbios_build_type_3_table();
+
+        smbios_smp_sockets = DIV_ROUND_UP(smp_cpus, smp_cores * smp_threads);
+        assert(smbios_smp_sockets >= 1);
+
+        for (i = 0; i < smbios_smp_sockets; i++) {
+            smbios_build_type_4_table(i);
+        }
+
+#define MAX_DIMM_SZ (16ll * ONE_GB)
+#define GET_DIMM_SZ ((i < dimm_cnt - 1) ? MAX_DIMM_SZ \
+                                        : ((ram_size - 1) % MAX_DIMM_SZ) + 1)
+
+        dimm_cnt = QEMU_ALIGN_UP(ram_size, MAX_DIMM_SZ) / MAX_DIMM_SZ;
+
+        smbios_build_type_16_table(dimm_cnt, ram_size);
+
+        for (i = 0; i < dimm_cnt; i++) {
+            smbios_build_type_17_table(i, GET_DIMM_SZ);
+        }
+
+        for (i = 0; i < mem_array_size; i++) {
+            smbios_build_type_19_table(i, mem_array[i].address,
+                                       mem_array[i].length);
+        }
+
+        smbios_build_type_32_table();
+        smbios_build_type_127_table();
+
+        smbios_validate_table();
+        smbios_entry_point_setup();
+        smbios_immutable = true;
+    }
+
+    /* return tables blob and entry point (anchor), and their sizes */
+    *tables = smbios_tables;
+    *tables_len = smbios_tables_len;
+    *anchor = (uint8_t *)&ep;
+    *anchor_len = sizeof(struct smbios_entry_point);
+}
+
+static void save_opt(const char **dest, QemuOpts *opts, const char *name)
+{
+    const char *val = qemu_opt_get(opts, name);
+
+    if (val) {
+        *dest = val;
+    }
+}
+
+void smbios_entry_add(QemuOpts *opts)
+{
+    Error *local_err = NULL;
+    const char *val;
+
+    assert(!smbios_immutable);
+
+    val = qemu_opt_get(opts, "file");
+    if (val) {
+        struct smbios_structure_header *header;
+        int size;
+        struct smbios_table *table; /* legacy mode only */
+
+        qemu_opts_validate(opts, qemu_smbios_file_opts, &local_err);
+        if (local_err) {
+            error_report_err(local_err);
+            exit(1);
+        }
+
+        size = get_image_size(val);
+        if (size == -1 || size < sizeof(struct smbios_structure_header)) {
+            error_report("Cannot read SMBIOS file %s", val);
+            exit(1);
+        }
+
+        /*
+         * NOTE: standard double '\0' terminator expected, per smbios spec.
+         * (except in legacy mode, where the second '\0' is implicit and
+         *  will be inserted by the BIOS).
+         */
+        smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size);
+        header = (struct smbios_structure_header *)(smbios_tables +
+                                                    smbios_tables_len);
+
+        if (load_image(val, (uint8_t *)header) != size) {
+            error_report("Failed to load SMBIOS file %s", val);
+            exit(1);
+        }
+
+        if (test_bit(header->type, have_fields_bitmap)) {
+            error_report("can't load type %d struct, fields already specified!",
+                         header->type);
+            exit(1);
+        }
+        set_bit(header->type, have_binfile_bitmap);
+
+        if (header->type == 4) {
+            smbios_type4_count++;
+        }
+
+        smbios_tables_len += size;
+        if (size > smbios_table_max) {
+            smbios_table_max = size;
+        }
+        smbios_table_cnt++;
+
+        /* add a copy of the newly loaded blob to legacy smbios_entries */
+        /* NOTE: This code runs before smbios_set_defaults(), so we don't
+         *       yet know which mode (legacy vs. aggregate-table) will be
+         *       required. We therefore add the binary blob to both legacy
+         *       (smbios_entries) and aggregate (smbios_tables) tables, and
+         *       delete the one we don't need from smbios_set_defaults(),
+         *       once we know which machine version has been requested.
+         */
+        if (!smbios_entries) {
+            smbios_entries_len = sizeof(uint16_t);
+            smbios_entries = g_malloc0(smbios_entries_len);
+        }
+        smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
+                                                   size + sizeof(*table));
+        table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
+        table->header.type = SMBIOS_TABLE_ENTRY;
+        table->header.length = cpu_to_le16(sizeof(*table) + size);
+        memcpy(table->data, header, size);
+        smbios_entries_len += sizeof(*table) + size;
+        (*(uint16_t *)smbios_entries) =
+                cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
+        /* end: add a copy of the newly loaded blob to legacy smbios_entries */
+
+        return;
+    }
+
+    val = qemu_opt_get(opts, "type");
+    if (val) {
+        unsigned long type = strtoul(val, NULL, 0);
+
+        if (type > SMBIOS_MAX_TYPE) {
+            error_report("out of range!");
+            exit(1);
+        }
+
+        if (test_bit(type, have_binfile_bitmap)) {
+            error_report("can't add fields, binary file already loaded!");
+            exit(1);
+        }
+        set_bit(type, have_fields_bitmap);
+
+        switch (type) {
+        case 0:
+            qemu_opts_validate(opts, qemu_smbios_type0_opts, &local_err);
+            if (local_err) {
+                error_report_err(local_err);
+                exit(1);
+            }
+            save_opt(&type0.vendor, opts, "vendor");
+            save_opt(&type0.version, opts, "version");
+            save_opt(&type0.date, opts, "date");
+            type0.uefi = qemu_opt_get_bool(opts, "uefi", false);
+
+            val = qemu_opt_get(opts, "release");
+            if (val) {
+                if (sscanf(val, "%hhu.%hhu", &type0.major, &type0.minor) != 2) {
+                    error_report("Invalid release");
+                    exit(1);
+                }
+                type0.have_major_minor = true;
+            }
+            return;
+        case 1:
+            qemu_opts_validate(opts, qemu_smbios_type1_opts, &local_err);
+            if (local_err) {
+                error_report_err(local_err);
+                exit(1);
+            }
+            save_opt(&type1.manufacturer, opts, "manufacturer");
+            save_opt(&type1.product, opts, "product");
+            save_opt(&type1.version, opts, "version");
+            save_opt(&type1.serial, opts, "serial");
+            save_opt(&type1.sku, opts, "sku");
+            save_opt(&type1.family, opts, "family");
+
+            val = qemu_opt_get(opts, "uuid");
+            if (val) {
+                if (qemu_uuid_parse(val, qemu_uuid) != 0) {
+                    error_report("Invalid UUID");
+                    exit(1);
+                }
+                qemu_uuid_set = true;
+            }
+            return;
+        case 2:
+            qemu_opts_validate(opts, qemu_smbios_type2_opts, &local_err);
+            if (local_err) {
+                error_report_err(local_err);
+                exit(1);
+            }
+            save_opt(&type2.manufacturer, opts, "manufacturer");
+            save_opt(&type2.product, opts, "product");
+            save_opt(&type2.version, opts, "version");
+            save_opt(&type2.serial, opts, "serial");
+            save_opt(&type2.asset, opts, "asset");
+            save_opt(&type2.location, opts, "location");
+            return;
+        case 3:
+            qemu_opts_validate(opts, qemu_smbios_type3_opts, &local_err);
+            if (local_err) {
+                error_report_err(local_err);
+                exit(1);
+            }
+            save_opt(&type3.manufacturer, opts, "manufacturer");
+            save_opt(&type3.version, opts, "version");
+            save_opt(&type3.serial, opts, "serial");
+            save_opt(&type3.asset, opts, "asset");
+            save_opt(&type3.sku, opts, "sku");
+            return;
+        case 4:
+            qemu_opts_validate(opts, qemu_smbios_type4_opts, &local_err);
+            if (local_err) {
+                error_report_err(local_err);
+                exit(1);
+            }
+            save_opt(&type4.sock_pfx, opts, "sock_pfx");
+            save_opt(&type4.manufacturer, opts, "manufacturer");
+            save_opt(&type4.version, opts, "version");
+            save_opt(&type4.serial, opts, "serial");
+            save_opt(&type4.asset, opts, "asset");
+            save_opt(&type4.part, opts, "part");
+            return;
+        case 17:
+            qemu_opts_validate(opts, qemu_smbios_type17_opts, &local_err);
+            if (local_err) {
+                error_report_err(local_err);
+                exit(1);
+            }
+            save_opt(&type17.loc_pfx, opts, "loc_pfx");
+            save_opt(&type17.bank, opts, "bank");
+            save_opt(&type17.manufacturer, opts, "manufacturer");
+            save_opt(&type17.serial, opts, "serial");
+            save_opt(&type17.asset, opts, "asset");
+            save_opt(&type17.part, opts, "part");
+            type17.speed = qemu_opt_get_number(opts, "speed", 0);
+            return;
+        default:
+            error_report("Don't know how to build fields for SMBIOS type %ld",
+                         type);
+            exit(1);
+        }
+    }
+
+    error_report("Must specify type= or file=");
+    exit(1);
+}
diff --git a/include/hw/i386/smbios.h b/include/hw/i386/smbios.h
deleted file mode 100644
index e727233..0000000
--- a/include/hw/i386/smbios.h
+++ /dev/null
@@ -1,237 +0,0 @@
-#ifndef QEMU_SMBIOS_H
-#define QEMU_SMBIOS_H
-/*
- * SMBIOS Support
- *
- * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
- *
- * Authors:
- *  Alex Williamson <alex.williamson@hp.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/option.h"
-#include "exec/cpu-common.h"
-
-#define SMBIOS_MAX_TYPE 127
-
-/* memory area description, used by type 19 table */
-struct smbios_phys_mem_area {
-    uint64_t address;
-    uint64_t length;
-};
-
-void smbios_entry_add(QemuOpts *opts);
-void smbios_set_cpuid(uint32_t version, uint32_t features);
-void smbios_set_defaults(const char *manufacturer, const char *product,
-                         const char *version, bool legacy_mode,
-                         bool uuid_encoded);
-uint8_t *smbios_get_table_legacy(size_t *length);
-void smbios_get_tables(const struct smbios_phys_mem_area *mem_array,
-                       const unsigned int mem_array_size,
-                       const ram_addr_t ram_size,
-                       uint8_t **tables, size_t *tables_len,
-                       uint8_t **anchor, size_t *anchor_len);
-
-/*
- * SMBIOS spec defined tables
- */
-
-/* SMBIOS entry point (anchor).
- * BIOS must place this at a 16-bit-aligned address between 0xf0000 and 0xfffff.
- */
-struct smbios_entry_point {
-    uint8_t anchor_string[4];
-    uint8_t checksum;
-    uint8_t length;
-    uint8_t smbios_major_version;
-    uint8_t smbios_minor_version;
-    uint16_t max_structure_size;
-    uint8_t entry_point_revision;
-    uint8_t formatted_area[5];
-    uint8_t intermediate_anchor_string[5];
-    uint8_t intermediate_checksum;
-    uint16_t structure_table_length;
-    uint32_t structure_table_address;
-    uint16_t number_of_structures;
-    uint8_t smbios_bcd_revision;
-} QEMU_PACKED;
-
-/* This goes at the beginning of every SMBIOS structure. */
-struct smbios_structure_header {
-    uint8_t type;
-    uint8_t length;
-    uint16_t handle;
-} QEMU_PACKED;
-
-/* SMBIOS type 0 - BIOS Information */
-struct smbios_type_0 {
-    struct smbios_structure_header header;
-    uint8_t vendor_str;
-    uint8_t bios_version_str;
-    uint16_t bios_starting_address_segment;
-    uint8_t bios_release_date_str;
-    uint8_t bios_rom_size;
-    uint64_t bios_characteristics;
-    uint8_t bios_characteristics_extension_bytes[2];
-    uint8_t system_bios_major_release;
-    uint8_t system_bios_minor_release;
-    uint8_t embedded_controller_major_release;
-    uint8_t embedded_controller_minor_release;
-} QEMU_PACKED;
-
-/* UUID encoding. The time_* fields are little-endian, as specified by SMBIOS
- * version 2.6.
- */
-struct smbios_uuid {
-    uint32_t time_low;
-    uint16_t time_mid;
-    uint16_t time_hi_and_version;
-    uint8_t clock_seq_hi_and_reserved;
-    uint8_t clock_seq_low;
-    uint8_t node[6];
-} QEMU_PACKED;
-
-/* SMBIOS type 1 - System Information */
-struct smbios_type_1 {
-    struct smbios_structure_header header;
-    uint8_t manufacturer_str;
-    uint8_t product_name_str;
-    uint8_t version_str;
-    uint8_t serial_number_str;
-    struct smbios_uuid uuid;
-    uint8_t wake_up_type;
-    uint8_t sku_number_str;
-    uint8_t family_str;
-} QEMU_PACKED;
-
-/* SMBIOS type 2 - Base Board */
-struct smbios_type_2 {
-    struct smbios_structure_header header;
-    uint8_t manufacturer_str;
-    uint8_t product_str;
-    uint8_t version_str;
-    uint8_t serial_number_str;
-    uint8_t asset_tag_number_str;
-    uint8_t feature_flags;
-    uint8_t location_str;
-    uint16_t chassis_handle;
-    uint8_t board_type;
-    uint8_t contained_element_count;
-    /* contained elements follow */
-} QEMU_PACKED;
-
-/* SMBIOS type 3 - System Enclosure (v2.7) */
-struct smbios_type_3 {
-    struct smbios_structure_header header;
-    uint8_t manufacturer_str;
-    uint8_t type;
-    uint8_t version_str;
-    uint8_t serial_number_str;
-    uint8_t asset_tag_number_str;
-    uint8_t boot_up_state;
-    uint8_t power_supply_state;
-    uint8_t thermal_state;
-    uint8_t security_status;
-    uint32_t oem_defined;
-    uint8_t height;
-    uint8_t number_of_power_cords;
-    uint8_t contained_element_count;
-    uint8_t sku_number_str;
-    /* contained elements follow */
-} QEMU_PACKED;
-
-/* SMBIOS type 4 - Processor Information (v2.6) */
-struct smbios_type_4 {
-    struct smbios_structure_header header;
-    uint8_t socket_designation_str;
-    uint8_t processor_type;
-    uint8_t processor_family;
-    uint8_t processor_manufacturer_str;
-    uint32_t processor_id[2];
-    uint8_t processor_version_str;
-    uint8_t voltage;
-    uint16_t external_clock;
-    uint16_t max_speed;
-    uint16_t current_speed;
-    uint8_t status;
-    uint8_t processor_upgrade;
-    uint16_t l1_cache_handle;
-    uint16_t l2_cache_handle;
-    uint16_t l3_cache_handle;
-    uint8_t serial_number_str;
-    uint8_t asset_tag_number_str;
-    uint8_t part_number_str;
-    uint8_t core_count;
-    uint8_t core_enabled;
-    uint8_t thread_count;
-    uint16_t processor_characteristics;
-    uint16_t processor_family2;
-} QEMU_PACKED;
-
-/* SMBIOS type 16 - Physical Memory Array (v2.7) */
-struct smbios_type_16 {
-    struct smbios_structure_header header;
-    uint8_t location;
-    uint8_t use;
-    uint8_t error_correction;
-    uint32_t maximum_capacity;
-    uint16_t memory_error_information_handle;
-    uint16_t number_of_memory_devices;
-    uint64_t extended_maximum_capacity;
-} QEMU_PACKED;
-
-/* SMBIOS type 17 - Memory Device (v2.8) */
-struct smbios_type_17 {
-    struct smbios_structure_header header;
-    uint16_t physical_memory_array_handle;
-    uint16_t memory_error_information_handle;
-    uint16_t total_width;
-    uint16_t data_width;
-    uint16_t size;
-    uint8_t form_factor;
-    uint8_t device_set;
-    uint8_t device_locator_str;
-    uint8_t bank_locator_str;
-    uint8_t memory_type;
-    uint16_t type_detail;
-    uint16_t speed;
-    uint8_t manufacturer_str;
-    uint8_t serial_number_str;
-    uint8_t asset_tag_number_str;
-    uint8_t part_number_str;
-    uint8_t attributes;
-    uint32_t extended_size;
-    uint16_t configured_clock_speed;
-    uint16_t minimum_voltage;
-    uint16_t maximum_voltage;
-    uint16_t configured_voltage;
-} QEMU_PACKED;
-
-/* SMBIOS type 19 - Memory Array Mapped Address (v2.7) */
-struct smbios_type_19 {
-    struct smbios_structure_header header;
-    uint32_t starting_address;
-    uint32_t ending_address;
-    uint16_t memory_array_handle;
-    uint8_t partition_width;
-    uint64_t extended_starting_address;
-    uint64_t extended_ending_address;
-} QEMU_PACKED;
-
-/* SMBIOS type 32 - System Boot Information */
-struct smbios_type_32 {
-    struct smbios_structure_header header;
-    uint8_t reserved[6];
-    uint8_t boot_status;
-} QEMU_PACKED;
-
-/* SMBIOS type 127 -- End-of-table */
-struct smbios_type_127 {
-    struct smbios_structure_header header;
-} QEMU_PACKED;
-
-#endif /*QEMU_SMBIOS_H */
diff --git a/include/hw/smbios/smbios.h b/include/hw/smbios/smbios.h
new file mode 100644
index 0000000..e727233
--- /dev/null
+++ b/include/hw/smbios/smbios.h
@@ -0,0 +1,237 @@
+#ifndef QEMU_SMBIOS_H
+#define QEMU_SMBIOS_H
+/*
+ * SMBIOS Support
+ *
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * Authors:
+ *  Alex Williamson <alex.williamson@hp.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/option.h"
+#include "exec/cpu-common.h"
+
+#define SMBIOS_MAX_TYPE 127
+
+/* memory area description, used by type 19 table */
+struct smbios_phys_mem_area {
+    uint64_t address;
+    uint64_t length;
+};
+
+void smbios_entry_add(QemuOpts *opts);
+void smbios_set_cpuid(uint32_t version, uint32_t features);
+void smbios_set_defaults(const char *manufacturer, const char *product,
+                         const char *version, bool legacy_mode,
+                         bool uuid_encoded);
+uint8_t *smbios_get_table_legacy(size_t *length);
+void smbios_get_tables(const struct smbios_phys_mem_area *mem_array,
+                       const unsigned int mem_array_size,
+                       const ram_addr_t ram_size,
+                       uint8_t **tables, size_t *tables_len,
+                       uint8_t **anchor, size_t *anchor_len);
+
+/*
+ * SMBIOS spec defined tables
+ */
+
+/* SMBIOS entry point (anchor).
+ * BIOS must place this at a 16-bit-aligned address between 0xf0000 and 0xfffff.
+ */
+struct smbios_entry_point {
+    uint8_t anchor_string[4];
+    uint8_t checksum;
+    uint8_t length;
+    uint8_t smbios_major_version;
+    uint8_t smbios_minor_version;
+    uint16_t max_structure_size;
+    uint8_t entry_point_revision;
+    uint8_t formatted_area[5];
+    uint8_t intermediate_anchor_string[5];
+    uint8_t intermediate_checksum;
+    uint16_t structure_table_length;
+    uint32_t structure_table_address;
+    uint16_t number_of_structures;
+    uint8_t smbios_bcd_revision;
+} QEMU_PACKED;
+
+/* This goes at the beginning of every SMBIOS structure. */
+struct smbios_structure_header {
+    uint8_t type;
+    uint8_t length;
+    uint16_t handle;
+} QEMU_PACKED;
+
+/* SMBIOS type 0 - BIOS Information */
+struct smbios_type_0 {
+    struct smbios_structure_header header;
+    uint8_t vendor_str;
+    uint8_t bios_version_str;
+    uint16_t bios_starting_address_segment;
+    uint8_t bios_release_date_str;
+    uint8_t bios_rom_size;
+    uint64_t bios_characteristics;
+    uint8_t bios_characteristics_extension_bytes[2];
+    uint8_t system_bios_major_release;
+    uint8_t system_bios_minor_release;
+    uint8_t embedded_controller_major_release;
+    uint8_t embedded_controller_minor_release;
+} QEMU_PACKED;
+
+/* UUID encoding. The time_* fields are little-endian, as specified by SMBIOS
+ * version 2.6.
+ */
+struct smbios_uuid {
+    uint32_t time_low;
+    uint16_t time_mid;
+    uint16_t time_hi_and_version;
+    uint8_t clock_seq_hi_and_reserved;
+    uint8_t clock_seq_low;
+    uint8_t node[6];
+} QEMU_PACKED;
+
+/* SMBIOS type 1 - System Information */
+struct smbios_type_1 {
+    struct smbios_structure_header header;
+    uint8_t manufacturer_str;
+    uint8_t product_name_str;
+    uint8_t version_str;
+    uint8_t serial_number_str;
+    struct smbios_uuid uuid;
+    uint8_t wake_up_type;
+    uint8_t sku_number_str;
+    uint8_t family_str;
+} QEMU_PACKED;
+
+/* SMBIOS type 2 - Base Board */
+struct smbios_type_2 {
+    struct smbios_structure_header header;
+    uint8_t manufacturer_str;
+    uint8_t product_str;
+    uint8_t version_str;
+    uint8_t serial_number_str;
+    uint8_t asset_tag_number_str;
+    uint8_t feature_flags;
+    uint8_t location_str;
+    uint16_t chassis_handle;
+    uint8_t board_type;
+    uint8_t contained_element_count;
+    /* contained elements follow */
+} QEMU_PACKED;
+
+/* SMBIOS type 3 - System Enclosure (v2.7) */
+struct smbios_type_3 {
+    struct smbios_structure_header header;
+    uint8_t manufacturer_str;
+    uint8_t type;
+    uint8_t version_str;
+    uint8_t serial_number_str;
+    uint8_t asset_tag_number_str;
+    uint8_t boot_up_state;
+    uint8_t power_supply_state;
+    uint8_t thermal_state;
+    uint8_t security_status;
+    uint32_t oem_defined;
+    uint8_t height;
+    uint8_t number_of_power_cords;
+    uint8_t contained_element_count;
+    uint8_t sku_number_str;
+    /* contained elements follow */
+} QEMU_PACKED;
+
+/* SMBIOS type 4 - Processor Information (v2.6) */
+struct smbios_type_4 {
+    struct smbios_structure_header header;
+    uint8_t socket_designation_str;
+    uint8_t processor_type;
+    uint8_t processor_family;
+    uint8_t processor_manufacturer_str;
+    uint32_t processor_id[2];
+    uint8_t processor_version_str;
+    uint8_t voltage;
+    uint16_t external_clock;
+    uint16_t max_speed;
+    uint16_t current_speed;
+    uint8_t status;
+    uint8_t processor_upgrade;
+    uint16_t l1_cache_handle;
+    uint16_t l2_cache_handle;
+    uint16_t l3_cache_handle;
+    uint8_t serial_number_str;
+    uint8_t asset_tag_number_str;
+    uint8_t part_number_str;
+    uint8_t core_count;
+    uint8_t core_enabled;
+    uint8_t thread_count;
+    uint16_t processor_characteristics;
+    uint16_t processor_family2;
+} QEMU_PACKED;
+
+/* SMBIOS type 16 - Physical Memory Array (v2.7) */
+struct smbios_type_16 {
+    struct smbios_structure_header header;
+    uint8_t location;
+    uint8_t use;
+    uint8_t error_correction;
+    uint32_t maximum_capacity;
+    uint16_t memory_error_information_handle;
+    uint16_t number_of_memory_devices;
+    uint64_t extended_maximum_capacity;
+} QEMU_PACKED;
+
+/* SMBIOS type 17 - Memory Device (v2.8) */
+struct smbios_type_17 {
+    struct smbios_structure_header header;
+    uint16_t physical_memory_array_handle;
+    uint16_t memory_error_information_handle;
+    uint16_t total_width;
+    uint16_t data_width;
+    uint16_t size;
+    uint8_t form_factor;
+    uint8_t device_set;
+    uint8_t device_locator_str;
+    uint8_t bank_locator_str;
+    uint8_t memory_type;
+    uint16_t type_detail;
+    uint16_t speed;
+    uint8_t manufacturer_str;
+    uint8_t serial_number_str;
+    uint8_t asset_tag_number_str;
+    uint8_t part_number_str;
+    uint8_t attributes;
+    uint32_t extended_size;
+    uint16_t configured_clock_speed;
+    uint16_t minimum_voltage;
+    uint16_t maximum_voltage;
+    uint16_t configured_voltage;
+} QEMU_PACKED;
+
+/* SMBIOS type 19 - Memory Array Mapped Address (v2.7) */
+struct smbios_type_19 {
+    struct smbios_structure_header header;
+    uint32_t starting_address;
+    uint32_t ending_address;
+    uint16_t memory_array_handle;
+    uint8_t partition_width;
+    uint64_t extended_starting_address;
+    uint64_t extended_ending_address;
+} QEMU_PACKED;
+
+/* SMBIOS type 32 - System Boot Information */
+struct smbios_type_32 {
+    struct smbios_structure_header header;
+    uint8_t reserved[6];
+    uint8_t boot_status;
+} QEMU_PACKED;
+
+/* SMBIOS type 127 -- End-of-table */
+struct smbios_type_127 {
+    struct smbios_structure_header header;
+} QEMU_PACKED;
+
+#endif /*QEMU_SMBIOS_H */
diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c
index 0de1742..613867a 100644
--- a/tests/bios-tables-test.c
+++ b/tests/bios-tables-test.c
@@ -18,7 +18,7 @@
 #include "libqtest.h"
 #include "qemu/compiler.h"
 #include "hw/acpi/acpi-defs.h"
-#include "hw/i386/smbios.h"
+#include "hw/smbios/smbios.h"
 #include "qemu/bitmap.h"
 
 #define MACHINE_PC "pc"
diff --git a/vl.c b/vl.c
index 3f269dc..be59bfb 100644
--- a/vl.c
+++ b/vl.c
@@ -68,7 +68,7 @@ int main(int argc, char **argv)
 #include "hw/isa/isa.h"
 #include "hw/bt.h"
 #include "sysemu/watchdog.h"
-#include "hw/i386/smbios.h"
+#include "hw/smbios/smbios.h"
 #include "hw/xen/xen.h"
 #include "hw/qdev.h"
 #include "hw/loader.h"
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [Qemu-devel] [ARM SMBIOS RFC PATCH 5/5] smbios: implement smbios support for mach-virt
  2015-07-14 20:23 [Qemu-devel] [ARM SMBIOS RFC PATCH 0/5] SMBIOS Support for ARM Wei Huang
                   ` (3 preceding siblings ...)
  2015-07-14 20:23 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 4/5] smbios: move smbios code into a common folder Wei Huang
@ 2015-07-14 20:23 ` Wei Huang
  2015-07-14 21:15 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 0/5] SMBIOS Support for ARM Laszlo Ersek
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Wei Huang @ 2015-07-14 20:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Wei Huang, peter.maydell, drjones, ehabkost, mst, zhaoshenglong,
	pbonzini, imammedo, lersek, rth

This patch generates smbios tables for ARM mach-virt. Also add
CONFIG_SMBIOS=y for ARM default config.

Signed-off-by: Wei Huang <wei@redhat.com>
---
 default-configs/arm-softmmu.mak  |  1 +
 hw/arm/virt.c                    | 24 ++++++++++++++++++++++++
 include/hw/arm/virt-acpi-build.h |  1 +
 3 files changed, 26 insertions(+)

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 74f1db3..99b41e9 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -102,3 +102,4 @@ CONFIG_XIO3130=y
 CONFIG_IOH3420=y
 CONFIG_I82801B11=y
 CONFIG_ACPI=y
+CONFIG_SMBIOS=y
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 4846892..09c800b 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -48,6 +48,7 @@
 #include "hw/arm/sysbus-fdt.h"
 #include "hw/platform-bus.h"
 #include "hw/arm/fdt.h"
+#include "hw/smbios/smbios.h"
 
 /* Number of external interrupt lines to configure the GIC with */
 #define NUM_IRQS 256
@@ -780,12 +781,34 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
     return board->fdt;
 }
 
+static void virt_build_smbios(VirtGuestInfo *guest_info)
+{
+    FWCfgState *fw_cfg = guest_info->fw_cfg;
+    uint8_t *smbios_tables, *smbios_anchor;
+    size_t smbios_tables_len, smbios_anchor_len;
+
+    smbios_set_defaults("QEMU", "QEMU Virtual Machine",
+                        "1.0", false, false);
+
+    smbios_get_tables(NULL, 0, guest_info->ram_size,
+                      &smbios_tables, &smbios_tables_len,
+                      &smbios_anchor, &smbios_anchor_len);
+
+    if (smbios_anchor) {
+        fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables",
+                        smbios_tables, smbios_tables_len);
+        fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor",
+                        smbios_anchor, smbios_anchor_len);
+    }
+}
+
 static
 void virt_guest_info_machine_done(Notifier *notifier, void *data)
 {
     VirtGuestInfoState *guest_info_state = container_of(notifier,
                                               VirtGuestInfoState, machine_done);
     virt_acpi_setup(&guest_info_state->info);
+    virt_build_smbios(&guest_info_state->info);
 }
 
 static void machvirt_init(MachineState *machine)
@@ -894,6 +917,7 @@ static void machvirt_init(MachineState *machine)
 
     guest_info->smp_cpus = smp_cpus;
     guest_info->fw_cfg = fw_cfg_find();
+    guest_info->ram_size = machine->ram_size;
     guest_info->memmap = vbi->memmap;
     guest_info->irqmap = vbi->irqmap;
     guest_info_state->machine_done.notify = virt_guest_info_machine_done;
diff --git a/include/hw/arm/virt-acpi-build.h b/include/hw/arm/virt-acpi-build.h
index 04f174d..ef274c6 100644
--- a/include/hw/arm/virt-acpi-build.h
+++ b/include/hw/arm/virt-acpi-build.h
@@ -29,6 +29,7 @@
 typedef struct VirtGuestInfo {
     int smp_cpus;
     FWCfgState *fw_cfg;
+    ram_addr_t ram_size;
     const MemMapEntry *memmap;
     const int *irqmap;
 } VirtGuestInfo;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [ARM SMBIOS RFC PATCH 0/5] SMBIOS Support for ARM
  2015-07-14 20:23 [Qemu-devel] [ARM SMBIOS RFC PATCH 0/5] SMBIOS Support for ARM Wei Huang
                   ` (4 preceding siblings ...)
  2015-07-14 20:23 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 5/5] smbios: implement smbios support for mach-virt Wei Huang
@ 2015-07-14 21:15 ` Laszlo Ersek
  2015-07-15 22:46 ` Laszlo Ersek
  2015-07-16 15:00 ` Gabriel L. Somlo
  7 siblings, 0 replies; 11+ messages in thread
From: Laszlo Ersek @ 2015-07-14 21:15 UTC (permalink / raw)
  To: Wei Huang
  Cc: peter.maydell, drjones, ehabkost, mst, Ard Biesheuvel,
	zhaoshenglong, qemu-devel, imammedo, pbonzini, rth

Cc'ing Ard.

On 07/14/15 22:23, Wei Huang wrote:
> SMBIOS tables present userful system hardware info to management
> applications, such as DMI tools. Even though SMBIOS was originally
> developed for Intel x86, it has been extended to both Itanium and 
> ARM (32bit & 64bit). More and more ARM server releases, such as 
> RHEL Server for ARM, start to integrate support for SMBIOS.
> 
> This patchset is intendted to provid SMBIOS tables for ARM mach-virt
> machine. The SMBIOS tables are created and stored in fw_cfg, awaiting
> OVMF (AAVMF) to parse/present SMBIOS entry.
> 
> NOTE: This is RFC and the patches haven't been fully tested yet.
> Laszlo is kind enough to offer help on fixing AAVMF to enable support
> for SMBIOS.

I intend to start working on this tomorrow. (Well, not in ~50 minutes
for sure, but you get the idea.)

Thanks!
Laszlo

> Any comments are welcomed for next release.
> 
> Thanks,
> -Wei
> 
> Wei Huang (5):
>   smbios: extract x86 smbios building code into a function
>   smbios: remove dependency on x86 e820 tables
>   smbios: pass ram size as a parameter to build smbios tables
>   smbios: move smbios code into a common folder
>   smbios: implement smbios support for mach-virt
> 
>  arch_init.c                        |    2 +-
>  default-configs/arm-softmmu.mak    |    1 +
>  default-configs/i386-softmmu.mak   |    1 +
>  default-configs/x86_64-softmmu.mak |    1 +
>  hw/Makefile.objs                   |    1 +
>  hw/arm/virt.c                      |   24 +
>  hw/i386/Makefile.objs              |    2 +-
>  hw/i386/pc.c                       |   56 +-
>  hw/i386/pc_piix.c                  |    2 +-
>  hw/i386/pc_q35.c                   |    2 +-
>  hw/i386/smbios.c                   | 1102 ------------------------------------
>  hw/smbios/Makefile.objs            |    1 +
>  hw/smbios/smbios.c                 | 1102 ++++++++++++++++++++++++++++++++++++
>  include/hw/arm/virt-acpi-build.h   |    1 +
>  include/hw/i386/smbios.h           |  227 --------
>  include/hw/smbios/smbios.h         |  237 ++++++++
>  tests/bios-tables-test.c           |    2 +-
>  vl.c                               |    2 +-
>  18 files changed, 1414 insertions(+), 1352 deletions(-)
>  delete mode 100644 hw/i386/smbios.c
>  create mode 100644 hw/smbios/Makefile.objs
>  create mode 100644 hw/smbios/smbios.c
>  delete mode 100644 include/hw/i386/smbios.h
>  create mode 100644 include/hw/smbios/smbios.h
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [ARM SMBIOS RFC PATCH 4/5] smbios: move smbios code into a common folder
  2015-07-14 20:23 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 4/5] smbios: move smbios code into a common folder Wei Huang
@ 2015-07-15 12:08   ` Laszlo Ersek
  2015-07-15 14:32     ` Wei Huang
  0 siblings, 1 reply; 11+ messages in thread
From: Laszlo Ersek @ 2015-07-15 12:08 UTC (permalink / raw)
  To: Wei Huang
  Cc: peter.maydell, drjones, ehabkost, mst, zhaoshenglong, qemu-devel,
	imammedo, pbonzini, rth

On 07/14/15 22:23, Wei Huang wrote:
> To share smbios among different architectures, this patch moves SMBIOS
> code (smbios.c and smbios.h) from x86 specific folders into new
> hw/smbios directories. As a result, CONFIG_SMBIOS=y is defined in
> x86 default config files.
> 
> Signed-off-by: Wei Huang <wei@redhat.com>
> ---
>  arch_init.c                        |    2 +-
>  default-configs/i386-softmmu.mak   |    1 +
>  default-configs/x86_64-softmmu.mak |    1 +
>  hw/Makefile.objs                   |    1 +
>  hw/i386/Makefile.objs              |    2 +-
>  hw/i386/pc.c                       |    2 +-
>  hw/i386/pc_piix.c                  |    2 +-
>  hw/i386/pc_q35.c                   |    2 +-
>  hw/i386/smbios.c                   | 1102 ------------------------------------
>  hw/smbios/Makefile.objs            |    1 +
>  hw/smbios/smbios.c                 | 1102 ++++++++++++++++++++++++++++++++++++
>  include/hw/i386/smbios.h           |  237 --------
>  include/hw/smbios/smbios.h         |  237 ++++++++
>  tests/bios-tables-test.c           |    2 +-
>  vl.c                               |    2 +-
>  15 files changed, 1350 insertions(+), 1346 deletions(-)
>  delete mode 100644 hw/i386/smbios.c
>  create mode 100644 hw/smbios/Makefile.objs
>  create mode 100644 hw/smbios/smbios.c
>  delete mode 100644 include/hw/i386/smbios.h
>  create mode 100644 include/hw/smbios/smbios.h

Can you please send the next version of this series (I assume there's
going to be one) with rename detection enabled? At least
"hw/i386/smbios.c" --> "hw/smbios/smbios.c" appears a rename. A few
lines may have changed, but without enabling rename detection, it's
really hard to tell.

Thanks
Laszlo

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [ARM SMBIOS RFC PATCH 4/5] smbios: move smbios code into a common folder
  2015-07-15 12:08   ` Laszlo Ersek
@ 2015-07-15 14:32     ` Wei Huang
  0 siblings, 0 replies; 11+ messages in thread
From: Wei Huang @ 2015-07-15 14:32 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: peter.maydell, drjones, ehabkost, mst, zhaoshenglong, qemu-devel,
	imammedo, pbonzini, rth



On 07/15/2015 07:08 AM, Laszlo Ersek wrote:
> On 07/14/15 22:23, Wei Huang wrote:
>> To share smbios among different architectures, this patch moves SMBIOS
>> code (smbios.c and smbios.h) from x86 specific folders into new
>> hw/smbios directories. As a result, CONFIG_SMBIOS=y is defined in
>> x86 default config files.
>>
>> Signed-off-by: Wei Huang <wei@redhat.com>
>> ---
>>  arch_init.c                        |    2 +-
>>  default-configs/i386-softmmu.mak   |    1 +
>>  default-configs/x86_64-softmmu.mak |    1 +
>>  hw/Makefile.objs                   |    1 +
>>  hw/i386/Makefile.objs              |    2 +-
>>  hw/i386/pc.c                       |    2 +-
>>  hw/i386/pc_piix.c                  |    2 +-
>>  hw/i386/pc_q35.c                   |    2 +-
>>  hw/i386/smbios.c                   | 1102 ------------------------------------
>>  hw/smbios/Makefile.objs            |    1 +
>>  hw/smbios/smbios.c                 | 1102 ++++++++++++++++++++++++++++++++++++
>>  include/hw/i386/smbios.h           |  237 --------
>>  include/hw/smbios/smbios.h         |  237 ++++++++
>>  tests/bios-tables-test.c           |    2 +-
>>  vl.c                               |    2 +-
>>  15 files changed, 1350 insertions(+), 1346 deletions(-)
>>  delete mode 100644 hw/i386/smbios.c
>>  create mode 100644 hw/smbios/Makefile.objs
>>  create mode 100644 hw/smbios/smbios.c
>>  delete mode 100644 include/hw/i386/smbios.h
>>  create mode 100644 include/hw/smbios/smbios.h
> 
> Can you please send the next version of this series (I assume there's
> going to be one) with rename detection enabled? At least
> "hw/i386/smbios.c" --> "hw/smbios/smbios.c" appears a rename. A few
> lines may have changed, but without enabling rename detection, it's
> really hard to tell.
Good point. I will do it in next version.

> 
> Thanks
> Laszlo
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [ARM SMBIOS RFC PATCH 0/5] SMBIOS Support for ARM
  2015-07-14 20:23 [Qemu-devel] [ARM SMBIOS RFC PATCH 0/5] SMBIOS Support for ARM Wei Huang
                   ` (5 preceding siblings ...)
  2015-07-14 21:15 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 0/5] SMBIOS Support for ARM Laszlo Ersek
@ 2015-07-15 22:46 ` Laszlo Ersek
  2015-07-16 15:00 ` Gabriel L. Somlo
  7 siblings, 0 replies; 11+ messages in thread
From: Laszlo Ersek @ 2015-07-15 22:46 UTC (permalink / raw)
  To: Wei Huang, qemu-devel
  Cc: peter.maydell, drjones, ehabkost, mst, zhaoshenglong,
	Gabriel L. Somlo (GMail),
	pbonzini, imammedo, rth

On 07/14/15 22:23, Wei Huang wrote:
> SMBIOS tables present userful system hardware info to management
> applications, such as DMI tools. Even though SMBIOS was originally
> developed for Intel x86, it has been extended to both Itanium and 
> ARM (32bit & 64bit). More and more ARM server releases, such as 
> RHEL Server for ARM, start to integrate support for SMBIOS.
> 
> This patchset is intendted to provid SMBIOS tables for ARM mach-virt
> machine. The SMBIOS tables are created and stored in fw_cfg, awaiting
> OVMF (AAVMF) to parse/present SMBIOS entry.
> 
> NOTE: This is RFC and the patches haven't been fully tested yet.
> Laszlo is kind enough to offer help on fixing AAVMF to enable support
> for SMBIOS. Any comments are welcomed for next release.

Your series is functional; I posted a matching patch set for edk2 (with
example dmidecode output in the blurb):

  http://thread.gmane.org/gmane.comp.bios.tianocore.devel/17470

I'll let others review your patches, especially concerning the concrete
SMBIOS contents.

Thanks!
Laszlo

> 
> Thanks,
> -Wei
> 
> Wei Huang (5):
>   smbios: extract x86 smbios building code into a function
>   smbios: remove dependency on x86 e820 tables
>   smbios: pass ram size as a parameter to build smbios tables
>   smbios: move smbios code into a common folder
>   smbios: implement smbios support for mach-virt
> 
>  arch_init.c                        |    2 +-
>  default-configs/arm-softmmu.mak    |    1 +
>  default-configs/i386-softmmu.mak   |    1 +
>  default-configs/x86_64-softmmu.mak |    1 +
>  hw/Makefile.objs                   |    1 +
>  hw/arm/virt.c                      |   24 +
>  hw/i386/Makefile.objs              |    2 +-
>  hw/i386/pc.c                       |   56 +-
>  hw/i386/pc_piix.c                  |    2 +-
>  hw/i386/pc_q35.c                   |    2 +-
>  hw/i386/smbios.c                   | 1102 ------------------------------------
>  hw/smbios/Makefile.objs            |    1 +
>  hw/smbios/smbios.c                 | 1102 ++++++++++++++++++++++++++++++++++++
>  include/hw/arm/virt-acpi-build.h   |    1 +
>  include/hw/i386/smbios.h           |  227 --------
>  include/hw/smbios/smbios.h         |  237 ++++++++
>  tests/bios-tables-test.c           |    2 +-
>  vl.c                               |    2 +-
>  18 files changed, 1414 insertions(+), 1352 deletions(-)
>  delete mode 100644 hw/i386/smbios.c
>  create mode 100644 hw/smbios/Makefile.objs
>  create mode 100644 hw/smbios/smbios.c
>  delete mode 100644 include/hw/i386/smbios.h
>  create mode 100644 include/hw/smbios/smbios.h
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [ARM SMBIOS RFC PATCH 0/5] SMBIOS Support for ARM
  2015-07-14 20:23 [Qemu-devel] [ARM SMBIOS RFC PATCH 0/5] SMBIOS Support for ARM Wei Huang
                   ` (6 preceding siblings ...)
  2015-07-15 22:46 ` Laszlo Ersek
@ 2015-07-16 15:00 ` Gabriel L. Somlo
  7 siblings, 0 replies; 11+ messages in thread
From: Gabriel L. Somlo @ 2015-07-16 15:00 UTC (permalink / raw)
  To: qemu-devel
  Cc: wei, peter.maydell, drjones, ehabkost, zhaoshenglong, mst,
	imammedo, pbonzini, lersek, rth

On Tue, 14 Jul 2015 Wei Huang <wei@redhat.com> wrote:
> 
> SMBIOS tables present userful system hardware info to management
> applications, such as DMI tools. Even though SMBIOS was originally
> developed for Intel x86, it has been extended to both Itanium and 
> ARM (32bit & 64bit). More and more ARM server releases, such as 
> RHEL Server for ARM, start to integrate support for SMBIOS.
> 
> This patchset is intendted to provid SMBIOS tables for ARM mach-virt
> machine. The SMBIOS tables are created and stored in fw_cfg, awaiting
> OVMF (AAVMF) to parse/present SMBIOS entry.
> 
> NOTE: This is RFC and the patches haven't been fully tested yet.
> Laszlo is kind enough to offer help on fixing AAVMF to enable support
> for SMBIOS. Any comments are welcomed for next release.

Since I was the last person to tinker with smbios in a significant
way, here goes:

Patch 3/5: in the commit blurb,
           s/architect-independent/architecture-independent/
                                            ^^^
Whole series:

Acked-by: Gabriel Somlo <somlo@cmu.edu>

I built and ran it (on pc/q35) and saw no regressions. If you will:

Regression-tested-by: Gabriel Somlo <somlo@cmu.edu>

Cheers,
--Gabriel

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2015-07-16 15:04 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-14 20:23 [Qemu-devel] [ARM SMBIOS RFC PATCH 0/5] SMBIOS Support for ARM Wei Huang
2015-07-14 20:23 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 1/5] smbios: extract x86 smbios building code into a function Wei Huang
2015-07-14 20:23 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 2/5] smbios: remove dependency on x86 e820 tables Wei Huang
2015-07-14 20:23 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 3/5] smbios: pass ram size as a parameter to build smbios tables Wei Huang
2015-07-14 20:23 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 4/5] smbios: move smbios code into a common folder Wei Huang
2015-07-15 12:08   ` Laszlo Ersek
2015-07-15 14:32     ` Wei Huang
2015-07-14 20:23 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 5/5] smbios: implement smbios support for mach-virt Wei Huang
2015-07-14 21:15 ` [Qemu-devel] [ARM SMBIOS RFC PATCH 0/5] SMBIOS Support for ARM Laszlo Ersek
2015-07-15 22:46 ` Laszlo Ersek
2015-07-16 15:00 ` Gabriel L. Somlo

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.