diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | Makefile | 18 | ||||
| -rw-r--r-- | NEWS | 19 | ||||
| -rw-r--r-- | completion/biosdecode.bash | 40 | ||||
| -rw-r--r-- | completion/dmidecode.bash | 60 | ||||
| -rw-r--r-- | completion/ownership.bash | 33 | ||||
| -rw-r--r-- | completion/vpddecode.bash | 43 | ||||
| -rw-r--r-- | config.h | 2 | ||||
| -rw-r--r-- | dmidecode.c | 387 | ||||
| -rw-r--r-- | dmidecode.h | 3 | ||||
| -rw-r--r-- | dmioem.c | 349 | ||||
| -rw-r--r-- | dmiopt.c | 17 | ||||
| -rw-r--r-- | dmiopt.h | 3 | ||||
| -rw-r--r-- | man/dmidecode.8 | 8 | ||||
| -rw-r--r-- | util.c | 2 | ||||
| -rw-r--r-- | util.h | 2 | ||||
| -rw-r--r-- | version.h | 2 | 
17 files changed, 864 insertions, 126 deletions
diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 0ff0ae9..0000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.pc -debian/files @@ -36,6 +36,7 @@ sbindir = $(prefix)/sbin  mandir  = $(prefix)/share/man  man8dir = $(mandir)/man8  docdir  = $(prefix)/share/doc/dmidecode +compdir = $(shell pkg-config --variable=completionsdir bash-completion 2>/dev/null || echo $(prefix)/etc/bash_completion.d)  INSTALL         := install  INSTALL_DATA    := $(INSTALL) -m 644 @@ -113,9 +114,9 @@ util.o : util.c types.h util.h config.h  strip : $(PROGRAMS)  	strip $(PROGRAMS) -install : install-bin install-man install-doc +install : install-bin install-man install-doc install-completion -uninstall : uninstall-bin uninstall-man uninstall-doc +uninstall : uninstall-bin uninstall-man uninstall-doc uninstall-completion  install-bin : $(PROGRAMS)  	$(INSTALL_DIR) $(DESTDIR)$(sbindir) @@ -144,5 +145,18 @@ install-doc :  uninstall-doc :  	$(RM) -r $(DESTDIR)$(docdir) +install-completion : +	if [ -d $(compdir) ] ; then \ +	$(INSTALL_DIR) $(DESTDIR)$(compdir) ; \ +	for program in $(PROGRAMS) ; do \ +	$(INSTALL_DATA) completion/$$program.bash $(DESTDIR)$(compdir)/$$program ; done ; \ +	fi + +uninstall-completion : +	if [ -d $(DESTDIR)$(compdir) ]; then \ +	for program in $(PROGRAMS) ; do \ +	$(RM) $(DESTDIR)$(compdir)/$$program ; done ; \ +	fi +  clean :  	$(RM) *.o $(PROGRAMS) core @@ -1,3 +1,22 @@ +Version 3.6 (Wed Apr 24 2024) +  - [PORTABILITY] Use -DALIGNMENT_WORKAROUND on arm. +  - [PORTABILITY] Read SMBIOS entry point via kenv on DragonFly BSD. +  - Support for SMBIOS 3.6.0. This includes new memory device types, new +    processor upgrades, and Loongarch support. +  - Support for SMBIOS 3.7.0. This includes new port types, new processor +    upgrades, new slot characteristics and new fields for memory modules. +  - Add bash completion. +  - Decode HPE OEM records 197, 239 and 245. +  - Implement options --list-strings and --list-types. +  - Update HPE OEM records 203, 212, 216, 221, 233, 236, 237, 238 and 242. +  - Update Redfish support. +  - Bug fixes: +    Fix option --from-dump for user root +    Fix enabled slot characteristics not being printed +  - Minor improvements: +    Print slot width on its own line +    Use standard strings for slot width +  Version 3.5 (Tue Mar 14 2023)    - Decode HPE OEM records 216, 224, 230, 238 and 242.    - Fortify entry point length checks. diff --git a/completion/biosdecode.bash b/completion/biosdecode.bash new file mode 100644 index 0000000..42e0fae --- /dev/null +++ b/completion/biosdecode.bash @@ -0,0 +1,40 @@ +# bash completion for biosdecode                           -*- shell-script -*- + +_comp_cmd_biosdecode() { +	local cur prev +	COMPREPLY=() +	cur=${COMP_WORDS[COMP_CWORD]} +	prev=${COMP_WORDS[COMP_CWORD - 1]} + +	case $prev in +	-d | --dev-mem) +		: "${cur:=/dev/}" +		local IFS=$'\n' +		compopt -o filenames +		COMPREPLY=($(compgen -f -- "$cur")) +		return 0 +		;; +	--pir) +		COMPREPLY=($(compgen -W ' +			full +		' -- "$cur")) +		return 0 +		;; +	-[hV] | --help | --version) +		return 0 +		;; +	esac + +	if [[ $cur == -* ]]; then +		COMPREPLY=($(compgen -W ' +			--dev-mem +			--pir +			--help +			--version +		' -- "$cur")) +		return 0 +	fi + +} && complete -F _comp_cmd_biosdecode biosdecode + +# ex: filetype=sh diff --git a/completion/dmidecode.bash b/completion/dmidecode.bash new file mode 100644 index 0000000..200d6cd --- /dev/null +++ b/completion/dmidecode.bash @@ -0,0 +1,60 @@ +# bash completion for dmidecode                            -*- shell-script -*- + +_comp_cmd_dmidecode() { +	local cur prev +	COMPREPLY=() +	cur=${COMP_WORDS[COMP_CWORD]} +	prev=${COMP_WORDS[COMP_CWORD - 1]} + +	case $prev in +	-d | --dev-mem | --dump-bin | --from-dump) +		if [[ $prev == -d || $prev == --dev-mem ]]; then +			: "${cur:=/dev/}" +		fi +		local IFS=$'\n' +		compopt -o filenames +		COMPREPLY=($(compgen -f -- "$cur")) +		return 0 +		;; +	-s | --string) +		COMPREPLY=($(compgen -W '$("$1" --list-strings)' -- "$cur")) +		return 0 +		;; +	-t | --type) +		COMPREPLY=($(compgen -W '$("$1" --list-types)' -- "$cur")) +		return 0 +		;; +	--dump-bin | --from-dump) +		local IFS=$'\n' +		compopt -o filenames +		COMPREPLY=($(compgen -f -- "$cur")) +		return 0 +		;; +	-[hVH] | --help | --version | --handle | --oem-string) +		return 0 +		;; +	esac + +	if [[ $cur == -* ]]; then +		COMPREPLY=($(compgen -W ' +			--dev-mem +			--help +			--quiet +			--string +			--list-strings +			--type +			--list-types +			--handle +			--dump +			--dump-bin +			--from-dump +			--no-sysfs +			--oem-string +			--version +		' -- "$cur")) +		return 0 +	fi + +} && complete -F _comp_cmd_dmidecode dmidecode + +# ex: filetype=sh diff --git a/completion/ownership.bash b/completion/ownership.bash new file mode 100644 index 0000000..6a25d29 --- /dev/null +++ b/completion/ownership.bash @@ -0,0 +1,33 @@ +# bash completion for ownership                            -*- shell-script -*- + +_comp_cmd_ownership() { +	local cur prev +	COMPREPLY=() +	cur=${COMP_WORDS[COMP_CWORD]} +	prev=${COMP_WORDS[COMP_CWORD - 1]} + +	case $prev in +	-d | --dev-mem) +		: "${cur:=/dev/}" +		local IFS=$'\n' +		compopt -o filenames +		COMPREPLY=($(compgen -f -- "$cur")) +		return 0 +		;; +	-[hV] | --help | --version) +		return 0 +		;; +	esac + +	if [[ $cur == -* ]]; then +		COMPREPLY=($(compgen -W ' +			--dev-mem +			--help +			--version +		' -- "$cur")) +		return 0 +	fi + +} && complete -F _comp_cmd_ownership ownership + +# ex: filetype=sh diff --git a/completion/vpddecode.bash b/completion/vpddecode.bash new file mode 100644 index 0000000..0745127 --- /dev/null +++ b/completion/vpddecode.bash @@ -0,0 +1,43 @@ +# bash completion for vpddecode                            -*- shell-script -*- + +_comp_cmd_vpddecode() { +	local cur prev +	COMPREPLY=() +	cur=${COMP_WORDS[COMP_CWORD]} +	prev=${COMP_WORDS[COMP_CWORD - 1]} + +	case $prev in +	-d | --dev-mem) +		: "${cur:=/dev/}" +		local IFS=$'\n' +		compopt -o filenames +		COMPREPLY=($(compgen -f -- "$cur")) +		return 0 +		;; +	-s | --string) +		COMPREPLY=($(compgen -W '$( +			"$1" --string 2>&1 | while IFS=\$'\\n' read -r line ; do +				[[ $line == "  "* ]] && printf "%s\n" "$line" +			done +		' -- "$cur")) +		return 0 +		;; +	-[hV] | --help | --version) +		return 0 +		;; +	esac + +	if [[ $cur == -* ]]; then +		COMPREPLY=($(compgen -W ' +			--dev-mem +			--help +			--string +			--dump +			--version +		' -- "$cur")) +		return 0 +	fi + +} && complete -F _comp_cmd_vpddecode vpddecode + +# ex: filetype=sh @@ -22,7 +22,7 @@  #endif  /* Use memory alignment workaround or not */ -#ifdef __ia64__ +#if defined(__ia64__) || defined(__arm__)  #define ALIGNMENT_WORKAROUND  #endif diff --git a/dmidecode.c b/dmidecode.c index 54f59c1..45a6c06 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-2020 Jean Delvare <jdelvare@suse.de> + *   Copyright (C) 2002-2024 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 @@ -57,7 +57,9 @@   *    Family "2.0", Level 00, Revision 00.43, January 26, 2015   *    https://trustedcomputinggroup.org/pc-client-platform-tpm-profile-ptp-specification/   *  - "RedFish Host Interface Specification" (DMTF DSP0270) - *    https://www.dmtf.org/sites/default/files/DSP0270_1.0.1.pdf + *    https://www.dmtf.org/sites/default/files/standards/documents/DSP0270_1.3.0.pdf + *  - LoongArch Reference Manual, volume 1 + *    https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#_cpucfg   */  #include <fcntl.h> @@ -69,7 +71,7 @@  #include <arpa/inet.h>  #include <sys/socket.h> -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__DragonFly__)  #include <errno.h>  #include <kenv.h>  #endif @@ -88,7 +90,7 @@ static const char *bad_index = "<BAD INDEX>";  enum cpuid_type cpuid_type = cpuid_none; -#define SUPPORTED_SMBIOS_VER 0x030500 +#define SUPPORTED_SMBIOS_VER 0x030700  #define FLAG_NO_FILE_OFFSET     (1 << 0)  #define FLAG_STOP_AT_EOT        (1 << 1) @@ -781,6 +783,7 @@ static const char *dmi_processor_family(const struct dmi_header *h, u16 ver)  		{ 0x13, "M2" },  		{ 0x14, "Celeron M" },  		{ 0x15, "Pentium 4 HT" }, +		{ 0x16, "Intel" },  		{ 0x18, "Duron" },  		{ 0x19, "K5" }, @@ -974,6 +977,8 @@ static const char *dmi_processor_family(const struct dmi_header *h, u16 ver)  		{ 0x100, "ARMv7" },  		{ 0x101, "ARMv8" }, +		{ 0x102, "ARMv9" }, +		{ 0x103, "ARM" },  		{ 0x104, "SH-3" },  		{ 0x105, "SH-4" },  		{ 0x118, "ARM" }, @@ -988,6 +993,24 @@ static const char *dmi_processor_family(const struct dmi_header *h, u16 ver)  		{ 0x200, "RV32" },  		{ 0x201, "RV64" },  		{ 0x202, "RV128" }, + +		{ 0x258, "LoongArch" }, +		{ 0x259, "Loongson 1" }, +		{ 0x25A, "Loongson 2" }, +		{ 0x25B, "Loongson 3" }, +		{ 0x25C, "Loongson 2K" }, +		{ 0x25D, "Loongson 3A" }, +		{ 0x25E, "Loongson 3B" }, +		{ 0x25F, "Loongson 3C" }, +		{ 0x260, "Loongson 3D" }, +		{ 0x261, "Loongson 3E" }, +		{ 0x262, "Dual-Core Loongson 2K 2xxx" }, +		{ 0x26C, "Quad-Core Loongson 3A 5xxx" }, +		{ 0x26D, "Multi-Core Loongson 3A 5xxx" }, +		{ 0x26E, "Quad-Core Loongson 3B 5xxx" }, +		{ 0x26F, "Multi-Core Loongson 3B 5xxx" }, +		{ 0x270, "Multi-Core Loongson 3C 5xxx" }, +		{ 0x271, "Multi-Core Loongson 3D 5xxx" },  	};  	/*  	 * Note to developers: when adding entries to this list, check if @@ -1073,7 +1096,7 @@ static enum cpuid_type dmi_get_cpuid_type(const struct dmi_header *h)  		else  			return cpuid_80486;  	} -	else if ((type >= 0x100 && type <= 0x101) /* ARM */ +	else if ((type >= 0x100 && type <= 0x102) /* ARM */  	      || (type >= 0x118 && type <= 0x119)) /* ARM */  	{  		/* @@ -1106,6 +1129,9 @@ static enum cpuid_type dmi_get_cpuid_type(const struct dmi_header *h)  	      || (type >= 0xB6 && type <= 0xB7) /* AMD */  	      || (type >= 0xE4 && type <= 0xEF)) /* AMD */  		return cpuid_x86_amd; +	else if ((type >= 0x258 && type <= 0x262) /* Loongarch */ +	      || (type >= 0x26C && type <= 0x271)) /* Loongarch */ +		return cpuid_loongarch;  	/* neither X86 nor ARM */  	return cpuid_none; @@ -1203,6 +1229,11 @@ void dmi_print_cpuid(void (*print_cb)(const char *name, const char *format, ...)  				 ((eax >> 4) & 0xF) | (((eax >> 8) & 0xF) == 0xF ? (eax >> 12) & 0xF0 : 0),  				 eax & 0xF);  			break; + +		case cpuid_loongarch: /* LoongArch Reference Manual, volume 1 */ +			eax = DWORD(p); +			print_cb(label, "Processor Identity 0x%08x\n", eax); +			break;  		default:  			return;  	} @@ -1415,10 +1446,27 @@ static const char *dmi_processor_upgrade(u8 code)  		"Socket BGA1528",  		"Socket LGA4189",  		"Socket LGA1200", -		"Socket LGA4677" /* 0x3F */ +		"Socket LGA4677", +		"Socket LGA1700", +		"Socket BGA1744", +		"Socket BGA1781", +		"Socket BGA1211", +		"Socket BGA2422", +		"Socket LGA1211", +		"Socket LGA2422", +		"Socket LGA5773", +		"Socket BGA5773", +		"Socket AM5", +		"Socket SP5", +		"Socket SP6", +		"Socket BGA883", +		"Socket BGA1190", +		"Socket BGA4129", +		"Socket LGA4710", +		"Socket LGA7529" /* 0x50 */  	}; -	if (code >= 0x01 && code <= 0x3F) +	if (code >= 0x01 && code <= 0x50)  		return upgrade[code - 0x01];  	return out_of_spec;  } @@ -1939,14 +1987,16 @@ static const char *dmi_port_type(u8 code)  		"Modem Port",  		"Network Port",  		"SATA", -		"SAS" /* 0x21 */ +		"SAS", +		"MFDP (Multi-Function Display Port)", +		"Thunderbolt" /* 0x23 */  	};  	static const char *type_0xA0[] = {  		"8251 Compatible", /* 0xA0 */  		"8251 FIFO Compatible" /* 0xA1 */  	}; -	if (code <= 0x21) +	if (code <= 0x23)  		return type[code];  	if (code >= 0xA0 && code <= 0xA1)  		return type_0xA0[code - 0xA0]; @@ -2062,49 +2112,31 @@ static const char *dmi_slot_type(u8 code)  	return out_of_spec;  } -/* If hide_unknown is set, return NULL instead of "Other" or "Unknown" */ -static const char *dmi_slot_bus_width(u8 code, int hide_unknown) +static const char *dmi_slot_bus_width(u8 code)  {  	/* 7.10.2 */  	static const char *width[] = {  		"Other", /* 0x01 */  		"Unknown", -		"8-bit", -		"16-bit", -		"32-bit", -		"64-bit", -		"128-bit", -		"x1", -		"x2", -		"x4", -		"x8", -		"x12", -		"x16", -		"x32" /* 0x0E */ +		"8 bit", +		"16 bit", +		"32 bit", +		"64 bit", +		"128 bit", +		"1x or x1", +		"2x or x2", +		"4x or x4", +		"8x or x8", +		"12x or x12", +		"16x or x16", +		"32x or x32" /* 0x0E */  	};  	if (code >= 0x01 && code <= 0x0E) -	{ -		if (code <= 0x02 && hide_unknown) -			return NULL;  		return width[code - 0x01]; -	}  	return out_of_spec;  } -static void dmi_slot_type_with_width(u8 type, u8 width) -{ -	const char *type_str, *width_str; - -	type_str = dmi_slot_type(type); -	width_str = dmi_slot_bus_width(width, 1); - -	if (width_str) -		pr_attr("Type", "%s %s", width_str, type_str); -	else -		pr_attr("Type", "%s", type_str); -} -  static const char *dmi_slot_current_usage(u8 code)  {  	/* 7.10.3 */ @@ -2220,12 +2252,13 @@ static void dmi_slot_characteristics(const char *attr, u8 code1, u8 code2)  		"PCIe slot bifurcation is supported",  		"Async/surprise removal is supported",  		"Flexbus slot, CXL 1.0 capable", -		"Flexbus slot, CXL 2.0 capable" /* 6 */ +		"Flexbus slot, CXL 2.0 capable", +		"Flexbus slot, CXL 3.0 capable" /* 7 */  	};  	if (code1 & (1 << 0))  		pr_attr(attr, "Unknown"); -	else if ((code1 & 0xFE) == 0 && (code2 & 0x07) == 0) +	else if ((code1 & 0xFE) == 0 && code2 == 0)  		pr_attr(attr, "None");  	else  	{ @@ -2235,7 +2268,7 @@ static void dmi_slot_characteristics(const char *attr, u8 code1, u8 code2)  		for (i = 1; i <= 7; i++)  			if (code1 & (1 << i))  				pr_list_item("%s", characteristics1[i - 1]); -		for (i = 0; i <= 6; i++) +		for (i = 0; i <= 7; i++)  			if (code2 & (1 << i))  				pr_list_item("%s", characteristics2[i]);  		pr_list_end(); @@ -2314,7 +2347,7 @@ static void dmi_slot_physical_width(u8 code)  {  	if (code)  		pr_attr("Slot Physical Width", "%s", -			dmi_slot_bus_width(code, 0)); +			dmi_slot_bus_width(code));  }  static void dmi_slot_pitch(u16 code) @@ -2640,7 +2673,7 @@ static const char *dmi_memory_array_location(u8 code)  		"PC-98/C24 Add-on Card",  		"PC-98/E Add-on Card",  		"PC-98/Local Bus Add-on Card", -		"CXL Flexbus 1.0" /* 0xA4 */ +		"CXL Add-on Card" /* 0xA4 */  	};  	if (code >= 0x01 && code <= 0x0A) @@ -2826,10 +2859,11 @@ static const char *dmi_memory_device_type(u8 code)  		"HBM",  		"HBM2",  		"DDR5", -		"LPDDR5" /* 0x23 */ +		"LPDDR5", +		"HBM3" /* 0x24 */  	}; -	if (code >= 0x01 && code <= 0x23) +	if (code >= 0x01 && code <= 0x24)  		return type[code - 0x01];  	return out_of_spec;  } @@ -2937,6 +2971,8 @@ static void dmi_memory_manufacturer_id(const char *attr, u16 code)  {  	/* 7.18.8 */  	/* 7.18.10 */ +	/* 7.18.15 */ +	/* 7.17.17 */  	/* LSB is 7-bit Odd Parity number of continuation codes */  	if (code == 0)  		pr_attr(attr, "Unknown"); @@ -2967,6 +3003,45 @@ static void dmi_memory_size(const char *attr, u64 code)  		dmi_print_memory_size(attr, code, 0);  } +static void dmi_memory_revision(const char *attr_type, u16 code, u8 mem_type) +{ +	/* 7.18.16 */ +	/* 7.18.18 */ +	char attr[22]; + +	if (code == 0xFF00) +	{ +		snprintf(attr, sizeof(attr), "%s Revision Number", attr_type); +		pr_attr(attr, "Unknown"); +	} +	else if (mem_type == 0x22 || mem_type == 0x23)	/* DDR5 */ +	{ +		u8 dev_type = (code >> 8) & 0x0F; +		u8 dev_rev = code & 0xFF; + +		if (code & 0x8000)			/* Installed */ +		{ +			snprintf(attr, sizeof(attr), "%s Device Type", +				 attr_type); +			pr_attr(attr, "%hu", dev_type); +			snprintf(attr, sizeof(attr), "%s Device Revision", +				 attr_type); +			pr_attr(attr, "%hu.%hu", dev_rev >> 4, dev_rev & 0x0F); +		} +		else +		{ +			snprintf(attr, sizeof(attr), "%s Device Type", +				 attr_type); +			pr_attr(attr, "Not Installed"); +		} +	} +	else						/* Generic fallback */ +	{ +		snprintf(attr, sizeof(attr), "%s Revision Number", attr_type); +		pr_attr(attr, "0x%04x", code); +	} +} +  /*   * 7.19 32-bit Memory Error Information (Type 18)   */ @@ -3813,7 +3888,7 @@ static const char *dmi_protocol_record_type(u8 type)  }  /* - * DSP0270: 8.6: Protocol IP Assignment types + * DSP0270: 8.4.2: Protocol IP Assignment types   */  static const char *dmi_protocol_assignment_type(u8 type)  { @@ -3831,7 +3906,7 @@ static const char *dmi_protocol_assignment_type(u8 type)  }  /* - * DSP0270: 8.6: Protocol IP Address type + * DSP0270: 8.4.3: Protocol IP Address type   */  static const char *dmi_address_type(u8 type)  { @@ -3847,7 +3922,7 @@ static const char *dmi_address_type(u8 type)  }  /* - *  DSP0270: 8.6 Protocol Address decode + *  DSP0270: 8.4.3 Protocol Address decode   */  static const char *dmi_address_decode(u8 *data, char *storage, u8 addrtype)  { @@ -3859,7 +3934,7 @@ static const char *dmi_address_decode(u8 *data, char *storage, u8 addrtype)  }  /* - * DSP0270: 8.5: Parse the protocol record format + * DSP0270: 8.4: Parse the protocol record format   */  static void dmi_parse_protocol_record(u8 *rec)  { @@ -3874,11 +3949,11 @@ static void dmi_parse_protocol_record(u8 *rec)  	const char *hname;  	char attr[38]; -	/* DSP0270: 8.5: Protocol Identifier */ +	/* DSP0270: 8.4: Protocol Identifier */  	rid = rec[0x0]; -	/* DSP0270: 8.5: Protocol Record Length */ +	/* DSP0270: 8.4: Protocol Record Length */  	rlen = rec[0x1]; -	/* DSP0270: 8.5: Protocol Record Data */ +	/* DSP0270: 8.4: Protocol Record Data */  	rdata = &rec[0x2];  	pr_attr("Protocol ID", "%02x (%s)", rid, @@ -3887,7 +3962,7 @@ static void dmi_parse_protocol_record(u8 *rec)  	/*  	 * Don't decode anything other than Redfish for now  	 * Note 0x4 is Redfish over IP in 7.43.2 -	 * and DSP0270: 8.5 +	 * and DSP0270: 8.4  	 */  	if (rid != 0x4)  		return; @@ -3901,7 +3976,7 @@ static void dmi_parse_protocol_record(u8 *rec)  		return;  	/* -	 * DSP0270: 8.6: Redfish Over IP Service UUID +	 * DSP0270: 8.4.1: Redfish Over IP Service UUID  	 * Note: ver is hardcoded to 0x311 here just for  	 * convenience.  It could get passed from the SMBIOS  	 * header, but that's a lot of passing of pointers just @@ -3914,7 +3989,7 @@ static void dmi_parse_protocol_record(u8 *rec)  	dmi_system_uuid(pr_subattr, "Service UUID", &rdata[0], 0x311);  	/* -	 * DSP0270: 8.6: Redfish Over IP Host IP Assignment Type +	 * DSP0270: 8.4.1: Redfish Over IP Host IP Assignment Type  	 * Note, using decimal indices here, as the DSP0270  	 * uses decimal, so as to make it more comparable  	 */ @@ -3922,34 +3997,34 @@ static void dmi_parse_protocol_record(u8 *rec)  	pr_subattr("Host IP Assignment Type", "%s",  		dmi_protocol_assignment_type(assign_val)); -	/* DSP0270: 8.6: Redfish Over IP Host Address format */ +	/* DSP0270: 8.4.1: Redfish Over IP Host Address format */  	addrtype = rdata[17];  	addrstr = dmi_address_type(addrtype);  	pr_subattr("Host IP Address Format", "%s",  		addrstr); -	/* DSP0270: 8.6 IP Assignment types */ +	/* DSP0270: 8.4.1 IP Assignment types */  	/* We only use the Host IP Address and Mask if the assignment type is static */  	if (assign_val == 0x1 || assign_val == 0x3)  	{ -		/* DSP0270: 8.6: the Host IPv[4|6] Address */ +		/* DSP0270: 8.4.1: the Host IPv[4|6] Address */  		sprintf(attr, "%s Address", addrstr);  		pr_subattr(attr, "%s",  			dmi_address_decode(&rdata[18], buf, addrtype)); -		/* DSP0270: 8.6: Prints the Host IPv[4|6] Mask */ +		/* DSP0270: 8.4.1: Prints the Host IPv[4|6] Mask */  		sprintf(attr, "%s Mask", addrstr);  		pr_subattr(attr, "%s",  			dmi_address_decode(&rdata[34], buf, addrtype));  	} -	/* DSP0270: 8.6: Get the Redfish Service IP Discovery Type */ +	/* DSP0270: 8.4.1: Get the Redfish Service IP Discovery Type */  	assign_val = rdata[50];  	/* Redfish Service IP Discovery type mirrors Host IP Assignment type */  	pr_subattr("Redfish Service IP Discovery Type", "%s",  		dmi_protocol_assignment_type(assign_val)); -	/* DSP0270: 8.6: Get the Redfish Service IP Address Format */ +	/* DSP0270: 8.4.1: Get the Redfish Service IP Address Format */  	addrtype = rdata[51];  	addrstr = dmi_address_type(addrtype);  	pr_subattr("Redfish Service IP Address Format", "%s", @@ -3960,30 +4035,30 @@ static void dmi_parse_protocol_record(u8 *rec)  		u16 port;  		u32 vlan; -		/* DSP0270: 8.6: Prints the Redfish IPv[4|6] Service Address */ +		/* DSP0270: 8.4.1: Prints the Redfish IPv[4|6] Service Address */  		sprintf(attr, "%s Redfish Service Address", addrstr);  		pr_subattr(attr, "%s",  			dmi_address_decode(&rdata[52], buf,  			addrtype)); -		/* DSP0270: 8.6: Prints the Redfish IPv[4|6] Service Mask */ +		/* DSP0270: 8.4.1: Prints the Redfish IPv[4|6] Service Mask */  		sprintf(attr, "%s Redfish Service Mask", addrstr);  		pr_subattr(attr, "%s",  			dmi_address_decode(&rdata[68], buf,  			addrtype)); -		/* DSP0270: 8.6: Redfish vlan and port info */ +		/* DSP0270: 8.4.1: Redfish vlan and port info */  		port = WORD(&rdata[84]);  		vlan = DWORD(&rdata[86]);  		pr_subattr("Redfish Service Port", "%hu", port);  		pr_subattr("Redfish Service Vlan", "%u", vlan);  	} -	/* DSP0270: 8.6: Redfish host length and name */ +	/* DSP0270: 8.4.1: Redfish host length and name */  	hlen = rdata[90];  	/* -	 * DSP0270: 8.6: The length of the host string + 91 (the minimum +	 * DSP0270: 8.4.1: The length of the host string + 91 (the minimum  	 * size of a protocol record) cannot exceed the record length  	 * (rec[0x1])  	 */ @@ -4004,15 +4079,39 @@ static const char *dmi_parse_device_type(u8 type)  	const char *devname[] = {  		"USB",		/* 0x2 */  		"PCI/PCIe",	/* 0x3 */ +		"USB v2",	/* 0x4 */ +		"PCI/PCIe v2",	/* 0x5 */  	}; -	if (type >= 0x2 && type <= 0x3) +	if (type >= 0x2 && type <= 0x5)  		return devname[type - 0x2];  	if (type >= 0x80)  		return "OEM";  	return out_of_spec;  } +/* + * DSP0270: 8.3.7: Device Characteristics + */ +static void dmi_device_characteristics(u16 code) +{ +	const char *characteristics[] = { +		"Credential bootstrapping via IPMI is supported", /* 0 */ +		/* Reserved */ +	}; + +	if ((code & 0x1) == 0) +		pr_list_item("None"); +	else +	{ +		int i; + +		for (i = 0; i < 1; i++) +			if (code & (1 << i)) +				pr_list_item("%s", characteristics[i]); +	} +} +  static void dmi_parse_controller_structure(const struct dmi_header *h)  {  	int i; @@ -4055,7 +4154,7 @@ static void dmi_parse_controller_structure(const struct dmi_header *h)  	if (len != 0)  	{ -		/* DSP0270: 8.3 Table 2: Device Type */ +		/* DSP0270: 8.3.1 Table 3: Device Type values */  		type = data[0x6];  		pr_attr("Device Type", "%s", @@ -4092,7 +4191,84 @@ static void dmi_parse_controller_structure(const struct dmi_header *h)  			pr_attr("SubDeviceID", "0x%04x",  				WORD(&pcidata[0x6]));  		} -		else if (type == 0x4 && len >= 5) +		else if (type == 0x4 && len >= 0x0d) +		{ +			/* USB Device Type v2 - need at least 12 bytes */ +			u8 *usbdata = &data[7]; +			/* USB Device Descriptor v2: idVendor */ +			pr_attr("idVendor", "0x%04x", +				WORD(&usbdata[0x1])); +			/* USB Device Descriptor v2: idProduct */ +			pr_attr("idProduct", "0x%04x", +				WORD(&usbdata[0x3])); + +			/* +			 * USB Serial number is here, but its useless, don't +			 * bother decoding it +			 */ + +			/* USB Device Descriptor v2: MAC Address */ +			pr_attr("MAC Address", "%02x:%02x:%02x:%02x:%02x:%02x", +				usbdata[0x6], usbdata[0x7], usbdata[0x8], +				usbdata[0x9], usbdata[0xa], usbdata[0xb]); + +			/* DSP0270 v1.3.0 support */ +			if (len >= 0x11) +			{ +				/* USB Device Descriptor v2: Device Characteristics */ +				pr_list_start("Device Characteristics", NULL); +				dmi_device_characteristics(WORD(&usbdata[0xc])); +				pr_list_end(); + +				/* USB Device Descriptor v2: Credential Bootstrapping Handle */ +				if (WORD(&usbdata[0x0c]) & 0x1) +				{ +					pr_attr("Credential Bootstrapping Handle", "0x%04x", +							WORD(&usbdata[0xe])); +				} +			} +		} +		else if (type == 0x5 && len >= 0x14) +		{ +			/* PCI Device Type v2 - Need at least 19 bytes */ +			u8 *pcidata = &data[0x7]; +			/* PCI Device Descriptor v2: VendorID */ +			pr_attr("VendorID", "0x%04x", +				WORD(&pcidata[0x1])); +			/* PCI Device Descriptor v2: DeviceID */ +			pr_attr("DeviceID", "0x%04x", +				WORD(&pcidata[0x3])); +			/* PCI Device Descriptor v2: PCI SubvendorID */ +			pr_attr("SubVendorID", "0x%04x", +				WORD(&pcidata[0x5])); +			/* PCI Device Descriptor v2: PCI SubdeviceID */ +			pr_attr("SubDeviceID", "0x%04x", +				WORD(&pcidata[0x7])); +			/* PCI Device Descriptor v2: MAC Address */ +			pr_attr("MAC Address", "%02x:%02x:%02x:%02x:%02x:%02x", +				pcidata[0x9], pcidata[0xa], pcidata[0xb], +				pcidata[0xc], pcidata[0xd], pcidata[0xe]); +			/* PCI Device Descriptor v2: +			 *		Segment Group Number, Bus Number, Device/Function Number +			 */ +			dmi_slot_segment_bus_func(WORD(&pcidata[0xf]), pcidata[0x11], pcidata[0x12]); + +			/* DSP0270 v1.3.0 support */ +			if (len >= 0x18) +			{ +				/* PCI Device Descriptor v2: Device Characteristics */ +				pr_list_start("Device Characteristics", NULL); +				dmi_device_characteristics(WORD(&pcidata[0x13]) ); +				pr_list_end(); +				/* PCI Device Descriptor v2: Credential Bootstrapping Handle */ +				if (WORD(&pcidata[0x13]) & 0x1) +				{ +					pr_attr("Credential Bootstrapping Handle", "0x%04x", +							WORD(&pcidata[0x15])); +				} +			} +		} +		else if (type >= 0x80 && len >= 5)  		{  			/* OEM Device Type - Need at least 4 bytes */  			u8 *oemdata = &data[0x7]; @@ -4105,7 +4281,7 @@ static void dmi_parse_controller_structure(const struct dmi_header *h)  	}  	/* -	 * DSP0270: 8.2 and 8.5: Protocol record count and protocol records +	 * DSP0270: 8.2 and 8.4: Protocol record count and protocol records  	 * Move to the Protocol Count.  	 */  	data = &data[total_read]; @@ -4148,7 +4324,7 @@ static void dmi_parse_controller_structure(const struct dmi_header *h)  			dmi_parse_protocol_record(rec);  			/* -			 * DSP0270: 8.6 +			 * DSP0270: 8.4.1  			 * Each record is rec[1] bytes long, starting at the  			 * data byte immediately following the length field.  			 * That means we need to add the byte for the rec id, @@ -4451,6 +4627,9 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)  				pr_attr("Thread Count", "%u",  					h->length >= 0x30 && data[0x25] == 0xFF ?  					WORD(data + 0x2E) : data[0x25]); +			if (h->length >= 0x32 && WORD(data + 0x30) != 0) +				pr_attr("Thread Enabled", "%u", +					WORD(data + 0x30));  			dmi_processor_characteristics("Characteristics",  						      WORD(data + 0x26));  			break; @@ -4548,7 +4727,8 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)  			if (h->length < 0x0C) break;  			pr_attr("Designation", "%s",  				dmi_string(h, data[0x04])); -			dmi_slot_type_with_width(data[0x05], data[0x06]); +			pr_attr("Type", "%s", dmi_slot_type(data[0x05])); +			pr_attr("Data Bus Width", "%s", dmi_slot_bus_width(data[0x06]));  			pr_attr("Current Usage", "%s",  				dmi_slot_current_usage(data[0x07]));  			pr_attr("Length", "%s", @@ -4561,7 +4741,7 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)  			if (h->length < 0x11) break;  			dmi_slot_segment_bus_func(WORD(data + 0x0D), data[0x0F], data[0x10]);  			if (h->length < 0x13) break; -			pr_attr("Data Bus Width", "%u", data[0x11]); +			pr_attr("Data Bus Width (Base)", "%u", data[0x11]);  			pr_attr("Peer Devices", "%u", data[0x12]);  			if (h->length < 0x13 + data[0x12] * 5) break;  			dmi_slot_peers(data[0x12], data + 0x13); @@ -4755,6 +4935,15 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)  			dmi_memory_size("Cache Size", QWORD(data + 0x44));  			if (h->length < 0x54) break;  			dmi_memory_size("Logical Size", QWORD(data + 0x4C)); +			if (h->length < 0x64) break; +			dmi_memory_manufacturer_id("PMIC0 Manufacturer ID", +						   WORD(data + 0x5C)); +			dmi_memory_revision("PMIC0", WORD(data + 0x5E), +					    data[0x12]); +			dmi_memory_manufacturer_id("RCD Manufacturer ID", +						   WORD(data + 0x60)); +			dmi_memory_revision("RCD", WORD(data + 0x62), +					    data[0x12]);  			break;  		case 18: /* 7.19 32-bit Memory Error Information */ @@ -5718,14 +5907,14 @@ static void overwrite_smbios3_address(u8 *buf)  	buf[0x17] = 0;  } -static int smbios3_decode(u8 *buf, const char *devmem, u32 flags) +static int smbios3_decode(u8 *buf, size_t buf_len, const char *devmem, u32 flags)  {  	u32 ver, len;  	u64 offset;  	u8 *table;  	/* Don't let checksum run beyond the buffer */ -	if (buf[0x06] > 0x20) +	if (buf[0x06] > buf_len)  	{  		fprintf(stderr,  			"Entry point length too large (%u bytes, expected %u).\n", @@ -5799,14 +5988,14 @@ static void dmi_fixup_version(u16 *ver)  	}  } -static int smbios_decode(u8 *buf, const char *devmem, u32 flags) +static int smbios_decode(u8 *buf, size_t buf_len, const char *devmem, u32 flags)  {  	u16 ver, num;  	u32 len;  	u8 *table;  	/* Don't let checksum run beyond the buffer */ -	if (buf[0x05] > 0x20) +	if (buf[0x05] > buf_len)  	{  		fprintf(stderr,  			"Entry point length too large (%u bytes, expected %u).\n", @@ -5910,7 +6099,7 @@ static int address_from_efi(off_t *address)  	FILE *efi_systab;  	const char *filename;  	char linebuf[64]; -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__DragonFly__)  	char addrstr[KENV_MVALLEN + 1];  #endif  	const char *eptype; @@ -5948,11 +6137,14 @@ static int address_from_efi(off_t *address)  	if (ret == EFI_NO_SMBIOS)  		fprintf(stderr, "%s: SMBIOS entry point missing\n", filename); -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__DragonFly__)  	/*  	 * On FreeBSD, SMBIOS anchor base address in UEFI mode is exposed  	 * via kernel environment:  	 * https://svnweb.freebsd.org/base?view=revision&revision=307326 +	 * +	 * DragonFly BSD adopted the same method as FreeBSD, see commit +	 * 5e488df32cb01056a5b714a522e51c69ab7b4612  	 */  	ret = kenv(KENV_GET, "hint.smbios.0.mem", addrstr, sizeof(addrstr));  	if (ret == -1) @@ -6009,6 +6201,12 @@ int main(int argc, char * const argv[])  		goto exit_free;  	} +	if (opt.flags & FLAG_LIST) +	{ +		/* Already handled in parse_command_line() */ +		goto exit_free; +	} +  	if (opt.flags & FLAG_HELP)  	{  		print_help(); @@ -6025,25 +6223,33 @@ int main(int argc, char * const argv[])  		pr_comment("dmidecode %s", VERSION);  	/* Read from dump if so instructed */ +	size = 0x20;  	if (opt.flags & FLAG_FROM_DUMP)  	{  		if (!(opt.flags & FLAG_QUIET))  			pr_info("Reading SMBIOS/DMI data from file %s.",  				opt.dumpfile); -		if ((buf = mem_chunk(0, 0x20, opt.dumpfile)) == NULL) +		if ((buf = read_file(0, &size, opt.dumpfile)) == NULL)  		{  			ret = 1;  			goto exit_free;  		} +		/* Truncated entry point can't be processed */ +		if (size < 0x20) +		{ +			ret = 1; +			goto done; +		} +  		if (memcmp(buf, "_SM3_", 5) == 0)  		{ -			if (smbios3_decode(buf, opt.dumpfile, 0)) +			if (smbios3_decode(buf, size, opt.dumpfile, 0))  				found++;  		}  		else if (memcmp(buf, "_SM_", 4) == 0)  		{ -			if (smbios_decode(buf, opt.dumpfile, 0)) +			if (smbios_decode(buf, size, opt.dumpfile, 0))  				found++;  		}  		else if (memcmp(buf, "_DMI_", 5) == 0) @@ -6059,7 +6265,6 @@ 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(0, &size, SYS_ENTRY_FILE)) != NULL)  	{ @@ -6067,12 +6272,12 @@ int main(int argc, char * const argv[])  			pr_info("Getting SMBIOS data from sysfs.");  		if (size >= 24 && memcmp(buf, "_SM3_", 5) == 0)  		{ -			if (smbios3_decode(buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET)) +			if (smbios3_decode(buf, size, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET))  				found++;  		}  		else if (size >= 31 && memcmp(buf, "_SM_", 4) == 0)  		{ -			if (smbios_decode(buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET)) +			if (smbios_decode(buf, size, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET))  				found++;  		}  		else if (size >= 15 && memcmp(buf, "_DMI_", 5) == 0) @@ -6109,12 +6314,12 @@ int main(int argc, char * const argv[])  	if (memcmp(buf, "_SM3_", 5) == 0)  	{ -		if (smbios3_decode(buf, opt.devmem, 0)) +		if (smbios3_decode(buf, 0x20, opt.devmem, 0))  			found++;  	}  	else if (memcmp(buf, "_SM_", 4) == 0)  	{ -		if (smbios_decode(buf, opt.devmem, 0)) +		if (smbios_decode(buf, 0x20, opt.devmem, 0))  			found++;  	}  	goto done; @@ -6135,7 +6340,7 @@ memory_scan:  	{  		if (memcmp(buf + fp, "_SM3_", 5) == 0)  		{ -			if (smbios3_decode(buf + fp, opt.devmem, 0)) +			if (smbios3_decode(buf + fp, 0x20, opt.devmem, 0))  			{  				found++;  				goto done; @@ -6148,7 +6353,7 @@ memory_scan:  	{  		if (memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0)  		{ -			if (smbios_decode(buf + fp, opt.devmem, 0)) +			if (smbios_decode(buf + fp, 0x20, opt.devmem, 0))  			{  				found++;  				goto done; diff --git a/dmidecode.h b/dmidecode.h index 318cdc6..e03c957 100644 --- a/dmidecode.h +++ b/dmidecode.h @@ -1,7 +1,7 @@  /*   * This file is part of the dmidecode project.   * - *   Copyright (C) 2005-2020 Jean Delvare <jdelvare@suse.de> + *   Copyright (C) 2005-2023 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 @@ -40,6 +40,7 @@ enum cpuid_type  	cpuid_arm_soc_id,  	cpuid_x86_intel,  	cpuid_x86_amd, +	cpuid_loongarch,  };  extern enum cpuid_type cpuid_type; @@ -2,7 +2,8 @@   * Decoding of OEM-specific entries   * This file is part of the dmidecode project.   * - *   Copyright (C) 2007-2020 Jean Delvare <jdelvare@suse.de> + *   Copyright (C) 2007-2024 Jean Delvare <jdelvare@suse.de> + *   Copyright (C) 2017-2024 Jerry Hoemann <jerry.hoemann@hpe.com>   *   *   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 @@ -161,11 +162,12 @@ static void dmi_print_hp_net_iface_rec(u8 id, u8 bus, u8 dev, const u8 *mac)  	}  } -typedef enum { G6 = 6, G7, G8, G9, G10, G10P } dmi_hpegen_t; +typedef enum { G6 = 6, G7, G8, G9, G10, G10P, G11 } dmi_hpegen_t;  static int dmi_hpegen(const char *s)  {  	struct { const char *name; dmi_hpegen_t gen; } table[] = { +		{ "Gen11",	G11 },  		{ "Gen10 Plus",	G10P },  		{ "Gen10",	G10 },  		{ "Gen9",	G9 }, @@ -187,25 +189,21 @@ static int dmi_hpegen(const char *s)  	return (dmi_vendor == VENDOR_HPE) ? G10P : G6;  } -static void dmi_hp_240_attr(u64 defined, u64 set) +static void dmi_hp_197_qdf(const u8 *qdf)  { -	static const char *attributes[] = { -		"Updatable", -		"Reset Required", -		"Authentication Required", -		"In Use", -		"UEFI Image", -	}; -	unsigned int i; +	char str[7]; +	int i, j, len = 6; -	pr_list_start("Attributes Defined/Set", NULL); -	for (i = 0; i < ARRAY_SIZE(attributes); i++) +	if (!is_printable(qdf, len)) +		return; + +	for (i = 0, j = 0;  i < len;  i++)  	{ -		if (!(defined.l & (1UL << i))) -			continue; -		pr_list_item("%s: %s", attributes[i], set.l & (1UL << i) ? "Yes" : "No"); +		if (qdf[i] != ' ') +			str[j++] = qdf[i];  	} -	pr_list_end(); +	str[j] = '\0'; +	pr_attr("QDF/S-SPEC", "%s", str);  }  static void dmi_hp_203_assoc_hndl(const char *fname, u16 num) @@ -291,7 +289,13 @@ static void dmi_hp_203_devloc(const char *fname, unsigned int code)  		"USB",  		"Dynamic Smart Array Controller",  		"URL", -		"NVMe Drive Bay" /* 0x0F */ +		"NVMe Drive Bay", /* 0x0F */ +		"NVDIMM Processor", +		"NVDIMM Board", +		"NVMe Riser", +		"NVDIMM Name Space", +		"VROC SATA", +		"VROC NVMe", /* 0x15 */  	};  	if (code < ARRAY_SIZE(location)) @@ -361,8 +365,10 @@ static void dmi_hp_216_fw_type(u16 code)  		"Secondary System Programmable Logic Device",  		"CPU MEZZ Programmable Logic Device", /* 0x37 */  		"Intel Artic Sound -M Accelerator Models Firmware", -		"Ampere System Control Processor (SCP – PMPro+SMPro)", +		"Ampere System Control Processor (SCP - PMPro+SMPro)",  		"Intel CFR information", /* 0x3A */ +		"OCP cards", +		"DC-SCM CPLD",  	};  	if (code < ARRAY_SIZE(type)) @@ -384,8 +390,10 @@ static void dmi_hp_216_version(u8 format, u8 *data)  		pr_attr(name, "No Version Data");  		break;  	case 1: -		pr_attr(name, "%c.%d.%d", data[0] & (1 << 7) ? 'B' : 'R', -					  data[0] & 0x7, data[1] & 0x7); +		if (data[0] >> 7) +			pr_attr(name, "0x%02X B.0x%02X", data[1] & 0x7F, data[0] & 0x7F); +		else +			pr_attr(name, "0x%02X", data[1] & 0x7F);  		break;  	case 2:  		pr_attr(name, "%d.%d", data[0] >> 4, data[0] & 0x0f); @@ -580,6 +588,8 @@ static void dmi_hp_238_loc(const char *fname, unsigned int code)  		"USB Hub for NAND Controller",  		"Reserved",  		"Debug Port", /* 0x07 */ +		"Reserved", +		"OCP USB", /* 0x09 */  	};  	if (code < ARRAY_SIZE(location)) @@ -619,6 +629,106 @@ static void dmi_hp_238_speed(const char *fname, unsigned int code)  	pr_attr(fname, "%s", str);  } +static void dmi_hp_239_usb_device(u8 class, u8 subclass, u8 protocol) +{ +	/* https://www.usb.org/defined-class-codes */ +	/* https://www.usb.org/sites/default/files/Mass_Storage_Specification_Overview_v1.4_2-19-2010.pdf */ +	const char *str = "Reserved"; +	if (class == 0x08) +	{ +		static const char * const sub_class_name[] = { +			"SCSI command set not reported", /* 0x00 */ +			"RBC", +			"ATAPI", +			"Obsolete", +			"UFI", +			"Obsolete", +			"SCSI", +			"LSD FS", +			"IEEE 1667" /* 0x08 */ +		}; +		pr_attr("USB Class", "%s", "Mass Storage"); +		if (subclass == 0xFF) +		{ +			str = "Vendor Specific"; +		} +		else if (subclass < ARRAY_SIZE(sub_class_name)) +		{ +			str = sub_class_name[subclass]; +		} +		pr_attr("USB SubClass", "%s", str); + +		switch (protocol) { +		case 0x00: +			str = "CBI w/ completion interrupt"; +			break; +		case 0x01: +			str = "CBI w/o completion interrupt"; +			break; +		case 0x02: +			str = "Obsolete"; +			break; +		case 0x50: +			str = "Bulk-Only"; +			break; +		case 0x62: +			str = "UAS"; +			break; +		case 0xFF: +			str = "Vendor Specific"; +			break; +		default: +			str = "Reserved"; +		} +		pr_attr("USB Protocol", "%s", str); +	} +	else if (class == 0x09 && subclass == 0) +	{ +		pr_attr("USB Class", "%s", "HUB"); +		switch (protocol) { +		case 0: +			str = "Full Speed"; +			break; +		case 1: +			str = "Hi-Speed w/ single TT"; +			break; +		case 2: +			str = "Hi-Speed w/ multiple TT"; +			break; +		default: +			str = "Reserved"; +		} +		pr_attr("USB Protocol", str); +	} +	else +	{ +		pr_attr("USB Class", "0x%02x", class); +		pr_attr("USB SubClass", "0x%02x", subclass); +		pr_attr("USB Protocol", "0x%02x", protocol); +	} +} + +static void dmi_hp_240_attr(u64 defined, u64 set) +{ +	static const char *attributes[] = { +		"Updatable", +		"Reset Required", +		"Authentication Required", +		"In Use", +		"UEFI Image", +	}; +	unsigned int i; + +	pr_list_start("Attributes Defined/Set", NULL); +	for (i = 0; i < ARRAY_SIZE(attributes); i++) +	{ +		if (!(defined.l & (1UL << i))) +			continue; +		pr_list_item("%s: %s", attributes[i], set.l & (1UL << i) ? "Yes" : "No"); +	} +	pr_list_end(); +} +  static void dmi_hp_242_hdd_type(u8 code)  {  	const char *str = "Reserved"; @@ -651,8 +761,17 @@ static void dmi_hp_242_form_factor(u8 code)  		"MicroSSD",  		"CFast", /* 0x09 */  	}; +	static const char * const form2[] = { +		"EDSFF Unknown", /* 0x20 */ +		"EDSFF 1U Short", +		"EDSFF 1U Long", +		"EDSFF E3 Short", +		"EDSFF E3 Long", /* 0x24 */ +	};  	if (code < ARRAY_SIZE(form))  		str = form[code]; +	else if (code >= 0x20 && code < 0x20 + ARRAY_SIZE(form2)) +		str = form2[code - 0x20];  	pr_attr("Form Factor", "%s", str);  } @@ -665,6 +784,31 @@ static void dmi_hp_242_speed(const char *attr, u16 speed)  		pr_attr(attr, "%s", "Unknown");  } +static void dmi_hp_245_pcie_riser(const struct dmi_header *h) +{ +	const char *str = "Reserved"; +	u8 *data = h->data; + +	pr_attr("Board Type", "PCIe Riser"); +	if (h->length < 0x09) return; +	switch (data[0x05]) +	{ +		case 1: str = "Primary"; break; +		case 2: str = "Secondary"; break; +		case 3: str = "Tertiary"; break; +		case 4: str = "Quaternary"; break; +		case 10: str = "Front"; break; +	} +	pr_attr("Riser Position", "%s", str); +	pr_attr("Riser ID", "%d", data[0x06]); +	if (data[0x07]) +	{ +		str = (data[0x07] >> 7) ? "B." : ""; +		pr_attr("CPLD Version", "%s0x%02X", str, (data[0x07] & 0x7F)); +	} +	pr_attr("Riser Name", dmi_string(h, data[0x08])); +} +  static int dmi_decode_hp(const struct dmi_header *h)  {  	u8 *data = h->data; @@ -700,6 +844,69 @@ static int dmi_decode_hp(const struct dmi_header *h)  			pr_attr("Virtual Serial Port", "%s", feat & (1 << 4) ? "Enabled" : "Disabled");  			break; +		case 197: +			/* +			 * Vendor Specific: HPE Processor Specific Information +			 * +			 * Processor Information structure (Type 197) for each possibly installed +			 * physical processor to go along with each standard Processor Info +			 * Record (Type 4).  The Type 197 record will be ignored for Processor +			 * slots that are empty (specified in the Type 4 records). +			 * +			 * Processor Wattage value will be filled in with information gotten from +			 * the CPUID instruction or possibly estimated based on CPU Family/Type. +			 * +			 * Designator bytes will be 0FFh if the location of the processor does not +			 * use it.  If a system has processor slots, but no sockets, then the value +			 * in the Socket Designator will be 0FFh. A system would have one or the +			 * other, or both. +			 * +			 * Offset |  Name      | Width | Description +			 * -------+------------+-------+------------- +			 *  0x00  | Type       | BYTE  | 0xC5, Processor Information +			 *  0x01  | Length     | BYTE  | Length of structure +			 *  0x02  | Handle     | WORD  | Unique handle +			 *  0x04  | Assoc Dev  | WORD  | Handle of Associated Type 4 Record +			 *  0x06  | APIC ID    | BYTE  | Processor local APIC ID +			 *  0x07  | OEM Status | BYTE  | Bits: 0: BSP, 1: x2APIC, 2: Therm Margining +			 *  0x08  | Phys Slot  | BYTE  | Matches silk screen +			 *  0x09  | Phys Socket| BYTE  | Matches silk screen +			 *  0x0A  | Max Wattage| WORD  | Rated max wattage of the processor +			 *  0x0C  | x2APIC ID  | DWORD | Processor x2APIC (if OEM Status -> x2APIC) +			 *  0x10  | Proc UUID  | QWORD | Processor Unique Identifier +			 *  0x18  | Conn Speed | WORD  | Interconnect speed in MT/s +			 *  0x1A  | QDF/S-SPEC |6 BYTES| Processor QDF/S-SPEC Numbers (Intel only) +			 *  0x20  | Reserved   | DWORD | Gen11 Reserved +			 */ +			pr_handle_name("%s Processor Specific Information", company); +			if (h->length < 0x0A) break; +			if (!(opt.flags & FLAG_QUIET)) +				pr_attr("Associated Handle", "0x%04X", WORD(data + 0x04)); +			pr_attr("APIC ID", "%u", data[0x06]); +			feat = data[0x07]; +			pr_attr("BSP", "%s", feat & 0x01 ? "Yes" : "No"); +			pr_attr("x2APIC", "%s", feat & 0x02 ? "Yes" : "No"); +			pr_attr("Advanced Thermal Margining", "%s", feat & 0x04 ? "Yes" : "No"); +			if (data[0x08] != 0xFF) +				pr_attr("Physical Slot", "%d", data[0x08]); +			if (data[0x09] != 0xFF) +				pr_attr("Physical Socket", "%d", data[0x09]); +			if (h->length < 0x0C) break; +			if (WORD(data + 0x0A)) +				pr_attr("Maximum Power", "%d W", WORD(data + 0x0A)); +			if (h->length < 0x10) break; +			if (feat & 0x02) +				pr_attr("x2APIC ID", "0x%08x", DWORD(data + 0x0C)); +			if (h->length < 0x18) break; +			if (DWORD(data + 0x10) || DWORD(data + 0x14)) +				pr_attr("UUID", "0x%08x%08x", DWORD(data + 0x14), DWORD(data + 0x10)); +			if (h->length < 0x1A) break; +			if (WORD(data + 0x18)) +				pr_attr("Interconnect Speed", "%d MT/s", WORD(data + 0x18)); +			if (h->length < 0x20) break; +			dmi_hp_197_qdf(data + 0x1A); +			break; +  		case 199:  			/*  			 * Vendor Specific: CPU Microcode Patch @@ -789,6 +996,10 @@ static int dmi_decode_hp(const struct dmi_header *h)  			}  			dmi_hp_203_assoc_hndl("Parent Handle", WORD(data + 0x12));  			pr_attr("Flags", "0x%04X", WORD(data + 0x14)); +			if (WORD(data + 0x14) & 0x01) +				pr_subattr("Peer Bifurcated Device", "Yes"); +			if (WORD(data + 0x14) & 0x02) +				pr_subattr("Upstream Device", "Yes");  			dmi_hp_203_devtyp("Device Type", data[0x16]);  			dmi_hp_203_devloc("Device Location", data[0x17]);  			pr_attr("Device Instance", "%d", data[0x18]); @@ -853,6 +1064,7 @@ static int dmi_decode_hp(const struct dmi_header *h)  			 *  			 * Type 221: is deprecated in the latest docs  			 */ +			if (gen >= G8 && h->type == 221) return 0;  			pr_handle_name("%s %s", company, h->type == 221 ?  				       "BIOS iSCSI NIC PCI and MAC Information" :  				       "BIOS PXE NIC PCI and MAC Information"); @@ -875,6 +1087,7 @@ static int dmi_decode_hp(const struct dmi_header *h)  			 *  			 * Source: hpwdt kernel driver  			 */ +			if (gen >= G9) return 0;  			pr_handle_name("%s 64-bit CRU Information", company);  			if (h->length < 0x18) break;  			if (is_printable(data + 0x04, 4)) @@ -1034,6 +1247,7 @@ static int dmi_decode_hp(const struct dmi_header *h)  			 *  0x07  | Dev No | BYTE  | PCI Device/Function No  			 *  0x08  |   MAC  | 32B   | MAC addr padded w/ 0s  			 *  0x28  | Port No| BYTE  | Each NIC maps to a Port +			 *  0x29  | DevPath| STRING| UEFI Device Path of network port  			 */  			pr_handle_name("%s BIOS PXE NIC PCI and MAC Information",  				       company); @@ -1044,6 +1258,8 @@ static int dmi_decode_hp(const struct dmi_header *h)  			nic = h->length > 0x28 ? data[0x28] : 0xFF;  			dmi_print_hp_net_iface_rec(nic, data[0x06], data[0x07],  						   &data[0x08]); +			if (h->length < 0x2A) break; +			pr_attr("UEFI Device Path", "%s", dmi_string(h, data[0x29]));  			break;  		case 236: @@ -1064,6 +1280,7 @@ static int dmi_decode_hp(const struct dmi_header *h)  			 *  0x13  | A2 Bays    | BYTE  | (deprecated) Number of SAS drive bays behind port 0xA2  			 *  0x14  | Name       | STRING| (deprecated) Backplane Name  			 */ +			if (gen >= G11) return 0;  			pr_handle_name("%s HDD Backplane FRU Information", company);  			if (h->length < 0x08) break;  			pr_attr("FRU I2C Address", "0x%X raw(0x%X)", data[0x4] >> 1, data[0x4]); @@ -1094,7 +1311,8 @@ static int dmi_decode_hp(const struct dmi_header *h)  			 *  0x06  | Manufacture|STRING | DIMM Manufacturer  			 *  0x07  | Part Number|STRING | DIMM Manufacturer's Part Number  			 *  0x08  | Serial Num |STRING | DIMM Vendor Serial Number -			 *  0x09  | Spare Part |STRING | DIMM Spare Part Number +			 *  0x09  | Man Date   | BYTE  | DIMM Manufacture Date (YEAR) in BCD +			 *  0x0A  | Man Date   | BYTE  | DIMM Manufacture Date (WEEK) in BCD  			 */  			if (gen < G9) return 0;  			pr_handle_name("%s DIMM Vendor Information", company); @@ -1105,8 +1323,9 @@ static int dmi_decode_hp(const struct dmi_header *h)  			pr_attr("DIMM Manufacturer Part Number", "%s", dmi_string(h, data[0x07]));  			if (h->length < 0x09) break;  			pr_attr("DIMM Vendor Serial Number", "%s", dmi_string(h, data[0x08])); -			if (h->length < 0x0A) break; -			pr_attr("DIMM Spare Part Number", "%s", dmi_string(h, data[0x09])); +			if (h->length < 0x0B) break; +			if (WORD(data + 0x09)) +				pr_attr("DIMM Manufacture Date", "20%02x-W%02x", data[0x09], data[0x0A]);  			break;  		case 238: @@ -1146,6 +1365,54 @@ static int dmi_decode_hp(const struct dmi_header *h)  			pr_attr("Device Path", "%s", dmi_string(h, data[0xE]));  			break; +		case 239: +			/* +			 * Vendor Specific: HPE USB Device Correlation Record +			 * +			 * This record provides a mechanism for software to correlate USB device +			 * information provided in SMBIOS record Type 8 and Type 238. It +			 * additionally provides device specific data that is typically not +			 * available in SMBIOS to allow HP tools to understand how these device +			 * entries correlate to both UEFI and Legacy USB Boot entries. This record +			 * will only contain information for a device detected by the BIOS during +			 * POST and does not comprehend a hot plug event after the system has +			 * booted. This record will only be supported on UEFI Based systems. +			 * +			 * Offset |  Name      | Width | Description +			 * -------+------------+-------+------------ +			 *  0x00  | Type       | BYTE  | 0xEF, HP Device Correlation Record +			 *  0x01  | Length     | BYTE  | Length of structure +			 *  0x02  | Handle     | WORD  | Unique handle +			 *  0x04  | Hand Assoc | WORD  | Handle to map to Type 238 +			 *  0x06  | Vendor ID  | WORD  | Vendor ID of detected USB Device +			 *  0x08  | Flags      | WORD  | Bit[0] - Indicates presence of SD card +			 *  0x0A  | Class      | BYTE  | USB Device Class per USB HID Dev Spec +			 *  0x0B  | Sub Class  | BYTE  | USB Device SubClass per USB HID Dev Spec +			 *  0x0C  | Protocol   | BYTE  | Device Protocol per USB HID Dev Spec +			 *  0x0D  | Product ID | WORD  | USB Product ID +			 *  0x0F  | Capacity   | DWORD | USB Device Capacity (if apropos) in Mbytes +			 *  0x13  | Device Path| STRING| UEFI Device Path +			 *  0x14  | Device Name| STRING| UEFI Device Structured Name +			 *  0x15  | UEFI Name  | STRING| Device Name +			 *  0x16  | Location   | STRING| USB Device Location +			 */ +			if (gen < G9) return 0; +			pr_handle_name("%s USB Device Correlation Record", company); +			if (h->length < 0x17) break; +			if (!(opt.flags & FLAG_QUIET)) +				pr_attr("Associated Handle", "0x%04X", WORD(data + 0x04)); +			pr_attr("USB Vendor ID", "0x%04x", WORD(data + 0x06)); +			pr_attr("Embedded SD Card", "%s", data[0x08] & 0x01 ? "Present" : "Empty"); +			dmi_hp_239_usb_device(data[0x0A], data[0x0B], data[0x0C]); +			pr_attr("USB Product ID", "0x%04x", WORD(data + 0x0D)); +			if (DWORD(data + 0x0F)) +				pr_attr("USB Capacity", "%u MB", DWORD(data + 0x0F)); +			pr_attr("UEFI Device Path", "%s", dmi_string(h, data[0x13])); +			pr_attr("UEFI Device Name", "%s", dmi_string(h, data[0x14])); +			pr_attr("Device Name", "%s", dmi_string(h, data[0x15])); +			pr_attr("Device Location", "%s", dmi_string(h, data[0x16])); +			break; +  		case 240:  			/*  			 * Vendor Specific: HPE Proliant Inventory Record @@ -1264,6 +1531,40 @@ static int dmi_decode_hp(const struct dmi_header *h)  			dmi_hp_242_speed("Negotiated Speed", WORD(data + 0x3A));  			dmi_hp_242_speed("Capable Speed", WORD(data + 0x3C));  			break; + +		case 245: +			/* +			 * Vendor Specific: HPE Extension Board Inventory Record +			 * +			 * This record provides a mechanism for software to retrieve installed +			 * Extension Boards in system, such as Riser Cards, etc. Each extension +			 * board discovered at system boot time has a corresponding record +			 * produced in SMBIOS Type 245. This record is currently applicable +			 * for ML, DL and Alletra series servers in Gen11 and will be backward +			 * compatible with next generations +			 * +			 * This is a variant record. Definition of fields 0x05 ... vary based +			 * upon field 0x04 Board Type. +			 * +			 * Offset |  Name      | Width | Description +			 * --------------------------------------- +			 *  0x00  | Type       | BYTE  | 0xF5, Extension Board Inventory Record +			 *  0x01  | Length     | BYTE  | Length of structure +			 *  0x02  | Handle     | WORD  | Unique handle +			 *  0x04  | Board Type | WORD  | 0: PCIe Riser, Other Reserved +			 * +			 *  If Board Type == 0 +			 *  0x05  | Riser Pos  | WORD  | +			 *  0x06  | Riser ID   | BYTE  | +			 *  0x07  | CPLD Vers  | BTYE  | 0-> No CPLD. Bits [7][6:0] Release:Vers +			 *  0x08  | Riser Name | STRING| +			 */ +			pr_handle_name("%s ProLiant Extension Board Inventory Record", company); +			if (h->length < 0x05) break; +			if (data[0x04] == 0) +				dmi_hp_245_pcie_riser(h); +			break; +  		default:  			return 0;  	} @@ -2,7 +2,7 @@   * Command line handling of dmidecode   * This file is part of the dmidecode project.   * - *   Copyright (C) 2005-2008 Jean Delvare <jdelvare@suse.de> + *   Copyright (C) 2005-2023 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 @@ -265,6 +265,7 @@ static u32 parse_opt_handle(const char *arg)  int parse_command_line(int argc, char * const argv[])  {  	int option; +	unsigned int i;  	const char *optstring = "d:hqs:t:uH:V";  	struct option longopts[] = {  		{ "dev-mem", required_argument, NULL, 'd' }, @@ -279,6 +280,8 @@ int parse_command_line(int argc, char * const argv[])  		{ "handle", required_argument, NULL, 'H' },  		{ "oem-string", required_argument, NULL, 'O' },  		{ "no-sysfs", no_argument, NULL, 'S' }, +		{ "list-strings", no_argument, NULL, 'L' }, +		{ "list-types", no_argument, NULL, 'T' },  		{ "version", no_argument, NULL, 'V' },  		{ NULL, 0, NULL, 0 }  	}; @@ -332,6 +335,16 @@ int parse_command_line(int argc, char * const argv[])  			case 'S':  				opt.flags |= FLAG_NO_SYSFS;  				break; +			case 'L': +				for (i = 0; i < ARRAY_SIZE(opt_string_keyword); i++) +					fprintf(stdout, "%s\n", opt_string_keyword[i].keyword); +				opt.flags |= FLAG_LIST; +				return 0; +			case 'T': +				for (i = 0; i < ARRAY_SIZE(opt_type_keyword); i++) +					fprintf(stdout, "%s\n", opt_type_keyword[i].keyword); +				opt.flags |= FLAG_LIST; +				return 0;  			case 'V':  				opt.flags |= FLAG_VERSION;  				break; @@ -377,7 +390,9 @@ void print_help(void)  		" -q, --quiet            Less verbose output\n"  		"     --no-quirks        Decode everything without quirks\n"  		" -s, --string KEYWORD   Only display the value of the given DMI string\n" +		"     --list-strings     List available string keywords and exit\n"  		" -t, --type TYPE        Only display the entries of given type\n" +		"     --list-types       List available type keywords and exit\n"  		" -H, --handle HANDLE    Only display the entry of given handle\n"  		" -u, --dump             Do not decode the entries\n"  		"     --dump-bin FILE    Dump the DMI data to a binary file\n" @@ -2,7 +2,7 @@   * Command line handling of dmidecode   * This file is part of the dmidecode project.   * - *   Copyright (C) 2005-2008 Jean Delvare <jdelvare@suse.de> + *   Copyright (C) 2005-2023 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 @@ -47,6 +47,7 @@ extern struct opt opt;  #define FLAG_FROM_DUMP          (1 << 5)  #define FLAG_NO_SYSFS           (1 << 6)  #define FLAG_NO_QUIRKS          (1 << 7) +#define FLAG_LIST               (1 << 8)  int parse_command_line(int argc, char * const argv[]);  void print_help(void); diff --git a/man/dmidecode.8 b/man/dmidecode.8 index 83affc2..77c89a5 100644 --- a/man/dmidecode.8 +++ b/man/dmidecode.8 @@ -127,6 +127,10 @@ typically from files under  .IR /sys/devices/virtual/dmi/id .  Most of these files are even readable by regular users.  .TP +.BR "  " "  " "--list-strings" +List available string keywords, which can then be passed to the \fB--string\fP +option. +.TP  .BR "-t" ", " "--type \fITYPE\fP"  Only display the entries of type \fITYPE\fP. It can be either a  \s-1DMI\s0 type number, or a comma-separated list of type numbers, or a @@ -150,6 +154,10 @@ is printed and  .B dmidecode  exits with an error.  .TP +.BR "  " "  " "--list-types" +List available type keywords, which can then be passed to the \fB--type\fP +option. +.TP  .BR "-H" ", " "--handle \fIHANDLE\fP"  Only display the entry whose handle matches \fIHANDLE\fP.  \fIHANDLE\fP is a 16-bit integer. @@ -2,7 +2,7 @@   * Common "util" functions   * This file is part of the dmidecode project.   * - *   Copyright (C) 2002-2018 Jean Delvare <jdelvare@suse.de> + *   Copyright (C) 2002-2023 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 @@ -1,7 +1,7 @@  /*   * This file is part of the dmidecode project.   * - *   Copyright (C) 2003-2017 Jean Delvare <jdelvare@suse.de> + *   Copyright (C) 2003-2023 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 @@ -1 +1 @@ -#define VERSION "3.5" +#define VERSION "3.6"  | 
