summary refs log tree commit diff stats
path: root/hw/i386/smbios.c
diff options
context:
space:
mode:
authorEduardo Habkost <ehabkost@redhat.com>2014-10-29 11:26:08 -0200
committerMichael S. Tsirkin <mst@redhat.com>2014-11-02 13:44:52 +0200
commitcaad057bb6ce86a9cb71520af395fd0bd04a659f (patch)
tree9b26db555e09f85d22fd934e334769d124fb2997 /hw/i386/smbios.c
parent2cad57c7177766e2779f30fed9e4578bc7ad62ac (diff)
downloadfocaccia-qemu-caad057bb6ce86a9cb71520af395fd0bd04a659f.tar.gz
focaccia-qemu-caad057bb6ce86a9cb71520af395fd0bd04a659f.zip
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
c97294ec1b9e36887e119589d456557d72ab37b5.

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>
Diffstat (limited to 'hw/i386/smbios.c')
-rw-r--r--hw/i386/smbios.c27
1 files changed, 24 insertions, 3 deletions
diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c
index 0ae5960b8c..8a7ad48921 100644
--- a/hw/i386/smbios.c
+++ b/hw/i386/smbios.c
@@ -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) {