summaryrefslogtreecommitdiff
path: root/dmioem.c
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 /dmioem.c
parentc9aac994d65f7bcc3659e3219d6729a24c803fcf (diff)
New upstream version 3.7upstream/3.7upstream
Diffstat (limited to 'dmioem.c')
-rw-r--r--dmioem.c750
1 files changed, 702 insertions, 48 deletions
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);