diff options
| author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2017-05-31 23:24:59 +0200 | 
|---|---|---|
| committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2017-05-31 23:24:59 +0200 | 
| commit | 703721ff8e0955029c99208b7d99f7bde68243f4 (patch) | |
| tree | 8380a4a5c7aedd162cc2b7d8d33a17d9e4e436d8 | |
| parent | 0e7659200e3c881e354aab00b758d25408a21544 (diff) | |
| parent | a1e93482d9cc9ace5fc1494677b45d965f1ddcb7 (diff) | |
Merge tag 'upstream/3.1' into feature/upstream
Upstream version 3.1
| -rw-r--r-- | AUTHORS | 2 | ||||
| -rw-r--r-- | CHANGELOG | 98 | ||||
| -rw-r--r-- | README | 7 | ||||
| -rw-r--r-- | biosdecode.c | 34 | ||||
| -rw-r--r-- | dmidecode.c | 410 | ||||
| -rw-r--r-- | dmiopt.c | 41 | ||||
| -rw-r--r-- | man/dmidecode.8 | 7 | ||||
| -rw-r--r-- | util.c | 69 | ||||
| -rw-r--r-- | util.h | 4 | ||||
| -rw-r--r-- | version.h | 2 | 
10 files changed, 569 insertions, 105 deletions
| @@ -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 @@ -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> @@ -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; +			}  		}  	} @@ -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 @@ -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); @@ -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); @@ -1 +1 @@ -#define VERSION "3.0" +#define VERSION "3.1" | 
