summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff.email>2026-03-10 09:31:17 +0100
committerJörg Frings-Fürst <debian@jff.email>2026-03-10 09:31:17 +0100
commit22f77b46ab555f57523990094a3e40a55f2c492a (patch)
tree0b2dad175ecf9514c5c9d8fb9473010c2337a3b3
parentc9aac994d65f7bcc3659e3219d6729a24c803fcf (diff)
New upstream version 3.7upstream/3.7upstream
-rw-r--r--AUTHORS1
-rw-r--r--Makefile5
-rw-r--r--NEWS15
-rw-r--r--README8
-rw-r--r--biosdecode.c10
-rw-r--r--config.h5
-rw-r--r--dmidecode.c377
-rw-r--r--dmidecode.h12
-rw-r--r--dmioem.c750
-rw-r--r--dmioem.h4
-rw-r--r--man/dmidecode.817
-rw-r--r--types.h97
-rw-r--r--util.c16
-rw-r--r--util.h1
-rw-r--r--version.h2
15 files changed, 1051 insertions, 269 deletions
diff --git a/AUTHORS b/AUTHORS
index 7065f72..b3573a3 100644
--- a/AUTHORS
+++ b/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
diff --git a/Makefile b/Makefile
index 6fc946b..985992e 100644
--- a/Makefile
+++ b/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 ?=
diff --git a/NEWS b/NEWS
index 8c4059e..912c540 100644
--- a/NEWS
+++ b/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.
diff --git a/README b/README
index c87e52c..65060b2 100644
--- a/README
+++ b/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 **
diff --git a/biosdecode.c b/biosdecode.c
index 99a27fe..c387276 100644
--- a/biosdecode.c
+++ b/biosdecode.c
@@ -2,7 +2,7 @@
* BIOS Decode
*
* Copyright (C) 2000-2002 Alan Cox <alan@redhat.com>
- * Copyright (C) 2002-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;
}
diff --git a/config.h b/config.h
index 0a1af7d..416d4a6 100644
--- a/config.h
+++ b/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
diff --git a/dmidecode.c b/dmidecode.c
index 45a6c06..463f12b 100644
--- a/dmidecode.c
+++ b/dmidecode.c
@@ -2,7 +2,7 @@
* DMI Decode
*
* Copyright (C) 2000-2002 Alan Cox <alan@redhat.com>
- * Copyright (C) 2002-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;
diff --git a/dmidecode.h b/dmidecode.h
index e03c957..40f8a62 100644
--- a/dmidecode.h
+++ b/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
diff --git a/dmioem.c b/dmioem.c
index 2f1f9f6..bdf41d2 100644
--- a/dmioem.c
+++ b/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 },
@@ -130,6 +133,144 @@ static int dmi_decode_acer(const struct dmi_header *h)
}
/*
+ * 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.
*
* Code contributed by John Cagle and Tyler Bell.
@@ -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);
diff --git a/dmioem.h b/dmioem.h
index b79b769..4558a23 100644
--- a/dmioem.h
+++ b/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);
diff --git a/man/dmidecode.8 b/man/dmidecode.8
index 77c89a5..c4c292d 100644
--- a/man/dmidecode.8
+++ b/man/dmidecode.8
@@ -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
diff --git a/types.h b/types.h
index 51c32d7..28126b1 100644
--- a/types.h
+++ b/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;
+typedef unsigned long long int u64;
/*
- * 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.
+ * Per SMBIOS v2.8.0 and later, all structures assume a little-endian
+ * ordering convention.
*/
+static inline u16 WORD(const void *x)
+{
+ u16 ret;
+ memcpy(&ret, x, sizeof(ret));
#ifdef BIGENDIAN
-typedef struct {
- u32 h;
- u32 l;
-} u64;
+#ifdef bswap_16
+ ret = bswap_16(ret);
#else
-typedef struct {
- u32 l;
- u32 h;
-} u64;
+ ret = __builtin_bswap16(ret);
+#endif
#endif
+ return ret;
+}
-#if defined(ALIGNMENT_WORKAROUND) || defined(BIGENDIAN)
-static inline u64 U64(u32 low, u32 high)
+static inline u32 DWORD(const void *x)
{
- u64 self;
-
- self.l = low;
- self.h = high;
-
- return self;
+ 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;
+}
-/*
- * 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 */
+#undef BIGENDIAN
#endif
diff --git a/util.c b/util.c
index dce84ff..7903c3e 100644
--- a/util.c
+++ b/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;
-}
diff --git a/util.h b/util.h
index 0d37f35..e6c5e49 100644
--- a/util.h
+++ b/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);
diff --git a/version.h b/version.h
index dc5afe3..3c9b749 100644
--- a/version.h
+++ b/version.h
@@ -1 +1 @@
-#define VERSION "3.6"
+#define VERSION "3.7"