mirror of
https://git.jff.email/cgit/dmidecode.git
synced 2026-08-07 08:07:48 +00:00
Update upstream source from tag 'upstream/3.7'
Update to upstream version '3.7'
with Debian dir c76a11fb14
This commit is contained in:
commit
48e6eede2a
1
AUTHORS
1
AUTHORS
@ -24,6 +24,7 @@ Petr Oros <poros@redhat.com>
|
||||
Prabhakar Pujeri <prabhakar.pujeri@dell.com>
|
||||
Erwan Velu <e.velu@criteo.com>
|
||||
Jerry Hoemann <jerry.hoemann@hpe.com>
|
||||
Armin Wolf <W_Armin@gmx.de>
|
||||
|
||||
MANY THANKS TO (IN CHRONOLOGICAL ORDER)
|
||||
Werner Heuser
|
||||
|
||||
5
Makefile
5
Makefile
@ -19,14 +19,11 @@ CFLAGS ?= -O2
|
||||
#CFLAGS ?= -g
|
||||
|
||||
CFLAGS += -W -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual \
|
||||
-Wcast-align -Wwrite-strings -Wmissing-prototypes -Winline -Wundef
|
||||
-Wcast-align -Wwrite-strings -Wmissing-prototypes -Wundef
|
||||
|
||||
# Let lseek and mmap support 64-bit wide offsets
|
||||
CFLAGS += -D_FILE_OFFSET_BITS=64
|
||||
|
||||
#CFLAGS += -DBIGENDIAN
|
||||
#CFLAGS += -DALIGNMENT_WORKAROUND
|
||||
|
||||
# Pass linker flags here (can be set from environment too)
|
||||
LDFLAGS ?=
|
||||
|
||||
|
||||
15
NEWS
15
NEWS
@ -1,3 +1,18 @@
|
||||
Version 3.7 (Thu Dec 18 2025)
|
||||
- [COMPATIBILITY] Use binary unit prefixes.
|
||||
- [COMPATIBILITY] Rename BIOS to Firmware.
|
||||
- [PORTABILITY] Improve variable declarations.
|
||||
- [PORTABILITY] Stop open-coding the u64 type.
|
||||
- [PORTABILITY] Use unaligned memory accesses unconditionally.
|
||||
- [PORTABILITY] No longer build with -Winline.
|
||||
- Support for SMBIOS 3.8.0. This includes a new processor family.
|
||||
- Support for SMBIOS 3.9.0. This includes chassis type name adjustments,
|
||||
new rack attributes, slot ID for more slot types, and new memory device
|
||||
form factors and types.
|
||||
- Decode HPE OEM records 193, 195, 202, 211, 226, 229, 232 and 244.
|
||||
- Update HPE OEM records 203, 216, 242 and 245.
|
||||
- EDSFF slot names now include their .S/.L suffix.
|
||||
|
||||
Version 3.6 (Wed Apr 24 2024)
|
||||
- [PORTABILITY] Use -DALIGNMENT_WORKAROUND on arm.
|
||||
- [PORTABILITY] Read SMBIOS entry point via kenv on DragonFly BSD.
|
||||
|
||||
8
README
8
README
@ -41,14 +41,6 @@ Optionally, you can run "make strip" prior to "make install" if you want
|
||||
smaller binaries. However, be aware that this will prevent any further
|
||||
attempt to debug the programs.
|
||||
|
||||
Two parameters can be set in the Makefile file to make dmidecode work on
|
||||
non-i386 systems. They should be used if your system uses the big endian
|
||||
byte ordering (Motorola) or doesn't support unaligned memory accesses,
|
||||
respectively. For example, compiling for a SPARC processor would require
|
||||
both (but I am not aware of SPARC-based systems implementing SMBIOS).
|
||||
Compiling for an IA64 processor requires the memory alignment workaround,
|
||||
and it is enabled automatically.
|
||||
|
||||
|
||||
** DOCUMENTATION **
|
||||
|
||||
|
||||
10
biosdecode.c
10
biosdecode.c
@ -2,7 +2,7 @@
|
||||
* BIOS Decode
|
||||
*
|
||||
* Copyright (C) 2000-2002 Alan Cox <alan@redhat.com>
|
||||
* Copyright (C) 2002-2017 Jean Delvare <jdelvare@suse.de>
|
||||
* Copyright (C) 2002-2025 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
|
||||
@ -111,8 +111,8 @@ static int smbios3_decode(const u8 *p, size_t len)
|
||||
p[0x07], p[0x08], p[0x09]);
|
||||
printf("\tStructure Table Maximum Length: %u bytes\n",
|
||||
DWORD(p + 0x0C));
|
||||
printf("\tStructure Table 64-bit Address: 0x%08X%08X\n",
|
||||
QWORD(p + 0x10).h, QWORD(p + 0x10).l);
|
||||
printf("\tStructure Table 64-bit Address: 0x%016llX\n",
|
||||
QWORD(p + 0x10));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -284,8 +284,8 @@ static int acpi_decode(const u8 *p, size_t len)
|
||||
|
||||
if (DWORD(p + 20) < 32) return 1;
|
||||
|
||||
printf("\tXSD Table 64-bit Address: 0x%08X%08X\n",
|
||||
QWORD(p + 24).h, QWORD(p + 24).l);
|
||||
printf("\tXSD Table 64-bit Address: 0x%016llX\n",
|
||||
QWORD(p + 24));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
5
config.h
5
config.h
@ -21,11 +21,6 @@
|
||||
#define USE_MMAP
|
||||
#endif
|
||||
|
||||
/* Use memory alignment workaround or not */
|
||||
#if defined(__ia64__) || defined(__arm__)
|
||||
#define ALIGNMENT_WORKAROUND
|
||||
#endif
|
||||
|
||||
/* Avoid unaligned memcpy on /dev/mem */
|
||||
#ifdef __aarch64__
|
||||
#define USE_SLOW_MEMCPY
|
||||
|
||||
377
dmidecode.c
377
dmidecode.c
@ -2,7 +2,7 @@
|
||||
* DMI Decode
|
||||
*
|
||||
* Copyright (C) 2000-2002 Alan Cox <alan@redhat.com>
|
||||
* Copyright (C) 2002-2024 Jean Delvare <jdelvare@suse.de>
|
||||
* Copyright (C) 2002-2025 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
|
||||
@ -85,12 +85,11 @@
|
||||
#include "dmioem.h"
|
||||
#include "dmioutput.h"
|
||||
|
||||
#define out_of_spec "<OUT OF SPEC>"
|
||||
static const char *bad_index = "<BAD INDEX>";
|
||||
|
||||
enum cpuid_type cpuid_type = cpuid_none;
|
||||
|
||||
#define SUPPORTED_SMBIOS_VER 0x030700
|
||||
#define SUPPORTED_SMBIOS_VER 0x030900
|
||||
|
||||
#define FLAG_NO_FILE_OFFSET (1 << 0)
|
||||
#define FLAG_STOP_AT_EOT (1 << 1)
|
||||
@ -163,7 +162,7 @@ const char *dmi_string(const struct dmi_header *dm, u8 s)
|
||||
static const char *dmi_smbios_structure_type(u8 code)
|
||||
{
|
||||
static const char *type[] = {
|
||||
"BIOS", /* 0 */
|
||||
"Platform Firmware", /* 0 */
|
||||
"System",
|
||||
"Base Board",
|
||||
"Chassis",
|
||||
@ -176,7 +175,7 @@ static const char *dmi_smbios_structure_type(u8 code)
|
||||
"On Board Devices",
|
||||
"OEM Strings",
|
||||
"System Configuration Options",
|
||||
"BIOS Language",
|
||||
"Firmware Language",
|
||||
"Group Associations",
|
||||
"System Event Log",
|
||||
"Physical Memory Array",
|
||||
@ -274,28 +273,29 @@ static void dmi_dump(const struct dmi_header *h)
|
||||
}
|
||||
}
|
||||
|
||||
/* shift is 0 if the value is in bytes, 1 if it is in kilobytes */
|
||||
void dmi_print_memory_size(const char *attr, u64 code, int shift)
|
||||
/* shift is 0 if the value is in bytes, 1 if it is in kibibytes */
|
||||
void dmi_print_memory_size(void (*print_cb)(const char *name, const char *format, ...),
|
||||
const char *attr, u64 code, int shift)
|
||||
{
|
||||
unsigned long capacity;
|
||||
u16 split[7];
|
||||
static const char *unit[8] = {
|
||||
"bytes", "kB", "MB", "GB", "TB", "PB", "EB", "ZB"
|
||||
"bytes", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB"
|
||||
};
|
||||
int i;
|
||||
|
||||
/*
|
||||
* We split the overall size in powers of thousand: EB, PB, TB, GB,
|
||||
* MB, kB and B. In practice, it is expected that only one or two
|
||||
* We split the overall size in powers of 1024: EiB, PiB, TiB, GiB,
|
||||
* MiB, KiB and B. In practice, it is expected that only one or two
|
||||
* (consecutive) of these will be non-zero.
|
||||
*/
|
||||
split[0] = code.l & 0x3FFUL;
|
||||
split[1] = (code.l >> 10) & 0x3FFUL;
|
||||
split[2] = (code.l >> 20) & 0x3FFUL;
|
||||
split[3] = ((code.h << 2) & 0x3FCUL) | (code.l >> 30);
|
||||
split[4] = (code.h >> 8) & 0x3FFUL;
|
||||
split[5] = (code.h >> 18) & 0x3FFUL;
|
||||
split[6] = code.h >> 28;
|
||||
split[0] = code & 0x3FFULL;
|
||||
split[1] = (code >> 10) & 0x3FFULL;
|
||||
split[2] = (code >> 20) & 0x3FFULL;
|
||||
split[3] = (code >> 30) & 0x3FFULL;
|
||||
split[4] = (code >> 40) & 0x3FFULL;
|
||||
split[5] = (code >> 50) & 0x3FFULL;
|
||||
split[6] = (code >> 60) & 0x3FFULL;
|
||||
|
||||
/*
|
||||
* Now we find the highest unit with a non-zero value. If the following
|
||||
@ -315,11 +315,33 @@ void dmi_print_memory_size(const char *attr, u64 code, int shift)
|
||||
else
|
||||
capacity = split[i];
|
||||
|
||||
pr_attr(attr, "%lu %s", capacity, unit[i + shift]);
|
||||
print_cb(attr, "%lu %s", capacity, unit[i + shift]);
|
||||
}
|
||||
|
||||
/* shift is 0 if the value is in bytes, 1 if it is in kB, 2 if it is in MB */
|
||||
void dmi_print_storage_size(const char *attr, u64 code, unsigned int shift)
|
||||
{
|
||||
u64 divisor;
|
||||
static const char *unit[8] = {
|
||||
"bytes", "kB", "MB", "GB", "TB", "PB", "EB", "ZB"
|
||||
};
|
||||
|
||||
/*
|
||||
* We want to choose the unit which will let us display a number
|
||||
* between 1.0 and 999.9.
|
||||
*/
|
||||
divisor = 1;
|
||||
while (code / divisor >= 1000 && shift + 1 < ARRAY_SIZE(unit))
|
||||
{
|
||||
shift++;
|
||||
divisor *= 1000;
|
||||
}
|
||||
|
||||
pr_attr(attr, "%.1f %s", (float)code / divisor, unit[shift]);
|
||||
}
|
||||
|
||||
/*
|
||||
* 7.1 BIOS Information (Type 0)
|
||||
* 7.1 Platform Firmware Information (Type 0)
|
||||
*/
|
||||
|
||||
static void dmi_bios_runtime_size(u32 code)
|
||||
@ -332,7 +354,7 @@ static void dmi_bios_runtime_size(u32 code)
|
||||
}
|
||||
else
|
||||
{
|
||||
format = "%u kB";
|
||||
format = "%u KiB";
|
||||
code >>= 10;
|
||||
}
|
||||
|
||||
@ -342,13 +364,12 @@ static void dmi_bios_runtime_size(u32 code)
|
||||
static void dmi_bios_rom_size(u8 code1, u16 code2)
|
||||
{
|
||||
static const char *unit[4] = {
|
||||
"MB", "GB", out_of_spec, out_of_spec
|
||||
"MiB", "GiB", out_of_spec, out_of_spec
|
||||
};
|
||||
|
||||
if (code1 != 0xFF)
|
||||
{
|
||||
u64 s = { .l = (code1 + 1) << 6 };
|
||||
dmi_print_memory_size("ROM Size", s, 1);
|
||||
dmi_print_memory_size(pr_attr, "ROM Size", (u64)(code1 + 1) << 6, 1);
|
||||
}
|
||||
else
|
||||
pr_attr("ROM Size", "%u %s", code2 & 0x3FFF, unit[code2 >> 14]);
|
||||
@ -358,7 +379,7 @@ static void dmi_bios_characteristics(u64 code)
|
||||
{
|
||||
/* 7.1.1 */
|
||||
static const char *characteristics[] = {
|
||||
"BIOS characteristics not supported", /* 3 */
|
||||
"Firmware characteristics not supported", /* 3 */
|
||||
"ISA is supported",
|
||||
"MCA is supported",
|
||||
"EISA is supported",
|
||||
@ -366,13 +387,13 @@ static void dmi_bios_characteristics(u64 code)
|
||||
"PC Card (PCMCIA) is supported",
|
||||
"PNP is supported",
|
||||
"APM is supported",
|
||||
"BIOS is upgradeable",
|
||||
"BIOS shadowing is allowed",
|
||||
"Firmware is upgradeable",
|
||||
"Firmware shadowing is allowed",
|
||||
"VLB is supported",
|
||||
"ESCD support is available",
|
||||
"Boot from CD is supported",
|
||||
"Selectable boot is supported",
|
||||
"BIOS ROM is socketed",
|
||||
"Firmware ROM is socketed",
|
||||
"Boot from PC Card (PCMCIA) is supported",
|
||||
"EDD is supported",
|
||||
"Japanese floppy for NEC 9800 1.2 MB is supported (int 13h)",
|
||||
@ -393,14 +414,14 @@ static void dmi_bios_characteristics(u64 code)
|
||||
/*
|
||||
* This isn't very clear what this bit is supposed to mean
|
||||
*/
|
||||
if (code.l & (1 << 3))
|
||||
if (code & (1ULL << 3))
|
||||
{
|
||||
pr_list_item("%s", characteristics[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 4; i <= 31; i++)
|
||||
if (code.l & (1 << i))
|
||||
if (code & (1ULL << i))
|
||||
pr_list_item("%s", characteristics[i - 3]);
|
||||
}
|
||||
|
||||
@ -447,8 +468,8 @@ static void dmi_bios_characteristics_x2(u8 code)
|
||||
* 7.2 System Information (Type 1)
|
||||
*/
|
||||
|
||||
static void dmi_system_uuid(void (*print_cb)(const char *name, const char *format, ...),
|
||||
const char *attr, const u8 *p, u16 ver)
|
||||
void dmi_system_uuid(void (*print_cb)(const char *name, const char *format, ...),
|
||||
const char *attr, const u8 *p, u16 ver)
|
||||
{
|
||||
int only0xFF = 1, only0x00 = 1;
|
||||
int i;
|
||||
@ -626,10 +647,10 @@ static const char *dmi_chassis_type(u8 code)
|
||||
"Rack Mount Chassis",
|
||||
"Sealed-case PC",
|
||||
"Multi-system",
|
||||
"CompactPCI",
|
||||
"AdvancedTCA",
|
||||
"Compact PCI",
|
||||
"Advanced TCA",
|
||||
"Blade",
|
||||
"Blade Enclosing",
|
||||
"Blade Enclosure",
|
||||
"Tablet",
|
||||
"Convertible",
|
||||
"Detachable",
|
||||
@ -730,6 +751,18 @@ static void dmi_chassis_elements(u8 count, u8 len, const u8 *p)
|
||||
pr_list_end();
|
||||
}
|
||||
|
||||
static const char *dmi_chassis_rack_type(u8 code)
|
||||
{
|
||||
static const char *type[] = {
|
||||
"Unspecified", /* 0x00 */
|
||||
"OU" /* 0x01 */
|
||||
};
|
||||
|
||||
if (code <= 0x01)
|
||||
return type[code];
|
||||
return out_of_spec;
|
||||
}
|
||||
|
||||
/*
|
||||
* 7.5 Processor Information (Type 4)
|
||||
*/
|
||||
@ -942,6 +975,7 @@ static const char *dmi_processor_family(const struct dmi_header *h, u16 ver)
|
||||
{ 0xCD, "Core i5" },
|
||||
{ 0xCE, "Core i3" },
|
||||
{ 0xCF, "Core i9" },
|
||||
{ 0xD0, "Xeon D" },
|
||||
|
||||
{ 0xD2, "C7-M" },
|
||||
{ 0xD3, "C7-D" },
|
||||
@ -1011,6 +1045,15 @@ static const char *dmi_processor_family(const struct dmi_header *h, u16 ver)
|
||||
{ 0x26F, "Multi-Core Loongson 3B 5xxx" },
|
||||
{ 0x270, "Multi-Core Loongson 3C 5xxx" },
|
||||
{ 0x271, "Multi-Core Loongson 3D 5xxx" },
|
||||
|
||||
{ 0x300, "Core 3" },
|
||||
{ 0x301, "Core 5" },
|
||||
{ 0x302, "Core 7" },
|
||||
{ 0x303, "Core 9" },
|
||||
{ 0x304, "Core Ultra 3" },
|
||||
{ 0x305, "Core Ultra 5" },
|
||||
{ 0x306, "Core Ultra 7" },
|
||||
{ 0x307, "Core Ultra 9" },
|
||||
};
|
||||
/*
|
||||
* Note to developers: when adding entries to this list, check if
|
||||
@ -1140,8 +1183,9 @@ static enum cpuid_type dmi_get_cpuid_type(const struct dmi_header *h)
|
||||
void dmi_print_cpuid(void (*print_cb)(const char *name, const char *format, ...),
|
||||
const char *label, enum cpuid_type sig, const u8 *p)
|
||||
{
|
||||
u32 eax, midr, jep106, soc_revision;
|
||||
u16 dx;
|
||||
u32 eax, midr, soc_revision;
|
||||
u16 dx, soc_id;
|
||||
u8 jep106_code, jep106_bank;
|
||||
|
||||
switch (sig)
|
||||
{
|
||||
@ -1181,12 +1225,12 @@ void dmi_print_cpuid(void (*print_cb)(const char *name, const char *format, ...)
|
||||
|
||||
case cpuid_arm_soc_id: /* ARM with SOC ID */
|
||||
/*
|
||||
* If Soc ID is supported, the first DWORD is the JEP-106 code;
|
||||
* the second DWORD is the SoC revision value.
|
||||
*/
|
||||
jep106 = DWORD(p);
|
||||
soc_revision = DWORD(p + 4);
|
||||
/*
|
||||
* If SoC ID is supported, the first WORD is a SiP
|
||||
* defined SoC ID; the next BYTE is the JEP-106
|
||||
* identification code of the SiP; the next BYTE is
|
||||
* its bank index; lastly, the next DWORD is the SoC
|
||||
* revision value.
|
||||
*
|
||||
* According to SMC Calling Convention (SMCCC) v1.3 specification
|
||||
* (https://developer.arm.com/documentation/den0028/d/), the format
|
||||
* of the values returned by the SMCCC_ARCH_SOC_ID call is as follows:
|
||||
@ -1201,9 +1245,14 @@ void dmi_print_cpuid(void (*print_cb)(const char *name, const char *format, ...)
|
||||
* Bit[31] must be zero
|
||||
* Bits[30:0] SoC revision
|
||||
*/
|
||||
soc_id = WORD(p);
|
||||
jep106_code = p[2] & 0x7F;
|
||||
jep106_bank = p[3] & 0x7F;
|
||||
soc_revision = DWORD(p + 4);
|
||||
|
||||
pr_attr("Signature",
|
||||
"JEP-106 Bank 0x%02x Manufacturer 0x%02x, SoC ID 0x%04x, SoC Revision 0x%08x",
|
||||
(jep106 >> 24) & 0x7F, (jep106 >> 16) & 0x7F, jep106 & 0xFFFF, soc_revision);
|
||||
jep106_bank, jep106_code, soc_id, soc_revision);
|
||||
return;
|
||||
|
||||
case cpuid_x86_intel: /* Intel */
|
||||
@ -1369,8 +1418,8 @@ static const char *dmi_processor_status(u8 code)
|
||||
static const char *status[] = {
|
||||
"Unknown", /* 0x00 */
|
||||
"Enabled",
|
||||
"Disabled By User",
|
||||
"Disabled By BIOS",
|
||||
"Disabled by user",
|
||||
"Disabled by firmware",
|
||||
"Idle", /* 0x04 */
|
||||
out_of_spec,
|
||||
out_of_spec,
|
||||
@ -1463,10 +1512,17 @@ static const char *dmi_processor_upgrade(u8 code)
|
||||
"Socket BGA1190",
|
||||
"Socket BGA4129",
|
||||
"Socket LGA4710",
|
||||
"Socket LGA7529" /* 0x50 */
|
||||
"Socket LGA7529",
|
||||
"Socket BGA1964",
|
||||
"Socket BGA1792",
|
||||
"Socket BGA2049",
|
||||
"Socket BGA2551",
|
||||
"Socket LGA1851",
|
||||
"Socket BGA2114",
|
||||
"Socket BGA2833" /* 0x57 */
|
||||
};
|
||||
|
||||
if (code >= 0x01 && code <= 0x50)
|
||||
if (code >= 0x01 && code <= 0x57)
|
||||
return upgrade[code - 0x01];
|
||||
return out_of_spec;
|
||||
}
|
||||
@ -1710,7 +1766,7 @@ static void dmi_memory_module_size(const char *attr, u8 code)
|
||||
pr_attr(attr, "Not Installed");
|
||||
return;
|
||||
default:
|
||||
pr_attr(attr, "%u MB%s", 1 << (code & 0x7F),
|
||||
pr_attr(attr, "%u MiB%s", 1 << (code & 0x7F),
|
||||
connection);
|
||||
}
|
||||
}
|
||||
@ -1765,18 +1821,16 @@ static void dmi_cache_size_2(const char *attr, u32 code)
|
||||
|
||||
if (code & 0x80000000)
|
||||
{
|
||||
code &= 0x7FFFFFFFLU;
|
||||
size.l = code << 6;
|
||||
size.h = code >> 26;
|
||||
code &= 0x7FFFFFFFULL;
|
||||
size = (u64)code << 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
size.l = code;
|
||||
size.h = 0;
|
||||
size = code;
|
||||
}
|
||||
|
||||
/* Use a more convenient unit for large cache size */
|
||||
dmi_print_memory_size(attr, size, 1);
|
||||
dmi_print_memory_size(pr_attr, attr, size, 1);
|
||||
}
|
||||
|
||||
static void dmi_cache_size(const char *attr, u16 code)
|
||||
@ -2009,7 +2063,7 @@ static const char *dmi_port_type(u8 code)
|
||||
* 7.10 System Slots (Type 9)
|
||||
*/
|
||||
|
||||
static const char *dmi_slot_type(u8 code)
|
||||
static void dmi_slot_type(u8 code, u8 length)
|
||||
{
|
||||
/* 7.10.1 */
|
||||
static const char *type[] = {
|
||||
@ -2102,14 +2156,35 @@ static const char *dmi_slot_type(u8 code)
|
||||
* Note to developers: when adding entries to these lists, check if
|
||||
* function dmi_slot_id below needs updating too.
|
||||
*/
|
||||
const char *t, *suffix = "";
|
||||
|
||||
if (code >= 0x01 && code <= 0x28)
|
||||
return type[code - 0x01];
|
||||
if (code == 0x30)
|
||||
return type_0x30[code - 0x30];
|
||||
if (code >= 0xA0 && code <= 0xC6)
|
||||
return type_0xA0[code - 0xA0];
|
||||
return out_of_spec;
|
||||
t = type[code - 0x01];
|
||||
else if (code == 0x30)
|
||||
t = type_0x30[code - 0x30];
|
||||
else if (code >= 0xA0 && code <= 0xC6)
|
||||
t = type_0xA0[code - 0xA0];
|
||||
else
|
||||
t = out_of_spec;
|
||||
|
||||
/* For EDSFF slots, add the length suffix */
|
||||
switch (code)
|
||||
{
|
||||
case 0xC5: /* EDSFF E1 */
|
||||
case 0xC6: /* EDSFF E3 */
|
||||
switch (length)
|
||||
{
|
||||
case 0x03: /* Short */
|
||||
suffix = ".S";
|
||||
break;
|
||||
case 0x04: /* Long */
|
||||
suffix = ".L";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
pr_attr("Type", "%s%s", t, suffix);
|
||||
}
|
||||
|
||||
static const char *dmi_slot_bus_width(u8 code)
|
||||
@ -2188,11 +2263,20 @@ static void dmi_slot_id(u8 code1, u8 code2, u8 type)
|
||||
case 0x11: /* AGP */
|
||||
case 0x12: /* PCI-X */
|
||||
case 0x13: /* AGP */
|
||||
case 0x1F: /* PCI Express 2 */
|
||||
case 0x20: /* PCI Express 3 */
|
||||
case 0x14: /* M.2 */
|
||||
case 0x15: /* M.2 */
|
||||
case 0x16: /* M.2 */
|
||||
case 0x17: /* M.2 */
|
||||
case 0x1F: /* PCI Express 2 (U.2) */
|
||||
case 0x20: /* PCI Express 3 (U.2) */
|
||||
case 0x21: /* PCI Express Mini */
|
||||
case 0x22: /* PCI Express Mini */
|
||||
case 0x23: /* PCI Express Mini */
|
||||
case 0x24: /* PCI Express 4 (U.2) */
|
||||
case 0x25: /* PCI Express 5 (U.2) */
|
||||
case 0x26: /* OCP */
|
||||
case 0x27: /* OCP */
|
||||
case 0x28: /* OCP */
|
||||
case 0xA5: /* PCI Express */
|
||||
case 0xA6: /* PCI Express */
|
||||
case 0xA7: /* PCI Express */
|
||||
@ -2224,6 +2308,8 @@ static void dmi_slot_id(u8 code1, u8 code2, u8 type)
|
||||
case 0xC2: /* PCI Express 5 */
|
||||
case 0xC3: /* PCI Express 5 */
|
||||
case 0xC4: /* PCI Express 6+ */
|
||||
case 0xC5: /* EDSFF */
|
||||
case 0xC6: /* EDSFF */
|
||||
pr_attr("ID", "%u", code1);
|
||||
break;
|
||||
case 0x07: /* PCMCIA */
|
||||
@ -2461,7 +2547,7 @@ static void dmi_system_configuration_options(const struct dmi_header *h)
|
||||
}
|
||||
|
||||
/*
|
||||
* 7.14 BIOS Language Information (Type 13)
|
||||
* 7.14 Firmware Language Information (Type 13)
|
||||
*/
|
||||
|
||||
static void dmi_bios_languages(const struct dmi_header *h)
|
||||
@ -2752,10 +2838,10 @@ static void dmi_memory_device_size(u16 code)
|
||||
pr_attr("Size", "Unknown");
|
||||
else
|
||||
{
|
||||
u64 s = { .l = code & 0x7FFF };
|
||||
u64 s = (u64)code & 0x7FFFULL;
|
||||
if (!(code & 0x8000))
|
||||
s.l <<= 10;
|
||||
dmi_print_memory_size("Size", s, 1);
|
||||
s <<= 10;
|
||||
dmi_print_memory_size(pr_attr, "Size", s, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2768,11 +2854,11 @@ static void dmi_memory_device_extended_size(u32 code)
|
||||
* as an integer without rounding
|
||||
*/
|
||||
if (code & 0x3FFUL)
|
||||
pr_attr("Size", "%lu MB", (unsigned long)code);
|
||||
pr_attr("Size", "%lu MiB", (unsigned long)code);
|
||||
else if (code & 0xFFC00UL)
|
||||
pr_attr("Size", "%lu GB", (unsigned long)code >> 10);
|
||||
pr_attr("Size", "%lu GiB", (unsigned long)code >> 10);
|
||||
else
|
||||
pr_attr("Size", "%lu TB", (unsigned long)code >> 20);
|
||||
pr_attr("Size", "%lu TiB", (unsigned long)code >> 20);
|
||||
}
|
||||
|
||||
static void dmi_memory_voltage_value(const char *attr, u16 code)
|
||||
@ -2803,10 +2889,13 @@ static const char *dmi_memory_device_form_factor(u8 code)
|
||||
"SODIMM",
|
||||
"SRIMM",
|
||||
"FB-DIMM",
|
||||
"Die" /* 0x10 */
|
||||
"Die",
|
||||
"CAMM",
|
||||
"CUDIMM",
|
||||
"CSODIMM" /* 0x13 */
|
||||
};
|
||||
|
||||
if (code >= 0x01 && code <= 0x10)
|
||||
if (code >= 0x01 && code <= 0x13)
|
||||
return form_factor[code - 0x01];
|
||||
return out_of_spec;
|
||||
}
|
||||
@ -2860,10 +2949,11 @@ static const char *dmi_memory_device_type(u8 code)
|
||||
"HBM2",
|
||||
"DDR5",
|
||||
"LPDDR5",
|
||||
"HBM3" /* 0x24 */
|
||||
"HBM3",
|
||||
"MRDIMM" /* 0x25 */
|
||||
};
|
||||
|
||||
if (code >= 0x01 && code <= 0x24)
|
||||
if (code >= 0x01 && code <= 0x25)
|
||||
return type[code - 0x01];
|
||||
return out_of_spec;
|
||||
}
|
||||
@ -2923,7 +3013,7 @@ static void dmi_memory_device_speed(const char *attr, u16 code1, u32 code2)
|
||||
}
|
||||
}
|
||||
|
||||
static void dmi_memory_technology(u8 code)
|
||||
static const char *dmi_memory_technology(u8 code)
|
||||
{
|
||||
/* 7.18.6 */
|
||||
static const char * const technology[] = {
|
||||
@ -2933,12 +3023,12 @@ static void dmi_memory_technology(u8 code)
|
||||
"NVDIMM-N",
|
||||
"NVDIMM-F",
|
||||
"NVDIMM-P",
|
||||
"Intel Optane DC persistent memory" /* 0x07 */
|
||||
"Intel Optane persistent memory",
|
||||
"MRDIMM" /* 0x08 */
|
||||
};
|
||||
if (code >= 0x01 && code <= 0x07)
|
||||
pr_attr("Memory Technology", "%s", technology[code - 0x01]);
|
||||
else
|
||||
pr_attr("Memory Technology", "%s", out_of_spec);
|
||||
if (code >= 0x01 && code <= 0x08)
|
||||
return technology[code - 0x01];
|
||||
return out_of_spec;
|
||||
}
|
||||
|
||||
static void dmi_memory_operating_mode_capability(u16 code)
|
||||
@ -2967,7 +3057,7 @@ static void dmi_memory_operating_mode_capability(u16 code)
|
||||
}
|
||||
}
|
||||
|
||||
static void dmi_memory_manufacturer_id(const char *attr, u16 code)
|
||||
void dmi_memory_manufacturer_id(const char *attr, u16 code)
|
||||
{
|
||||
/* 7.18.8 */
|
||||
/* 7.18.10 */
|
||||
@ -2981,7 +3071,7 @@ static void dmi_memory_manufacturer_id(const char *attr, u16 code)
|
||||
(code & 0x7F) + 1, code >> 8);
|
||||
}
|
||||
|
||||
static void dmi_memory_product_id(const char *attr, u16 code)
|
||||
void dmi_memory_product_id(const char *attr, u16 code)
|
||||
{
|
||||
/* 7.18.9 */
|
||||
/* 7.18.11 */
|
||||
@ -2995,12 +3085,12 @@ static void dmi_memory_size(const char *attr, u64 code)
|
||||
{
|
||||
/* 7.18.12 */
|
||||
/* 7.18.13 */
|
||||
if (code.h == 0xFFFFFFFF && code.l == 0xFFFFFFFF)
|
||||
if (code == ~0ULL)
|
||||
pr_attr(attr, "Unknown");
|
||||
else if (code.h == 0x0 && code.l == 0x0)
|
||||
else if (code == 0ULL)
|
||||
pr_attr(attr, "None");
|
||||
else
|
||||
dmi_print_memory_size(attr, code, 0);
|
||||
dmi_print_memory_size(pr_attr, attr, code, 0);
|
||||
}
|
||||
|
||||
static void dmi_memory_revision(const char *attr_type, u16 code, u8 mem_type)
|
||||
@ -3127,21 +3217,15 @@ static void dmi_mapped_address_size(u32 code)
|
||||
if (code == 0)
|
||||
pr_attr("Range Size", "Invalid");
|
||||
else
|
||||
{
|
||||
u64 size;
|
||||
|
||||
size.h = 0;
|
||||
size.l = code;
|
||||
dmi_print_memory_size("Range Size", size, 1);
|
||||
}
|
||||
dmi_print_memory_size(pr_attr, "Range Size", (u64)code, 1);
|
||||
}
|
||||
|
||||
static void dmi_mapped_address_extended_size(u64 start, u64 end)
|
||||
{
|
||||
if (start.h == end.h && start.l == end.l)
|
||||
if (start == end)
|
||||
pr_attr("Range Size", "Invalid");
|
||||
else
|
||||
dmi_print_memory_size("Range Size", u64_range(start, end), 0);
|
||||
dmi_print_memory_size(pr_attr, "Range Size", end - start + 1, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3566,10 +3650,10 @@ static const char *dmi_system_boot_status(u8 code)
|
||||
|
||||
static void dmi_64bit_memory_error_address(const char *attr, u64 code)
|
||||
{
|
||||
if (code.h == 0x80000000 && code.l == 0x00000000)
|
||||
if (code == 0x8000000000000000ULL)
|
||||
pr_attr(attr, "Unknown");
|
||||
else
|
||||
pr_attr(attr, "0x%08X%08X", code.h, code.l);
|
||||
pr_attr(attr, "0x%016llX", code);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3703,9 +3787,9 @@ static void dmi_ipmi_base_address(u8 type, const u8 *p, u8 lsb)
|
||||
else
|
||||
{
|
||||
u64 address = QWORD(p);
|
||||
pr_attr("Base Address", "0x%08X%08X (%s)",
|
||||
address.h, (address.l & ~1) | lsb,
|
||||
address.l & 1 ? "I/O" : "Memory-mapped");
|
||||
pr_attr("Base Address", "0x%016llX (%s)",
|
||||
(address & ~1ULL) | lsb,
|
||||
(address & 1ULL) ? "I/O" : "Memory-mapped");
|
||||
}
|
||||
}
|
||||
|
||||
@ -4374,14 +4458,14 @@ static void dmi_tpm_characteristics(u64 code)
|
||||
/*
|
||||
* This isn't very clear what this bit is supposed to mean
|
||||
*/
|
||||
if (code.l & (1 << 2))
|
||||
if (code & (1ULL << 2))
|
||||
{
|
||||
pr_list_item("%s", characteristics[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 3; i <= 5; i++)
|
||||
if (code.l & (1 << i))
|
||||
if (code & (1ULL << i))
|
||||
pr_list_item("%s", characteristics[i - 2]);
|
||||
}
|
||||
|
||||
@ -4445,8 +4529,8 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
|
||||
*/
|
||||
switch (h->type)
|
||||
{
|
||||
case 0: /* 7.1 BIOS Information */
|
||||
pr_handle_name("BIOS Information");
|
||||
case 0: /* 7.1 Platform Firmware Information */
|
||||
pr_handle_name("Platform Firmware Information");
|
||||
if (h->length < 0x12) break;
|
||||
pr_attr("Vendor", "%s",
|
||||
dmi_string(h, data[0x04]));
|
||||
@ -4468,17 +4552,17 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
|
||||
dmi_bios_rom_size(data[0x09], h->length < 0x1A ? 16 : WORD(data + 0x18));
|
||||
pr_list_start("Characteristics", NULL);
|
||||
dmi_bios_characteristics(QWORD(data + 0x0A));
|
||||
if (h->length >= 0x13)
|
||||
dmi_bios_characteristics_x1(data[0x12]);
|
||||
if (h->length >= 0x14)
|
||||
dmi_bios_characteristics_x2(data[0x13]);
|
||||
pr_list_end();
|
||||
if (h->length < 0x13) break;
|
||||
dmi_bios_characteristics_x1(data[0x12]);
|
||||
if (h->length < 0x14) break;
|
||||
dmi_bios_characteristics_x2(data[0x13]);
|
||||
if (h->length < 0x18) break;
|
||||
if (data[0x14] != 0xFF && data[0x15] != 0xFF)
|
||||
pr_attr("BIOS Revision", "%u.%u",
|
||||
pr_attr("Platform Firmware Revision", "%u.%u",
|
||||
data[0x14], data[0x15]);
|
||||
if (data[0x16] != 0xFF && data[0x17] != 0xFF)
|
||||
pr_attr("Firmware Revision", "%u.%u",
|
||||
pr_attr("Embedded Controller Firmware Revision", "%u.%u",
|
||||
data[0x16], data[0x17]);
|
||||
break;
|
||||
|
||||
@ -4562,14 +4646,32 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
|
||||
pr_attr("OEM Information", "0x%08X",
|
||||
DWORD(data + 0x0D));
|
||||
if (h->length < 0x13) break;
|
||||
dmi_chassis_height(data[0x11]);
|
||||
if (data[0x11] != 0xFF)
|
||||
dmi_chassis_height(data[0x11]);
|
||||
dmi_chassis_power_cords(data[0x12]);
|
||||
if (h->length < 0x15) break;
|
||||
if (h->length < 0x15 + data[0x13] * data[0x14]) break;
|
||||
dmi_chassis_elements(data[0x13], data[0x14], data + 0x15);
|
||||
if (h->length < 0x16 + data[0x13] * data[0x14]) break;
|
||||
pr_attr("SKU Number", "%s",
|
||||
dmi_string(h, data[0x15 + data[0x13] * data[0x14]]));
|
||||
/*
|
||||
* Many old implementations have stray zero bytes at
|
||||
* the end of this record, probably due to some
|
||||
* confusion regarding the preceding variable length
|
||||
* section. Only decode the following fields if they
|
||||
* are defined in the SMBIOS specification version
|
||||
* which is implemented.
|
||||
*/
|
||||
if (ver >= 0x0207)
|
||||
pr_attr("SKU Number", "%s",
|
||||
dmi_string(h, data[0x15 + data[0x13] * data[0x14]]));
|
||||
if (h->length < 0x18 + data[0x13] * data[0x14]) break;
|
||||
if (ver >= 0x0309)
|
||||
{
|
||||
pr_attr("Rack Type", "%s",
|
||||
dmi_chassis_rack_type(data[0x16 + data[0x13] * data[0x14]]));
|
||||
pr_attr("Rack Height", "%hhu",
|
||||
data[0x17 + data[0x13] * data[0x14]]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: /* 7.5 Processor Information */
|
||||
@ -4586,7 +4688,12 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
|
||||
dmi_processor_id(h);
|
||||
pr_attr("Version", "%s",
|
||||
dmi_string(h, data[0x10]));
|
||||
dmi_processor_voltage("Voltage", data[0x11]);
|
||||
/*
|
||||
* Since SMBIOS 3.8.0, the processor voltage field
|
||||
* is deprecated, so ignore it if no value is set.
|
||||
*/
|
||||
if (data[0x11])
|
||||
dmi_processor_voltage("Voltage", data[0x11]);
|
||||
dmi_processor_frequency("External Clock", data + 0x12);
|
||||
dmi_processor_frequency("Max Speed", data + 0x14);
|
||||
dmi_processor_frequency("Current Speed", data + 0x16);
|
||||
@ -4645,9 +4752,9 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
|
||||
dmi_memory_controller_interleave(data[0x06]));
|
||||
pr_attr("Current Interleave", "%s",
|
||||
dmi_memory_controller_interleave(data[0x07]));
|
||||
pr_attr("Maximum Memory Module Size", "%u MB",
|
||||
pr_attr("Maximum Memory Module Size", "%u MiB",
|
||||
1 << data[0x08]);
|
||||
pr_attr("Maximum Total Memory Size", "%u MB",
|
||||
pr_attr("Maximum Total Memory Size", "%u MiB",
|
||||
data[0x0E] * (1 << data[0x08]));
|
||||
dmi_memory_controller_speeds("Supported Speeds",
|
||||
WORD(data + 0x09));
|
||||
@ -4727,7 +4834,7 @@ 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]));
|
||||
pr_attr("Type", "%s", dmi_slot_type(data[0x05]));
|
||||
dmi_slot_type(data[0x05], data[0x08]);
|
||||
pr_attr("Data Bus Width", "%s", dmi_slot_bus_width(data[0x06]));
|
||||
pr_attr("Current Usage", "%s",
|
||||
dmi_slot_current_usage(data[0x07]));
|
||||
@ -4770,8 +4877,8 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
|
||||
dmi_system_configuration_options(h);
|
||||
break;
|
||||
|
||||
case 13: /* 7.14 BIOS Language Information */
|
||||
pr_handle_name("BIOS Language Information");
|
||||
case 13: /* 7.14 Firmware Language Information */
|
||||
pr_handle_name("Firmware Language Information");
|
||||
if (h->length < 0x16) break;
|
||||
if (ver >= 0x0201)
|
||||
{
|
||||
@ -4838,17 +4945,15 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
|
||||
if (h->length < 0x17)
|
||||
pr_attr("Maximum Capacity", "Unknown");
|
||||
else
|
||||
dmi_print_memory_size("Maximum Capacity",
|
||||
dmi_print_memory_size(pr_attr,
|
||||
"Maximum Capacity",
|
||||
QWORD(data + 0x0F), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
u64 capacity;
|
||||
|
||||
capacity.h = 0;
|
||||
capacity.l = DWORD(data + 0x07);
|
||||
dmi_print_memory_size("Maximum Capacity",
|
||||
capacity, 1);
|
||||
dmi_print_memory_size(pr_attr,
|
||||
"Maximum Capacity",
|
||||
DWORD(data + 0x07), 1);
|
||||
}
|
||||
if (!(opt.flags & FLAG_QUIET))
|
||||
dmi_memory_array_error_handle(WORD(data + 0x0B));
|
||||
@ -4915,7 +5020,8 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
|
||||
dmi_memory_voltage_value("Configured Voltage",
|
||||
WORD(data + 0x26));
|
||||
if (h->length < 0x34) break;
|
||||
dmi_memory_technology(data[0x28]);
|
||||
pr_attr("Memory Technology", "%s",
|
||||
dmi_memory_technology(data[0x28]));
|
||||
dmi_memory_operating_mode_capability(WORD(data + 0x29));
|
||||
pr_attr("Firmware Version", "%s",
|
||||
dmi_string(h, data[0x2B]));
|
||||
@ -4974,10 +5080,8 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
|
||||
start = QWORD(data + 0x0F);
|
||||
end = QWORD(data + 0x17);
|
||||
|
||||
pr_attr("Starting Address", "0x%08X%08Xk",
|
||||
start.h, start.l);
|
||||
pr_attr("Ending Address", "0x%08X%08Xk",
|
||||
end.h, end.l);
|
||||
pr_attr("Starting Address", "0x%016llX", start);
|
||||
pr_attr("Ending Address", "0x%016llX", end);
|
||||
dmi_mapped_address_extended_size(start, end);
|
||||
}
|
||||
else
|
||||
@ -5007,10 +5111,8 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
|
||||
start = QWORD(data + 0x13);
|
||||
end = QWORD(data + 0x1B);
|
||||
|
||||
pr_attr("Starting Address", "0x%08X%08Xk",
|
||||
start.h, start.l);
|
||||
pr_attr("Ending Address", "0x%08X%08Xk",
|
||||
end.h, end.l);
|
||||
pr_attr("Starting Address", "0x%016llX", start);
|
||||
pr_attr("Ending Address", "0x%016llX", end);
|
||||
dmi_mapped_address_extended_size(start, end);
|
||||
}
|
||||
else
|
||||
@ -5529,7 +5631,7 @@ static void dmi_decode(const struct dmi_header *h, u16 ver)
|
||||
break;
|
||||
|
||||
default:
|
||||
if (dmi_decode_oem(h))
|
||||
if (dmi_decode_oem(h, ver))
|
||||
break;
|
||||
if (opt.flags & FLAG_QUIET)
|
||||
return;
|
||||
@ -5932,7 +6034,8 @@ static int smbios3_decode(u8 *buf, size_t buf_len, const char *devmem, u32 flags
|
||||
buf[0x07], buf[0x08], buf[0x09]);
|
||||
|
||||
offset = QWORD(buf + 0x10);
|
||||
if (!(flags & FLAG_NO_FILE_OFFSET) && offset.h && sizeof(off_t) < 8)
|
||||
if (!(flags & FLAG_NO_FILE_OFFSET) && (offset & 0xFFFFFFFF00000000ULL)
|
||||
&& sizeof(off_t) < 8)
|
||||
{
|
||||
fprintf(stderr, "64-bit addresses not supported, sorry.\n");
|
||||
return 0;
|
||||
@ -5940,7 +6043,7 @@ static int smbios3_decode(u8 *buf, size_t buf_len, const char *devmem, u32 flags
|
||||
|
||||
/* Maximum length, may get trimmed */
|
||||
len = DWORD(buf + 0x0C);
|
||||
table = dmi_table_get(((off_t)offset.h << 32) | offset.l, &len, 0, ver,
|
||||
table = dmi_table_get(offset, &len, 0, ver,
|
||||
devmem, flags | FLAG_STOP_AT_EOT);
|
||||
if (table == NULL)
|
||||
return 1;
|
||||
|
||||
12
dmidecode.h
12
dmidecode.h
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of the dmidecode project.
|
||||
*
|
||||
* Copyright (C) 2005-2023 Jean Delvare <jdelvare@suse.de>
|
||||
* Copyright (C) 2005-2025 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
|
||||
@ -23,6 +23,8 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define out_of_spec "<OUT OF SPEC>"
|
||||
|
||||
struct dmi_header
|
||||
{
|
||||
u8 type;
|
||||
@ -47,8 +49,14 @@ extern enum cpuid_type cpuid_type;
|
||||
|
||||
int is_printable(const u8 *data, int len);
|
||||
const char *dmi_string(const struct dmi_header *dm, u8 s);
|
||||
void dmi_print_memory_size(const char *addr, u64 code, int shift);
|
||||
void dmi_print_memory_size(void (*print_cb)(const char *name, const char *format, ...),
|
||||
const char *attr, u64 code, int shift);
|
||||
void dmi_print_storage_size(const char *attr, u64 code, unsigned int shift);
|
||||
void dmi_print_cpuid(void (*print_cb)(const char *name, const char *format, ...),
|
||||
const char *label, enum cpuid_type sig, const u8 *p);
|
||||
void dmi_memory_manufacturer_id(const char *attr, u16 code);
|
||||
void dmi_memory_product_id(const char *attr, u16 code);
|
||||
void dmi_system_uuid(void (*print_cb)(const char *name, const char *format, ...),
|
||||
const char *attr, const u8 *p, u16 ver);
|
||||
|
||||
#endif
|
||||
|
||||
750
dmioem.c
750
dmioem.c
@ -2,8 +2,8 @@
|
||||
* Decoding of OEM-specific entries
|
||||
* This file is part of the dmidecode project.
|
||||
*
|
||||
* Copyright (C) 2007-2024 Jean Delvare <jdelvare@suse.de>
|
||||
* Copyright (C) 2017-2024 Jerry Hoemann <jerry.hoemann@hpe.com>
|
||||
* Copyright (C) 2007-2025 Jean Delvare <jdelvare@suse.de>
|
||||
* Copyright (C) 2017-2025 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
|
||||
@ -38,6 +38,7 @@ enum DMI_VENDORS
|
||||
{
|
||||
VENDOR_UNKNOWN,
|
||||
VENDOR_ACER,
|
||||
VENDOR_DELL,
|
||||
VENDOR_HP,
|
||||
VENDOR_HPE,
|
||||
VENDOR_IBM,
|
||||
@ -56,6 +57,8 @@ void dmi_set_vendor(const char *v, const char *p)
|
||||
{
|
||||
const struct { const char *str; enum DMI_VENDORS id; } vendor[] = {
|
||||
{ "Acer", VENDOR_ACER },
|
||||
{ "Dell Computer Corporation", VENDOR_DELL },
|
||||
{ "Dell Inc.", VENDOR_DELL },
|
||||
{ "HP", VENDOR_HP },
|
||||
{ "Hewlett-Packard", VENDOR_HP },
|
||||
{ "HPE", VENDOR_HPE },
|
||||
@ -129,6 +132,144 @@ static int dmi_decode_acer(const struct dmi_header *h)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dell-specific data structures are decoded here.
|
||||
*/
|
||||
|
||||
static void dmi_dell_bios_flags(u64 flags)
|
||||
{
|
||||
/*
|
||||
* TODO: The meaning of the other bits is unknown.
|
||||
*/
|
||||
pr_attr("ACPI WMI Supported", "%s", (flags & (1ULL << 1)) ? "Yes" : "No");
|
||||
}
|
||||
|
||||
static void dmi_dell_hotkeys(const struct dmi_header *h)
|
||||
{
|
||||
int count = (h->length - 0x04) / 0x04;
|
||||
u8 *hotkey = h->data + 0x04;
|
||||
int i;
|
||||
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
pr_list_start("Hotkey Mappings", NULL);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
pr_list_item("Scancode 0x%04hx -> Keycode 0x%04hx",
|
||||
WORD(hotkey + 0x00), WORD(hotkey + 0x02));
|
||||
hotkey += 0x04;
|
||||
}
|
||||
pr_list_end();
|
||||
}
|
||||
|
||||
static void dmi_dell_indexed_io_access(const struct dmi_header *h)
|
||||
{
|
||||
static const char *checksum_types[] = {
|
||||
"Word Checksum",
|
||||
"Byte Checksum",
|
||||
"CRC Checksum",
|
||||
"Negative Word Checksum", /* 0x03 */
|
||||
};
|
||||
int tokens = (h->length - 0x0C) / 0x05;
|
||||
const char *str = out_of_spec;
|
||||
u8 *data = h->data;
|
||||
u8 *token;
|
||||
u8 type;
|
||||
int i;
|
||||
|
||||
pr_attr("Index Port", "0x%04hx", WORD(data + 0x04));
|
||||
pr_attr("Data Port", "0x%04hx", WORD(data + 0x06));
|
||||
|
||||
type = data[0x08];
|
||||
if (type < ARRAY_SIZE(checksum_types))
|
||||
str = checksum_types[type];
|
||||
|
||||
pr_attr("Type", "%s", str);
|
||||
pr_attr("Checked Range Start Index", "0x%02hhx", data[0x09]);
|
||||
pr_attr("Checked Range End Index", "0x%02hhx", data[0x0a]);
|
||||
pr_attr("Check Value Index", "0x%02hhx", data[0x0b]);
|
||||
|
||||
/*
|
||||
* Final token seems to be a terminator, so we ignore it.
|
||||
*/
|
||||
if (tokens <= 1)
|
||||
return;
|
||||
|
||||
pr_list_start("Tokens", NULL);
|
||||
for (i = 0; i < tokens - 1; i++)
|
||||
{
|
||||
token = data + 0x0C + 0x05 * i;
|
||||
pr_list_item("0x%04hx (location 0x%02hhx, AND mask 0x%02hhx, OR mask 0x%02hhx)",
|
||||
WORD(token + 0x00), token[0x02], token[0x03], token[0x04]);
|
||||
}
|
||||
pr_list_end();
|
||||
}
|
||||
|
||||
static void dmi_dell_token_interface(const struct dmi_header *h)
|
||||
{
|
||||
int tokens = (h->length - 0x0B) / 0x06;
|
||||
u8 *data = h->data;
|
||||
u8 *token;
|
||||
int i;
|
||||
|
||||
pr_attr("Command I/O Address", "0x%04x", WORD(data + 0x04));
|
||||
pr_attr("Command I/O Code", "0x%02x", data[0x06]);
|
||||
pr_attr("Supported Command Classes Bitmap", "0x%08x", DWORD(data + 0x07));
|
||||
|
||||
/*
|
||||
* Final token is a terminator, so we ignore it.
|
||||
*/
|
||||
if (tokens <= 1)
|
||||
return;
|
||||
|
||||
pr_list_start("Tokens", NULL);
|
||||
for (i = 0; i < tokens - 1; i++)
|
||||
{
|
||||
token = data + 0x0B + 0x06 * i;
|
||||
pr_list_item("0x%04hx (location 0x%04hx, value 0x%04hx)",
|
||||
WORD(token + 0x00), WORD(token + 0x02),
|
||||
WORD(token + 0x04));
|
||||
}
|
||||
pr_list_end();
|
||||
}
|
||||
|
||||
static int dmi_decode_dell(const struct dmi_header *h)
|
||||
{
|
||||
u8 *data = h->data;
|
||||
|
||||
switch (h->type)
|
||||
{
|
||||
case 177:
|
||||
pr_handle_name("Dell BIOS Flags");
|
||||
if (h->length < 0x0C) break;
|
||||
dmi_dell_bios_flags(QWORD(data + 0x04));
|
||||
break;
|
||||
|
||||
case 178:
|
||||
pr_handle_name("Dell Hotkeys");
|
||||
dmi_dell_hotkeys(h);
|
||||
break;
|
||||
|
||||
case 212:
|
||||
pr_handle_name("Dell Indexed I/O Access");
|
||||
if (h->length < 0x0C) break;
|
||||
dmi_dell_indexed_io_access(h);
|
||||
break;
|
||||
|
||||
case 218:
|
||||
pr_handle_name("Dell Token Interface");
|
||||
if (h->length < 0x0B) break;
|
||||
dmi_dell_token_interface(h);
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* HPE-specific data structures are decoded here.
|
||||
*
|
||||
@ -162,11 +303,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, G11 } dmi_hpegen_t;
|
||||
typedef enum { G6 = 6, G7, G8, G9, G10, G10P, G11, G12 } dmi_hpegen_t;
|
||||
|
||||
static int dmi_hpegen(const char *s)
|
||||
{
|
||||
struct { const char *name; dmi_hpegen_t gen; } table[] = {
|
||||
{ "Gen12", G12 },
|
||||
{ "Gen11", G11 },
|
||||
{ "Gen10 Plus", G10P },
|
||||
{ "Gen10", G10 },
|
||||
@ -217,14 +359,6 @@ static void dmi_hp_203_assoc_hndl(const char *fname, u16 num)
|
||||
pr_attr(fname, "0x%04X", num);
|
||||
}
|
||||
|
||||
static void dmi_hp_203_pciinfo(const char *fname, u16 num)
|
||||
{
|
||||
if (num == 0xFFFF)
|
||||
pr_attr(fname, "Device Not Present");
|
||||
else
|
||||
pr_attr(fname, "0x%04x", num);
|
||||
}
|
||||
|
||||
static void dmi_hp_203_bayenc(const char *fname, u8 num)
|
||||
{
|
||||
switch (num)
|
||||
@ -261,7 +395,8 @@ static void dmi_hp_203_devtyp(const char *fname, unsigned int code)
|
||||
"Dynamic Smart Array Controller",
|
||||
"File",
|
||||
"NVME Hard Drive",
|
||||
"NVDIMM" /* 0x11 */
|
||||
"NVDIMM", /* 0x11 */
|
||||
"Embedded GPU"
|
||||
};
|
||||
|
||||
if (code < ARRAY_SIZE(type))
|
||||
@ -328,8 +463,8 @@ static void dmi_hp_216_fw_type(u16 code)
|
||||
"SPI Descriptor Version",
|
||||
"Innovation Engine Firmware (IE Firmware)",
|
||||
"UMB Backplane Firmware",
|
||||
"Reserved", /* 0x14 */
|
||||
"Reserved",
|
||||
"Embedded Diagnostics",
|
||||
"Reserved", /* 0x15 */
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
@ -363,12 +498,19 @@ static void dmi_hp_216_fw_type(u16 code)
|
||||
"Intel SATA VROC",
|
||||
"Intel SPS Firmware",
|
||||
"Secondary System Programmable Logic Device",
|
||||
"CPU MEZZ Programmable Logic Device", /* 0x37 */
|
||||
"CPU Mezzanine Board CPLD", /* 0x37 */
|
||||
"Intel Artic Sound -M Accelerator Models Firmware",
|
||||
"Ampere System Control Processor (SCP - PMPro+SMPro)",
|
||||
"Intel CFR information", /* 0x3A */
|
||||
"OCP cards",
|
||||
"DC-SCM CPLD",
|
||||
"Power Distribution Board CPLD",
|
||||
"PCIe Switch Board CPLD",
|
||||
"Sideband Board CPLD",
|
||||
"PCIe Riser MCU Firmware", /* 0x40 */
|
||||
"PCIe Switch Board Firmware",
|
||||
"Power Supply Firmware",
|
||||
"BMC Firmware",
|
||||
};
|
||||
|
||||
if (code < ARRAY_SIZE(type))
|
||||
@ -438,7 +580,7 @@ static void dmi_hp_216_version(u8 format, u8 *data)
|
||||
pr_attr(name, "%d", data[0]);
|
||||
break;
|
||||
case 14:
|
||||
pr_attr(name, "%d.%d.%d.%d", data[0], data[1], data[2], data[3]);
|
||||
pr_attr(name, "%d.%d.%d.%d", data[0], data[1], data[2], WORD(data+3));
|
||||
break;
|
||||
case 15:
|
||||
pr_attr(name, "%d.%d.%d.%d (%.2d/%.2d/%d)",
|
||||
@ -453,7 +595,13 @@ static void dmi_hp_216_version(u8 format, u8 *data)
|
||||
pr_attr(name, "%08X", DWORD(data));
|
||||
break;
|
||||
case 18:
|
||||
pr_attr(name, "%d.%2d", data[0], data[1]);
|
||||
pr_attr(name, "%d.%02d", data[0], data[1]);
|
||||
break;
|
||||
case 19:
|
||||
pr_attr(name, "0x%02x.0x%02x.0x%02x", data[0], data[1], data[2]);
|
||||
break;
|
||||
case 20:
|
||||
pr_attr(name, "%d.%d.%d.%d", data[0], data[1], data[2], data[3]);
|
||||
break;
|
||||
case 3: /* fall through */
|
||||
default:
|
||||
@ -545,6 +693,7 @@ static void dmi_hp_224_chipid(u16 code)
|
||||
"Nationz TPM",
|
||||
"STMicroGen10 Plus TPM",
|
||||
"STMicroGen11 TPM", /* 0x05 */
|
||||
"STMicroGen12 TPM",
|
||||
};
|
||||
if ((code & 0xff) < ARRAY_SIZE(chipid))
|
||||
str = chipid[code & 0xff];
|
||||
@ -576,6 +725,22 @@ static void dmi_hp_230_method_bus_seg_addr(u8 code, u8 bus_seg, u8 addr)
|
||||
pr_attr("I2C Address", "0x%02x", addr >> 1);
|
||||
}
|
||||
|
||||
static void dmi_hp_232_encrypt(u8 code)
|
||||
{
|
||||
const char *str = "Reserved";
|
||||
static const char * const status[] = {
|
||||
"Not Encrypted",
|
||||
"Encrypted",
|
||||
"Unknown",
|
||||
"Not Supported",
|
||||
};
|
||||
|
||||
if (code < ARRAY_SIZE(status))
|
||||
str = status[code];
|
||||
|
||||
pr_attr("Encryption Status", "%s", str);
|
||||
}
|
||||
|
||||
static void dmi_hp_238_loc(const char *fname, unsigned int code)
|
||||
{
|
||||
const char *str = "Reserved";
|
||||
@ -722,9 +887,9 @@ static void dmi_hp_240_attr(u64 defined, u64 set)
|
||||
pr_list_start("Attributes Defined/Set", NULL);
|
||||
for (i = 0; i < ARRAY_SIZE(attributes); i++)
|
||||
{
|
||||
if (!(defined.l & (1UL << i)))
|
||||
if (!(defined & (1ULL << i)))
|
||||
continue;
|
||||
pr_list_item("%s: %s", attributes[i], set.l & (1UL << i) ? "Yes" : "No");
|
||||
pr_list_item("%s: %s", attributes[i], set & (1ULL << i) ? "Yes" : "No");
|
||||
}
|
||||
pr_list_end();
|
||||
}
|
||||
@ -784,6 +949,22 @@ static void dmi_hp_242_speed(const char *attr, u16 speed)
|
||||
pr_attr(attr, "%s", "Unknown");
|
||||
}
|
||||
|
||||
static void dmi_hp_244_health(u8 code)
|
||||
{
|
||||
const char *str = "Reserved";
|
||||
static const char * const health[] = {
|
||||
"Healthy", /* 0x00 */
|
||||
"DIMM Missing",
|
||||
"Config Inactive",
|
||||
"SPA Missing",
|
||||
"New Goal",
|
||||
"Locked", /* 0x05 */
|
||||
};
|
||||
if (code < ARRAY_SIZE(health))
|
||||
str = health[code];
|
||||
pr_attr("Interleave Set Health", "%s", str);
|
||||
}
|
||||
|
||||
static void dmi_hp_245_pcie_riser(const struct dmi_header *h)
|
||||
{
|
||||
const char *str = "Reserved";
|
||||
@ -809,10 +990,31 @@ static void dmi_hp_245_pcie_riser(const struct dmi_header *h)
|
||||
pr_attr("Riser Name", dmi_string(h, data[0x08]));
|
||||
}
|
||||
|
||||
static int dmi_decode_hp(const struct dmi_header *h)
|
||||
static void dmi_hp_245_pcie_mhs_riser(const struct dmi_header *h)
|
||||
{
|
||||
u8 *data = h->data;
|
||||
int nic, ptr;
|
||||
u8 i, count;
|
||||
int len = h->length;
|
||||
|
||||
pr_attr("Board Type", "PCIe Riser (MHS Platform)");
|
||||
if (h->length < 0x0B) return;
|
||||
pr_attr("Riser ID", "%d", data[0x05]);
|
||||
if (data[0x06])
|
||||
pr_attr("Firmware Version", "%x.%x", data[0x06], data[0x07]);
|
||||
pr_attr("Downgradable", "%s", data[0x08] & 0x01 ? "Yes" : "No");
|
||||
pr_attr("Riser Name", dmi_string(h, data[0x09]));
|
||||
count = data[0x0A];
|
||||
pr_attr("Slot Count", "%d", count);
|
||||
pr_list_start("Slot IDs", NULL);
|
||||
for (i = 0; (i < count) && ((0x0B + i) < len); i++)
|
||||
pr_list_item("0x%x", data[0x0B + i]);
|
||||
pr_list_end();
|
||||
}
|
||||
|
||||
static int dmi_decode_hp(const struct dmi_header *h, u16 ver)
|
||||
{
|
||||
u8 *data = h->data;
|
||||
int nic, ptr, i;
|
||||
u32 feat;
|
||||
const char *company = (dmi_vendor == VENDOR_HP) ? "HP" : "HPE";
|
||||
int gen;
|
||||
@ -823,6 +1025,37 @@ static int dmi_decode_hp(const struct dmi_header *h)
|
||||
|
||||
switch (h->type)
|
||||
{
|
||||
case 193:
|
||||
/*
|
||||
* Vendor Specific: Other ROM Info
|
||||
*
|
||||
* Offset | Name | Width | Description
|
||||
* -------------------------------------
|
||||
* 0x00 | Type | BYTE | 0xC1, ROM Structure Indicator
|
||||
* 0x01 | Length | BYTE | Length of structure
|
||||
* 0x02 | Handle | WORD | Unique handle
|
||||
* 0x04 | ROM | BYTE | 01: Redundant ROM installed
|
||||
* 0x05 | ROM vers | STRING| Version of the Redundant ROM
|
||||
* 0x06 | Reserved | BYTE | Reserved in Gen9 forward
|
||||
* 0x07 | OEM ROM | STRING| If not blank, OEM ROM binary file name
|
||||
* 0x08 | OEM Date | STRING| If not blank, OEM ROM binary build date
|
||||
*/
|
||||
if (gen < G9) return 0;
|
||||
pr_handle_name("%s ProLiant Other ROM Info", company);
|
||||
if (h->length < 0x09) break;
|
||||
if ((gen < G12) && (data[0x04] & 0x01))
|
||||
pr_attr("Redundant ROM Version", "%s", dmi_string(h, data[0x05]));
|
||||
if (data[0x07])
|
||||
{
|
||||
const char *str = dmi_string(h, data[0x07]);
|
||||
if (strncmp(str, " ", 2))
|
||||
{
|
||||
pr_attr("OEM ROM Binary Filename", "%s", str);
|
||||
pr_attr("OEM ROM Binary Build Date", "%s", dmi_string(h, data[0x08]));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 194:
|
||||
/*
|
||||
* Vendor Specific: Super IO Enable/Disable Features
|
||||
@ -844,6 +1077,37 @@ static int dmi_decode_hp(const struct dmi_header *h)
|
||||
pr_attr("Virtual Serial Port", "%s", feat & (1 << 4) ? "Enabled" : "Disabled");
|
||||
break;
|
||||
|
||||
case 195:
|
||||
/*
|
||||
* Vendor Specific: Server System ID
|
||||
*
|
||||
* Offset | Name | Width | Description
|
||||
* ----------------------------------------------
|
||||
* 0x00 | Type | BYTE | 0xC3, Server System ID
|
||||
* 0x01 | Length | BYTE | Length of structure
|
||||
* 0x02 | Handle | WORD | Unique handle
|
||||
* 0x04 | System ID | STRING| Server System ID
|
||||
* 0x05 | Platform ID| BYTE | Low byte of Platform ID from XREG in CPLD
|
||||
* 0x06 | Platform ID| BYTE | High byte of Platform ID from XREG in CPLD
|
||||
* 0x07 | GUID |16 BYTE| RESERVED: Deprecated Gen 11 and later.
|
||||
*
|
||||
* This structure exists to define a unique system ID that replaces the
|
||||
* old system EISA ID. It is to be used in systems where the system
|
||||
* EISA ID port is not present.
|
||||
*
|
||||
* It also exposes the Platform ID from the CPLD Xregister. This value is
|
||||
* used by iLO to identify the platform and will be used for identification
|
||||
* and matching of certain flash deliverables.
|
||||
*/
|
||||
|
||||
pr_handle_name("%s ProLiant Server System ID", company);
|
||||
if (h->length < 0x05) break;
|
||||
pr_attr("Server System ID", "%s", dmi_string(h, data[0x04]));
|
||||
if (h->length < 0x07) break;
|
||||
/* Display byte order is uncertain, to be confirmed */
|
||||
pr_attr("Platform ID", "%d:%d", data[0x05], data[0x06]);
|
||||
break;
|
||||
|
||||
case 197:
|
||||
/*
|
||||
* Vendor Specific: HPE Processor Specific Information
|
||||
@ -922,14 +1186,19 @@ static int dmi_decode_hp(const struct dmi_header *h)
|
||||
pr_handle_name("%s ProLiant CPU Microcode Patch Support Info", company);
|
||||
|
||||
for (ptr = 0x4; ptr + 12 <= h->length; ptr += 12) {
|
||||
u32 cpuid = DWORD(data + ptr + 2 * 4);
|
||||
u8 cpuid[4];
|
||||
u32 date;
|
||||
|
||||
memcpy(cpuid, data + ptr + 2 * 4, 4);
|
||||
/* AMD omits BaseFamily. Reconstruction valid on family >= 15. */
|
||||
if (cpuid_type == cpuid_x86_amd)
|
||||
cpuid = ((cpuid & 0xfff00) << 8) | 0x0f00 | (cpuid & 0xff);
|
||||
{
|
||||
cpuid[3] = cpuid[2] & 0x0f;
|
||||
cpuid[2] = cpuid[1];
|
||||
cpuid[1] = 0x0f;
|
||||
}
|
||||
|
||||
dmi_print_cpuid(pr_attr, "CPU ID", cpuid_type, (u8 *) &cpuid);
|
||||
dmi_print_cpuid(pr_attr, "CPU ID", cpuid_type, cpuid);
|
||||
|
||||
date = DWORD(data + ptr + 4);
|
||||
pr_subattr("Date", "%04x-%02x-%02x",
|
||||
@ -938,6 +1207,98 @@ static int dmi_decode_hp(const struct dmi_header *h)
|
||||
}
|
||||
break;
|
||||
|
||||
case 202:
|
||||
/*
|
||||
* Vendor Specific: HPE DIMM Location Record
|
||||
*
|
||||
* This record allows software to correlate a Type 17 Memory Device Record
|
||||
* with a specific DIMM (DIMM, Board, and/or Processor number if appropriate).
|
||||
*
|
||||
* There will be one Record Type 202 for each DIMM socket possible in the system.
|
||||
* A system will include a record for each DIMM socket even if that DIMM socket
|
||||
* is on a memory board which is not currently installed.
|
||||
*
|
||||
* Offset | Name | Width | Description
|
||||
* -------------------------------------
|
||||
* 0x00 | Type | BYTE | 0xCA, DIMM Location Record
|
||||
* 0x01 | Length | BYTE | Length of structure
|
||||
* 0x02 | Handle | WORD | Unique handle
|
||||
* 0x04 | Assoc Record | WORD | Handle of Associated Type 17 Memory Record
|
||||
* 0x06 | Board Number | BYTE | 1-based Memory Board number. 0FFh: DIMM on system board
|
||||
* 0x07 | DIMM Number | BYTE | 1-based DIMM number
|
||||
* 0x08 | Proc Number | BYTE | 1-based procssor number. 0FFh don't display
|
||||
* 0x09 | Log DIMM Num | BYTE | 1-based Logical DIMM number mapping to ACPI numbering
|
||||
* 0x0A | UEFI Dev Path| STRING| String number for UEFI Device Path
|
||||
* 0x0B | UEFI Dev Name| STRING| String number for UEFI Device Structured Name
|
||||
* 0x0C | Device Name | STRING| String number for Device Name
|
||||
* 0x0D | Mem Cntrl Num| BYTE | 1-based Memory controller number
|
||||
* 0x0E | Mem Chan Num | BYTE | 1-based memory channel number (matches silk screen)
|
||||
* 0x0F | IE DIMM Num | BYTE | 0-based DIMM number repored by IE. FF -> not supported
|
||||
* | Reserved G12 or later
|
||||
* 0x10 | IE PLDM ID | BYTE | IE PLDM Sensor ID. FF -> not supported
|
||||
* | Reserved G12 or later
|
||||
* 0x11 | Vendor ID | WORD | Module manufacturers ID code as read by SPD
|
||||
* 0x13 | Device ID | WORD | (NVDIMM only) Module product ID code from SPD
|
||||
* 0x15 | Sub Cntrl Ven| WORD | (NVDIMM only) Controller manufacturer ID from SPD
|
||||
* 0x17 | Sub Cntrl Dev| WORD | (NVDIMM only) Controller product ID from SPD
|
||||
* 0x19 | Interleave | BYTE | 1-based unique interleave set within Procssor Number
|
||||
* 0x1A | Part Number | STRING| String number for HPE part number from OEM SPD
|
||||
* 0x1B | DIMM Index | BYTE | 0-based DIMM Index Per Channel
|
||||
*/
|
||||
|
||||
if (gen < G9) return 0;
|
||||
pr_handle_name("%s DIMM Location Record", company);
|
||||
|
||||
if (h->length < 0x09) break;
|
||||
if (!(opt.flags & FLAG_QUIET))
|
||||
pr_attr("Associated Memory Record", "0x%04X", WORD(data + 0x04));
|
||||
if (data[0x06] == 0xFF)
|
||||
pr_attr("Board Number", "%s", "System Board");
|
||||
else
|
||||
pr_attr("Board Number", "%d", data[0x06]);
|
||||
pr_attr("DIMM Number", "%d", data[0x07]);
|
||||
if (data[0x08] != 0xFF)
|
||||
pr_attr("Processor Number", "%d", data[0x08]);
|
||||
|
||||
if (h->length < 0x0A) break;
|
||||
pr_attr("Logical DIMM Number", "%d", data[0x09]);
|
||||
|
||||
if (h->length < 0x0D) break;
|
||||
if (data[0x0A])
|
||||
pr_attr("UEFI Device Path", "%s", dmi_string(h, data[0x0A]));
|
||||
if (data[0x0B])
|
||||
pr_attr("UEFI Device Name", "%s", dmi_string(h, data[0x0B]));
|
||||
if (data[0x0C])
|
||||
pr_attr("Device Name", "%s", dmi_string(h, data[0x0C]));
|
||||
|
||||
if (h->length < 0x19) break;
|
||||
if (data[0x0D])
|
||||
pr_attr("Memory Controller Number", "%d", data[0x0D]);
|
||||
if (data[0x0E])
|
||||
pr_attr("Memory Channel Number", "%d", data[0x0E]);
|
||||
if (gen < G12 && data[0x0F] != 0xFF)
|
||||
pr_attr("IE DIMM Number", "%d", data[0x0F]);
|
||||
if (gen < G12 && data[0x10] != 0xFF)
|
||||
pr_attr("IE PLDM ID", "%d", data[0x10]);
|
||||
if (data[0x11] || data[0x12])
|
||||
pr_attr("Vendor ID", "0x%04X", WORD(data + 0x11));
|
||||
if (data[0x13] || data[0x14])
|
||||
pr_attr("Device ID", "0x%04X", WORD(data + 0x13));
|
||||
if (data[0x15] || data[0x16])
|
||||
dmi_memory_manufacturer_id("Controller Manufacturer ID", WORD(data + 0x15));
|
||||
if (data[0x17] || data[0x18])
|
||||
dmi_memory_product_id("Controller Product ID", WORD(data + 0x17));
|
||||
|
||||
if (h->length < 0x1A) break;
|
||||
if (data[0x19])
|
||||
pr_attr("Best Interleave", "%d", data[0x19]);
|
||||
if (h->length < 0x1B) break;
|
||||
pr_attr("Part Number", "%s", dmi_string(h, data[0x1A]));
|
||||
|
||||
if (h->length < 0x1C) break;
|
||||
pr_attr("DIMM Index", "%d", data[0x1B]);
|
||||
break;
|
||||
|
||||
case 203:
|
||||
/*
|
||||
* Vendor Specific: HP Device Correlation Record
|
||||
@ -987,12 +1348,12 @@ static int dmi_decode_hp(const struct dmi_header *h)
|
||||
}
|
||||
else
|
||||
{
|
||||
dmi_hp_203_pciinfo("PCI Vendor ID", WORD(data + 0x08));
|
||||
dmi_hp_203_pciinfo("PCI Device ID", WORD(data + 0x0A));
|
||||
dmi_hp_203_pciinfo("PCI Sub Vendor ID", WORD(data + 0x0C));
|
||||
dmi_hp_203_pciinfo("PCI Sub Device ID", WORD(data + 0x0E));
|
||||
dmi_hp_203_pciinfo("PCI Class Code", (char)data[0x10]);
|
||||
dmi_hp_203_pciinfo("PCI Sub Class Code", (char)data[0x11]);
|
||||
pr_attr("PCI Vendor ID", "0x%04x", WORD(data + 0x08));
|
||||
pr_attr("PCI Device ID", "0x%04x", WORD(data + 0x0A));
|
||||
pr_attr("PCI Sub Vendor ID", "0x%04x", WORD(data + 0x0C));
|
||||
pr_attr("PCI Sub Device ID", "0x%04x", WORD(data + 0x0E));
|
||||
pr_attr("PCI Class Code", "0x%02x", data[0x10]);
|
||||
pr_attr("PCI Sub Class Code", "0x%02x", data[0x11]);
|
||||
}
|
||||
dmi_hp_203_assoc_hndl("Parent Handle", WORD(data + 0x12));
|
||||
pr_attr("Flags", "0x%04X", WORD(data + 0x14));
|
||||
@ -1081,6 +1442,55 @@ static int dmi_decode_hp(const struct dmi_header *h)
|
||||
}
|
||||
break;
|
||||
|
||||
case 211:
|
||||
/*
|
||||
* Vendor Specific: HPE ProLiant Processor TControl Information
|
||||
*
|
||||
* Provides information about the Tcontrol value for each installed
|
||||
* processor. This information is utilized to optimize the thermal fan
|
||||
* control systems on the system. For some systems, this can be handled
|
||||
* totally by the System ROM (systems with 7463 fan controllers). For
|
||||
* systems that utilize TAFI, the Health Driver handles fan control.
|
||||
* The Health Driver must know the value for Tcontrol for all processors
|
||||
* to be able to customize the fan control for the installed processors.
|
||||
*
|
||||
* Tcontrol is a value programmed into each processor by Intel that
|
||||
* indicates the processors thermal properties. The value is based on
|
||||
* how "leaky" the particular processor's transistors are. A more "leaky"
|
||||
* processor will get hotter for a given power input and thus will have a
|
||||
* higher Tcontrol value. Intel officially suggests keeping a processor
|
||||
* below the Tcontrol value for reliability reasons. HP is using Tcontrol
|
||||
* as the point at which we begin spinning up the fans.
|
||||
*
|
||||
* Software must check the corresponding Record Type 4 to determine if the
|
||||
* processor is installed. If the processor is not installed, the
|
||||
* corresponding Record Type 211 should not be utilized. Record Type 197
|
||||
* must be used to correlate Type 211 Record to the processor's APIC ID.
|
||||
* This must be done to know which TAFI controller must be programmed with
|
||||
* a particular Tcontrol value. Type 197 Record has an identifier which
|
||||
* relates it to a Type 4 Record, so it is possible to correlate a
|
||||
* Type 211 Record with a Type 197 Record.
|
||||
*
|
||||
* Offset | Name | Width | Description
|
||||
* -------------------------------------
|
||||
* 0x00 | Type | BYTE | 0xD3, TControl Info
|
||||
* 0x01 | Length | BYTE | Length of structure
|
||||
* 0x02 | Handle | WORD | Unique handle
|
||||
* 0x04 | Handle | WORD | Handle of Corresponding Type 4 Processor Record
|
||||
* 0x06 |Tcontrol| BYTE | Processor Tcontrol Value. 00 -> Value N/A.
|
||||
*/
|
||||
|
||||
pr_handle_name("%s ProLiant TControl Information", company);
|
||||
if (h->length < 0x07) break;
|
||||
if (!(opt.flags & FLAG_QUIET))
|
||||
pr_attr("Associated Processor Handle", "0x%04X",
|
||||
WORD(data + 0x04));
|
||||
if (data[0x06])
|
||||
pr_attr("TControl Value", "%d", data[0x06]);
|
||||
else
|
||||
pr_attr("TControl Value", "%s", "N/A");
|
||||
break;
|
||||
|
||||
case 212:
|
||||
/*
|
||||
* Vendor Specific: HPE 64-bit CRU Information
|
||||
@ -1100,11 +1510,8 @@ static int dmi_decode_hp(const struct dmi_header *h)
|
||||
if (DWORD(data + 0x04) == 0x55524324)
|
||||
{
|
||||
u64 paddr = QWORD(data + 0x08);
|
||||
paddr.l += DWORD(data + 0x14);
|
||||
if (paddr.l < DWORD(data + 0x14))
|
||||
paddr.h++;
|
||||
pr_attr("Physical Address", "0x%08x%08x",
|
||||
paddr.h, paddr.l);
|
||||
paddr += DWORD(data + 0x14);
|
||||
pr_attr("Physical Address", "0x%016llx", paddr);
|
||||
pr_attr("Length", "0x%08x", DWORD(data + 0x10));
|
||||
}
|
||||
break;
|
||||
@ -1202,6 +1609,90 @@ static int dmi_decode_hp(const struct dmi_header *h)
|
||||
dmi_hp_224_chipid(WORD(data + 0x0a));
|
||||
break;
|
||||
|
||||
case 226:
|
||||
/*
|
||||
* Vendor Specific: Physical Attribute Information
|
||||
*
|
||||
* This structure exists to store physical attributes for which virtual
|
||||
* attributes have been stored in the industry standard SMBIOS fields
|
||||
* which would normally store these physical attributes. This OEM SMBIOS
|
||||
* Record was initially defined for the SYNERGY project where it was
|
||||
* required that a virtual serial number and UUID be applied to the
|
||||
* system. These virtual values must be stored in the standard SMBIOS
|
||||
* fields so that industry standard software would detect these virtual
|
||||
* values, allowing a workload to transition from one physical piece of
|
||||
* hardware to another. This Record was created because a place was needed
|
||||
* to store the physical attributes (serial number and UUID) for use in
|
||||
* asset tracking and warranty events.
|
||||
*
|
||||
* Offset | Name | Width | Description
|
||||
* -------------------------------------
|
||||
* 0x00 | Type | BYTE | 0xE2, Physical Attribute
|
||||
* 0x01 | Length | BYTE | Length of structure
|
||||
* 0x02 | Handle | WORD | Unique handle
|
||||
* 0x04 | UUID |16 BYTE| if !0 => Physical Universal Unique ID Number
|
||||
* 0x14 | SN | STRING| Physical Serial Number. Match Record Type 1
|
||||
*/
|
||||
pr_handle_name("%s Physical Attribute Information", company);
|
||||
if (h->length < 0x15) break;
|
||||
if (QWORD(data + 0x0C) || QWORD(data + 0x04))
|
||||
dmi_system_uuid(pr_attr, "UUID", data + 0x04, ver);
|
||||
pr_attr("Serial Number", "%s", dmi_string(h, data[0x14]));
|
||||
break;
|
||||
|
||||
case 229:
|
||||
/*
|
||||
* Vendor Specific: Reserved Memory Location
|
||||
*
|
||||
* This OEM SMBIOS Record is used to communicate the physical address
|
||||
* location of memory regions reserved during POST by System Firmware.
|
||||
* These memory regions will be reserved for various purposes. It is
|
||||
* intended that this OEM SMBIOS Record be expandable to support any
|
||||
* future POST reserved memory requirements. The regions reserved by
|
||||
* POST will typically be reported by INT15h E820h as reserved memory.
|
||||
* This record was initially defined to communicate to iLO FW and Smart
|
||||
* Array Storage FW the location of a memory buffer reserved for passing
|
||||
* information between the Smart Array Controller and iLO FW for providing
|
||||
* hard drive temperatures to iLO FW fan control.
|
||||
*
|
||||
* Note: Multiple Type 229 Records may exist in the SMBIOS Table because
|
||||
* each SMBIOS Record has a maximum length of 256 bytes and it is possible
|
||||
* that there eventually would be enough reserved memory locations such
|
||||
* that a single record could exceed this limit (each reserved memory
|
||||
* location utilizes 16 bytes). Software utilizing the Type 229 Record
|
||||
* should be written to handle the possibility of multiple records.
|
||||
*
|
||||
* Offset| Name | Width | Description
|
||||
* -----------------------------------------
|
||||
* 0x00 | Type | BYTE | 0xE5, Reserved Memory Location
|
||||
* 0x01 | Length | BYTE | Length of structure
|
||||
* 0x02 | Handle | WORD | Unique handle
|
||||
* 0x04 | Signature | DWORD | Enumerated value that indicates the type
|
||||
* | of memory described by this Reserved
|
||||
* | Memory Location
|
||||
* 0x08 | Phys Addr | QWORD | 64-Bit physical memory address
|
||||
* 0x10 | Size of Loc | DWORD | Bit[30:0] - Size of the Memory Location
|
||||
* | Bit[31] - Indicates whether the size field in
|
||||
* | Bits[30:0] is in 1 byte or 1 Kbyte granularity
|
||||
* | 0 = Byte Granularity
|
||||
* | 1 = Kbyte Granularity
|
||||
* 0x14 | Mem Entries | 16 Bytes per Reserved Memory Entry
|
||||
*/
|
||||
pr_handle_name("%s Reserved Memory Location", company);
|
||||
for (ptr = 0x04, i = 1; ptr + 16 <= h->length; ptr += 16, i++)
|
||||
{
|
||||
pr_attr("Memory Location", "%d", i);
|
||||
pr_subattr("Signature",
|
||||
"%.4s", data + ptr);
|
||||
pr_subattr("Physical Address", "0x%016llX",
|
||||
QWORD(data + ptr + 0x04));
|
||||
feat = DWORD(data + ptr + 0x0C);
|
||||
dmi_print_memory_size(pr_subattr, "Size",
|
||||
feat & 0x7fffffff,
|
||||
feat >> 31);
|
||||
}
|
||||
break;
|
||||
|
||||
case 230:
|
||||
/*
|
||||
* Vendor Specific: Power Supply Information OEM SMBIOS Record
|
||||
@ -1230,6 +1721,75 @@ static int dmi_decode_hp(const struct dmi_header *h)
|
||||
dmi_hp_230_method_bus_seg_addr(data[0x08], data[0x09], data[0x0A]);
|
||||
break;
|
||||
|
||||
case 232:
|
||||
/*
|
||||
* Vendor Specific: DIMM Attributes Record
|
||||
*
|
||||
* This record is used to communicate information about DIMMs that is not
|
||||
* available via Industry Standard SMBIOS Records.
|
||||
*
|
||||
* There will be one Record Type 232 for each DIMM socket possible in the
|
||||
* system (just like Type 17 Records).
|
||||
*
|
||||
* Offset| Name | Width | Description
|
||||
* -----------------------------------------
|
||||
* 0x00 | Type | BYTE | 0xE8, DIMM Attributes Record
|
||||
* 0x01 | Length | BYTE | Length of structure
|
||||
* 0x02 | Handle | WORD | Unique handle
|
||||
* 0x04 | Assoc Handle| WORD | Associated Handle (Type 17)
|
||||
* 0x06 | DIMM Attr | DWORD | Attributes Bitfield (Defined in code)
|
||||
* 0x0A | Min Voltage | WORD | Minimum operating voltage in millivolts
|
||||
* 0x0C | Cfg Voltage | WORD | Configured operating voltage in millivolts
|
||||
* 0x0E | RESERVED |
|
||||
* .... | RESERVED |
|
||||
* 0x21 | RESERVED |
|
||||
* 0x22 | Map-Out | BYTE | Bit Field reason for DIMM being mapped out
|
||||
* 0x23 | Encryption | BYTE | Encryption status
|
||||
*/
|
||||
if (gen < G9) return 0;
|
||||
pr_handle_name("%s DIMM Attributes Record", company);
|
||||
|
||||
if (h->length < 0x0E) break;
|
||||
if (!(opt.flags & FLAG_QUIET))
|
||||
pr_attr("Associated Handle", "0x%04X", WORD(data + 0x04));
|
||||
|
||||
feat = DWORD(data + 0x06);
|
||||
pr_attr("Attributes", "0x%08X", feat);
|
||||
/* Bit [1:0] HP SmartMemory */
|
||||
pr_subattr("HPE Smart Memory",
|
||||
(feat & 0x03) == 0 ? "No" :
|
||||
(feat & 0x03) == 1 ? "Yes" : "Unknown");
|
||||
/* Bit [3:2] Indicator if DIMM is Load Reduced (LR) */
|
||||
/* Bit [2]: 1 = Field Supported */
|
||||
if (feat & (1 << 2))
|
||||
pr_subattr("Load Reduced DIMM installed",
|
||||
(feat & (1 << 3)) ? "Yes" : "No");
|
||||
/* Bit [5:4] HP Standard DIMM Indicator */
|
||||
/* Bit [4]: 1 = Field Supported */
|
||||
if (feat & (1 << 4))
|
||||
pr_subattr("HPE Standard Memory Installed",
|
||||
(feat & (1 << 5)) ? "Yes" : "No");
|
||||
if (WORD(data + 0x0A))
|
||||
pr_attr("Minimum Voltage", "%d mV", WORD(data + 0x0A));
|
||||
else
|
||||
pr_attr("Minimum Voltage", "Unknown");
|
||||
|
||||
if (WORD(data + 0x0C))
|
||||
pr_attr("Configured Voltage", "%d mV", WORD(data + 0x0C));
|
||||
else
|
||||
pr_attr("Configured Voltage", "Unknown");
|
||||
|
||||
if (h->length < 0x23) break;
|
||||
feat = data[0x22];
|
||||
if (feat) {
|
||||
pr_attr("Map-Out Reason", "0x%0X", feat);
|
||||
pr_subattr("Configuration Error", (feat & 0x01) ? "Yes" : "No");
|
||||
pr_subattr("Training Error", (feat & 0x02) ? "Yes" : "No");
|
||||
}
|
||||
if (h->length < 0x24) break;
|
||||
dmi_hp_232_encrypt(data[0x23]);
|
||||
break;
|
||||
|
||||
case 233:
|
||||
/*
|
||||
* Vendor Specific: HPE ProLiant NIC MAC Information
|
||||
@ -1346,14 +1906,20 @@ static int dmi_decode_hp(const struct dmi_header *h)
|
||||
* 0x0C | Parent Hub | BYTE | Instance number of internal Hub
|
||||
* 0x0D | Port Speed | BYTE | Enumerated value of speed configured by BIOS
|
||||
* 0x0E | Device Path| STRING| UEFI Device Path of USB endpoint
|
||||
* 0x0F | PCI Seg | WORD | PCI Segment number of the USB controller
|
||||
*/
|
||||
if (gen < G9) return 0;
|
||||
pr_handle_name("%s Proliant USB Port Connector Correlation Record", company);
|
||||
pr_handle_name("%s ProLiant USB Port Connector Correlation Record", company);
|
||||
if (h->length < 0x0F) break;
|
||||
if (!(opt.flags & FLAG_QUIET))
|
||||
pr_attr("Associated Handle", "0x%04X", WORD(data + 0x4));
|
||||
pr_attr("PCI Device", "%02x:%02x.%x", data[0x6],
|
||||
data[0x7] >> 3, data[0x7] & 0x7);
|
||||
if (h->length < 0x11)
|
||||
pr_attr("PCI Device", "%02x:%02x.%x", data[0x6],
|
||||
data[0x7] >> 3, data[0x7] & 0x7);
|
||||
else
|
||||
pr_attr("PCI Device", "%04x:%02x:%02x.%x",
|
||||
WORD(data + 0xF), data[0x6],
|
||||
data[0x7] >> 3, data[0x7] & 0x7);
|
||||
dmi_hp_238_loc("Location", data[0x8]);
|
||||
dmi_hp_238_flags("Management Port", WORD(data + 0x9));
|
||||
pr_attr("Port Instance", "%d", data[0xB]);
|
||||
@ -1415,7 +1981,7 @@ static int dmi_decode_hp(const struct dmi_header *h)
|
||||
|
||||
case 240:
|
||||
/*
|
||||
* Vendor Specific: HPE Proliant Inventory Record
|
||||
* Vendor Specific: HPE ProLiant Inventory Record
|
||||
*
|
||||
* Reports firmware version information for devices that report their
|
||||
* firmware using their UEFI drivers. Additionally provides association
|
||||
@ -1435,7 +2001,7 @@ static int dmi_decode_hp(const struct dmi_header *h)
|
||||
* 0x1B | Attr Set | QWORD | BitField: If defined, is attribute set?
|
||||
* 0x23 | Version | DWORD | Lowest supported version.
|
||||
*/
|
||||
pr_handle_name("%s Proliant Inventory Record", company);
|
||||
pr_handle_name("%s ProLiant Inventory Record", company);
|
||||
if (h->length < 0x27) break;
|
||||
if (!(opt.flags & FLAG_QUIET))
|
||||
pr_attr("Associated Handle", "0x%04X", WORD(data + 0x4));
|
||||
@ -1443,7 +2009,7 @@ static int dmi_decode_hp(const struct dmi_header *h)
|
||||
pr_attr("Version String", "%s", dmi_string(h, data[0x0A]));
|
||||
|
||||
if (DWORD(data + 0x0B))
|
||||
dmi_print_memory_size("Image Size", QWORD(data + 0xB), 0);
|
||||
dmi_print_memory_size(pr_attr, "Image Size", QWORD(data + 0xB), 0);
|
||||
else
|
||||
pr_attr("Image Size", "Not Available");
|
||||
|
||||
@ -1493,15 +2059,15 @@ static int dmi_decode_hp(const struct dmi_header *h)
|
||||
*/
|
||||
if (gen < G10) return 0;
|
||||
pr_handle_name("%s ProLiant Hard Drive Inventory Record", company);
|
||||
if (h->length < 0x2C) break;
|
||||
if (h->length < 0x2A) break;
|
||||
if (!(opt.flags & FLAG_QUIET))
|
||||
pr_attr("Associated Handle", "0x%04X", WORD(data + 0x4));
|
||||
dmi_hp_242_hdd_type(data[0x06]);
|
||||
pr_attr("ID", "%llx", QWORD(data + 0x07));
|
||||
if (h->length < 0x3E)
|
||||
pr_attr("Capacity", "%u MB", DWORD(data + 0x0F));
|
||||
dmi_print_storage_size("Capacity", DWORD(data + 0x0F), 2);
|
||||
else
|
||||
dmi_print_memory_size("Capacity", QWORD(data + 0x2C), 0);
|
||||
dmi_print_storage_size("Capacity", QWORD(data + 0x2C), 0);
|
||||
/* NB: Poweron low QWORD good for 2,104,351,365,926,255 years */
|
||||
pr_attr("Poweron", "%ld hours", QWORD(data + 0x13));
|
||||
if (data[0x24])
|
||||
@ -1517,6 +2083,7 @@ static int dmi_decode_hp(const struct dmi_header *h)
|
||||
pr_attr("Serial Number", dmi_string(h, data[0x27]));
|
||||
pr_attr("Model Number", dmi_string(h, data[0x28]));
|
||||
pr_attr("Firmware Revision", dmi_string(h, data[0x29]));
|
||||
if (h->length < 0x2C) break;
|
||||
pr_attr("Location", dmi_string(h, data[0x2A]));
|
||||
feat = data[0x2B];
|
||||
pr_attr("Encryption Status", "%s", (feat == 0) ? "Not Encrypted" :
|
||||
@ -1532,6 +2099,76 @@ static int dmi_decode_hp(const struct dmi_header *h)
|
||||
dmi_hp_242_speed("Capable Speed", WORD(data + 0x3C));
|
||||
break;
|
||||
|
||||
case 244:
|
||||
/*
|
||||
* Vendor Specific: HPE DIMM Current Configuration Record
|
||||
*
|
||||
* This record is used to communicate information about the currently
|
||||
* configured memory regions on DIMMs installed in the system.
|
||||
*
|
||||
* There will be at least one Type 244 Record for each DIMM installed
|
||||
* in the system with configured non-volatile or volatile memory.
|
||||
*
|
||||
* The number of DIMM Configuration Records for each DIMM is specified by
|
||||
* the Configured Region Count field in its corresponding Type 232 DIMM
|
||||
* Capabilities record. Each record represents a memory region on the
|
||||
* DIMM, labeled by its Region ID. The Memory Type field can be used to
|
||||
* determine the currently configured memory type for the region. When
|
||||
* set to Volatile, the data on the memory region is lost on a power
|
||||
* cycle. When set to Byte Accessible Persistent, the data on
|
||||
* the memory region is retained through a reset. The Region Memory Size
|
||||
* field contains the size of the configured region in MiB.
|
||||
*
|
||||
* The Passphrase State specifies the enable/disable state of the
|
||||
* Passphrase requirement and is only applicable when the DIMM region is
|
||||
* configured as Byte Accessible Persistent. The Interleave Set Index
|
||||
* specifies which interleave set the DIMM region belongs to, if any.
|
||||
* Regions with identical interleave set indices mean the DIMM regions
|
||||
* are interleaved. These indices should match what is found in the DIMM's
|
||||
* PCAT Interleave Information tables. Interleave set indices are
|
||||
* 1-based. This will be a unique value per interleave set. If the DIMM
|
||||
* region is not interleaved, the interleave set index will
|
||||
* still be a unique value.
|
||||
*
|
||||
* Offset | Name | Width | Description
|
||||
* ---------------------------------------
|
||||
* 0x00 | Type | BYTE | 0xF4, DIMM Current Configuration Record
|
||||
* 0x01 | Length | BYTE | Length of structure
|
||||
* 0x02 | Handle | WORD | Unique handle
|
||||
* 0x04 | Hndl Assoc | WORD | Handle of corresponding Type 17 record
|
||||
* 0x06 | Region ID | BYTE | Unique ID of memory region on DIMM
|
||||
* 0x07 | Region Type| WORD | Persistence Type. Bit Field: See code
|
||||
* 0x09 | Region Size| QWORD | Size of memory region in MiB
|
||||
* 0x11 | Passphrase | BYTE | Current state of Passphrase. See code
|
||||
* 0x12 | Set Index | WORD | Interleave set index. Region w/ same index
|
||||
* | are part of same interleave set.
|
||||
* 0x14 | DIMM Count | BYTE | Number of DIMMs in interleave set
|
||||
* 0x15 | Health | BYTE | Health of Interleave set defined in code
|
||||
*/
|
||||
|
||||
pr_handle_name("%s DIMM Current Configuration", company);
|
||||
if (h->length < 0x14) break;
|
||||
if (!(opt.flags & FLAG_QUIET))
|
||||
pr_attr("Associated Handle", "0x%04X", WORD(data + 0x04));
|
||||
pr_attr("Region ID", "%hhu", data[0x06]);
|
||||
feat = WORD(data + 0x07);
|
||||
pr_attr("Persistence Type", "%s", (feat & 0x01) ? "Volatile" :
|
||||
((feat >> 1) & 0x01) ? "Byte Accessible" :
|
||||
((feat >> 2) & 0x01) ? "Block I/O" :
|
||||
"Reserved");
|
||||
dmi_print_memory_size(pr_attr, "Size", QWORD(data + 0x09), 2);
|
||||
pr_attr("Passphrase Enabled", "%s", data[0x11] ? "Yes" : "No");
|
||||
feat = WORD(data + 0x12);
|
||||
if (feat)
|
||||
pr_attr("Interleave Set Index", "%u", feat);
|
||||
if (h->length < 0x15) break;
|
||||
if (feat)
|
||||
pr_attr("Interleave DIMM Count", "%hhu", data[0x14]);
|
||||
if (h->length < 0x16) break;
|
||||
if (feat)
|
||||
dmi_hp_244_health(data[0x15]);
|
||||
break;
|
||||
|
||||
case 245:
|
||||
/*
|
||||
* Vendor Specific: HPE Extension Board Inventory Record
|
||||
@ -1551,18 +2188,33 @@ static int dmi_decode_hp(const struct dmi_header *h)
|
||||
* 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
|
||||
* 0x04 | Board Type | WORD | See below
|
||||
*
|
||||
* 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|
|
||||
*
|
||||
* If Board Type == 1
|
||||
* 0x05 | Riser ID | BYTE |
|
||||
* 0x06 | Riser FW Major | BYTE |
|
||||
* 0x07 | Riser FW Minor | BYTE |
|
||||
* 0x08 | Misc Attr | BYTE |
|
||||
* 0x09 | Riser Name | STRING|
|
||||
* 0x0A | Slot Count | BYTE |
|
||||
* 0x0B | Slot ID | Varies| One per slot
|
||||
*/
|
||||
pr_handle_name("%s ProLiant Extension Board Inventory Record", company);
|
||||
if (h->length < 0x05) break;
|
||||
if (data[0x04] == 0)
|
||||
switch (data[0x04]) {
|
||||
case 0:
|
||||
dmi_hp_245_pcie_riser(h);
|
||||
break;
|
||||
case 1:
|
||||
dmi_hp_245_pcie_mhs_riser(h);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1693,15 +2345,17 @@ static int dmi_decode_ibm_lenovo(const struct dmi_header *h)
|
||||
* Dispatch vendor-specific entries decoding
|
||||
* Return 1 if decoding was successful, 0 otherwise
|
||||
*/
|
||||
int dmi_decode_oem(const struct dmi_header *h)
|
||||
int dmi_decode_oem(const struct dmi_header *h, u16 ver)
|
||||
{
|
||||
switch (dmi_vendor)
|
||||
{
|
||||
case VENDOR_HP:
|
||||
case VENDOR_HPE:
|
||||
return dmi_decode_hp(h);
|
||||
return dmi_decode_hp(h, ver);
|
||||
case VENDOR_ACER:
|
||||
return dmi_decode_acer(h);
|
||||
case VENDOR_DELL:
|
||||
return dmi_decode_dell(h);
|
||||
case VENDOR_IBM:
|
||||
case VENDOR_LENOVO:
|
||||
return dmi_decode_ibm_lenovo(h);
|
||||
|
||||
4
dmioem.h
4
dmioem.h
@ -19,7 +19,9 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
|
||||
struct dmi_header;
|
||||
|
||||
void dmi_set_vendor(const char *s, const char *p);
|
||||
int dmi_decode_oem(const struct dmi_header *h);
|
||||
int dmi_decode_oem(const struct dmi_header *h, u16 ver);
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
.TH DMIDECODE 8 "February 2023" "dmidecode"
|
||||
'\" t
|
||||
.\" ** The above line should force tbl to be a preprocessor **
|
||||
.TH DMIDECODE 8 "June 2025" "dmidecode"
|
||||
.\"
|
||||
.SH NAME
|
||||
dmidecode \- \s-1DMI\s0 table decoder
|
||||
@ -12,7 +14,7 @@ dmidecode \- \s-1DMI\s0 table decoder
|
||||
is a tool for dumping a computer's \s-1DMI\s0 (some say \s-1SMBIOS\s0) table
|
||||
contents in a human-readable format. This table contains a description of the
|
||||
system's hardware components, as well as other useful pieces of information
|
||||
such as serial numbers and \s-1BIOS\s0 revision. Thanks to this table, you can
|
||||
such as serial numbers and firmware revision. Thanks to this table, you can
|
||||
retrieve this information without having to probe for the actual hardware.
|
||||
While this is a good point in terms of report speed and safeness, this also
|
||||
makes the presented information possibly unreliable.
|
||||
@ -106,6 +108,9 @@ It must be a keyword from the following list:
|
||||
.BR processor\-version ,
|
||||
.BR processor\-frequency .
|
||||
.hy
|
||||
In this context, for historical reasons, "bios" designates the platform
|
||||
firmware (regardless of it technically implementing the BIOS standard),
|
||||
while "firmware" designates the embedded controller firmware, if applicable.
|
||||
Each keyword corresponds to a given \s-1DMI\s0 type and a given offset
|
||||
within this entry type.
|
||||
Not all strings may be meaningful or even defined on all systems. Some
|
||||
@ -147,6 +152,8 @@ keyword from the following list:
|
||||
.BR slot .
|
||||
.hy
|
||||
Refer to the DMI TYPES section below for details.
|
||||
In this context, for historical reasons, "bios" designates the platform
|
||||
firmware, regardless of it technically implementing the BIOS standard.
|
||||
If this option is used more than once, the set of displayed entries will be
|
||||
the union of all the given types.
|
||||
If \fITYPE\fP is not provided or not valid, a list of all valid keywords
|
||||
@ -201,7 +208,7 @@ determine the output format and are mutually exclusive.
|
||||
.P
|
||||
Please note in case of
|
||||
.B dmidecode
|
||||
is run on a system with BIOS that boasts new SMBIOS specification, which
|
||||
is run on a system with firmware that boasts new SMBIOS specification, which
|
||||
is not supported by the tool yet, it will print out relevant message in
|
||||
addition to requested data on the very top of the output. Thus informs the
|
||||
output data is not reliable.
|
||||
@ -213,7 +220,7 @@ r l
|
||||
__
|
||||
r l.
|
||||
Type Information
|
||||
0 BIOS
|
||||
0 Platform Firmware
|
||||
1 System
|
||||
2 Baseboard
|
||||
3 Chassis
|
||||
@ -226,7 +233,7 @@ Type Information
|
||||
10 On Board Devices
|
||||
11 OEM Strings
|
||||
12 System Configuration Options
|
||||
13 BIOS Language
|
||||
13 Firmware Language
|
||||
14 Group Associations
|
||||
15 System Event Log
|
||||
16 Physical Memory Array
|
||||
|
||||
111
types.h
111
types.h
@ -1,59 +1,84 @@
|
||||
#ifndef TYPES_H
|
||||
#define TYPES_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/*
|
||||
* Use the byte-order macros provided by the compiler if available, else
|
||||
* fall back to the ones provided by the C library.
|
||||
*/
|
||||
#ifdef __BYTE_ORDER__
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#define BIGENDIAN
|
||||
#endif
|
||||
#else /* __BYTE_ORDER__ */
|
||||
#include <endian.h>
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define BIGENDIAN
|
||||
#endif
|
||||
#endif /* __BYTE_ORDER__ */
|
||||
|
||||
#ifdef BIGENDIAN
|
||||
#ifndef bswap_16
|
||||
#include <byteswap.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef signed short i16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
/*
|
||||
* You may use the following defines to adjust the type definitions
|
||||
* depending on the architecture:
|
||||
* - Define BIGENDIAN on big-endian systems.
|
||||
* - Define ALIGNMENT_WORKAROUND if your system doesn't support
|
||||
* non-aligned memory access. In this case, we use a slower, but safer,
|
||||
* memory access method. This should be done automatically in config.h
|
||||
* for architectures which need it.
|
||||
*/
|
||||
|
||||
#ifdef BIGENDIAN
|
||||
typedef struct {
|
||||
u32 h;
|
||||
u32 l;
|
||||
} u64;
|
||||
#else
|
||||
typedef struct {
|
||||
u32 l;
|
||||
u32 h;
|
||||
} u64;
|
||||
#endif
|
||||
|
||||
#if defined(ALIGNMENT_WORKAROUND) || defined(BIGENDIAN)
|
||||
static inline u64 U64(u32 low, u32 high)
|
||||
{
|
||||
u64 self;
|
||||
|
||||
self.l = low;
|
||||
self.h = high;
|
||||
|
||||
return self;
|
||||
}
|
||||
#endif
|
||||
typedef unsigned long long int u64;
|
||||
|
||||
/*
|
||||
* Per SMBIOS v2.8.0 and later, all structures assume a little-endian
|
||||
* ordering convention.
|
||||
*/
|
||||
#if defined(ALIGNMENT_WORKAROUND) || defined(BIGENDIAN)
|
||||
#define WORD(x) (u16)((x)[0] + ((x)[1] << 8))
|
||||
#define DWORD(x) (u32)((x)[0] + ((x)[1] << 8) + ((x)[2] << 16) + ((x)[3] << 24))
|
||||
#define QWORD(x) (U64(DWORD(x), DWORD(x + 4)))
|
||||
#else /* ALIGNMENT_WORKAROUND || BIGENDIAN */
|
||||
#define WORD(x) (u16)(*(const u16 *)(x))
|
||||
#define DWORD(x) (u32)(*(const u32 *)(x))
|
||||
#define QWORD(x) (*(const u64 *)(x))
|
||||
#endif /* ALIGNMENT_WORKAROUND || BIGENDIAN */
|
||||
|
||||
static inline u16 WORD(const void *x)
|
||||
{
|
||||
u16 ret;
|
||||
memcpy(&ret, x, sizeof(ret));
|
||||
#ifdef BIGENDIAN
|
||||
#ifdef bswap_16
|
||||
ret = bswap_16(ret);
|
||||
#else
|
||||
ret = __builtin_bswap16(ret);
|
||||
#endif
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline u32 DWORD(const void *x)
|
||||
{
|
||||
u32 ret;
|
||||
memcpy(&ret, x, sizeof(ret));
|
||||
#ifdef BIGENDIAN
|
||||
#ifdef bswap_32
|
||||
ret = bswap_32(ret);
|
||||
#else
|
||||
ret = __builtin_bswap32(ret);
|
||||
#endif
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline u64 QWORD(const void *x)
|
||||
{
|
||||
u64 ret;
|
||||
memcpy(&ret, x, sizeof(ret));
|
||||
#ifdef BIGENDIAN
|
||||
#ifdef bswap_64
|
||||
ret = bswap_64(ret);
|
||||
#else
|
||||
ret = __builtin_bswap64(ret);
|
||||
#endif
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
#undef BIGENDIAN
|
||||
|
||||
#endif
|
||||
|
||||
16
util.c
16
util.c
@ -261,19 +261,3 @@ out:
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Returns end - start + 1, assuming start < end */
|
||||
u64 u64_range(u64 start, u64 end)
|
||||
{
|
||||
u64 res;
|
||||
|
||||
res.h = end.h - start.h;
|
||||
res.l = end.l - start.l;
|
||||
|
||||
if (end.l < start.l)
|
||||
res.h--;
|
||||
if (++res.l == 0)
|
||||
res.h++;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
1
util.h
1
util.h
@ -27,4 +27,3 @@
|
||||
int checksum(const u8 *buf, size_t len);
|
||||
void *read_file(off_t base, size_t *len, const char *filename);
|
||||
void *mem_chunk(off_t base, size_t len, const char *devmem);
|
||||
u64 u64_range(u64 start, u64 end);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user