diff --git a/src/interface/smbios/smbios_settings.c b/src/interface/smbios/smbios_settings.c index 893b958e..4ca14476 100644 --- a/src/interface/smbios/smbios_settings.c +++ b/src/interface/smbios/smbios_settings.c @@ -22,6 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include #include @@ -112,14 +113,16 @@ static int smbios_fetch ( struct settings *settings __unused, { uint8_t buf[structure.header.len]; + const void *raw; + union uuid uuid; /* Read SMBIOS structure */ if ( ( rc = read_smbios_structure ( &structure, buf, sizeof ( buf ) ) ) != 0 ) return rc; + /* A tag length of zero indicates a string */ if ( tag_len == 0 ) { - /* String */ if ( ( rc = read_smbios_string ( &structure, buf[tag_offset], data, len ) ) < 0 ) { @@ -128,15 +131,36 @@ static int smbios_fetch ( struct settings *settings __unused, if ( ! setting->type ) setting->type = &setting_type_string; return rc; - } else { - /* Raw data */ - if ( len > tag_len ) - len = tag_len; - memcpy ( data, &buf[tag_offset], len ); - if ( ! setting->type ) - setting->type = &setting_type_hex; - return tag_len; } + + /* Mangle UUIDs if necessary. iPXE treats UUIDs as + * being in network byte order (big-endian). SMBIOS + * specification version 2.6 states that UUIDs are + * stored with little-endian values in the first three + * fields; earlier versions did not specify an + * endianness. dmidecode assumes that the byte order + * is little-endian if and only if the SMBIOS version + * is 2.6 or higher; we match this behaviour. + */ + raw = &buf[tag_offset]; + if ( ( setting->type == &setting_type_uuid ) && + ( tag_len == sizeof ( uuid ) ) && + ( smbios_version() >= SMBIOS_VERSION ( 2, 6 ) ) ) { + DBG ( "SMBIOS detected mangled UUID\n" ); + memcpy ( &uuid, &buf[tag_offset], sizeof ( uuid ) ); + __bswap_32s ( &uuid.canonical.a ); + __bswap_16s ( &uuid.canonical.b ); + __bswap_16s ( &uuid.canonical.c ); + raw = &uuid; + } + + /* Return data */ + if ( len > tag_len ) + len = tag_len; + memcpy ( data, raw, len ); + if ( ! setting->type ) + setting->type = &setting_type_hex; + return tag_len; } }