summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2017-05-31 23:24:59 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2017-05-31 23:24:59 +0200
commit703721ff8e0955029c99208b7d99f7bde68243f4 (patch)
tree8380a4a5c7aedd162cc2b7d8d33a17d9e4e436d8
parent0e7659200e3c881e354aab00b758d25408a21544 (diff)
parenta1e93482d9cc9ace5fc1494677b45d965f1ddcb7 (diff)
Merge tag 'upstream/3.1' into feature/upstream
Upstream version 3.1
-rw-r--r--AUTHORS2
-rw-r--r--CHANGELOG98
-rw-r--r--README7
-rw-r--r--biosdecode.c34
-rw-r--r--dmidecode.c410
-rw-r--r--dmiopt.c41
-rw-r--r--man/dmidecode.87
-rw-r--r--util.c69
-rw-r--r--util.h4
-rw-r--r--version.h2
10 files changed, 569 insertions, 105 deletions
diff --git a/AUTHORS b/AUTHORS
index d4badfa..748b985 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -19,6 +19,8 @@ Jarod Wilson <jarod@redhat.com>
Anton Arapov <anton@redhat.com>
Roy Franz <roy.franz@linaro.org>
Tyler Bell <tyler.bell@hp.com>
+Xie XiuQi <xiexiuqi@huawei.com>
+Petr Oros <poros@redhat.com>
MANY THANKS TO (IN CHRONOLOGICAL ORDER)
Werner Heuser
diff --git a/CHANGELOG b/CHANGELOG
index f0a51a4..6f9123d 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,103 @@
2015-09-03 Jean Delvare <jdelvare@suse.de>
+ * version.h: Set version to 3.1.
+
+2017-05-23 Jean Delvare <jdelvare@suse.de>
+
+ * dmidecode.c, dmiopt.c: Add a new option to extract OEM strings, like
+ we already have for many other strings.
+ * dmidecode.8: Document the new option.
+
+2017-04-27 Jean Delvare <jdelvare@suse.de>
+
+ Update to support SMBIOS specification version 3.1.1.
+
+ * dmidecode.c: Add support for 3-digit versions.
+ * dmidecode.c: Add new enumerated values for processors (DMI type 4).
+
+2017-04-27 Jean Delvare <jdelvare@suse.de>
+
+ Update to support SMBIOS specification version 3.1.0.
+
+ * dmidecode.c: Add support for extended BIOS ROM size (DMI type 0).
+ * dmidecode.c: Add new enumerated values for chassis types
+ (DMI type 3).
+ * dmidecode.c: Add new enumerated values for processors (DMI type 4).
+ * dmidecode.c: Don't assume 8-bit processor family in dmi_processor_id
+ (DMI type 4).
+ * dmidecode.c: Decode the MIDR register on ARM processors
+ (DMI type 4).
+ * dmidecode.c: Add support for large cache sizes (DMI type 7).
+ * dmidecode.c: Add Mini PCIe system slot enumerated values
+ (DMI type 9).
+ * dmidecode.c: Clarify the memory speed unit (DMI type 17).
+ * dmidecode.c: Add support for structure type 43 (TPM Device).
+
+2017-04-11 Jean Delvare <jdelvare@suse.de>
+
+ * util.c: Don't leak a file descriptor in function read_file.
+ * util.c, util.c, dmidecode.c: Let callers pass an offset to function
+ read_file.
+ * dmidecode.c: Fix reading from SMBIOS 3 dump files using a 64-bit
+ entry point.
+
+2017-04-10 Jean Delvare <jdelvare@suse.de>
+
+ * dmidecode.c: Decode the processor ID of the Intel Core M, AMD
+ Athlon X4 and AMD Opteron X1000/X2000 processors (DMI type 4).
+ * dmidecode.c: Display the IPMI interrupt number as a decimal
+ number (DMI type 38).
+
+2017-01-20 Jean Delvare <jdelvare@suse.de>
+
+ * biosdecode.c: Decode the entry point defined in the Intel
+ Multiprocessor specification.
+
+2017-01-20 Jean Delvare <jdelvare@suse.de>
+
+ * dmidecode.c: Only decode one DMI table.
+ This fixes Savannah bug #50022:
+ https://savannah.nongnu.org/bugs/?50022
+
+2016-09-22 Jean Delvare <jdelvare@suse.de>
+
+ * README: Explain that we can no longer support Cygwin.
+
+2016-06-30 Petr Oros <poros@redhat.com>
+
+ * dmidecode.c: Unmask LRDIMM in memory type detail (DMI type 17).
+
+2015-11-02 Jean Delvare <jdelvare@suse.de>
+
+ * dmidecode.c, util.c, util.h: Let read_file return the actual data
+ size.
+ * dmidecode.c: Use read_file to read the DMI table from sysfs.
+ This fixes Savannah bug #46176:
+ https://savannah.nongnu.org/bugs/?46176
+ * dmidecode.c: Check the sysfs entry point length.
+
+2015-10-21 Xie XiuQi <xiexiuqi@huawei.com>
+
+ * dmidecode.c: Handle SMBIOS 3.0 entry points on EFI systems.
+
+2015-10-20 Jean Delvare <jdelvare@suse.de>
+
+ * dmidecode.c: Handle OEM-specific types in group associations
+ (DMI type 14).
+
+2015-10-14 Jean Delvare <jdelvare@suse.de>
+
+ * util.c: Avoid SIGBUS on mmap failure.
+ This fixes Savannah bug #46066:
+ https://savannah.nongnu.org/bugs/?46066
+ * util.c: Fix error paths in mem_chunk.
+
+2015-10-01 Roy Franz <roy.franz@linaro.org>
+
+ * dmiopt.c: Add "--no-sysfs" option description to -h output.
+
+2015-09-03 Jean Delvare <jdelvare@suse.de>
+
* version.h: Set version to 3.0.
2015-08-04 Tyler Bell <tyler.bell@hp.com>
diff --git a/README b/README
index 391a5cb..f612b36 100644
--- a/README
+++ b/README
@@ -28,7 +28,7 @@ and other interesting material, such as a list of related projects and
articles.
This program was first written for Linux, and has since been reported to work
-on FreeBSD, NetBSD, OpenBSD, BeOS, Cygwin and Solaris as well.
+on FreeBSD, NetBSD, OpenBSD, BeOS and Solaris as well.
There's no configure script, so simply run "make" to build dmidecode, and
"make install" to install it. You also can use "make uninstall" to remove
@@ -83,9 +83,8 @@ successfully run.
CYGWIN
-Dmidecode was reported to work under Cygwin. It seems that /dev/mem doesn't
-work properly before version 1.5.10 though, so you will need to use at least
-this version.
+Dmidecode used to work under Cygwin. However the /dev/mem interface was
+removed at some point in time so it no longer works.
** MISCELLANEOUS TOOLS **
diff --git a/biosdecode.c b/biosdecode.c
index 3bbfe28..ad3d4bc 100644
--- a/biosdecode.c
+++ b/biosdecode.c
@@ -2,7 +2,7 @@
* BIOS Decode
*
* Copyright (C) 2000-2002 Alan Cox <alan@redhat.com>
- * Copyright (C) 2002-2015 Jean Delvare <jdelvare@suse.de>
+ * Copyright (C) 2002-2017 Jean Delvare <jdelvare@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -52,6 +52,9 @@
* - Fujitsu application panel technical details
* As of July 23rd, 2004
* http://apanel.sourceforge.net/tech.php
+ * - Intel Multiprocessor Specification
+ * Version 1.4
+ * http://www.intel.com/design/archives/processors/pro/docs/242016.htm
*/
#include <stdio.h>
@@ -546,6 +549,34 @@ static int fjkeyinf_decode(const u8 *p, size_t len)
}
/*
+ * Intel Multiprocessor
+ */
+
+static size_t mp_length(const u8 *p)
+{
+ return 16 * p[8];
+}
+
+static int mp_decode(const u8 *p, size_t len)
+{
+ if (!checksum(p, len))
+ return 0;
+
+ printf("Intel Multiprocessor present.\n");
+ printf("\tSpecification Revision: %s\n",
+ p[9] == 0x01 ? "1.1" : p[9] == 0x04 ? "1.4" : "Invalid");
+ if (p[11])
+ printf("\tDefault Configuration: #%d\n", p[11]);
+ else
+ printf("\tConfiguration Table Address: 0x%08X\n",
+ DWORD(p + 4));
+ printf("\tMode: %s\n", p[12] & (1 << 7) ?
+ "IMCR and PIC" : "Virtual Wire");
+
+ return 1;
+}
+
+/*
* Main
*/
@@ -562,6 +593,7 @@ static struct bios_entry bios_entries[] = {
{ "32OS", 0, 0xE0000, 0xFFFFF, compaq_length, compaq_decode },
{ "\252\125VPD", 0, 0xF0000, 0xFFFFF, vpd_length, vpd_decode },
{ "FJKEYINF", 0, 0xF0000, 0xFFFFF, fjkeyinf_length, fjkeyinf_decode },
+ { "_MP_", 0, 0xE0000, 0xFFFFF, mp_length, mp_decode },
{ NULL, 0, 0, 0, NULL, NULL }
};
diff --git a/dmidecode.c b/dmidecode.c
index f41c85b..6559567 100644
--- a/dmidecode.c
+++ b/dmidecode.c
@@ -2,7 +2,7 @@
* DMI Decode
*
* Copyright (C) 2000-2002 Alan Cox <alan@redhat.com>
- * Copyright (C) 2002-2015 Jean Delvare <jdelvare@suse.de>
+ * Copyright (C) 2002-2017 Jean Delvare <jdelvare@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@
* are deemed to be part of the source code.
*
* Unless specified otherwise, all references are aimed at the "System
- * Management BIOS Reference Specification, Version 3.0.0" document,
+ * Management BIOS Reference Specification, Version 3.1.1" document,
* available from http://www.dmtf.org/standards/smbios.
*
* Note to contributors:
@@ -50,6 +50,12 @@
* - DMTF DSP0239 version 1.1.0
* "Management Component Transport Protocol (MCTP) IDs and Codes"
* http://www.dmtf.org/standards/pmci
+ * - "TPM Main, Part 2 TPM Structures"
+ * Specification version 1.2, level 2, revision 116
+ * https://trustedcomputinggroup.org/tpm-main-specification/
+ * - "PC Client Platform TPM Profile (PTP) Specification"
+ * Family "2.0", Level 00, Revision 00.43, January 26, 2015
+ * https://trustedcomputinggroup.org/pc-client-platform-tpm-profile-ptp-specification/
*/
#include <stdio.h>
@@ -69,13 +75,14 @@
#define out_of_spec "<OUT OF SPEC>"
static const char *bad_index = "<BAD INDEX>";
-#define SUPPORTED_SMBIOS_VER 0x0300
+#define SUPPORTED_SMBIOS_VER 0x030101
#define FLAG_NO_FILE_OFFSET (1 << 0)
#define FLAG_STOP_AT_EOT (1 << 1)
-#define SYS_ENTRY_FILE "/sys/firmware/dmi/tables/smbios_entry_point"
-#define SYS_TABLE_FILE "/sys/firmware/dmi/tables/DMI"
+#define SYS_FIRMWARE_DIR "/sys/firmware/dmi/tables"
+#define SYS_ENTRY_FILE SYS_FIRMWARE_DIR "/smbios_entry_point"
+#define SYS_TABLE_FILE SYS_FIRMWARE_DIR "/DMI"
/*
* Type-independant Stuff
@@ -169,10 +176,13 @@ static const char *dmi_smbios_structure_type(u8 code)
"Power Supply",
"Additional Information",
"Onboard Device",
- "Management Controller Host Interface", /* 42 */
+ "Management Controller Host Interface",
+ "TPM Device", /* 43 */
};
- if (code <= 42)
+ if (code >= 128)
+ return "OEM-specific";
+ if (code <= 43)
return type[code];
return out_of_spec;
}
@@ -292,6 +302,18 @@ static void dmi_bios_runtime_size(u32 code)
printf(" %u kB", code >> 10);
}
+static void dmi_bios_rom_size(u8 code1, u16 code2)
+{
+ static const char *unit[4] = {
+ "MB", "GB", out_of_spec, out_of_spec
+ };
+
+ if (code1 != 0xFF)
+ printf(" %u kB", (code1 + 1) << 6);
+ else
+ printf(" %u %s", code2 & 0x3FFF, unit[code2 >> 14]);
+}
+
static void dmi_bios_characteristics(u64 code, const char *prefix)
{
/* 7.1.1 */
@@ -550,12 +572,16 @@ static const char *dmi_chassis_type(u8 code)
"Blade Enclosing",
"Tablet",
"Convertible",
- "Detachable" /* 0x20 */
+ "Detachable",
+ "IoT Gateway",
+ "Embedded PC",
+ "Mini PC",
+ "Stick PC" /* 0x24 */
};
code &= 0x7F; /* bits 6:0 are chassis type, 7th bit is the lock bit */
- if (code >= 0x01 && code <= 0x20)
+ if (code >= 0x01 && code <= 0x24)
return type[code - 0x01];
return out_of_spec;
}
@@ -717,7 +743,9 @@ static const char *dmi_processor_family(const struct dmi_header *h, u16 ver)
{ 0x2A, "Core Solo Mobile" },
{ 0x2B, "Atom" },
{ 0x2C, "Core M" },
-
+ { 0x2D, "Core m3" },
+ { 0x2E, "Core m5" },
+ { 0x2F, "Core m7" },
{ 0x30, "Alpha" },
{ 0x31, "Alpha 21064" },
{ 0x32, "Alpha 21066" },
@@ -769,6 +797,9 @@ static const char *dmi_processor_family(const struct dmi_header *h, u16 ver)
{ 0x66, "Athlon X4" },
{ 0x67, "Opteron X1000" },
{ 0x68, "Opteron X2000" },
+ { 0x69, "Opteron A-Series" },
+ { 0x6A, "Opteron X3000" },
+ { 0x6B, "Zen" },
{ 0x70, "Hobbit" },
@@ -880,6 +911,8 @@ static const char *dmi_processor_family(const struct dmi_header *h, u16 ver)
{ 0xFA, "i860" },
{ 0xFB, "i960" },
+ { 0x100, "ARMv7" },
+ { 0x101, "ARMv8" },
{ 0x104, "SH-3" },
{ 0x105, "SH-4" },
{ 0x118, "ARM" },
@@ -891,6 +924,10 @@ static const char *dmi_processor_family(const struct dmi_header *h, u16 ver)
{ 0x15E, "DSP" },
{ 0x1F4, "Video Processor" },
};
+ /*
+ * Note to developers: when adding entries to this list, check if
+ * function dmi_processor_id below needs updating too.
+ */
/* Special case for ambiguous value 0x30 (SMBIOS 2.0 only) */
if (ver == 0x0200 && data[0x06] == 0x30 && h->length >= 0x08)
@@ -943,7 +980,7 @@ static const char *dmi_processor_family(const struct dmi_header *h, u16 ver)
}
}
-static void dmi_processor_id(u8 type, const u8 *p, const char *version, const char *prefix)
+static void dmi_processor_id(const struct dmi_header *h, const char *prefix)
{
/* Intel AP-485 revision 36, table 2-4 */
static const char *flags[32] = {
@@ -980,13 +1017,14 @@ static void dmi_processor_id(u8 type, const u8 *p, const char *version, const ch
NULL, /* 30 */
"PBE (Pending break enabled)" /* 31 */
};
- /*
- * Extra flags are now returned in the ECX register when one calls
- * the CPUID instruction. Their meaning is explained in table 3-5, but
- * DMI doesn't support this yet.
- */
+ const u8 *data = h->data;
+ const u8 *p = data + 0x08;
u32 eax, edx;
int sig = 0;
+ u16 type;
+
+ type = (data[0x06] == 0xFE && h->length >= 0x2A) ?
+ WORD(data + 0x28) : data[0x06];
/*
* This might help learn about new processors supporting the
@@ -1026,8 +1064,24 @@ static void dmi_processor_id(u8 type, const u8 *p, const char *version, const ch
return;
}
}
+ else if ((type >= 0x100 && type <= 0x101) /* ARM */
+ || (type >= 0x118 && type <= 0x119)) /* ARM */
+ {
+ u32 midr = DWORD(p);
+ /*
+ * The format of this field was not defined for ARM processors
+ * before version 3.1.0 of the SMBIOS specification, so we
+ * silently skip it if it reads all zeroes.
+ */
+ if (midr == 0)
+ return;
+ printf("%sSignature: Implementor 0x%02x, Variant 0x%x, Architecture %u, Part 0x%03x, Revision %u\n",
+ prefix, midr >> 24, (midr >> 20) & 0xF,
+ (midr >> 16) & 0xF, (midr >> 4) & 0xFFF, midr & 0xF);
+ return;
+ }
else if ((type >= 0x0B && type <= 0x15) /* Intel, Cyrix */
- || (type >= 0x28 && type <= 0x2B) /* Intel */
+ || (type >= 0x28 && type <= 0x2F) /* Intel */
|| (type >= 0xA1 && type <= 0xB3) /* Intel */
|| type == 0xB5 /* Intel */
|| (type >= 0xB9 && type <= 0xC7) /* Intel */
@@ -1039,12 +1093,14 @@ static void dmi_processor_id(u8 type, const u8 *p, const char *version, const ch
|| type == 0x1F /* AMD */
|| (type >= 0x38 && type <= 0x3F) /* AMD */
|| (type >= 0x46 && type <= 0x4F) /* AMD */
+ || (type >= 0x66 && type <= 0x6B) /* AMD */
|| (type >= 0x83 && type <= 0x8F) /* AMD */
|| (type >= 0xB6 && type <= 0xB7) /* AMD */
|| (type >= 0xE4 && type <= 0xEF)) /* AMD */
sig = 2;
else if (type == 0x01 || type == 0x02)
{
+ const char *version = dmi_string(h, data[0x10]);
/*
* Some X86-class CPU have family "Other" or "Unknown". In this case,
* we use the version string to determine if they are known to
@@ -1062,9 +1118,14 @@ static void dmi_processor_id(u8 type, const u8 *p, const char *version, const ch
else
return;
}
- else /* not X86-class */
+ else /* neither X86 nor ARM */
return;
+ /*
+ * Extra flags are now returned in the ECX register when one calls
+ * the CPUID instruction. Their meaning is explained in table 3-5, but
+ * DMI doesn't support this yet.
+ */
eax = DWORD(p);
edx = DWORD(p + 4);
switch (sig)
@@ -1200,10 +1261,18 @@ static const char *dmi_processor_upgrade(u8 code)
"Socket LGA1150",
"Socket BGA1168",
"Socket BGA1234",
- "Socket BGA1364" /* 0x30 */
+ "Socket BGA1364",
+ "Socket AM4",
+ "Socket LGA1151",
+ "Socket BGA1356",
+ "Socket BGA1440",
+ "Socket BGA1515",
+ "Socket LGA3647-1",
+ "Socket SP3",
+ "Socket SP3r2" /* 0x38 */
};
- if (code >= 0x01 && code <= 0x30)
+ if (code >= 0x01 && code <= 0x38)
return upgrade[code - 0x01];
return out_of_spec;
}
@@ -1476,6 +1545,21 @@ static void dmi_cache_size(u16 code)
printf(" %u kB", code);
}
+static void dmi_cache_size_2(u32 code)
+{
+ if (code & 0x80000000)
+ {
+ code &= 0x7FFFFFFFLU;
+ /* Use a more convenient unit for large cache size */
+ if (code >= 0x8000)
+ printf(" %u MB", code >> 4);
+ else
+ printf(" %u kB", code << 6);
+ }
+ else
+ printf(" %u kB", code);
+}
+
static void dmi_cache_types(u16 code, const char *sep)
{
/* 7.8.2 */
@@ -1712,7 +1796,10 @@ static const char *dmi_slot_type(u8 code)
"MXM 3.0 Type A",
"MXM 3.0 Type B",
"PCI Express 2 SFF-8639",
- "PCI Express 3 SFF-8639" /* 0x20 */
+ "PCI Express 3 SFF-8639",
+ "PCI Express Mini 52-pin with bottom-side keep-outs",
+ "PCI Express Mini 52-pin without bottom-side keep-outs",
+ "PCI Express Mini 76-pin" /* 0x23 */
};
static const char *type_0xA0[] = {
"PC-98/C20", /* 0xA0 */
@@ -1744,7 +1831,7 @@ static const char *dmi_slot_type(u8 code)
* function dmi_slot_id below needs updating too.
*/
- if (code >= 0x01 && code <= 0x20)
+ if (code >= 0x01 && code <= 0x23)
return type[code - 0x01];
if (code >= 0xA0 && code <= 0xB6)
return type_0xA0[code - 0xA0];
@@ -1826,6 +1913,9 @@ static void dmi_slot_id(u8 code1, u8 code2, u8 type, const char *prefix)
case 0x13: /* AGP */
case 0x1F: /* PCI Express 2 */
case 0x20: /* PCI Express 3 */
+ case 0x21: /* PCI Express Mini */
+ case 0x22: /* PCI Express Mini */
+ case 0x23: /* PCI Express Mini */
case 0xA5: /* PCI Express */
case 0xA6: /* PCI Express */
case 0xA7: /* PCI Express */
@@ -2274,10 +2364,13 @@ static void dmi_memory_device_extended_size(u32 code)
{
code &= 0x7FFFFFFFUL;
- /* Use the most suitable unit depending on size */
+ /*
+ * Use the greatest unit for which the exact value can be displayed
+ * as an integer without rounding
+ */
if (code & 0x3FFUL)
printf(" %lu MB", (unsigned long)code);
- else if (code & 0xFFFFFUL)
+ else if (code & 0xFFC00UL)
printf(" %lu GB", (unsigned long)code >> 10);
else
printf(" %lu TB", (unsigned long)code >> 20);
@@ -2389,7 +2482,7 @@ static void dmi_memory_device_type_detail(u16 code)
"LRDIMM" /* 15 */
};
- if ((code & 0x7FFE) == 0)
+ if ((code & 0xFFFE) == 0)
printf(" None");
else
{
@@ -2406,7 +2499,7 @@ static void dmi_memory_device_speed(u16 code)
if (code == 0)
printf(" Unknown");
else
- printf(" %u MHz", code);
+ printf(" %u MT/s", code);
}
/*
@@ -2946,7 +3039,7 @@ static void dmi_64bit_memory_error_address(u64 code)
* first 5 characters of the device name to be trimmed. It's easy to
* check and fix, so do it, but warn.
*/
-static void dmi_fixup_type_34(struct dmi_header *h)
+static void dmi_fixup_type_34(struct dmi_header *h, int display)
{
u8 *p = h->data;
@@ -2954,7 +3047,10 @@ static void dmi_fixup_type_34(struct dmi_header *h)
if (h->length == 0x10
&& is_printable(p + 0x0B, 0x10 - 0x0B))
{
- printf("Invalid entry length (%u). Fixed up to %u.\n", 0x10, 0x0B);
+ if (!(opt.flags & FLAG_QUIET) && display)
+ fprintf(stderr,
+ "Invalid entry length (%u). Fixed up to %u.\n",
+ 0x10, 0x0B);
h->length = 0x0B;
}
}
@@ -3223,6 +3319,57 @@ static const char *dmi_management_controller_host_type(u8 code)
}
/*
+ * 7.44 TPM Device (Type 43)
+ */
+
+static void dmi_tpm_vendor_id(const u8 *p)
+{
+ char vendor_id[5];
+ int i;
+
+ /* ASCII filtering */
+ for (i = 0; i < 4 && p[i] != 0; i++)
+ {
+ if (p[i] < 32 || p[i] >= 127)
+ vendor_id[i] = '.';
+ else
+ vendor_id[i] = p[i];
+ }
+
+ /* Terminate the string */
+ vendor_id[i] = '\0';
+
+ printf(" %s", vendor_id);
+}
+
+static void dmi_tpm_characteristics(u64 code, const char *prefix)
+{
+ /* 7.1.1 */
+ static const char *characteristics[] = {
+ "TPM Device characteristics not supported", /* 2 */
+ "Family configurable via firmware update",
+ "Family configurable via platform software support",
+ "Family configurable via OEM proprietary mechanism" /* 5 */
+ };
+ int i;
+
+ /*
+ * This isn't very clear what this bit is supposed to mean
+ */
+ if (code.l & (1 << 2))
+ {
+ printf("%s%s\n",
+ prefix, characteristics[0]);
+ return;
+ }
+
+ for (i = 3; i <= 5; i++)
+ if (code.l & (1 << i))
+ printf("%s%s\n",
+ prefix, characteristics[i - 2]);
+}
+
+/*
* Main
*/
@@ -3257,8 +3404,9 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
dmi_bios_runtime_size((0x10000 - WORD(data + 0x06)) << 4);
printf("\n");
}
- printf("\tROM Size: %u kB\n",
- (data[0x09] + 1) << 6);
+ printf("\tROM Size:");
+ dmi_bios_rom_size(data[0x09], h->length < 0x1A ? 16 : WORD(data + 0x18));
+ printf("\n");
printf("\tCharacteristics:\n");
dmi_bios_characteristics(QWORD(data + 0x0A), "\t\t");
if (h->length < 0x13) break;
@@ -3382,7 +3530,7 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
dmi_processor_family(h, ver));
printf("\tManufacturer: %s\n",
dmi_string(h, data[0x07]));
- dmi_processor_id(data[0x06], data + 0x08, dmi_string(h, data[0x10]), "\t");
+ dmi_processor_id(h, "\t");
printf("\tVersion: %s\n",
dmi_string(h, data[0x10]));
printf("\tVoltage:");
@@ -3509,10 +3657,16 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
printf("\tLocation: %s\n",
dmi_cache_location((WORD(data + 0x05) >> 5) & 0x0003));
printf("\tInstalled Size:");
- dmi_cache_size(WORD(data + 0x09));
+ if (h->length >= 0x1B)
+ dmi_cache_size_2(DWORD(data + 0x17));
+ else
+ dmi_cache_size(WORD(data + 0x09));
printf("\n");
printf("\tMaximum Size:");
- dmi_cache_size(WORD(data + 0x07));
+ if (h->length >= 0x17)
+ dmi_cache_size_2(DWORD(data + 0x13));
+ else
+ dmi_cache_size(WORD(data + 0x07));
printf("\n");
printf("\tSupported SRAM Types:");
dmi_cache_types(WORD(data + 0x0B), "\n\t\t");
@@ -4234,7 +4388,7 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
}
if (data[0x11] != 0x00)
{
- printf("\tInterrupt Number: %x\n",
+ printf("\tInterrupt Number: %u\n",
data[0x11]);
}
break;
@@ -4331,6 +4485,43 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
}
break;
+ case 43: /* 7.44 TPM Device */
+ printf("TPM Device\n");
+ if (h->length < 0x1B) break;
+ printf("\tVendor ID:");
+ dmi_tpm_vendor_id(data + 0x04);
+ printf("\n");
+ printf("\tSpecification Version: %d.%d", data[0x08], data[0x09]);
+ switch (data[0x08])
+ {
+ case 0x01:
+ /*
+ * We skip the first 2 bytes, which are
+ * redundant with the above, and uncoded
+ * in a silly way.
+ */
+ printf("\tFirmware Revision: %u.%u\n",
+ data[0x0C], data[0x0D]);
+ break;
+ case 0x02:
+ printf("\tFirmware Revision: %u.%u\n",
+ DWORD(data + 0x0A) >> 16,
+ DWORD(data + 0x0A) && 0xFF);
+ /*
+ * We skip the next 4 bytes, as their
+ * format is not standardized and their
+ * usefulness seems limited anyway.
+ */
+ break;
+ }
+ printf("\tDescription: %s", dmi_string(h, data[0x12]));
+ printf("\tCharacteristics:\n");
+ dmi_tpm_characteristics(QWORD(data + 0x13), "\t\t");
+ if (h->length < 0x1F) break;
+ printf("\tOEM-specific Information: 0x%08X\n",
+ DWORD(data + 0x1B));
+ break;
+
case 126: /* 7.44 Inactive */
printf("Inactive\n");
break;
@@ -4364,6 +4555,21 @@ static void dmi_table_string(const struct dmi_header *h, const u8 *data, u16 ver
int key;
u8 offset = opt.string->offset;
+ if (opt.string->type == 11) /* OEM strings */
+ {
+ if (h->length < 5 || offset > data[4])
+ {
+ fprintf(stderr, "No OEM string number %u\n", offset);
+ return;
+ }
+
+ if (offset)
+ printf("%s\n", dmi_string(h, offset));
+ else
+ printf("%u\n", data[4]); /* count */
+ return;
+ }
+
if (offset >= h->length)
return;
@@ -4422,9 +4628,14 @@ static void dmi_table_decode(u8 *buf, u32 len, u16 num, u16 ver, u32 flags)
*/
if (h.length < 4)
{
- printf("Invalid entry length (%u). DMI table is "
- "broken! Stop.\n\n", (unsigned int)h.length);
- opt.flags |= FLAG_QUIET;
+ if (!(opt.flags & FLAG_QUIET))
+ {
+ fprintf(stderr,
+ "Invalid entry length (%u). DMI table "
+ "is broken! Stop.\n\n",
+ (unsigned int)h.length);
+ opt.flags |= FLAG_QUIET;
+ }
break;
}
@@ -4443,7 +4654,7 @@ static void dmi_table_decode(u8 *buf, u32 len, u16 num, u16 ver, u32 flags)
/* Fixup a common mistake */
if (h.type == 34)
- dmi_fixup_type_34(&h);
+ dmi_fixup_type_34(&h, display);
/* look for the next handle */
next = data + h.length;
@@ -4485,26 +4696,28 @@ static void dmi_table_decode(u8 *buf, u32 len, u16 num, u16 ver, u32 flags)
if (!(opt.flags & FLAG_QUIET))
{
if (num && i != num)
- printf("Wrong DMI structures count: %d announced, "
+ fprintf(stderr, "Wrong DMI structures count: %d announced, "
"only %d decoded.\n", num, i);
if ((unsigned long)(data - buf) > len
|| (num && (unsigned long)(data - buf) < len))
- printf("Wrong DMI structures length: %u bytes "
+ fprintf(stderr, "Wrong DMI structures length: %u bytes "
"announced, structures occupy %lu bytes.\n",
len, (unsigned long)(data - buf));
}
}
-static void dmi_table(off_t base, u32 len, u16 num, u16 ver, const char *devmem,
+static void dmi_table(off_t base, u32 len, u16 num, u32 ver, const char *devmem,
u32 flags)
{
u8 *buf;
if (ver > SUPPORTED_SMBIOS_VER && !(opt.flags & FLAG_QUIET))
{
- printf("# SMBIOS implementations newer than version %u.%u are not\n"
+ printf("# SMBIOS implementations newer than version %u.%u.%u are not\n"
"# fully supported by this version of dmidecode.\n",
- SUPPORTED_SMBIOS_VER >> 8, SUPPORTED_SMBIOS_VER & 0xFF);
+ SUPPORTED_SMBIOS_VER >> 16,
+ (SUPPORTED_SMBIOS_VER >> 8) & 0xFF,
+ SUPPORTED_SMBIOS_VER & 0xFF);
}
if (!(opt.flags & FLAG_QUIET))
@@ -4521,29 +4734,45 @@ static void dmi_table(off_t base, u32 len, u16 num, u16 ver, const char *devmem,
printf("\n");
}
- /*
- * When we are reading the DMI table from sysfs, we want to print
- * the address of the table (done above), but the offset of the
- * data in the file is 0. When reading from /dev/mem, the offset
- * in the file is the address.
- */
- if (flags & FLAG_NO_FILE_OFFSET)
- base = 0;
+ if ((flags & FLAG_NO_FILE_OFFSET) || (opt.flags & FLAG_FROM_DUMP))
+ {
+ /*
+ * When reading from sysfs or from a dump file, the file may be
+ * shorter than announced. For SMBIOS v3 this is expcted, as we
+ * only know the maximum table size, not the actual table size.
+ * For older implementations (and for SMBIOS v3 too), this
+ * would be the result of the kernel truncating the table on
+ * parse error.
+ */
+ size_t size = len;
+ buf = read_file(flags & FLAG_NO_FILE_OFFSET ? 0 : base,
+ &size, devmem);
+ if (!(opt.flags & FLAG_QUIET) && num && size != (size_t)len)
+ {
+ fprintf(stderr, "Wrong DMI structures length: %u bytes "
+ "announced, only %lu bytes available.\n",
+ len, (unsigned long)size);
+ }
+ len = size;
+ }
+ else
+ buf = mem_chunk(base, len, devmem);
- if ((buf = mem_chunk(base, len, devmem)) == NULL)
+ if (buf == NULL)
{
- fprintf(stderr, "Table is unreachable, sorry."
+ fprintf(stderr, "Failed to read table, sorry.\n");
#ifndef USE_MMAP
- " Try compiling dmidecode with -DUSE_MMAP."
+ if (!(flags & FLAG_NO_FILE_OFFSET))
+ fprintf(stderr,
+ "Try compiling dmidecode with -DUSE_MMAP.\n");
#endif
- "\n");
return;
}
if (opt.flags & FLAG_DUMP_BIN)
dmi_table_dump(buf, len);
else
- dmi_table_decode(buf, len, num, ver, flags);
+ dmi_table_decode(buf, len, num, ver >> 8, flags);
free(buf);
}
@@ -4580,13 +4809,13 @@ static void overwrite_smbios3_address(u8 *buf)
static int smbios3_decode(u8 *buf, const char *devmem, u32 flags)
{
- u16 ver;
+ u32 ver;
u64 offset;
if (!checksum(buf, buf[0x06]))
return 0;
- ver = (buf[0x07] << 8) + buf[0x08];
+ ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09];
if (!(opt.flags & FLAG_QUIET))
printf("SMBIOS %u.%u.%u present.\n",
buf[0x07], buf[0x08], buf[0x09]);
@@ -4599,7 +4828,7 @@ static int smbios3_decode(u8 *buf, const char *devmem, u32 flags)
}
dmi_table(((off_t)offset.h << 32) | offset.l,
- WORD(buf + 0x0C), 0, ver, devmem, flags | FLAG_STOP_AT_EOT);
+ DWORD(buf + 0x0C), 0, ver, devmem, flags | FLAG_STOP_AT_EOT);
if (opt.flags & FLAG_DUMP_BIN)
{
@@ -4633,14 +4862,16 @@ static int smbios_decode(u8 *buf, const char *devmem, u32 flags)
case 0x021F:
case 0x0221:
if (!(opt.flags & FLAG_QUIET))
- printf("SMBIOS version fixup (2.%d -> 2.%d).\n",
- ver & 0xFF, 3);
+ fprintf(stderr,
+ "SMBIOS version fixup (2.%d -> 2.%d).\n",
+ ver & 0xFF, 3);
ver = 0x0203;
break;
case 0x0233:
if (!(opt.flags & FLAG_QUIET))
- printf("SMBIOS version fixup (2.%d -> 2.%d).\n",
- 51, 6);
+ fprintf(stderr,
+ "SMBIOS version fixup (2.%d -> 2.%d).\n",
+ 51, 6);
ver = 0x0206;
break;
}
@@ -4649,7 +4880,7 @@ static int smbios_decode(u8 *buf, const char *devmem, u32 flags)
ver >> 8, ver & 0xFF);
dmi_table(DWORD(buf + 0x18), WORD(buf + 0x16), WORD(buf + 0x1C),
- ver, devmem, flags);
+ ver << 8, devmem, flags);
if (opt.flags & FLAG_DUMP_BIN)
{
@@ -4677,7 +4908,8 @@ static int legacy_decode(u8 *buf, const char *devmem, u32 flags)
buf[0x0E] >> 4, buf[0x0E] & 0x0F);
dmi_table(DWORD(buf + 0x08), WORD(buf + 0x06), WORD(buf + 0x0C),
- ((buf[0x0E] & 0xF0) << 4) + (buf[0x0E] & 0x0F), devmem, flags);
+ ((buf[0x0E] & 0xF0) << 12) + ((buf[0x0E] & 0x0F) << 8),
+ devmem, flags);
if (opt.flags & FLAG_DUMP_BIN)
{
@@ -4748,9 +4980,17 @@ int main(int argc, char * const argv[])
int ret = 0; /* Returned value */
int found = 0;
off_t fp;
+ size_t size;
int efi;
u8 *buf;
+ /*
+ * We don't want stdout and stderr to be mixed up if both are
+ * redirected to the same file.
+ */
+ setlinebuf(stdout);
+ setlinebuf(stderr);
+
if (sizeof(u8) != 1 || sizeof(u16) != 2 || sizeof(u32) != 4 || '\0' != 0)
{
fprintf(stderr, "%s: compiler incompatibility\n", argv[0]);
@@ -4817,22 +5057,23 @@ int main(int argc, char * const argv[])
* contain one of several types of entry points, so read enough for
* the largest one, then determine what type it contains.
*/
+ size = 0x20;
if (!(opt.flags & FLAG_NO_SYSFS)
- && (buf = read_file(0x20, SYS_ENTRY_FILE)) != NULL)
+ && (buf = read_file(0, &size, SYS_ENTRY_FILE)) != NULL)
{
if (!(opt.flags & FLAG_QUIET))
printf("Getting SMBIOS data from sysfs.\n");
- if (memcmp(buf, "_SM3_", 5) == 0)
+ if (size >= 24 && memcmp(buf, "_SM3_", 5) == 0)
{
if (smbios3_decode(buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET))
found++;
}
- else if (memcmp(buf, "_SM_", 4) == 0)
+ else if (size >= 31 && memcmp(buf, "_SM_", 4) == 0)
{
if (smbios_decode(buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET))
found++;
}
- else if (memcmp(buf, "_DMI_", 5) == 0)
+ else if (size >= 15 && memcmp(buf, "_DMI_", 5) == 0)
{
if (legacy_decode(buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET))
found++;
@@ -4864,8 +5105,16 @@ int main(int argc, char * const argv[])
goto exit_free;
}
- if (smbios_decode(buf, opt.devmem, 0))
- found++;
+ if (memcmp(buf, "_SM3_", 5) == 0)
+ {
+ if (smbios3_decode(buf, opt.devmem, 0))
+ found++;
+ }
+ else if (memcmp(buf, "_SM_", 4) == 0)
+ {
+ if (smbios_decode(buf, opt.devmem, 0))
+ found++;
+ }
goto done;
memory_scan:
@@ -4878,28 +5127,37 @@ memory_scan:
goto exit_free;
}
- for (fp = 0; fp <= 0xFFF0; fp += 16)
+ /* Look for a 64-bit entry point first */
+ for (fp = 0; fp <= 0xFFE0; fp += 16)
{
- if (memcmp(buf + fp, "_SM3_", 5) == 0 && fp <= 0xFFE0)
+ if (memcmp(buf + fp, "_SM3_", 5) == 0)
{
if (smbios3_decode(buf + fp, opt.devmem, 0))
{
found++;
- fp += 16;
+ goto done;
}
}
- else if (memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0)
+ }
+
+ /* If none found, look for a 32-bit entry point */
+ for (fp = 0; fp <= 0xFFF0; fp += 16)
+ {
+ if (memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0)
{
if (smbios_decode(buf + fp, opt.devmem, 0))
{
found++;
- fp += 16;
+ goto done;
}
}
else if (memcmp(buf + fp, "_DMI_", 5) == 0)
{
if (legacy_decode(buf + fp, opt.devmem, 0))
+ {
found++;
+ goto done;
+ }
}
}
diff --git a/dmiopt.c b/dmiopt.c
index 0d142d2..da42546 100644
--- a/dmiopt.c
+++ b/dmiopt.c
@@ -20,6 +20,7 @@
*/
#include <stdio.h>
+#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <getopt.h>
@@ -171,6 +172,10 @@ static const struct string_keyword opt_string_keyword[] = {
{ "processor-frequency", 4, 0x16 }, /* dmi_processor_frequency() */
};
+/* This is a template, 3rd field is set at runtime. */
+static struct string_keyword opt_oem_string_keyword =
+ { NULL, 11, 0x00 };
+
static void print_opt_string_list(void)
{
unsigned int i;
@@ -206,6 +211,34 @@ static int parse_opt_string(const char *arg)
return -1;
}
+static int parse_opt_oem_string(const char *arg)
+{
+ unsigned long val;
+ char *next;
+
+ if (opt.string)
+ {
+ fprintf(stderr, "Only one string can be specified\n");
+ return -1;
+ }
+
+ /* Return the number of OEM strings */
+ if (strcmp(arg, "count") == 0)
+ goto done;
+
+ val = strtoul(arg, &next, 10);
+ if (next == arg || val == 0x00 || val > 0xff)
+ {
+ fprintf(stderr, "Invalid OEM string number: %s\n", arg);
+ return -1;
+ }
+
+ opt_oem_string_keyword.offset = val;
+done:
+ opt.string = &opt_oem_string_keyword;
+ return 0;
+}
+
/*
* Command line options handling
@@ -225,6 +258,7 @@ int parse_command_line(int argc, char * const argv[])
{ "dump", no_argument, NULL, 'u' },
{ "dump-bin", required_argument, NULL, 'B' },
{ "from-dump", required_argument, NULL, 'F' },
+ { "oem-string", required_argument, NULL, 'O' },
{ "no-sysfs", no_argument, NULL, 'S' },
{ "version", no_argument, NULL, 'V' },
{ NULL, 0, NULL, 0 }
@@ -255,6 +289,11 @@ int parse_command_line(int argc, char * const argv[])
return -1;
opt.flags |= FLAG_QUIET;
break;
+ case 'O':
+ if (parse_opt_oem_string(optarg) < 0)
+ return -1;
+ opt.flags |= FLAG_QUIET;
+ break;
case 't':
opt.type = parse_opt_type(opt.type, optarg);
if (opt.type == NULL)
@@ -314,6 +353,8 @@ void print_help(void)
" -u, --dump Do not decode the entries\n"
" --dump-bin FILE Dump the DMI data to a binary file\n"
" --from-dump FILE Read the DMI data from a binary file\n"
+ " --no-sysfs Do not attempt to read DMI data from sysfs files\n"
+ " --oem-string N Only display the value of the given OEM string\n"
" -V, --version Display the version and exit\n";
printf("%s", help);
diff --git a/man/dmidecode.8 b/man/dmidecode.8
index a64cf5d..bef204e 100644
--- a/man/dmidecode.8
+++ b/man/dmidecode.8
@@ -134,13 +134,18 @@ Read the DMI data from a binary file previously generated using
Do not attempt to read DMI data from sysfs files. This is mainly useful for
debugging.
.TP
+.BR " " " " "--oem-string N"
+Only display the value of the \s-1OEM\s0 string number \fBN\fR. The first
+\s-1OEM\s0 string has number 1. With special value "count", return the
+number of OEM strings instead.
+.TP
.BR "-h" ", " "--help"
Display usage information and exit
.TP
.BR "-V" ", " "--version"
Display the version and exit
.P
-Options --string, --type and --dump-bin
+Options --string, --type, --dump-bin and --oem-string
determine the output format and are mutually exclusive.
.P
Please note in case of
diff --git a/util.c b/util.c
index 8cafe5c..0aafcb1 100644
--- a/util.c
+++ b/util.c
@@ -2,7 +2,7 @@
* Common "util" functions
* This file is part of the dmidecode project.
*
- * Copyright (C) 2002-2015 Jean Delvare <jdelvare@suse.de>
+ * Copyright (C) 2002-2017 Jean Delvare <jdelvare@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -89,15 +89,16 @@ int checksum(const u8 *buf, size_t len)
}
/*
- * Reads all of file, up to max_len bytes.
+ * Reads all of file from given offset, up to max_len bytes.
* A buffer of max_len bytes is allocated by this function, and
* needs to be freed by the caller.
* This provides a similar usage model to mem_chunk()
*
- * Returns pointer to buffer of max_len bytes, or NULL on error
+ * Returns pointer to buffer of max_len bytes, or NULL on error, and
+ * sets max_len to the length actually read.
*
*/
-void *read_file(size_t max_len, const char *filename)
+void *read_file(off_t base, size_t *max_len, const char *filename)
{
int fd;
size_t r2 = 0;
@@ -112,26 +113,34 @@ void *read_file(size_t max_len, const char *filename)
{
if (errno != ENOENT)
perror(filename);
- return(NULL);
+ return NULL;
}
- if ((p = malloc(max_len)) == NULL)
+ if (lseek(fd, base, SEEK_SET) == -1)
+ {
+ fprintf(stderr, "%s: ", filename);
+ perror("lseek");
+ p = NULL;
+ goto out;
+ }
+
+ if ((p = malloc(*max_len)) == NULL)
{
perror("malloc");
- return NULL;
+ goto out;
}
do
{
- r = read(fd, p + r2, max_len - r2);
+ r = read(fd, p + r2, *max_len - r2);
if (r == -1)
{
if (errno != EINTR)
{
- close(fd);
perror(filename);
free(p);
- return NULL;
+ p = NULL;
+ goto out;
}
}
else
@@ -139,7 +148,10 @@ void *read_file(size_t max_len, const char *filename)
}
while (r != 0);
+ *max_len = r2;
+out:
close(fd);
+
return p;
}
@@ -152,6 +164,7 @@ void *mem_chunk(off_t base, size_t len, const char *devmem)
void *p;
int fd;
#ifdef USE_MMAP
+ struct stat statbuf;
off_t mmoffset;
void *mmp;
#endif
@@ -165,10 +178,28 @@ void *mem_chunk(off_t base, size_t len, const char *devmem)
if ((p = malloc(len)) == NULL)
{
perror("malloc");
- return NULL;
+ goto out;
}
#ifdef USE_MMAP
+ if (fstat(fd, &statbuf) == -1)
+ {
+ fprintf(stderr, "%s: ", devmem);
+ perror("stat");
+ goto err_free;
+ }
+
+ /*
+ * mmap() will fail with SIGBUS if trying to map beyond the end of
+ * the file.
+ */
+ if (S_ISREG(statbuf.st_mode) && base + (off_t)len > statbuf.st_size)
+ {
+ fprintf(stderr, "mmap: Can't map beyond end of file %s\n",
+ devmem);
+ goto err_free;
+ }
+
#ifdef _SC_PAGESIZE
mmoffset = base % sysconf(_SC_PAGESIZE);
#else
@@ -199,19 +230,17 @@ try_read:
{
fprintf(stderr, "%s: ", devmem);
perror("lseek");
- free(p);
- return NULL;
+ goto err_free;
}
- if (myread(fd, p, len, devmem) == -1)
- {
- free(p);
- return NULL;
- }
+ if (myread(fd, p, len, devmem) == 0)
+ goto out;
+
+err_free:
+ free(p);
+ p = NULL;
-#ifdef USE_MMAP
out:
-#endif
if (close(fd) == -1)
perror(devmem);
diff --git a/util.h b/util.h
index 9d409cd..3094cf8 100644
--- a/util.h
+++ b/util.h
@@ -1,7 +1,7 @@
/*
* This file is part of the dmidecode project.
*
- * Copyright (C) 2003-2015 Jean Delvare <jdelvare@suse.de>
+ * Copyright (C) 2003-2017 Jean Delvare <jdelvare@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
int checksum(const u8 *buf, size_t len);
-void *read_file(size_t len, const char *filename);
+void *read_file(off_t base, size_t *len, const char *filename);
void *mem_chunk(off_t base, size_t len, const char *devmem);
int write_dump(size_t base, size_t len, const void *data, const char *dumpfile, int add);
u64 u64_range(u64 start, u64 end);
diff --git a/version.h b/version.h
index f3e8666..778ae5f 100644
--- a/version.h
+++ b/version.h
@@ -1 +1 @@
-#define VERSION "3.0"
+#define VERSION "3.1"