diff options
author | Jörg Frings-Fürst <debian@jff.email> | 2024-06-30 20:02:17 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff.email> | 2024-06-30 20:02:17 +0200 |
commit | c38426c9a9dd4efb236ef21d0c281d341445102a (patch) | |
tree | 45fa8b58371e9f40cd1fbd169cbd497eb300a2a1 | |
parent | 25d9e648d730c649a9769b04dc0a246fbc9680cb (diff) | |
parent | e8704754ec72eb19159d167d79a1d89a899ea632 (diff) |
Merge branch 'feature/upstream' into develop
-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" |