From 59820aacf5f9bcfde98753fde79ca2c779d755aa Mon Sep 17 00:00:00 2001
From: Mark Salter <msalter@redhat.com>
Date: Tue, 24 Feb 2015 23:42:05 -0500
Subject: [PATCH] Support SMBIOS 3.0 64-bit header
The SMBIOS 64-bit header adds suport for a 64-bit base address for the
SMBIOS tables. This patch adds code to parse deal with older 32-bit
headers and well as the 64-bit header. It also fixes 32-bit address
assumptions in a number of places.
Signed-off-by: Mark Salter <msalter@redhat.com>
---
dmidecode.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 112 insertions(+), 31 deletions(-)
diff --git a/dmidecode.c b/dmidecode.c
index fee3af1..6865cd7 100644
--- a/dmidecode.c
+++ b/dmidecode.c
@@ -4277,7 +4277,10 @@ static u16 get_smbios_version(unsigned char *smbios)
{
u16 ver;
- ver = (smbios[0x06] << 8) + smbios[0x07];
+ if (!memcmp(smbios, "_SM3_", 5))
+ ver = (smbios[0x07] << 8) + smbios[0x08];
+ else
+ ver = (smbios[0x06] << 8) + smbios[0x07];
/* Some BIOS report weird SMBIOS version, fix that up */
switch (ver) {
@@ -4348,7 +4351,33 @@ static void dmi_table_dump(u8 *buf, u16 len)
write_dump(32, len, buf, opt.dumpfile, 0);
}
-static void dmi_table(u32 base, u8 *buf, u16 len, u16 num, u16 ver)
+static u16 dmi_table_count(u8 *buf, u16 len)
+{
+ u8 *data;
+ u16 i = 0;
+
+ data = buf;
+ while (data+4 <= buf + len) /* 4 is the length of an SMBIOS structure header */
+ {
+ struct dmi_header h;
+
+ ++i;
+
+ to_dmi_header(&h, data);
+
+ if (h.length < 4)
+ break;
+
+ /* look for the next handle */
+ data += h.length;
+ while (data - buf + 1 < len && (data[0] != 0 || data[1] != 0))
+ data++;
+ data += 2;
+ }
+ return i;
+}
+
+static void dmi_table(u64 base, u8 *buf, u16 len, u16 num, u16 ver)
{
u8 *data;
int i = 0;
@@ -4372,8 +4401,13 @@ static void dmi_table(u32 base, u8 *buf, u16 len, u16 num, u16 ver)
{
printf("%u structures occupying %u bytes.\n",
num, len);
- if (!(opt.flags & FLAG_FROM_DUMP))
- printf("Table at 0x%08X.\n", base);
+ if (!(opt.flags & FLAG_FROM_DUMP)) {
+ if (base.h)
+ printf("Table at 0x%08X%08X.\n",
+ base.h, base.l);
+ else
+ printf("Table at 0x%08X.\n", base.l);
+ }
}
printf("\n");
}
@@ -4460,15 +4494,19 @@ static void dmi_table(u32 base, u8 *buf, u16 len, u16 num, u16 ver)
/*
* Build a crafted entry point with table address hard-coded to 32,
* as this is where we will put it in the output file. We adjust the
- * DMI checksum appropriately. The SMBIOS checksum needs no adjustment.
+ * checksum appropriately.
*/
-static void overwrite_dmi_address(u8 *buf)
+static void overwrite_address(u8 *cksum, u8 *addr, int addr_len)
{
- buf[0x05] += buf[0x08] + buf[0x09] + buf[0x0A] + buf[0x0B] - 32;
- buf[0x08] = 32;
- buf[0x09] = 0;
- buf[0x0A] = 0;
- buf[0x0B] = 0;
+ int i;
+
+ *cksum += addr[0] - 32;
+ addr[0] = 32;
+
+ for (i = 1; i < addr_len; ++i) {
+ *cksum += addr[i];
+ addr[i] = 0;
+ }
}
/**
@@ -4478,36 +4516,51 @@ static void overwrite_dmi_address(u8 *buf)
static void smbios_in_dumpfile(unsigned char *smbios)
{
u8 crafted[32];
+ u8 len;
memcpy(crafted, smbios, 32);
- overwrite_dmi_address(crafted + 0x10);
+ if (!memcmp(smbios, "_SM3_", 5)) {
+ overwrite_address(crafted + 0x05, crafted + 0x10, 8);
+ len = crafted[0x06];
+ } else {
+ overwrite_address(crafted + 0x15, crafted + 0x18, 4);
+ len = crafted[0x05];
+ }
if (!(opt.flags & FLAG_QUIET))
printf("# Writing %d bytes to %s.\n", crafted[0x05],
opt.dumpfile);
- write_dump(0, crafted[0x05], crafted, opt.dumpfile, 1);
+ write_dump(0, len, crafted, opt.dumpfile, 1);
}
static int smbios_decode(u8 *buf, const char *devmem)
{
u16 ver;
- u16 len;
- u32 base;
+ u16 len, num;
+ u64 base;
u8 *dmibuf;
- if (!checksum(buf, buf[0x05])
- || memcmp(buf + 0x10, "_DMI_", 5) != 0
- || !checksum(buf + 0x10, 0x0F))
- return 0;
+ if (!memcmp(buf, "_SM3_", 5)) {
+ if (!checksum(buf, buf[0x06]))
+ return 0;
+ base = QWORD(buf + 0x10);
+ len = WORD(buf + 0x0C);
+ } else {
+ if (!checksum(buf, buf[0x05])
+ || memcmp(buf + 0x10, "_DMI_", 5) != 0
+ || !checksum(buf + 0x10, 0x0F))
+ return 0;
+ base.h = 0;
+ base.l = DWORD(buf + 0x18);
+ len = WORD(buf + 0x16);
+ }
ver = get_smbios_version(buf);
-
- base = DWORD(buf + 0x18);
- len = WORD(buf + 0x16);
- dmibuf = mem_chunk(base, len, devmem);
+ dmibuf = mem_chunk(base.l, len, devmem);
if (!dmibuf) {
fprintf(stderr, "Table is unreachable, sorry."
+
#ifndef USE_MMAP
" Try compiling dmidecode with -DUSE_MMAP."
#endif
@@ -4515,7 +4568,13 @@ static int smbios_decode(u8 *buf, const char *devmem)
return 0;
}
- dmi_table(base, dmibuf, len, WORD(buf + 0x1C), ver);
+ /* version 3 64-bit header doesn't have number of tables */
+ if (!memcmp(buf, "_SM3_", 5))
+ num = dmi_table_count(dmibuf, len);
+ else
+ num = WORD(buf + 0x1C);
+
+ dmi_table(base, dmibuf, len, num, ver);
free(dmibuf);
@@ -4529,6 +4588,7 @@ static void dmifs_smbios_decode(void)
{
u16 ver;
u8 *smbios;
+ u64 base;
struct dmi_table *dt;
dt = dmi_get_table();
@@ -4538,8 +4598,28 @@ static void dmifs_smbios_decode(void)
smbios = dt->smbios;
ver = get_smbios_version(dt->smbios);
- dmi_table(DWORD(smbios + 0x18), dmi_get_raw_data(dt->dmi_list),
- WORD(smbios + 0x16), WORD(smbios + 0x1C), ver);
+
+ if (!memcmp(smbios, "_SM3_", 5)) {
+ base = QWORD(smbios + 0x10);
+ dmi_table(base, dmi_get_raw_data(dt->dmi_list),
+ dt->dmi_size, dt->dmi_count, ver);
+ if (opt.flags & FLAG_DUMP_BIN) {
+ /*
+ * Table length in SMBIOS 3.0 header is a maximum size.
+ * Make it exact to avoid warnings/errors when decoding
+ * from file we are dumping.
+ */
+ dt->smbios[0x05] += dt->smbios[0x0c] + dt->smbios[0x0d];
+ dt->smbios[0x0c] = dt->dmi_size;
+ dt->smbios[0x0d] = dt->dmi_size >> 8;
+ dt->smbios[0x05] -= dt->smbios[0x0c] + dt->smbios[0x0d];
+ }
+ } else {
+ base.h = 0;
+ base.l = DWORD(smbios + 0x18);
+ dmi_table(base, dmi_get_raw_data(dt->dmi_list),
+ WORD(smbios + 0x16), WORD(smbios + 0x1C), ver);
+ }
if (opt.flags & FLAG_DUMP_BIN)
smbios_in_dumpfile(dt->smbios);
@@ -4550,7 +4630,7 @@ static void dmifs_smbios_decode(void)
static int legacy_decode(u8 *buf, const char *devmem)
{
u16 len;
- u32 base;
+ u64 base;
u8 *dmibuf;
if (!checksum(buf, 0x0F))
@@ -4561,8 +4641,9 @@ static int legacy_decode(u8 *buf, const char *devmem)
buf[0x0E] >> 4, buf[0x0E] & 0x0F);
len = WORD(buf + 0x06);
- base = DWORD(buf + 0x08);
- dmibuf = mem_chunk(base, len, devmem);
+ base.h = 0;
+ base.l = DWORD(buf + 0x08);
+ dmibuf = mem_chunk(base.l, len, devmem);
if (!dmibuf) {
fprintf(stderr, "Table is unreachable, sorry."
#ifndef USE_MMAP
@@ -4582,7 +4663,7 @@ static int legacy_decode(u8 *buf, const char *devmem)
u8 crafted[16];
memcpy(crafted, buf, 16);
- overwrite_dmi_address(crafted);
+ overwrite_address(crafted + 0x05, crafted + 0x08, 4);
printf("# Writing %d bytes to %s.\n", 0x0F, opt.dumpfile);
write_dump(0, 0x0F, crafted, opt.dumpfile, 1);
@@ -4689,7 +4770,7 @@ int main(int argc, char * const argv[])
goto exit_free;
}
- if (memcmp(buf, "_SM_", 4) == 0)
+ if (memcmp(buf, "_SM_", 4) == 0 || memcmp(buf, "_SM3_", 5) == 0)
{
if (smbios_decode(buf, opt.dumpfile))
found++;
--
1.8.3.1