virtio,pc,pci: bugfixes

Some minor fixes plus a big patchset from Igor fixing
 a regression with windows.
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmX4NzsPHG1zdEByZWRo
 YXQuY29tAAoJECgfDbjSjVRpkp0H/1foAaDYrApMiIkji4aI94bq/fwTnu5CshNP
 +YEzwJCS4qbl67/Ix2Z+xVz7twjQbgGdLd6hb9ZypAQfclUk5tDoKyCmqHtQMakX
 T080FayOvWmUEostAw7MXvuz0HpJlgnJaJBn29l1hHjA/XXahKqcc705cup+W8hv
 F7xb6AoFcbdETMzNaoqekNaHiiYyQPITY9p/UYPLzj2zyLsspR9kBebIeA1yhtXw
 Tmc3+FMquoM2fMNxpwfhCBswg662MlOXhLN3dmyLqeJRl09x1GvaeJIGMY2MbefM
 RMMv0/jqwAyii5HXew2rPIbLdULGq+hSjZo2NOlx3EOjTCaOkXc=
 =XGMp
 -----END PGP SIGNATURE-----

Merge tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu into staging

virtio,pc,pci: bugfixes

Some minor fixes plus a big patchset from Igor fixing
a regression with windows.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# -----BEGIN PGP SIGNATURE-----
#
# iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmX4NzsPHG1zdEByZWRo
# YXQuY29tAAoJECgfDbjSjVRpkp0H/1foAaDYrApMiIkji4aI94bq/fwTnu5CshNP
# +YEzwJCS4qbl67/Ix2Z+xVz7twjQbgGdLd6hb9ZypAQfclUk5tDoKyCmqHtQMakX
# T080FayOvWmUEostAw7MXvuz0HpJlgnJaJBn29l1hHjA/XXahKqcc705cup+W8hv
# F7xb6AoFcbdETMzNaoqekNaHiiYyQPITY9p/UYPLzj2zyLsspR9kBebIeA1yhtXw
# Tmc3+FMquoM2fMNxpwfhCBswg662MlOXhLN3dmyLqeJRl09x1GvaeJIGMY2MbefM
# RMMv0/jqwAyii5HXew2rPIbLdULGq+hSjZo2NOlx3EOjTCaOkXc=
# =XGMp
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 18 Mar 2024 12:44:43 GMT
# gpg:                using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469
# gpg:                issuer "mst@redhat.com"
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [full]
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>" [full]
# Primary key fingerprint: 0270 606B 6F3C DF3D 0B17  0970 C350 3912 AFBE 8E67
#      Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA  8A0D 281F 0DB8 D28D 5469

* tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu: (24 commits)
  smbios: add extra comments to smbios_get_table_legacy()
  tests: acpi: update expected SSDT.dimmpxm blob
  pc/q35: set SMBIOS entry point type to 'auto' by default
  tests: acpi/smbios: whitelist expected blobs
  smbios: error out when building type 4 table is not possible
  smbios: in case of entry point is 'auto' try to build v2 tables 1st
  smbios: extend smbios-entry-point-type with 'auto' value
  smbios: clear smbios_type4_count before building tables
  smbios: get rid of global smbios_ep_type
  smbios: handle errors consistently
  smbios: build legacy mode code only for 'pc' machine
  smbios: rename/expose structures/bitmaps used by both legacy and modern code
  smbios: add smbios_add_usr_blob_size() helper
  smbios: don't check type4 structures in legacy mode
  smbios: avoid mangling user provided tables
  smbios: get rid of smbios_legacy global
  smbios: get rid of smbios_smp_sockets global
  smbios: cleanup smbios_get_tables() from legacy handling
  tests: smbios: add test for legacy mode CLI options
  tests: smbios: add test for -smbios type=11 option
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2024-03-19 10:25:15 +00:00
commit 9359197f0b
22 changed files with 558 additions and 331 deletions

View File

@ -29,7 +29,7 @@ bit 1
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

View File

@ -1650,14 +1650,14 @@ static void virt_build_smbios(VirtMachineState *vms)
}
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);

View File

@ -76,6 +76,7 @@ config I440FX
select PIIX
select DIMM
select SMBIOS
select SMBIOS_LEGACY
select FW_CFG_DMA
config ISAPC

View File

@ -48,7 +48,8 @@ const char *fw_cfg_arch_key_name(uint16_t key)
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 @@ void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg)
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 @@ void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg)
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);

View File

@ -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);

View File

@ -672,7 +672,7 @@ void pc_machine_done(Notifier *notifier, void *data)
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 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
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,

View File

@ -525,12 +525,16 @@ DEFINE_I440FX_MACHINE(v9_0, "pc-i440fx-9.0", NULL,
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,

View File

@ -376,11 +376,14 @@ DEFINE_Q35_MACHINE(v9_0, "pc-q35-9.0", NULL,
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,

View File

@ -355,10 +355,11 @@ static void virt_build_smbios(LoongArchMachineState *lams)
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) {

View File

@ -1275,8 +1275,7 @@ static void virt_build_smbios(RISCVVirtState *s)
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 @@ static void virt_build_smbios(RISCVVirtState *s)
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);

View File

@ -1,2 +1,4 @@
config SMBIOS
bool
config SMBIOS_LEGACY
bool

View File

@ -4,5 +4,9 @@ smbios_ss.add(when: 'CONFIG_IPMI',
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'))

View File

@ -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 @@ opts_init(smbios_register_config);
*/
#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 @@ static void smbios_build_type_0_table(void)
{
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 @@ static void smbios_build_type_1_table(void)
{
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 @@ static void smbios_build_type_3_table(void)
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 @@ static void smbios_build_type_4_table(MachineState *ms, unsigned instance)
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_default_processor_family(uint16_t processor_family)
}
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 @@ void smbios_set_defaults(const char *manufacturer, const char *product,
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 @@ static void smbios_entry_point_setup(void)
}
}
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 @@ void smbios_get_tables(MachineState *ms,
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 @@ void smbios_get_tables(MachineState *ms,
} 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 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
{
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 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
* (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 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
}
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 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
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 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
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;

192
hw/smbios/smbios_legacy.c Normal file
View File

@ -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;
}

View File

@ -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)
{
}

View File

@ -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_type_127 {
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,

View File

@ -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
##

View File

@ -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:

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -858,6 +858,27 @@ static void test_vm_prepare(const char *params, test_data *data)
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 @@ static void process_acpi_tables_noexit(test_data *data)
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 @@ static void test_acpi_q35_pvpanic_isa(void)
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 @@ int main(int argc, char *argv[])
#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);