Merge branch 'feature/upstream' into develop

This commit is contained in:
Jörg Frings-Fürst 2024-06-30 20:02:17 +02:00
commit c38426c9a9
17 changed files with 864 additions and 126 deletions

2
.gitignore vendored
View File

@ -1,2 +0,0 @@
.pc
debian/files

View File

@ -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

19
NEWS
View File

@ -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.

View File

@ -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

60
completion/dmidecode.bash Normal file
View File

@ -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

33
completion/ownership.bash Normal file
View File

@ -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

43
completion/vpddecode.bash Normal file
View File

@ -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

View File

@ -22,7 +22,7 @@
#endif
/* Use memory alignment workaround or not */
#ifdef __ia64__
#if defined(__ia64__) || defined(__arm__)
#define ALIGNMENT_WORKAROUND
#endif

View File

@ -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;

View File

@ -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;

349
dmioem.c
View File

@ -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;
}

View File

@ -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"

View File

@ -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);

View File

@ -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
util.c
View File

@ -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

2
util.h
View File

@ -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

View File

@ -1 +1 @@
#define VERSION "3.5"
#define VERSION "3.6"