summaryrefslogtreecommitdiffstats
path: root/src/interface/smbios
diff options
context:
space:
mode:
authorMichael Brown2013-03-20 01:14:38 +0100
committerMichael Brown2013-03-20 01:19:42 +0100
commit9e896d0eeaa07d47b2bed4c92072fd638ce3eb55 (patch)
tree5e60ae170d2044942ae856b11da968fb30c741fc /src/interface/smbios
parent[smbios] Provide SMBIOS version number via smbios_version() (diff)
downloadipxe-9e896d0eeaa07d47b2bed4c92072fd638ce3eb55.tar.gz
ipxe-9e896d0eeaa07d47b2bed4c92072fd638ce3eb55.tar.xz
ipxe-9e896d0eeaa07d47b2bed4c92072fd638ce3eb55.zip
[smbios] Mangle UUIDs for SMBIOS version 2.6 and newer
iPXE treats UUIDs as being in network byte order (big-endian). The 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. This results in some inconsistency between the BIOS, vendor PXE, iPXE, and operating system interpretations of the SMBIOS UUID. dmidecode assumes that the byte order is little-endian if and only if the SMBIOS version is 2.6 or higher. Choose to match this behaviour. Reported-by: Matthew Helton <mwhelton@gmail.com> Reported-by: Alexandru Bordei <alexandru.bordei@gmail.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/interface/smbios')
-rw-r--r--src/interface/smbios/smbios_settings.c42
1 files changed, 33 insertions, 9 deletions
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 <stdint.h>
#include <string.h>
#include <errno.h>
+#include <byteswap.h>
#include <ipxe/settings.h>
#include <ipxe/init.h>
#include <ipxe/uuid.h>
@@ -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;
}
}