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