Merge tag 'pull-for-9.0-20240319' of https://github.com/legoater/qemu into staging
aspeed, pnv, vfio queue:
* user device fixes for Aspeed and PowerNV machines
* coverity fix for iommufd
# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmX5mm0ACgkQUaNDx8/7
# 7KE/MQ/9GeX4yNBxY2iTATdmPXwjMw8AtKyfIQb605nIO0ch1Z98ywl5VMwCNohn
# ppY9L5bFpEASgRlFVm73X4DGxKyRGpRPqylsvINh0hKciRpmRkELHY3llhnXsd7P
# Q197pDtFr54FeX8j4+hSAu4paT97fPENlKn0J6lto2I1cXGcD1LYNDFhysoXdGme
# brJgo7KjQJZPZ560ZewskL5FWf3G9EkRjpqd8y0G5OtNmAPgAaahOMHhDCXan182
# J89I9CHI5xN45MRfAs8JamSaj/GyNsr4h04WhPa0+VZQ5vsaeW2Ekt4ypj+oAV+p
# wykhYzQk4ALZcmmph2flSAtLa7uheI+imyqubMthQCDj3G8onSQBMd5/4WRK6O49
# 0oE1DpPDEfhlJEQYxaYhOeqeA9iaP+w6V+yE+L5oGlMO66cR7GZsPu0x7kXailbH
# IoHw9mO+vMkpuyeP7M3hA8WRFCdFpf1Nn1Ao5Jz3KoiTyJWlIvX5VSaj12sjddQ2
# fU9SKu2Q5QqS5uQGakkY64EyUy7RkGIX6zY2NIscVe2lfAfKf3mZwu7OIuLjEy5O
# lRn35vWV8fOdRooKoDPTNcdBCaNPi+RApin8chOv5P+F+ie7+Twf9sb1AgH/pIcv
# HptvTXbvSFNbbdb+OE8a5qsqTvnrN8d31IXzrWRYsJB07x2IyoA=
# =zR3v
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 19 Mar 2024 14:00:13 GMT
# gpg: using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1
# gpg: Good signature from "Cédric Le Goater <clg@kaod.org>" [undefined]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: A0F6 6548 F048 95EB FE6B 0B60 51A3 43C7 CFFB ECA1
* tag 'pull-for-9.0-20240319' of https://github.com/legoater/qemu:
aspeed/smc: Only wire flash devices at reset
ppc/pnv: I2C controller is not user creatable
vfio/iommufd: Fix memory leak
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/.travis.yml b/.travis.yml
index 76859d4..597d151 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -35,7 +35,7 @@
- TEST_BUILD_CMD=""
- TEST_CMD="make check V=1"
# This is broadly a list of "mainline" system targets which have support across the major distros
- - MAIN_SOFTMMU_TARGETS="aarch64-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
+ - MAIN_SYSTEM_TARGETS="aarch64-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
- CCACHE_SLOPPINESS="include_file_ctime,include_file_mtime"
- CCACHE_MAXSIZE=1G
- G_MESSAGES_DEBUG=error
@@ -114,7 +114,7 @@
env:
- TEST_CMD="make check check-tcg V=1"
- CONFIG="--disable-containers --enable-fdt=system
- --target-list=${MAIN_SOFTMMU_TARGETS} --cxx=/bin/false"
+ --target-list=${MAIN_SYSTEM_TARGETS} --cxx=/bin/false"
- UNRELIABLE=true
- name: "[ppc64] GCC check-tcg"
@@ -185,7 +185,7 @@
env:
- TEST_CMD="make check check-tcg V=1"
- CONFIG="--disable-containers --enable-fdt=system
- --target-list=${MAIN_SOFTMMU_TARGETS},s390x-linux-user"
+ --target-list=${MAIN_SYSTEM_TARGETS},s390x-linux-user"
- UNRELIABLE=true
script:
- BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$?
@@ -226,7 +226,7 @@
- genisoimage
env:
- CONFIG="--disable-containers --enable-fdt=system --audio-drv-list=sdl
- --disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}"
+ --disable-user --target-list-exclude=${MAIN_SYSTEM_TARGETS}"
- name: "[s390x] GCC (user)"
arch: s390x
diff --git a/docs/specs/pvpanic.rst b/docs/specs/pvpanic.rst
index 61a8048..b0f2786 100644
--- a/docs/specs/pvpanic.rst
+++ b/docs/specs/pvpanic.rst
@@ -29,7 +29,7 @@
a guest panic has happened and will be handled by the guest;
the host should record it or report it, but should not affect
the execution of the guest.
-bit 2
+bit 2 (to be implemented)
a regular guest shutdown has happened and should be processed by the host
PCI Interface
diff --git a/docs/system/introduction.rst b/docs/system/introduction.rst
index 51ac132..746707e 100644
--- a/docs/system/introduction.rst
+++ b/docs/system/introduction.rst
@@ -1,6 +1,8 @@
Introduction
============
+.. _Accelerators:
+
Virtualisation Accelerators
---------------------------
diff --git a/docs/system/s390x/cpu-topology.rst b/docs/system/s390x/cpu-topology.rst
index 5133fdc..d5b506e 100644
--- a/docs/system/s390x/cpu-topology.rst
+++ b/docs/system/s390x/cpu-topology.rst
@@ -25,17 +25,19 @@
Prerequisites
-------------
-To use the CPU topology, you need to run with KVM on a s390x host that
-uses the Linux kernel v6.0 or newer (which provide the so-called
+To use the CPU topology, you currently need to choose the KVM accelerator.
+See :ref:`Accelerators` for more details about accelerators and how to select them.
+
+The s390x host needs to use a Linux kernel v6.0 or newer (which provides the so-called
``KVM_CAP_S390_CPU_TOPOLOGY`` capability that allows QEMU to signal the
CPU topology facility via the so-called STFLE bit 11 to the VM).
Enabling CPU topology
---------------------
-Currently, CPU topology is only enabled in the host model by default.
+Currently, CPU topology is enabled by default only in the "host" CPU model.
-Enabling CPU topology in a CPU model is done by setting the CPU flag
+Enabling CPU topology in another CPU model is done by setting the CPU flag
``ctop`` to ``on`` as in:
.. code-block:: bash
@@ -132,7 +134,7 @@
.. code-block:: bash
- $ qemu-system-s390x -m 2G \
+ $ qemu-system-s390x -accel kvm -m 2G \
-cpu gen16b,ctop=on \
-smp cpus=5,sockets=8,cores=4,maxcpus=32 \
-device host-s390x-cpu,core-id=14 \
@@ -227,7 +229,7 @@
.. code-block:: bash
- $ qemu-system-s390x -m 2G \
+ $ qemu-system-s390x -accel kvm -m 2G \
-cpu gen16b,ctop=on \
-smp cpus=1,sockets=8,cores=4,maxcpus=32 \
\
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index e5cd935..a9a913a 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1650,14 +1650,14 @@
}
smbios_set_defaults("QEMU", product,
- vmc->smbios_old_sys_ver ? "1.0" : mc->name, false,
- true, SMBIOS_ENTRY_POINT_TYPE_64);
+ vmc->smbios_old_sys_ver ? "1.0" : mc->name,
+ true);
/* build the array of physical mem area from base_memmap */
mem_array.address = vms->memmap[VIRT_MEM].base;
mem_array.length = ms->ram_size;
- smbios_get_tables(ms, &mem_array, 1,
+ smbios_get_tables(ms, SMBIOS_ENTRY_POINT_TYPE_64, &mem_array, 1,
&smbios_tables, &smbios_tables_len,
&smbios_anchor, &smbios_anchor_len,
&error_fatal);
diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig
index a1846be..a6ee052 100644
--- a/hw/i386/Kconfig
+++ b/hw/i386/Kconfig
@@ -76,6 +76,7 @@
select PIIX
select DIMM
select SMBIOS
+ select SMBIOS_LEGACY
select FW_CFG_DMA
config ISAPC
diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c
index 98a478c..d802d27 100644
--- a/hw/i386/fw_cfg.c
+++ b/hw/i386/fw_cfg.c
@@ -48,7 +48,8 @@
return NULL;
}
-void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg)
+void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg,
+ SmbiosEntryPointType ep_type)
{
#ifdef CONFIG_SMBIOS
uint8_t *smbios_tables, *smbios_anchor;
@@ -63,17 +64,18 @@
if (pcmc->smbios_defaults) {
/* These values are guest ABI, do not change */
smbios_set_defaults("QEMU", mc->desc, mc->name,
- pcmc->smbios_legacy_mode, pcmc->smbios_uuid_encoded,
- pcms->smbios_entry_point_type);
+ pcmc->smbios_uuid_encoded);
}
/* tell smbios about cpuid version and features */
smbios_set_cpuid(cpu->env.cpuid_version, cpu->env.features[FEAT_1_EDX]);
- smbios_tables = smbios_get_table_legacy(ms, &smbios_tables_len);
- if (smbios_tables) {
+ if (pcmc->smbios_legacy_mode) {
+ smbios_tables = smbios_get_table_legacy(&smbios_tables_len,
+ &error_fatal);
fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
smbios_tables, smbios_tables_len);
+ return;
}
/* build the array of physical mem area from e820 table */
@@ -87,7 +89,7 @@
array_count++;
}
}
- smbios_get_tables(ms, mem_array, array_count,
+ smbios_get_tables(ms, ep_type, mem_array, array_count,
&smbios_tables, &smbios_tables_len,
&smbios_anchor, &smbios_anchor_len,
&error_fatal);
diff --git a/hw/i386/fw_cfg.h b/hw/i386/fw_cfg.h
index 1e1de6b..92e310f 100644
--- a/hw/i386/fw_cfg.h
+++ b/hw/i386/fw_cfg.h
@@ -23,7 +23,8 @@
FWCfgState *fw_cfg_arch_create(MachineState *ms,
uint16_t boot_cpus,
uint16_t apic_id_limit);
-void fw_cfg_build_smbios(PCMachineState *ms, FWCfgState *fw_cfg);
+void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg,
+ SmbiosEntryPointType ep_type);
void fw_cfg_build_feature_control(MachineState *ms, FWCfgState *fw_cfg);
void fw_cfg_add_acpi_dsdt(Aml *scope, FWCfgState *fw_cfg);
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index feb7a93..e80f02b 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -672,7 +672,7 @@
acpi_setup();
if (x86ms->fw_cfg) {
- fw_cfg_build_smbios(pcms, x86ms->fw_cfg);
+ fw_cfg_build_smbios(pcms, x86ms->fw_cfg, pcms->smbios_entry_point_type);
fw_cfg_build_feature_control(MACHINE(pcms), x86ms->fw_cfg);
/* update FW_CFG_NB_CPUS to account for -device added CPUs */
fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus);
@@ -1832,7 +1832,7 @@
mc->nvdimm_supported = true;
mc->smp_props.dies_supported = true;
mc->default_ram_id = "pc.ram";
- pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_64;
+ pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_AUTO;
object_class_property_add(oc, PC_MACHINE_MAX_RAM_BELOW_4G, "size",
pc_machine_get_max_ram_below_4g, pc_machine_set_max_ram_below_4g,
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index c9a6c0a..18ba076 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -525,12 +525,16 @@
static void pc_i440fx_8_2_machine_options(MachineClass *m)
{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+
pc_i440fx_9_0_machine_options(m);
m->alias = NULL;
m->is_default = false;
compat_props_add(m->compat_props, hw_compat_8_2, hw_compat_8_2_len);
compat_props_add(m->compat_props, pc_compat_8_2, pc_compat_8_2_len);
+ /* For pc-i44fx-8.2 and 8.1, use SMBIOS 3.X by default */
+ pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_64;
}
DEFINE_I440FX_MACHINE(v8_2, "pc-i440fx-8.2", NULL,
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 8a427c4..b5922b4 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -376,11 +376,14 @@
static void pc_q35_8_2_machine_options(MachineClass *m)
{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_q35_9_0_machine_options(m);
m->alias = NULL;
m->max_cpus = 1024;
compat_props_add(m->compat_props, hw_compat_8_2, hw_compat_8_2_len);
compat_props_add(m->compat_props, pc_compat_8_2, pc_compat_8_2_len);
+ /* For pc-q35-8.2 and 8.1, use SMBIOS 3.X by default */
+ pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_64;
}
DEFINE_Q35_MACHINE(v8_2, "pc-q35-8.2", NULL,
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index efce112..441d764 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -355,10 +355,11 @@
return;
}
- smbios_set_defaults("QEMU", product, mc->name, false,
- true, SMBIOS_ENTRY_POINT_TYPE_64);
+ smbios_set_defaults("QEMU", product, mc->name, true);
- smbios_get_tables(ms, NULL, 0, &smbios_tables, &smbios_tables_len,
+ smbios_get_tables(ms, SMBIOS_ENTRY_POINT_TYPE_64,
+ NULL, 0,
+ &smbios_tables, &smbios_tables_len,
&smbios_anchor, &smbios_anchor_len, &error_fatal);
if (smbios_anchor) {
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index a094af9..72a55b8 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -1275,8 +1275,7 @@
product = "KVM Virtual Machine";
}
- smbios_set_defaults("QEMU", product, mc->name, false,
- true, SMBIOS_ENTRY_POINT_TYPE_64);
+ smbios_set_defaults("QEMU", product, mc->name, true);
if (riscv_is_32bit(&s->soc[0])) {
smbios_set_default_processor_family(0x200);
@@ -1288,7 +1287,8 @@
mem_array.address = s->memmap[VIRT_DRAM].base;
mem_array.length = ms->ram_size;
- smbios_get_tables(ms, &mem_array, 1,
+ smbios_get_tables(ms, SMBIOS_ENTRY_POINT_TYPE_64,
+ &mem_array, 1,
&smbios_tables, &smbios_tables_len,
&smbios_anchor, &smbios_anchor_len,
&error_fatal);
diff --git a/hw/smbios/Kconfig b/hw/smbios/Kconfig
index 553adf4..8d989a2 100644
--- a/hw/smbios/Kconfig
+++ b/hw/smbios/Kconfig
@@ -1,2 +1,4 @@
config SMBIOS
bool
+config SMBIOS_LEGACY
+ bool
diff --git a/hw/smbios/meson.build b/hw/smbios/meson.build
index 7046967..a59039f 100644
--- a/hw/smbios/meson.build
+++ b/hw/smbios/meson.build
@@ -4,5 +4,9 @@
if_true: files('smbios_type_38.c'),
if_false: files('smbios_type_38-stub.c'))
+smbios_ss.add(when: 'CONFIG_SMBIOS_LEGACY',
+ if_true: files('smbios_legacy.c'),
+ if_false: files('smbios_legacy_stub.c'))
+
system_ss.add_all(when: 'CONFIG_SMBIOS', if_true: smbios_ss)
system_ss.add(when: 'CONFIG_SMBIOS', if_false: files('smbios-stub.c'))
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
index e3d5d8f..eed5787 100644
--- a/hw/smbios/smbios.c
+++ b/hw/smbios/smbios.c
@@ -19,7 +19,6 @@
#include "qemu/units.h"
#include "qapi/error.h"
#include "qemu/config-file.h"
-#include "qemu/error-report.h"
#include "qemu/module.h"
#include "qemu/option.h"
#include "sysemu/sysemu.h"
@@ -31,60 +30,31 @@
#include "hw/pci/pci_device.h"
#include "smbios_build.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 */
-
+/*
+ * SMBIOS tables provided by user with '-smbios file=<foo>' option
+ */
+uint8_t *usr_blobs;
+size_t usr_blobs_len;
+static unsigned usr_table_max;
+static unsigned usr_table_cnt;
uint8_t *smbios_tables;
size_t smbios_tables_len;
unsigned smbios_table_max;
unsigned smbios_table_cnt;
-static SmbiosEntryPointType smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_32;
static SmbiosEntryPoint 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 uint32_t smbios_cpuid_version, smbios_cpuid_features;
-static DECLARE_BITMAP(have_binfile_bitmap, SMBIOS_MAX_TYPE+1);
-static DECLARE_BITMAP(have_fields_bitmap, SMBIOS_MAX_TYPE+1);
+DECLARE_BITMAP(smbios_have_binfile_bitmap, SMBIOS_MAX_TYPE + 1);
+DECLARE_BITMAP(smbios_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;
+smbios_type0_t smbios_type0;
+smbios_type1_t smbios_type1;
static struct {
const char *manufacturer, *product, *version, *serial, *asset, *location;
@@ -539,126 +509,33 @@
*/
#define SMBIOS_21_MAX_TABLES_LEN 0xffff
-static void smbios_validate_table(MachineState *ms)
+static bool smbios_check_type4_count(uint32_t expected_t4_count, Error **errp)
{
- uint32_t expect_t4_count = smbios_legacy ?
- ms->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);
+ if (smbios_type4_count && smbios_type4_count != expected_t4_count) {
+ error_setg(errp, "Expected %d SMBIOS Type 4 tables, got %d instead",
+ expected_t4_count, smbios_type4_count);
+ return false;
}
+ return true;
+}
- if (smbios_ep_type == SMBIOS_ENTRY_POINT_TYPE_32 &&
+bool smbios_validate_table(SmbiosEntryPointType ep_type, Error **errp)
+{
+ if (ep_type == SMBIOS_ENTRY_POINT_TYPE_32 &&
smbios_tables_len > SMBIOS_21_MAX_TABLES_LEN) {
- error_report("SMBIOS 2.1 table length %zu exceeds %d",
- smbios_tables_len, SMBIOS_21_MAX_TABLES_LEN);
- exit(1);
+ error_setg(errp, "SMBIOS 2.1 table length %zu exceeds %d",
+ smbios_tables_len, SMBIOS_21_MAX_TABLES_LEN);
+ return false;
}
+ return true;
}
-
-/* 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(MachineState *ms, 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(ms);
- smbios_immutable = true;
- }
- *length = smbios_entries_len;
- return smbios_entries;
-}
-/* end: legacy setup functions for <= 2.0 machines */
-
-
bool smbios_skip_table(uint8_t type, bool required_table)
{
- if (test_bit(type, have_binfile_bitmap)) {
+ if (test_bit(type, smbios_have_binfile_bitmap)) {
return true; /* user provided their own binary blob(s) */
}
- if (test_bit(type, have_fields_bitmap)) {
+ if (test_bit(type, smbios_have_fields_bitmap)) {
return false; /* user provided fields via command line */
}
if (smbios_have_defaults && required_table) {
@@ -686,25 +563,25 @@
{
SMBIOS_BUILD_TABLE_PRE(0, T0_BASE, 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);
+ SMBIOS_TABLE_SET_STR(0, vendor_str, smbios_type0.vendor);
+ SMBIOS_TABLE_SET_STR(0, bios_version_str, smbios_type0.version);
t->bios_starting_address_segment = cpu_to_le16(0xE800); /* from SeaBIOS */
- SMBIOS_TABLE_SET_STR(0, bios_release_date_str, type0.date);
+ SMBIOS_TABLE_SET_STR(0, bios_release_date_str, smbios_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) {
+ if (smbios_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;
+ if (smbios_type0.have_major_minor) {
+ t->system_bios_major_release = smbios_type0.major;
+ t->system_bios_minor_release = smbios_type0.minor;
} else {
t->system_bios_major_release = 0;
t->system_bios_minor_release = 0;
@@ -734,18 +611,18 @@
{
SMBIOS_BUILD_TABLE_PRE(1, T1_BASE, 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);
+ SMBIOS_TABLE_SET_STR(1, manufacturer_str, smbios_type1.manufacturer);
+ SMBIOS_TABLE_SET_STR(1, product_name_str, smbios_type1.product);
+ SMBIOS_TABLE_SET_STR(1, version_str, smbios_type1.version);
+ SMBIOS_TABLE_SET_STR(1, serial_number_str, smbios_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_TABLE_SET_STR(1, sku_number_str, smbios_type1.sku);
+ SMBIOS_TABLE_SET_STR(1, family_str, smbios_type1.family);
SMBIOS_BUILD_TABLE_POST;
}
@@ -791,14 +668,16 @@
SMBIOS_BUILD_TABLE_POST;
}
-static void smbios_build_type_4_table(MachineState *ms, unsigned instance)
+static void smbios_build_type_4_table(MachineState *ms, unsigned instance,
+ SmbiosEntryPointType ep_type,
+ Error **errp)
{
char sock_str[128];
size_t tbl_len = SMBIOS_TYPE_4_LEN_V28;
unsigned threads_per_socket;
unsigned cores_per_socket;
- if (smbios_ep_type == SMBIOS_ENTRY_POINT_TYPE_64) {
+ if (ep_type == SMBIOS_ENTRY_POINT_TYPE_64) {
tbl_len = SMBIOS_TYPE_4_LEN_V30;
}
@@ -845,6 +724,12 @@
if (tbl_len == SMBIOS_TYPE_4_LEN_V30) {
t->core_count2 = t->core_enabled2 = cpu_to_le16(cores_per_socket);
t->thread_count2 = cpu_to_le16(threads_per_socket);
+ } else if (t->core_count == 0xFF || t->thread_count == 0xFF) {
+ error_setg(errp, "SMBIOS 2.0 doesn't support number of processor "
+ "cores/threads more than 255, use "
+ "-machine smbios-entry-point-type=64 option to enable "
+ "SMBIOS 3.0 support");
+ return;
}
SMBIOS_BUILD_TABLE_POST;
@@ -1132,31 +1017,15 @@
}
void smbios_set_defaults(const char *manufacturer, const char *product,
- const char *version, bool legacy_mode,
- bool uuid_encoded, SmbiosEntryPointType ep_type)
+ const char *version,
+ bool uuid_encoded)
{
smbios_have_defaults = true;
- smbios_legacy = legacy_mode;
smbios_uuid_encoded = uuid_encoded;
- smbios_ep_type = ep_type;
- /* 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(smbios_type1.manufacturer, manufacturer);
+ SMBIOS_SET_DEFAULT(smbios_type1.product, product);
+ SMBIOS_SET_DEFAULT(smbios_type1.version, version);
SMBIOS_SET_DEFAULT(type2.manufacturer, manufacturer);
SMBIOS_SET_DEFAULT(type2.product, product);
SMBIOS_SET_DEFAULT(type2.version, version);
@@ -1169,9 +1038,9 @@
SMBIOS_SET_DEFAULT(type17.manufacturer, manufacturer);
}
-static void smbios_entry_point_setup(void)
+static void smbios_entry_point_setup(SmbiosEntryPointType ep_type)
{
- switch (smbios_ep_type) {
+ switch (ep_type) {
case SMBIOS_ENTRY_POINT_TYPE_32:
memcpy(ep.ep21.anchor_string, "_SM_", 4);
memcpy(ep.ep21.intermediate_anchor_string, "_DMI_", 5);
@@ -1220,7 +1089,8 @@
}
}
-void smbios_get_tables(MachineState *ms,
+static bool smbios_get_tables_ep(MachineState *ms,
+ SmbiosEntryPointType ep_type,
const struct smbios_phys_mem_area *mem_array,
const unsigned int mem_array_size,
uint8_t **tables, size_t *tables_len,
@@ -1228,78 +1098,87 @@
Error **errp)
{
unsigned i, dimm_cnt, offset;
+ ERRP_GUARD();
- if (smbios_legacy) {
- *tables = *anchor = NULL;
- *tables_len = *anchor_len = 0;
- return;
+ assert(ep_type == SMBIOS_ENTRY_POINT_TYPE_32 ||
+ ep_type == SMBIOS_ENTRY_POINT_TYPE_64);
+
+ g_free(smbios_tables);
+ smbios_type4_count = 0;
+ smbios_tables = g_memdup2(usr_blobs, usr_blobs_len);
+ smbios_tables_len = usr_blobs_len;
+ smbios_table_max = usr_table_max;
+ smbios_table_cnt = usr_table_cnt;
+
+ smbios_build_type_0_table();
+ smbios_build_type_1_table();
+ smbios_build_type_2_table();
+ smbios_build_type_3_table();
+
+ assert(ms->smp.sockets >= 1);
+
+ for (i = 0; i < ms->smp.sockets; i++) {
+ smbios_build_type_4_table(ms, i, ep_type, errp);
+ if (*errp) {
+ goto err_exit;
+ }
}
- 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 = ms->smp.sockets;
- assert(smbios_smp_sockets >= 1);
-
- for (i = 0; i < smbios_smp_sockets; i++) {
- smbios_build_type_4_table(ms, i);
- }
-
- smbios_build_type_8_table();
- smbios_build_type_9_table(errp);
- smbios_build_type_11_table();
+ smbios_build_type_8_table();
+ smbios_build_type_9_table(errp);
+ smbios_build_type_11_table();
#define MAX_DIMM_SZ (16 * GiB)
#define GET_DIMM_SZ ((i < dimm_cnt - 1) ? MAX_DIMM_SZ \
: ((current_machine->ram_size - 1) % MAX_DIMM_SZ) + 1)
- dimm_cnt = QEMU_ALIGN_UP(current_machine->ram_size, MAX_DIMM_SZ) / MAX_DIMM_SZ;
+ dimm_cnt = QEMU_ALIGN_UP(current_machine->ram_size, MAX_DIMM_SZ) /
+ MAX_DIMM_SZ;
- /*
- * The offset determines if we need to keep additional space between
- * table 17 and table 19 header handle numbers so that they do
- * not overlap. For example, for a VM with larger than 8 TB guest
- * memory and DIMM like chunks of 16 GiB, the default space between
- * the two tables (T19_BASE - T17_BASE = 512) is not enough.
- */
- offset = (dimm_cnt > (T19_BASE - T17_BASE)) ? \
- dimm_cnt - (T19_BASE - T17_BASE) : 0;
+ /*
+ * The offset determines if we need to keep additional space between
+ * table 17 and table 19 header handle numbers so that they do
+ * not overlap. For example, for a VM with larger than 8 TB guest
+ * memory and DIMM like chunks of 16 GiB, the default space between
+ * the two tables (T19_BASE - T17_BASE = 512) is not enough.
+ */
+ offset = (dimm_cnt > (T19_BASE - T17_BASE)) ? \
+ dimm_cnt - (T19_BASE - T17_BASE) : 0;
- smbios_build_type_16_table(dimm_cnt);
+ smbios_build_type_16_table(dimm_cnt);
- 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, offset, mem_array[i].address,
- mem_array[i].length);
- }
-
- /*
- * make sure 16 bit handle numbers in the headers of tables 19
- * and 32 do not overlap.
- */
- assert((mem_array_size + offset) < (T32_BASE - T19_BASE));
-
- smbios_build_type_32_table();
- smbios_build_type_38_table();
- smbios_build_type_41_table(errp);
- smbios_build_type_127_table();
-
- smbios_validate_table(ms);
- smbios_entry_point_setup();
- smbios_immutable = true;
+ 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, offset, mem_array[i].address,
+ mem_array[i].length);
+ }
+
+ /*
+ * make sure 16 bit handle numbers in the headers of tables 19
+ * and 32 do not overlap.
+ */
+ assert((mem_array_size + offset) < (T32_BASE - T19_BASE));
+
+ smbios_build_type_32_table();
+ smbios_build_type_38_table();
+ smbios_build_type_41_table(errp);
+ smbios_build_type_127_table();
+
+ if (!smbios_check_type4_count(ms->smp.sockets, errp)) {
+ goto err_exit;
+ }
+ if (!smbios_validate_table(ep_type, errp)) {
+ goto err_exit;
+ }
+ smbios_entry_point_setup(ep_type);
+
/* return tables blob and entry point (anchor), and their sizes */
*tables = smbios_tables;
*tables_len = smbios_tables_len;
*anchor = (uint8_t *)&ep;
-
/* calculate length based on anchor string */
if (!strncmp((char *)&ep, "_SM_", 4)) {
*anchor_len = sizeof(struct smbios_21_entry_point);
@@ -1308,6 +1187,57 @@
} else {
abort();
}
+
+ return true;
+err_exit:
+ g_free(smbios_tables);
+ smbios_tables = NULL;
+ return false;
+}
+
+void smbios_get_tables(MachineState *ms,
+ SmbiosEntryPointType ep_type,
+ 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,
+ Error **errp)
+{
+ Error *local_err = NULL;
+ bool is_valid;
+ ERRP_GUARD();
+
+ switch (ep_type) {
+ case SMBIOS_ENTRY_POINT_TYPE_AUTO:
+ case SMBIOS_ENTRY_POINT_TYPE_32:
+ is_valid = smbios_get_tables_ep(ms, SMBIOS_ENTRY_POINT_TYPE_32,
+ mem_array, mem_array_size,
+ tables, tables_len,
+ anchor, anchor_len,
+ &local_err);
+ if (is_valid || ep_type != SMBIOS_ENTRY_POINT_TYPE_AUTO) {
+ break;
+ }
+ /*
+ * fall through in case AUTO endpoint is selected and
+ * SMBIOS 2.x tables can't be generated, to try if SMBIOS 3.x
+ * tables would work
+ */
+ case SMBIOS_ENTRY_POINT_TYPE_64:
+ error_free(local_err);
+ local_err = NULL;
+ is_valid = smbios_get_tables_ep(ms, SMBIOS_ENTRY_POINT_TYPE_64,
+ mem_array, mem_array_size,
+ tables, tables_len,
+ anchor, anchor_len,
+ &local_err);
+ break;
+ default:
+ abort();
+ }
+ if (!is_valid) {
+ error_propagate(errp, local_err);
+ }
}
static void save_opt(const char **dest, QemuOpts *opts, const char *name)
@@ -1393,13 +1323,10 @@
{
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 */
+ size_t size;
if (!qemu_opts_validate(opts, qemu_smbios_file_opts, errp)) {
return;
@@ -1416,9 +1343,9 @@
* (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);
+ usr_blobs = g_realloc(usr_blobs, usr_blobs_len + size);
+ header = (struct smbios_structure_header *)(usr_blobs +
+ usr_blobs_len);
if (load_image_size(val, (uint8_t *)header, size) != size) {
error_setg(errp, "Failed to load SMBIOS file %s", val);
@@ -1426,47 +1353,30 @@
}
if (header->type <= SMBIOS_MAX_TYPE) {
- if (test_bit(header->type, have_fields_bitmap)) {
+ if (test_bit(header->type, smbios_have_fields_bitmap)) {
error_setg(errp,
"can't load type %d struct, fields already specified!",
header->type);
return;
}
- set_bit(header->type, have_binfile_bitmap);
+ set_bit(header->type, smbios_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.
+ /*
+ * preserve blob size for legacy mode so it could build its
+ * blobs flavor from 'usr_blobs'
*/
- if (!smbios_entries) {
- smbios_entries_len = sizeof(uint16_t);
- smbios_entries = g_malloc0(smbios_entries_len);
+ smbios_add_usr_blob_size(size);
+
+ usr_blobs_len += size;
+ if (size > usr_table_max) {
+ usr_table_max = size;
}
- 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 */
+ usr_table_cnt++;
return;
}
@@ -1480,41 +1390,42 @@
return;
}
- if (test_bit(type, have_binfile_bitmap)) {
+ if (test_bit(type, smbios_have_binfile_bitmap)) {
error_setg(errp, "can't add fields, binary file already loaded!");
return;
}
- set_bit(type, have_fields_bitmap);
+ set_bit(type, smbios_have_fields_bitmap);
switch (type) {
case 0:
if (!qemu_opts_validate(opts, qemu_smbios_type0_opts, errp)) {
return;
}
- 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);
+ save_opt(&smbios_type0.vendor, opts, "vendor");
+ save_opt(&smbios_type0.version, opts, "version");
+ save_opt(&smbios_type0.date, opts, "date");
+ smbios_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) {
+ if (sscanf(val, "%hhu.%hhu", &smbios_type0.major,
+ &smbios_type0.minor) != 2) {
error_setg(errp, "Invalid release");
return;
}
- type0.have_major_minor = true;
+ smbios_type0.have_major_minor = true;
}
return;
case 1:
if (!qemu_opts_validate(opts, qemu_smbios_type1_opts, errp)) {
return;
}
- 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");
+ save_opt(&smbios_type1.manufacturer, opts, "manufacturer");
+ save_opt(&smbios_type1.product, opts, "product");
+ save_opt(&smbios_type1.version, opts, "version");
+ save_opt(&smbios_type1.serial, opts, "serial");
+ save_opt(&smbios_type1.sku, opts, "sku");
+ save_opt(&smbios_type1.family, opts, "family");
val = qemu_opt_get(opts, "uuid");
if (val) {
@@ -1592,12 +1503,15 @@
t = g_new0(struct type9_instance, 1);
save_opt(&t->slot_designation, opts, "slot_designation");
t->slot_type = qemu_opt_get_number(opts, "slot_type", 0);
- t->slot_data_bus_width = qemu_opt_get_number(opts, "slot_data_bus_width", 0);
+ t->slot_data_bus_width =
+ qemu_opt_get_number(opts, "slot_data_bus_width", 0);
t->current_usage = qemu_opt_get_number(opts, "current_usage", 0);
t->slot_length = qemu_opt_get_number(opts, "slot_length", 0);
t->slot_id = qemu_opt_get_number(opts, "slot_id", 0);
- t->slot_characteristics1 = qemu_opt_get_number(opts, "slot_characteristics1", 0);
- t->slot_characteristics2 = qemu_opt_get_number(opts, "slot_characteristics2", 0);
+ t->slot_characteristics1 =
+ qemu_opt_get_number(opts, "slot_characteristics1", 0);
+ t->slot_characteristics2 =
+ qemu_opt_get_number(opts, "slot_characteristics2", 0);
save_opt(&t->pcidev, opts, "pcidev");
QTAILQ_INSERT_TAIL(&type9, t, next);
return;
diff --git a/hw/smbios/smbios_legacy.c b/hw/smbios/smbios_legacy.c
new file mode 100644
index 0000000..c37a8ee
--- /dev/null
+++ b/hw/smbios/smbios_legacy.c
@@ -0,0 +1,192 @@
+/*
+ * SMBIOS legacy 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/osdep.h"
+#include "qemu/bswap.h"
+#include "hw/firmware/smbios.h"
+#include "sysemu/sysemu.h"
+#include "qapi/error.h"
+
+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;
+GArray *usr_blobs_sizes;
+
+void smbios_add_usr_blob_size(size_t size)
+{
+ if (!usr_blobs_sizes) {
+ usr_blobs_sizes = g_array_new(false, false, sizeof(size_t));
+ }
+ g_array_append_val(usr_blobs_sizes, size);
+}
+
+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),
+ smbios_type0.vendor);
+ smbios_maybe_add_str(0, offsetof(struct smbios_type_0, bios_version_str),
+ smbios_type0.version);
+ smbios_maybe_add_str(0, offsetof(struct smbios_type_0,
+ bios_release_date_str),
+ smbios_type0.date);
+ if (smbios_type0.have_major_minor) {
+ smbios_add_field(0, offsetof(struct smbios_type_0,
+ system_bios_major_release),
+ &smbios_type0.major, 1);
+ smbios_add_field(0, offsetof(struct smbios_type_0,
+ system_bios_minor_release),
+ &smbios_type0.minor, 1);
+ }
+}
+
+static void smbios_build_type_1_fields(void)
+{
+ smbios_maybe_add_str(1, offsetof(struct smbios_type_1, manufacturer_str),
+ smbios_type1.manufacturer);
+ smbios_maybe_add_str(1, offsetof(struct smbios_type_1, product_name_str),
+ smbios_type1.product);
+ smbios_maybe_add_str(1, offsetof(struct smbios_type_1, version_str),
+ smbios_type1.version);
+ smbios_maybe_add_str(1, offsetof(struct smbios_type_1, serial_number_str),
+ smbios_type1.serial);
+ smbios_maybe_add_str(1, offsetof(struct smbios_type_1, sku_number_str),
+ smbios_type1.sku);
+ smbios_maybe_add_str(1, offsetof(struct smbios_type_1, family_str),
+ smbios_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, Error **errp)
+{
+ int i;
+ size_t usr_offset;
+
+ /* complain if fields were given for types > 1 */
+ if (find_next_bit(smbios_have_fields_bitmap,
+ SMBIOS_MAX_TYPE + 1, 2) < SMBIOS_MAX_TYPE + 1) {
+ error_setg(errp, "can't process fields for smbios "
+ "types > 1 on machine versions < 2.1!");
+ goto err_exit;
+ }
+
+ if (test_bit(4, smbios_have_binfile_bitmap)) {
+ error_setg(errp, "can't process table for smbios "
+ "type 4 on machine versions < 2.1!");
+ goto err_exit;
+ }
+
+ g_free(smbios_entries);
+ smbios_entries_len = sizeof(uint16_t);
+ smbios_entries = g_malloc0(smbios_entries_len);
+
+ /*
+ * build a set of legacy smbios_table entries using user provided blobs
+ */
+ for (i = 0, usr_offset = 0; usr_blobs_sizes && i < usr_blobs_sizes->len;
+ i++)
+ {
+ struct smbios_table *table;
+ struct smbios_structure_header *header;
+ size_t size = g_array_index(usr_blobs_sizes, size_t, i);
+
+ header = (struct smbios_structure_header *)(usr_blobs + usr_offset);
+ 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;
+ /*
+ * update number of entries in the blob,
+ * see SeaBIOS: qemu_cfg_legacy():QEMU_CFG_SMBIOS_ENTRIES
+ */
+ (*(uint16_t *)smbios_entries) =
+ cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
+ usr_offset += size;
+ }
+
+ smbios_build_type_0_fields();
+ smbios_build_type_1_fields();
+ if (!smbios_validate_table(SMBIOS_ENTRY_POINT_TYPE_32, errp)) {
+ goto err_exit;
+ }
+
+ *length = smbios_entries_len;
+ return smbios_entries;
+err_exit:
+ g_free(smbios_entries);
+ return NULL;
+}
diff --git a/hw/smbios/smbios_legacy_stub.c b/hw/smbios/smbios_legacy_stub.c
new file mode 100644
index 0000000..f29b153
--- /dev/null
+++ b/hw/smbios/smbios_legacy_stub.c
@@ -0,0 +1,15 @@
+/*
+ * IPMI SMBIOS firmware handling
+ *
+ * Copyright (c) 2024 Igor Mammedov, Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/firmware/smbios.h"
+
+void smbios_add_usr_blob_size(size_t size)
+{
+}
diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h
index c21b8d3..8d3fb2f 100644
--- a/include/hw/firmware/smbios.h
+++ b/include/hw/firmware/smbios.h
@@ -2,6 +2,7 @@
#define QEMU_SMBIOS_H
#include "qapi/qapi-types-machine.h"
+#include "qemu/bitmap.h"
/*
* SMBIOS Support
@@ -16,8 +17,26 @@
*
*/
+extern uint8_t *usr_blobs;
+extern GArray *usr_blobs_sizes;
+
+typedef struct {
+ const char *vendor, *version, *date;
+ bool have_major_minor, uefi;
+ uint8_t major, minor;
+} smbios_type0_t;
+extern smbios_type0_t smbios_type0;
+
+typedef struct {
+ const char *manufacturer, *product, *version, *serial, *sku, *family;
+ /* uuid is in qemu_uuid */
+} smbios_type1_t;
+extern smbios_type1_t smbios_type1;
#define SMBIOS_MAX_TYPE 127
+extern DECLARE_BITMAP(smbios_have_binfile_bitmap, SMBIOS_MAX_TYPE + 1);
+extern DECLARE_BITMAP(smbios_have_fields_bitmap, SMBIOS_MAX_TYPE + 1);
+
#define offsetofend(TYPE, MEMBER) \
(offsetof(TYPE, MEMBER) + sizeof_field(TYPE, MEMBER))
@@ -307,14 +326,17 @@
struct smbios_structure_header header;
} QEMU_PACKED;
+bool smbios_validate_table(SmbiosEntryPointType ep_type, Error **errp);
+void smbios_add_usr_blob_size(size_t size);
void smbios_entry_add(QemuOpts *opts, Error **errp);
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, SmbiosEntryPointType ep_type);
+ const char *version,
+ bool uuid_encoded);
void smbios_set_default_processor_family(uint16_t processor_family);
-uint8_t *smbios_get_table_legacy(MachineState *ms, size_t *length);
+uint8_t *smbios_get_table_legacy(size_t *length, Error **errp);
void smbios_get_tables(MachineState *ms,
+ SmbiosEntryPointType ep_type,
const struct smbios_phys_mem_area *mem_array,
const unsigned int mem_array_size,
uint8_t **tables, size_t *tables_len,
diff --git a/qapi/common.json b/qapi/common.json
index 867a9ad..7558ce5 100644
--- a/qapi/common.json
+++ b/qapi/common.json
@@ -107,9 +107,9 @@
#
# @16: 16.0GT/s
#
-# @32: 32.0GT/s
+# @32: 32.0GT/s (since 9.0)
#
-# @64: 64.0GT/s
+# @64: 64.0GT/s (since 9.0)
#
# Since: 4.0
##
diff --git a/qapi/machine.json b/qapi/machine.json
index bb5a178..0840c91 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -1797,10 +1797,13 @@
#
# @64: SMBIOS version 3.0 (64-bit) Entry Point
#
+# @auto: Either 2.x or 3.x SMBIOS version, 2.x if configuration can be
+# described by it and 3.x otherwise (since: 9.0)
+#
# Since: 7.0
##
{ 'enum': 'SmbiosEntryPointType',
- 'data': [ '32', '64' ] }
+ 'data': [ '32', '64', 'auto' ] }
##
# @MemorySizeConfiguration:
diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
index 1a1c096..8ed3bb6 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -500,6 +500,16 @@
error_prepend((Error **) opaque, "%s ", name);
}
+static void check_compat_model_failed(Error **errp,
+ const S390CPUModel *max_model,
+ const char *msg)
+{
+ error_setg(errp, "%s. Maximum supported model in the current configuration: \'%s\'",
+ msg, max_model->def->name);
+ error_append_hint(errp, "Consider a different accelerator, try \"-accel help\"\n");
+ return;
+}
+
static void check_compatibility(const S390CPUModel *max_model,
const S390CPUModel *model, Error **errp)
{
@@ -507,15 +517,11 @@
S390FeatBitmap missing;
if (model->def->gen > max_model->def->gen) {
- error_setg(errp, "Selected CPU generation is too new. Maximum "
- "supported model in the configuration: \'%s\'",
- max_model->def->name);
+ check_compat_model_failed(errp, max_model, "Selected CPU generation is too new");
return;
} else if (model->def->gen == max_model->def->gen &&
model->def->ec_ga > max_model->def->ec_ga) {
- error_setg(errp, "Selected CPU GA level is too new. Maximum "
- "supported model in the configuration: \'%s\'",
- max_model->def->name);
+ check_compat_model_failed(errp, max_model, "Selected CPU GA level is too new");
return;
}
@@ -537,7 +543,9 @@
error_setg(errp, " ");
s390_feat_bitmap_to_ascii(missing, errp, error_prepend_missing_feat);
error_prepend(errp, "Some features requested in the CPU model are not "
- "available in the configuration: ");
+ "available in the current configuration: ");
+ error_append_hint(errp,
+ "Consider a different accelerator, QEMU, or kernel version\n");
}
S390CPUModel *get_max_cpu_model(Error **errp)
diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c
index dc9ead2..e820f50 100644
--- a/target/sparc/cpu.c
+++ b/target/sparc/cpu.c
@@ -574,9 +574,10 @@
{
unsigned int i;
+ qemu_printf("Available CPU types:\n");
for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
- qemu_printf("Sparc %16s IU " TARGET_FMT_lx
- " FPU %08x MMU %08x NWINS %d ",
+ qemu_printf(" %-20s (IU " TARGET_FMT_lx
+ " FPU %08x MMU %08x NWINS %d) ",
sparc_defs[i].name,
sparc_defs[i].iu_version,
sparc_defs[i].fpu_version,
diff --git a/tests/data/acpi/q35/SSDT.dimmpxm b/tests/data/acpi/q35/SSDT.dimmpxm
index 70f1334..9ea4e0d 100644
--- a/tests/data/acpi/q35/SSDT.dimmpxm
+++ b/tests/data/acpi/q35/SSDT.dimmpxm
Binary files differ
diff --git a/tests/data/smbios/type11_blob b/tests/data/smbios/type11_blob
new file mode 100644
index 0000000..1d8fea4
--- /dev/null
+++ b/tests/data/smbios/type11_blob
Binary files differ
diff --git a/tests/data/smbios/type11_blob.legacy b/tests/data/smbios/type11_blob.legacy
new file mode 100644
index 0000000..aef463a
--- /dev/null
+++ b/tests/data/smbios/type11_blob.legacy
Binary files differ
diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
index 21811a1..d1ff4db 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -858,6 +858,27 @@
g_free(args);
}
+static void process_smbios_tables_noexit(test_data *data)
+{
+ /*
+ * TODO: make SMBIOS tests work with UEFI firmware,
+ * Bug on uefi-test-tools to provide entry point:
+ * https://bugs.launchpad.net/qemu/+bug/1821884
+ */
+ if (!(data->uefi_fl1 && data->uefi_fl2)) {
+ SmbiosEntryPointType ep_type = test_smbios_entry_point(data);
+ test_smbios_structs(data, ep_type);
+ }
+}
+
+static void test_smbios(const char *params, test_data *data)
+{
+ test_vm_prepare(params, data);
+ boot_sector_test(data->qts);
+ process_smbios_tables_noexit(data);
+ qtest_quit(data->qts);
+}
+
static void process_acpi_tables_noexit(test_data *data)
{
test_acpi_load_tables(data);
@@ -868,15 +889,7 @@
test_acpi_asl(data);
}
- /*
- * TODO: make SMBIOS tests work with UEFI firmware,
- * Bug on uefi-test-tools to provide entry point:
- * https://bugs.launchpad.net/qemu/+bug/1821884
- */
- if (!(data->uefi_fl1 && data->uefi_fl2)) {
- SmbiosEntryPointType ep_type = test_smbios_entry_point(data);
- test_smbios_structs(data, ep_type);
- }
+ process_smbios_tables_noexit(data);
}
static void process_acpi_tables(test_data *data)
@@ -2064,6 +2077,50 @@
free_test_data(&data);
}
+static void test_acpi_pc_smbios_options(void)
+{
+ uint8_t req_type11[] = { 11 };
+ test_data data = {
+ .machine = MACHINE_PC,
+ .variant = ".pc_smbios_options",
+ .required_struct_types = req_type11,
+ .required_struct_types_len = ARRAY_SIZE(req_type11),
+ };
+
+ test_smbios("-smbios type=11,value=TEST", &data);
+ free_test_data(&data);
+}
+
+static void test_acpi_pc_smbios_blob(void)
+{
+ uint8_t req_type11[] = { 11 };
+ test_data data = {
+ .machine = MACHINE_PC,
+ .variant = ".pc_smbios_blob",
+ .required_struct_types = req_type11,
+ .required_struct_types_len = ARRAY_SIZE(req_type11),
+ };
+
+ test_smbios("-machine smbios-entry-point-type=32 "
+ "-smbios file=tests/data/smbios/type11_blob", &data);
+ free_test_data(&data);
+}
+
+static void test_acpi_isapc_smbios_legacy(void)
+{
+ uint8_t req_type11[] = { 1, 11 };
+ test_data data = {
+ .machine = "isapc",
+ .variant = ".pc_smbios_legacy",
+ .required_struct_types = req_type11,
+ .required_struct_types_len = ARRAY_SIZE(req_type11),
+ };
+
+ test_smbios("-smbios file=tests/data/smbios/type11_blob.legacy "
+ "-smbios type=1,family=TEST", &data);
+ free_test_data(&data);
+}
+
static void test_oem_fields(test_data *data)
{
int i;
@@ -2215,6 +2272,12 @@
#ifdef CONFIG_POSIX
qtest_add_func("acpi/piix4/acpierst", test_acpi_piix4_acpi_erst);
#endif
+ qtest_add_func("acpi/piix4/smbios-options",
+ test_acpi_pc_smbios_options);
+ qtest_add_func("acpi/piix4/smbios-blob",
+ test_acpi_pc_smbios_blob);
+ qtest_add_func("acpi/piix4/smbios-legacy",
+ test_acpi_isapc_smbios_legacy);
}
if (qtest_has_machine(MACHINE_Q35)) {
qtest_add_func("acpi/q35", test_acpi_q35_tcg);
diff --git a/tests/unit/meson.build b/tests/unit/meson.build
index cae925c..228a21d 100644
--- a/tests/unit/meson.build
+++ b/tests/unit/meson.build
@@ -173,9 +173,10 @@
slow_tests = {
'test-aio-multithread' : 120,
+ 'test-bufferiszero': 60,
'test-crypto-block' : 300,
- 'test-crypto-tlscredsx509': 45,
- 'test-crypto-tlssession': 45,
+ 'test-crypto-tlscredsx509': 90,
+ 'test-crypto-tlssession': 90,
'test-replication': 60,
}