diff options
Diffstat (limited to 'dmioem.c')
| -rw-r--r-- | dmioem.c | 750 |
1 files changed, 702 insertions, 48 deletions
@@ -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); |
