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:
commit
9359197f0b
@ -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
|
||||
|
@ -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);
|
||||
|
@ -76,6 +76,7 @@ config I440FX
|
||||
select PIIX
|
||||
select DIMM
|
||||
select SMBIOS
|
||||
select SMBIOS_LEGACY
|
||||
select FW_CFG_DMA
|
||||
|
||||
config ISAPC
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -1,2 +1,4 @@
|
||||
config SMBIOS
|
||||
bool
|
||||
config SMBIOS_LEGACY
|
||||
bool
|
||||
|
@ -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'))
|
||||
|
@ -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",
|
||||
error_setg(errp, "SMBIOS 2.1 table length %zu exceeds %d",
|
||||
smbios_tables_len, SMBIOS_21_MAX_TABLES_LEN);
|
||||
exit(1);
|
||||
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,24 +1098,30 @@ 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;
|
||||
|
||||
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);
|
||||
assert(ms->smp.sockets >= 1);
|
||||
|
||||
for (i = 0; i < smbios_smp_sockets; i++) {
|
||||
smbios_build_type_4_table(ms, i);
|
||||
for (i = 0; i < ms->smp.sockets; i++) {
|
||||
smbios_build_type_4_table(ms, i, ep_type, errp);
|
||||
if (*errp) {
|
||||
goto err_exit;
|
||||
}
|
||||
}
|
||||
|
||||
smbios_build_type_8_table();
|
||||
@ -1256,7 +1132,8 @@ void smbios_get_tables(MachineState *ms,
|
||||
#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
|
||||
@ -1290,16 +1167,18 @@ void smbios_get_tables(MachineState *ms,
|
||||
smbios_build_type_41_table(errp);
|
||||
smbios_build_type_127_table();
|
||||
|
||||
smbios_validate_table(ms);
|
||||
smbios_entry_point_setup();
|
||||
smbios_immutable = true;
|
||||
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
192
hw/smbios/smbios_legacy.c
Normal 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;
|
||||
}
|
15
hw/smbios/smbios_legacy_stub.c
Normal file
15
hw/smbios/smbios_legacy_stub.c
Normal 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)
|
||||
{
|
||||
}
|
@ -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,
|
||||
|
@ -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
|
||||
##
|
||||
|
@ -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.
BIN
tests/data/smbios/type11_blob
Normal file
BIN
tests/data/smbios/type11_blob
Normal file
Binary file not shown.
BIN
tests/data/smbios/type11_blob.legacy
Normal file
BIN
tests/data/smbios/type11_blob.legacy
Normal file
Binary file not shown.
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user