mirror of https://gitee.com/openkylin/qemu.git
smbios: Encode UUID according to SMBIOS specification
Differently from older versions, SMBIOS version 2.6 is explicit about
the encoding of UUID fields:
> Although RFC 4122 recommends network byte order for all fields, the PC
> industry (including the ACPI, UEFI, and Microsoft specifications) has
> consistently used little-endian byte encoding for the first three fields:
> time_low, time_mid, time_hi_and_version. The same encoding, also known as
> wire format, should also be used for the SMBIOS representation of the UUID.
>
> The UUID {00112233-4455-6677-8899-AABBCCDDEEFF} would thus be represented
> as 33 22 11 00 55 44 77 66 88 99 AA BB CC DD EE FF.
The dmidecode tool implements this and decodes the above "wire format"
when SMBIOS version >= 2.6. We moved from SMBIOS version 2.4 to 2.8 when
we started building the SMBIOS entry point inside QEMU, on commit
c97294ec1b
.
Change smbios_build_type_1_table() to encode the UUID as specified.
To make sure we won't change the guest-visible UUID when upgrading to a
newer QEMU version, keep the old behavior on pc-*-2.1 and older.
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
2cad57c717
commit
caad057bb6
|
@ -63,6 +63,7 @@ static bool has_acpi_build = true;
|
|||
static int legacy_acpi_table_size;
|
||||
static bool smbios_defaults = true;
|
||||
static bool smbios_legacy_mode;
|
||||
static bool smbios_uuid_encoded = true;
|
||||
/* Make sure that guest addresses aligned at 1Gbyte boundaries get mapped to
|
||||
* host addresses aligned at 1Gbyte boundaries. This way we can use 1GByte
|
||||
* pages in the host.
|
||||
|
@ -172,7 +173,7 @@ static void pc_init1(MachineState *machine,
|
|||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
/* These values are guest ABI, do not change */
|
||||
smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)",
|
||||
mc->name, smbios_legacy_mode);
|
||||
mc->name, smbios_legacy_mode, smbios_uuid_encoded);
|
||||
}
|
||||
|
||||
/* allocate ram and load rom/bios */
|
||||
|
@ -304,6 +305,7 @@ static void pc_init_pci(MachineState *machine)
|
|||
|
||||
static void pc_compat_2_1(MachineState *machine)
|
||||
{
|
||||
smbios_uuid_encoded = false;
|
||||
}
|
||||
|
||||
static void pc_compat_2_0(MachineState *machine)
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
static bool has_acpi_build = true;
|
||||
static bool smbios_defaults = true;
|
||||
static bool smbios_legacy_mode;
|
||||
static bool smbios_uuid_encoded = true;
|
||||
/* Make sure that guest addresses aligned at 1Gbyte boundaries get mapped to
|
||||
* host addresses aligned at 1Gbyte boundaries. This way we can use 1GByte
|
||||
* pages in the host.
|
||||
|
@ -163,7 +164,7 @@ static void pc_q35_init(MachineState *machine)
|
|||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
/* These values are guest ABI, do not change */
|
||||
smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)",
|
||||
mc->name, smbios_legacy_mode);
|
||||
mc->name, smbios_legacy_mode, smbios_uuid_encoded);
|
||||
}
|
||||
|
||||
/* allocate ram and load rom/bios */
|
||||
|
@ -283,6 +284,7 @@ static void pc_q35_init(MachineState *machine)
|
|||
|
||||
static void pc_compat_2_1(MachineState *machine)
|
||||
{
|
||||
smbios_uuid_encoded = false;
|
||||
}
|
||||
|
||||
static void pc_compat_2_0(MachineState *machine)
|
||||
|
|
|
@ -48,6 +48,7 @@ struct smbios_table {
|
|||
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 */
|
||||
|
||||
|
||||
|
@ -391,6 +392,11 @@ static void smbios_build_type_1_fields(void)
|
|||
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);
|
||||
}
|
||||
|
@ -523,6 +529,19 @@ static void smbios_build_type_0_table(void)
|
|||
SMBIOS_BUILD_TABLE_POST;
|
||||
}
|
||||
|
||||
/* Encode UUID from the big endian encoding described on RFC4122 to the wire
|
||||
* format specified by SMBIOS version 2.6.
|
||||
*/
|
||||
static void smbios_encode_uuid(struct smbios_uuid *uuid, const uint8_t *buf)
|
||||
{
|
||||
memcpy(uuid, buf, 16);
|
||||
if (smbios_uuid_encoded) {
|
||||
uuid->time_low = bswap32(uuid->time_low);
|
||||
uuid->time_mid = bswap16(uuid->time_mid);
|
||||
uuid->time_hi_and_version = bswap16(uuid->time_hi_and_version);
|
||||
}
|
||||
}
|
||||
|
||||
static void smbios_build_type_1_table(void)
|
||||
{
|
||||
SMBIOS_BUILD_TABLE_PRE(1, 0x100, true); /* required */
|
||||
|
@ -532,9 +551,9 @@ static void smbios_build_type_1_table(void)
|
|||
SMBIOS_TABLE_SET_STR(1, version_str, type1.version);
|
||||
SMBIOS_TABLE_SET_STR(1, serial_number_str, type1.serial);
|
||||
if (qemu_uuid_set) {
|
||||
memcpy(t->uuid, qemu_uuid, 16);
|
||||
smbios_encode_uuid(&t->uuid, qemu_uuid);
|
||||
} else {
|
||||
memset(t->uuid, 0, 16);
|
||||
memset(&t->uuid, 0, 16);
|
||||
}
|
||||
t->wake_up_type = 0x06; /* power switch */
|
||||
SMBIOS_TABLE_SET_STR(1, sku_number_str, type1.sku);
|
||||
|
@ -746,10 +765,12 @@ 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)
|
||||
const char *version, bool legacy_mode,
|
||||
bool uuid_encoded)
|
||||
{
|
||||
smbios_have_defaults = true;
|
||||
smbios_legacy = legacy_mode;
|
||||
smbios_uuid_encoded = uuid_encoded;
|
||||
|
||||
/* drop unwanted version of command-line file blob(s) */
|
||||
if (smbios_legacy) {
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
void smbios_entry_add(QemuOpts *opts);
|
||||
void smbios_set_cpuid(uint32_t version, uint32_t features);
|
||||
void smbios_set_defaults(const char *manufacturer, const char *product,
|
||||
const char *version, bool legacy_mode);
|
||||
const char *version, bool legacy_mode,
|
||||
bool uuid_encoded);
|
||||
uint8_t *smbios_get_table_legacy(size_t *length);
|
||||
void smbios_get_tables(uint8_t **tables, size_t *tables_len,
|
||||
uint8_t **anchor, size_t *anchor_len);
|
||||
|
@ -72,6 +73,18 @@ struct smbios_type_0 {
|
|||
uint8_t embedded_controller_minor_release;
|
||||
} QEMU_PACKED;
|
||||
|
||||
/* UUID encoding. The time_* fields are little-endian, as specified by SMBIOS
|
||||
* version 2.6.
|
||||
*/
|
||||
struct smbios_uuid {
|
||||
uint32_t time_low;
|
||||
uint16_t time_mid;
|
||||
uint16_t time_hi_and_version;
|
||||
uint8_t clock_seq_hi_and_reserved;
|
||||
uint8_t clock_seq_low;
|
||||
uint8_t node[6];
|
||||
} QEMU_PACKED;
|
||||
|
||||
/* SMBIOS type 1 - System Information */
|
||||
struct smbios_type_1 {
|
||||
struct smbios_structure_header header;
|
||||
|
@ -79,7 +92,7 @@ struct smbios_type_1 {
|
|||
uint8_t product_name_str;
|
||||
uint8_t version_str;
|
||||
uint8_t serial_number_str;
|
||||
uint8_t uuid[16];
|
||||
struct smbios_uuid uuid;
|
||||
uint8_t wake_up_type;
|
||||
uint8_t sku_number_str;
|
||||
uint8_t family_str;
|
||||
|
|
3
vl.c
3
vl.c
|
@ -190,6 +190,9 @@ int nb_numa_nodes;
|
|||
int max_numa_nodeid;
|
||||
NodeInfo numa_info[MAX_NODES];
|
||||
|
||||
/* The bytes in qemu_uuid[] are in the order specified by RFC4122, _not_ in the
|
||||
* little-endian "wire format" described in the SMBIOS 2.6 specification.
|
||||
*/
|
||||
uint8_t qemu_uuid[16];
|
||||
bool qemu_uuid_set;
|
||||
|
||||
|
|
Loading…
Reference in New Issue