Codebase list dmidecode / 31ec5f5
Import upstream version 3.3+git20210119.a4b31b2, md5 71c50f096c490cdb87a162532374ba1b Debian Janitor 3 years ago
6 changed file(s) with 502 addition(s) and 90 deletion(s). Raw diff Collapse all Expand all
0 .gitattributes export-ignore
1 .gitignore export-ignore
2
3 *.c diff=cpp
4 *.h diff=cpp
0 biosdecode
1 dmidecode
2 ownership
3 vpddecode
4 *.o
115115 size_t i;
116116
117117 for (i = 0; i < len; i++)
118 if (bp[i] < 32 || bp[i] == 127)
118 if (bp[i] < 32 || bp[i] >= 127)
119119 bp[i] = '.';
120120 }
121121
247247 {
248248 int j, l = strlen(s) + 1;
249249
250 off = 0;
251250 for (row = 0; row < ((l - 1) >> 4) + 1; row++)
252251 {
252 off = 0;
253253 for (j = 0; j < 16 && j < l - (row << 4); j++)
254254 off += sprintf(raw_data + off,
255255 j ? " %02X" : "%02X",
266266 }
267267
268268 /* shift is 0 if the value is in bytes, 1 if it is in kilobytes */
269 static void dmi_print_memory_size(const char *attr, u64 code, int shift)
269 void dmi_print_memory_size(const char *attr, u64 code, int shift)
270270 {
271271 unsigned long capacity;
272272 u16 split[7];
11061106 u16 dx = WORD(p);
11071107 /*
11081108 * Not all 80486 CPU support the CPUID instruction, we have to find
1109 * wether the one we have here does or not. Note that this trick
1109 * whether the one we have here does or not. Note that this trick
11101110 * works only because we know that 80486 must be little-endian.
11111111 */
11121112 if ((dx & 0x0F00) == 0x0400
13541354 "Socket LGA2066",
13551355 "Socket BGA1392",
13561356 "Socket BGA1510",
1357 "Socket BGA1528" /* 0x3C */
1358 };
1359
1360 if (code >= 0x01 && code <= 0x3C)
1357 "Socket BGA1528",
1358 "Socket LGA4189",
1359 "Socket LGA1200" /* 0x3E */
1360 };
1361
1362 if (code >= 0x01 && code <= 0x3E)
13611363 return upgrade[code - 0x01];
13621364 return out_of_spec;
13631365 }
13851387 "Hardware Thread",
13861388 "Execute Protection",
13871389 "Enhanced Virtualization",
1388 "Power/Performance Control" /* 7 */
1390 "Power/Performance Control",
1391 "128-bit Capable",
1392 "Arm64 SoC ID" /* 9 */
13891393 };
13901394
13911395 if ((code & 0x00FC) == 0)
13951399 int i;
13961400
13971401 pr_list_start(attr, NULL);
1398 for (i = 2; i <= 7; i++)
1402 for (i = 2; i <= 9; i++)
13991403 if (code & (1 << i))
14001404 pr_list_item("%s", characteristics[i - 2]);
14011405 pr_list_end();
19301934 "MXM Type IV",
19311935 "MXM 3.0 Type A",
19321936 "MXM 3.0 Type B",
1933 "PCI Express 2 SFF-8639",
1934 "PCI Express 3 SFF-8639",
1937 "PCI Express 2 SFF-8639 (U.2)",
1938 "PCI Express 3 SFF-8639 (U.2)",
19351939 "PCI Express Mini 52-pin with bottom-side keep-outs",
19361940 "PCI Express Mini 52-pin without bottom-side keep-outs",
1937 "PCI Express Mini 76-pin" /* 0x23 */
1941 "PCI Express Mini 76-pin",
1942 "PCI Express 4 SFF-8639 (U.2)",
1943 "PCI Express 5 SFF-8639 (U.2)",
1944 "OCP NIC 3.0 Small Form Factor (SFF)",
1945 "OCP NIC 3.0 Large Form Factor (LFF)",
1946 "OCP NIC Prior to 3.0" /* 0x28 */
19381947 };
19391948 static const char *type_0x30[] = {
19401949 "CXL FLexbus 1.0" /* 0x30 */
19691978 "PCI Express 4 x2",
19701979 "PCI Express 4 x4",
19711980 "PCI Express 4 x8",
1972 "PCI Express 4 x16" /* 0xBD */
1981 "PCI Express 4 x16",
1982 "PCI Express 5",
1983 "PCI Express 5 x1",
1984 "PCI Express 5 x2",
1985 "PCI Express 5 x4",
1986 "PCI Express 5 x8",
1987 "PCI Express 5 x16",
1988 "PCI Express 6+",
1989 "EDSFF E1",
1990 "EDSFF E3" /* 0xC6 */
19731991 };
19741992 /*
19751993 * Note to developers: when adding entries to these lists, check if
19761994 * function dmi_slot_id below needs updating too.
19771995 */
19781996
1979 if (code >= 0x01 && code <= 0x23)
1997 if (code >= 0x01 && code <= 0x28)
19801998 return type[code - 0x01];
19811999 if (code == 0x30)
19822000 return type_0x30[code - 0x30];
1983 if (code >= 0xA0 && code <= 0xBD)
2001 if (code >= 0xA0 && code <= 0xC6)
19842002 return type_0xA0[code - 0xA0];
19852003 return out_of_spec;
19862004 }
21152133 "PME signal is supported", /* 0 */
21162134 "Hot-plug devices are supported",
21172135 "SMBus signal is supported",
2118 "PCIe slot bifurcation is supported" /* 3 */
2136 "PCIe slot bifurcation is supported",
2137 "Async/surprise removal is supported",
2138 "Flexbus slot, CXL 1.0 capable",
2139 "Flexbus slot, CXL 2.0 capable" /* 6 */
21192140 };
21202141
21212142 if (code1 & (1 << 0))
21302151 for (i = 1; i <= 7; i++)
21312152 if (code1 & (1 << i))
21322153 pr_list_item("%s", characteristics1[i - 1]);
2133 for (i = 0; i <= 3; i++)
2154 for (i = 0; i <= 6; i++)
21342155 if (code2 & (1 << i))
21352156 pr_list_item("%s", characteristics2[i]);
21362157 pr_list_end();
21522173
21532174 for (i = 1; i <= n; i++, data += 5)
21542175 {
2155 sprintf(attr, "Peer Device %hu", i);
2176 sprintf(attr, "Peer Device %hhu", (u8)i);
21562177 pr_attr(attr, "%04x:%02x:%02x.%x (Width %u)",
21572178 WORD(data), data[2], data[3] >> 3, data[3] & 0x07,
21582179 data[4]);
22182239
22192240 for (i = 1; i <= count; i++)
22202241 {
2221 sprintf(attr, "String %hu", i);
2242 sprintf(attr, "String %hhu", (u8)i);
22222243 pr_attr(attr, "%s",dmi_string(h, i));
22232244 }
22242245 }
22362257
22372258 for (i = 1; i <= count; i++)
22382259 {
2239 sprintf(attr, "Option %hu", i);
2260 sprintf(attr, "Option %hhu", (u8)i);
22402261 pr_attr(attr, "%s",dmi_string(h, i));
22412262 }
22422263 }
24202441 {
24212442 if (len >= 0x02)
24222443 {
2423 sprintf(attr, "Descriptor %hu", i + 1);
2444 sprintf(attr, "Descriptor %d", i + 1);
24242445 pr_attr(attr, "%s",
24252446 dmi_event_log_descriptor_type(p[i * len]));
2426 sprintf(attr, "Data Format %hu", i + 1);
2447 sprintf(attr, "Data Format %d", i + 1);
24272448 pr_attr(attr, "%s",
24282449 dmi_event_log_descriptor_format(p[i * len + 1]));
24292450 }
26382659 "LPDDR4",
26392660 "Logical non-volatile device",
26402661 "HBM",
2641 "HBM2" /* 0x21 */
2642 };
2643
2644 if (code >= 0x01 && code <= 0x21)
2662 "HBM2",
2663 "DDR5",
2664 "LPDDR5" /* 0x23 */
2665 };
2666
2667 if (code >= 0x01 && code <= 0x23)
26452668 return type[code - 0x01];
26462669 return out_of_spec;
26472670 }
26832706 }
26842707 }
26852708
2686 static void dmi_memory_device_speed(const char *attr, u16 code)
2687 {
2688 if (code == 0)
2689 pr_attr(attr, "Unknown");
2690 else
2691 pr_attr(attr, "%u MT/s", code);
2709 static void dmi_memory_device_speed(const char *attr, u16 code1, u32 code2)
2710 {
2711 if (code1 == 0xFFFF)
2712 {
2713 if (code2 == 0)
2714 pr_attr(attr, "Unknown");
2715 else
2716 pr_attr(attr, "%lu MT/s", code2);
2717 }
2718 else
2719 {
2720 if (code1 == 0)
2721 pr_attr(attr, "Unknown");
2722 else
2723 pr_attr(attr, "%u MT/s", code1);
2724 }
26922725 }
26932726
26942727 static void dmi_memory_technology(u8 code)
33893422
33903423 for (i = 1; i <= count; i++)
33913424 {
3392 sprintf(attr, "Device %hu Load", i);
3425 sprintf(attr, "Device %hhu Load", (u8)i);
33933426 pr_attr(attr, "%u", p[3 * i]);
33943427 if (!(opt.flags & FLAG_QUIET))
33953428 {
3396 sprintf(attr, "Device %hu Handle", i);
3429 sprintf(attr, "Device %hhu Handle", (u8)i);
33973430 pr_attr(attr, "0x%04X", WORD(p + 3 * i + 1));
33983431 }
33993432 }
37063739 * convenience. It could get passed from the SMBIOS
37073740 * header, but that's a lot of passing of pointers just
37083741 * to get that info, and the only thing it is used for is
3709 * to determine the endianess of the field. Since we only
3742 * to determine the endianness of the field. Since we only
37103743 * do this parsing on versions of SMBIOS after 3.1.1, and the
3711 * endianess of the field is always little after version 2.6.0
3744 * endianness of the field is always little after version 2.6.0
37123745 * we can just pick a sufficiently recent version here.
37133746 */
37143747 dmi_system_uuid(pr_subattr, "Service UUID", &rdata[0], 0x311);
37153748
37163749 /*
37173750 * DSP0270: 8.6: Redfish Over IP Host IP Assignment Type
3718 * Note, using decimal indicies here, as the DSP0270
3751 * Note, using decimal indices here, as the DSP0270
37193752 * uses decimal, so as to make it more comparable
37203753 */
37213754 assign_val = rdata[16];
44504483 dmi_memory_device_type(data[0x12]));
44514484 dmi_memory_device_type_detail(WORD(data + 0x13));
44524485 if (h->length < 0x17) break;
4453 dmi_memory_device_speed("Speed", WORD(data + 0x15));
4486 /* If no module is present, the remaining fields are irrelevant */
4487 if (WORD(data + 0x0C) == 0)
4488 break;
4489 dmi_memory_device_speed("Speed", WORD(data + 0x15),
4490 h->length >= 0x5C ?
4491 DWORD(data + 0x54) : 0);
44544492 if (h->length < 0x1B) break;
44554493 pr_attr("Manufacturer", "%s",
44564494 dmi_string(h, data[0x17]));
44674505 pr_attr("Rank", "%u", data[0x1B] & 0x0F);
44684506 if (h->length < 0x22) break;
44694507 dmi_memory_device_speed("Configured Memory Speed",
4470 WORD(data + 0x20));
4508 WORD(data + 0x20),
4509 h->length >= 0x5C ?
4510 DWORD(data + 0x58) : 0);
44714511 if (h->length < 0x28) break;
44724512 dmi_memory_voltage_value("Minimum Voltage",
44734513 WORD(data + 0x22));
51415181 u8 *data;
51425182 int i = 0;
51435183
5184 /* First pass: Save the vendor so that so that we can decode OEM types */
5185 data = buf;
5186 while ((i < num || !num)
5187 && data + 4 <= buf + len) /* 4 is the length of an SMBIOS structure header */
5188 {
5189 u8 *next;
5190 struct dmi_header h;
5191
5192 to_dmi_header(&h, data);
5193
5194 /*
5195 * If a short entry is found (less than 4 bytes), not only it
5196 * is invalid, but we cannot reliably locate the next entry.
5197 * Also stop at end-of-table marker if so instructed.
5198 */
5199 if (h.length < 4 ||
5200 (h.type == 127 &&
5201 (opt.flags & (FLAG_QUIET | FLAG_STOP_AT_EOT))))
5202 break;
5203 i++;
5204
5205 /* Look for the next handle */
5206 next = data + h.length;
5207 while ((unsigned long)(next - buf + 1) < len
5208 && (next[0] != 0 || next[1] != 0))
5209 next++;
5210 next += 2;
5211
5212 /* Make sure the whole structure fits in the table */
5213 if ((unsigned long)(next - buf) > len)
5214 break;
5215
5216 /* Assign vendor for vendor-specific decodes later */
5217 if (h.type == 1 && h.length >= 6)
5218 {
5219 dmi_set_vendor(_dmi_string(&h, data[0x04], 0),
5220 _dmi_string(&h, data[0x05], 0));
5221 break;
5222 }
5223
5224 data = next;
5225 }
5226
5227 /* Second pass: Actually decode the data */
5228 i = 0;
51445229 data = buf;
51455230 while ((i < num || !num)
51465231 && data + 4 <= buf + len) /* 4 is the length of an SMBIOS structure header */
51995284 data = next;
52005285 break;
52015286 }
5202
5203 /* assign vendor for vendor-specific decodes later */
5204 if (h.type == 1 && h.length >= 5)
5205 dmi_set_vendor(dmi_string(&h, data[0x04]));
52065287
52075288 /* Fixup a common mistake */
52085289 if (h.type == 34)
3232
3333 int is_printable(const u8 *data, int len);
3434 const char *dmi_string(const struct dmi_header *dm, u8 s);
35 void dmi_print_memory_size(const char *addr, u64 code, int shift);
3536
3637 #endif
2222 #include <string.h>
2323
2424 #include "types.h"
25 #include "util.h"
2526 #include "dmidecode.h"
2627 #include "dmioem.h"
28 #include "dmiopt.h"
2729 #include "dmioutput.h"
2830
2931 /*
4143 };
4244
4345 static enum DMI_VENDORS dmi_vendor = VENDOR_UNKNOWN;
46 static const char *dmi_product = NULL;
4447
4548 /*
4649 * Remember the system vendor for later use. We only actually store the
4750 * value if we know how to decode at least one specific entry type for
4851 * that vendor.
4952 */
50 void dmi_set_vendor(const char *s)
51 {
52 int len;
53 void dmi_set_vendor(const char *v, const char *p)
54 {
55 const struct { const char *str; enum DMI_VENDORS id; } vendor[] = {
56 { "Acer", VENDOR_ACER },
57 { "HP", VENDOR_HP },
58 { "Hewlett-Packard", VENDOR_HP },
59 { "HPE", VENDOR_HPE },
60 { "Hewlett Packard Enterprise", VENDOR_HPE },
61 { "IBM", VENDOR_IBM },
62 { "LENOVO", VENDOR_LENOVO },
63 };
64 unsigned int i;
65 size_t len;
5366
5467 /*
5568 * Often DMI strings have trailing spaces. Ignore these
5669 * when checking for known vendor names.
5770 */
58 len = strlen(s);
59 while (len && s[len - 1] == ' ')
71 len = v ? strlen(v) : 0;
72 while (len && v[len - 1] == ' ')
6073 len--;
6174
62 if (strncmp(s, "Acer", len) == 0)
63 dmi_vendor = VENDOR_ACER;
64 else if (strncmp(s, "HP", len) == 0 || strncmp(s, "Hewlett-Packard", len) == 0)
65 dmi_vendor = VENDOR_HP;
66 else if (strncmp(s, "HPE", len) == 0 || strncmp(s, "Hewlett Packard Enterprise", len) == 0)
67 dmi_vendor = VENDOR_HPE;
68 else if (strncmp(s, "IBM", len) == 0)
69 dmi_vendor = VENDOR_IBM;
70 else if (strncmp(s, "LENOVO", len) == 0)
71 dmi_vendor = VENDOR_LENOVO;
75 for (i = 0; i < ARRAY_SIZE(vendor); i++)
76 {
77 if (strlen(vendor[i].str) == len &&
78 strncmp(v, vendor[i].str, len) == 0)
79 {
80 dmi_vendor = vendor[i].id;
81 break;
82 }
83 }
84
85 dmi_product = p;
7286 }
7387
7488 /*
132146 if (id == 0xFF)
133147 id = ++nic_ctr;
134148
135 sprintf(attr, "NIC %hu", id);
149 sprintf(attr, "NIC %hhu", id);
136150 if (dev == 0x00 && bus == 0x00)
137151 pr_attr(attr, "Disabled");
138152 else if (dev == 0xFF && bus == 0xFF)
146160 }
147161 }
148162
163 typedef enum { G6 = 6, G7, G8, G9, G10, G10P } dmi_hpegen_t;
164
165 static int dmi_hpegen(const char *s)
166 {
167 struct { const char *name; dmi_hpegen_t gen; } table[] = {
168 { "Gen10 Plus", G10P },
169 { "Gen10", G10 },
170 { "Gen9", G9 },
171 { "Gen8", G8 },
172 { "G7", G7 },
173 { "G6", G6 },
174 };
175 unsigned int i;
176
177 if (!strstr(s, "ProLiant") && !strstr(s, "Apollo") &&
178 !strstr(s, "Synergy") && !strstr(s, "Edgeline"))
179 return -1;
180
181 for (i = 0; i < ARRAY_SIZE(table); i++) {
182 if (strstr(s, table[i].name))
183 return(table[i].gen);
184 }
185
186 return (dmi_vendor == VENDOR_HPE) ? G10P : G6;
187 }
188
189 static void dmi_hp_240_attr(u64 defined, u64 set)
190 {
191 static const char *attributes[] = {
192 "Updatable",
193 "Reset Required",
194 "Authentication Required",
195 "In Use",
196 "UEFI Image",
197 };
198 unsigned int i;
199
200 pr_attr("Attributes Defined/Set", NULL);
201 for (i = 0; i < ARRAY_SIZE(attributes); i++)
202 {
203 if (!(defined.l & (1UL << i)))
204 continue;
205 pr_subattr(attributes[i], "%s", set.l & (1UL << i) ? "Yes" : "No");
206 }
207 }
208
209 static void dmi_hp_203_assoc_hndl(const char *fname, u16 num)
210 {
211 if (opt.flags & FLAG_QUIET)
212 return;
213
214 if (num == 0xFFFE)
215 pr_attr(fname, "N/A");
216 else
217 pr_attr(fname, "0x%04X", num);
218 }
219
220 static void dmi_hp_203_pciinfo(const char *fname, u16 num)
221 {
222 if (num == 0xFFFF)
223 pr_attr(fname, "Device Not Present");
224 else
225 pr_attr(fname, "0x%04x", num);
226 }
227
228 static void dmi_hp_203_bayenc(const char *fname, u8 num)
229 {
230 switch (num)
231 {
232 case 0x00:
233 pr_attr(fname, "Unknown");
234 break;
235 case 0xff:
236 pr_attr(fname, "Do Not Display");
237 break;
238 default:
239 pr_attr(fname, "%d", num);
240 }
241 }
242
243 static void dmi_hp_203_devtyp(const char *fname, unsigned int code)
244 {
245 static const char *str = "Reserved";
246 static const char *type[] = {
247 "Unknown", /* 0x00 */
248 "Reserved",
249 "Reserved",
250 "Flexible LOM",
251 "Embedded LOM",
252 "NIC in a Slot",
253 "Storage Controller",
254 "Smart Array Storage Controller",
255 "USB Hard Disk",
256 "Other PCI Device",
257 "RAM Disk",
258 "Firmware Volume",
259 "UEFI Shell",
260 "Generic UEFI USB Boot Entry",
261 "Dynamic Smart Array Controller",
262 "File",
263 "NVME Hard Drive",
264 "NVDIMM" /* 0x11 */
265 };
266
267 if (code < ARRAY_SIZE(type))
268 str = type[code];
269
270 pr_attr(fname, "%s", str);
271 }
272
273 static void dmi_hp_203_devloc(const char *fname, unsigned int code)
274 {
275 static const char *str = "Reserved";
276 static const char *location[] = {
277 "Unknown", /* 0x00 */
278 "Embedded",
279 "iLO Virtual Media",
280 "Front USB Port",
281 "Rear USB Port",
282 "Internal USB",
283 "Internal SD Card",
284 "Internal Virutal USB (Embedded NAND)",
285 "Embedded SATA Port",
286 "Embedded Smart Array",
287 "PCI Slot",
288 "RAM Memory",
289 "USB",
290 "Dynamic Smart Array Controller",
291 "URL",
292 "NVMe Drive Bay" /* 0x0F */
293 };
294
295 if (code < ARRAY_SIZE(location))
296 str = location[code];
297
298 pr_attr(fname, "%s", str);
299 }
300
149301 static int dmi_decode_hp(const struct dmi_header *h)
150302 {
151303 u8 *data = h->data;
152304 int nic, ptr;
153305 u32 feat;
154306 const char *company = (dmi_vendor == VENDOR_HP) ? "HP" : "HPE";
307 int gen;
308
309 gen = dmi_hpegen(dmi_product);
310 if (gen < 0)
311 return 0;
155312
156313 switch (h->type)
157314 {
315 case 203:
316 /*
317 * Vendor Specific: HP Device Correlation Record
318 *
319 * Offset | Name | Width | Description
320 * -------------------------------------
321 * 0x00 | Type | BYTE | 0xCB, Correlation Record
322 * 0x01 | Length | BYTE | Length of structure
323 * 0x02 | Handle | WORD | Unique handle
324 * 0x04 | Assoc Device | WORD | Handle of Associated Type 9 or Type 41 Record
325 * 0x06 | Assoc SMBus | WORD | Handle of Associated Type 228 SMBus Segment Record
326 * 0x08 | PCI Vendor ID| WORD | PCI Vendor ID of device 0xFFFF -> not present
327 * 0x0A | PCI Device ID| WORD | PCI Device ID of device 0xFFFF -> not present
328 * 0x0C | PCI SubVendor| WORD | PCI Sub Vendor ID of device 0xFFFF -> not present
329 * 0x0E | PCI SubDevice| WORD | PCI Sub Device ID of device 0xFFFF -> not present
330 * 0x10 | Class Code | BYTE | PCI Class Code of Endpoint. 0xFF if device not present.
331 * 0x11 | Class SubCode| BYTE | PCI Sub Class Code of Endpoint. 0xFF if device not present.
332 * 0x12 | Parent Handle| WORD |
333 * 0x14 | Flags | WORD |
334 * 0x16 | Device Type | BYTE | UEFI only
335 * 0x17 | Device Loc | BYTE | Device Location
336 * 0x18 | Dev Instance | BYTE | Device Instance
337 * 0x19 | Sub Instance | BYTE | NIC Port # or NVMe Drive Bay
338 * 0x1A | Bay | BYTE |
339 * 0x1B | Enclosure | BYTE |
340 * 0x1C | UEFI Dev Path| STRING| String number for UEFI Device Path
341 * 0x1D | Struct Name | STRING| String number for UEFI Device Structured Name
342 * 0x1E | Device Name | STRING| String number for UEFI Device Name
343 * 0x1F | UEFI Location| STRING| String number for UEFI Location
344 * 0x20 | Assoc Handle | WORD | Type 9 Handle. Defined if Flags[0] == 1.
345 * 0x22 | Part Number | STRING| PCI Device Part Number
346 * 0x23 | Serial Number| STRING| PCI Device Serial Number
347 * 0x24 | Seg Number | WORD | Segment Group number. 0 -> Single group topology
348 * 0x26 | Bus Number | BYTE | PCI Device Bus Number
349 * 0x27 | Func Number | BTYE | PCI Device and Function Number
350 */
351 if (gen < G9) break;
352 if (h->length < 0x1F) break;
353 pr_handle_name("%s HP Device Correlation Record", company);
354 dmi_hp_203_assoc_hndl("Associated Device Record", WORD(data + 0x04));
355 dmi_hp_203_assoc_hndl("Associated SMBus Record", WORD(data + 0x06));
356 if (WORD(data + 0x08) == 0xffff && WORD(data + 0x0A) == 0xffff &&
357 WORD(data + 0x0C) == 0xffff && WORD(data + 0x0E) == 0xffff &&
358 data[0x10] == 0xFF && data[0x11] == 0xFF)
359 {
360 pr_attr("PCI Device Info", "Device Not Present");
361 }
362 else
363 {
364 dmi_hp_203_pciinfo("PCI Vendor ID", WORD(data + 0x08));
365 dmi_hp_203_pciinfo("PCI Device ID", WORD(data + 0x0A));
366 dmi_hp_203_pciinfo("PCI Sub Vendor ID", WORD(data + 0x0C));
367 dmi_hp_203_pciinfo("PCI Sub Device ID", WORD(data + 0x0E));
368 dmi_hp_203_pciinfo("PCI Class Code", (char)data[0x10]);
369 dmi_hp_203_pciinfo("PCI Sub Class Code", (char)data[0x11]);
370 }
371 dmi_hp_203_assoc_hndl("Parent Handle", WORD(data + 0x12));
372 pr_attr("Flags", "0x%04X", WORD(data + 0x14));
373 dmi_hp_203_devtyp("Device Type", data[0x16]);
374 dmi_hp_203_devloc("Device Location", data[0x17]);
375 pr_attr("Device Instance", "%d", data[0x18]);
376 pr_attr("Device Sub-Instance", "%d", data[0x19]);
377 dmi_hp_203_bayenc("Bay", data[0x1A]);
378 dmi_hp_203_bayenc("Enclosure", data[0x1B]);
379 pr_attr("Device Path", "%s", dmi_string(h, data[0x1C]));
380 pr_attr("Structured Name", "%s", dmi_string(h, data[0x1D]));
381 pr_attr("Device Name", "%s", dmi_string(h, data[0x1E]));
382 if (h->length < 0x22) break;
383 pr_attr("UEFI Location", "%s", dmi_string(h, data[0x1F]));
384 if (!(opt.flags & FLAG_QUIET))
385 {
386 if (WORD(data + 0x14) & 1)
387 pr_attr("Associated Real/Phys Handle", "0x%04X",
388 WORD(data + 0x20));
389 else
390 pr_attr("Associated Real/Phys Handle", "N/A");
391 }
392 if (h->length < 0x24) break;
393 pr_attr("PCI Part Number", "%s", dmi_string(h, data[0x22]));
394 pr_attr("Serial Number", "%s", dmi_string(h, data[0x23]));
395 if (h->length < 0x28) break;
396 pr_attr("Segment Group Number", "0x%04x", WORD(data + 0x24));
397 pr_attr("PCI Device", "%02x:%02x.%x",
398 data[0x26], data[0x27] >> 3, data[0x27] & 7);
399 break;
400
158401 case 204:
159402 /*
160403 * Vendor Specific: HPE ProLiant System/Rack Locator
205448 nic++;
206449 ptr += 8;
207450 }
208 break;
209
210 case 233:
211 /*
212 * Vendor Specific: HPE ProLiant NIC MAC Information
213 *
214 * This prints the BIOS NIC number,
215 * PCI bus/device/function, and MAC address
216 *
217 * Offset | Name | Width | Description
218 * -------------------------------------
219 * 0x00 | Type | BYTE | 0xE9, NIC structure
220 * 0x01 | Length | BYTE | Length of structure
221 * 0x02 | Handle | WORD | Unique handle
222 * 0x04 | Grp No | WORD | 0 for single segment
223 * 0x06 | Bus No | BYTE | PCI Bus
224 * 0x07 | Dev No | BYTE | PCI Device/Function No
225 * 0x08 | MAC | 32B | MAC addr padded w/ 0s
226 * 0x28 | Port No| BYTE | Each NIC maps to a Port
227 */
228 pr_handle_name("%s BIOS PXE NIC PCI and MAC Information",
229 company);
230 if (h->length < 0x0E) break;
231 /* If the record isn't long enough, we don't have an ID
232 * use 0xFF to use the internal counter.
233 * */
234 nic = h->length > 0x28 ? data[0x28] : 0xFF;
235 dmi_print_hp_net_iface_rec(nic, data[0x06], data[0x07],
236 &data[0x08]);
237451 break;
238452
239453 case 212:
281495 pr_subattr("UEFI", "%s", feat & 0x1400 ? "Yes" : "No");
282496 break;
283497
498 case 233:
499 /*
500 * Vendor Specific: HPE ProLiant NIC MAC Information
501 *
502 * This prints the BIOS NIC number,
503 * PCI bus/device/function, and MAC address
504 *
505 * Offset | Name | Width | Description
506 * -------------------------------------
507 * 0x00 | Type | BYTE | 0xE9, NIC structure
508 * 0x01 | Length | BYTE | Length of structure
509 * 0x02 | Handle | WORD | Unique handle
510 * 0x04 | Grp No | WORD | 0 for single segment
511 * 0x06 | Bus No | BYTE | PCI Bus
512 * 0x07 | Dev No | BYTE | PCI Device/Function No
513 * 0x08 | MAC | 32B | MAC addr padded w/ 0s
514 * 0x28 | Port No| BYTE | Each NIC maps to a Port
515 */
516 pr_handle_name("%s BIOS PXE NIC PCI and MAC Information",
517 company);
518 if (h->length < 0x0E) break;
519 /* If the record isn't long enough, we don't have an ID
520 * use 0xFF to use the internal counter.
521 * */
522 nic = h->length > 0x28 ? data[0x28] : 0xFF;
523 dmi_print_hp_net_iface_rec(nic, data[0x06], data[0x07],
524 &data[0x08]);
525 break;
526
527 case 236:
528 /*
529 * Vendor Specific: HPE ProLiant HDD Backplane
530 *
531 * Offset | Name | Width | Description
532 * ---------------------------------------
533 * 0x00 | Type | BYTE | 0xEC, HDD Backplane
534 * 0x01 | Length | BYTE | Length of structure
535 * 0x02 | Handle | WORD | Unique handle
536 * 0x04 | I2C Address| BYTE | Backplane FRU I2C Address
537 * 0x05 | Box Number | WORD | Backplane Box Number
538 * 0x07 | NVRAM ID | WORD | Backplane NVRAM ID
539 * 0x09 | WWID | QWORD | SAS Expander WWID
540 * 0x11 | Total Bays | BYTE | Total SAS Bays
541 * 0x12 | A0 Bays | BYTE | (deprecated) Number of SAS drive bays behind port 0xA0
542 * 0x13 | A2 Bays | BYTE | (deprecated) Number of SAS drive bays behind port 0xA2
543 * 0x14 | Name | STRING| (deprecated) Backplane Name
544 */
545 pr_handle_name("%s HDD Backplane FRU Information", company);
546 if (h->length < 0x08) break;
547 pr_attr("FRU I2C Address", "0x%X raw(0x%X)", data[0x4] >> 1, data[0x4]);
548 pr_attr("Box Number", "%d", WORD(data + 0x5));
549 pr_attr("NVRAM ID", "0x%X", WORD(data + 0x7));
550 if (h->length < 0x11) break;
551 pr_attr("SAS Expander WWID", "0x%X", QWORD(data + 0x9));
552 if (h->length < 0x12) break;
553 pr_attr("Total SAS Bays", "%d", data[0x11]);
554 if (h->length < 0x15) break;
555 if (gen < G10P) {
556 pr_attr("A0 Bay Count", "%d", data[0x12]);
557 pr_attr("A2 Bay Count", "%d", data[0x13]);
558 pr_attr("Backplane Name", "%s", dmi_string(h, data[0x14]));
559 }
560 break;
561
562 case 240:
563 /*
564 * Vendor Specific: HPE Proliant Inventory Record
565 *
566 * Reports firmware version information for devices that report their
567 * firmware using their UEFI drivers. Additionally provides association
568 * with other SMBIOS records, such as Type 203 (which in turn is
569 * associated with Types 9, 41, and 228).
570 *
571 * Offset | Name | Width | Description
572 * ---------------------------------------
573 * 0x00 | Type | BYTE | 0xF0, HP Firmware Inventory Record
574 * 0x01 | Length | BYTE | Length of structure
575 * 0x02 | Handle | WORD | Unique handle
576 * 0x04 | Hndl Assoc | WORD | Handle to map to Type 203
577 * 0x06 | Pkg Vers | DWORD | FW Vers Release of All FW in Device
578 * 0x0A | Ver String | STRING| FW Version String
579 * 0x0B | Image Size | QWORD | FW image size (bytes)
580 * 0x13 | Attributes | QWORD | Bitfield: Is attribute defined?
581 * 0x1B | Attr Set | QWORD | BitField: If defined, is attribute set?
582 * 0x23 | Version | DWORD | Lowest supported version.
583 */
584 pr_handle_name("%s Proliant Inventory Record", company);
585 if (h->length < 0x27) break;
586 if (!(opt.flags & FLAG_QUIET))
587 pr_attr("Associated Handle", "0x%04X", WORD(data + 0x4));
588 pr_attr("Package Version", "0x%08X", DWORD(data + 0x6));
589 pr_attr("Version String", "%s", dmi_string(h, data[0x0A]));
590
591 if (DWORD(data + 0x0B))
592 dmi_print_memory_size("Image Size", QWORD(data + 0xB), 0);
593 else
594 pr_attr("Image Size", "Not Available");
595
596 dmi_hp_240_attr(QWORD(data + 0x13), QWORD(data + 0x1B));
597
598 if (DWORD(data + 0x23))
599 pr_attr("Lowest Supported Version", "0x%08X", DWORD(data + 0x23));
600 else
601 pr_attr("Lowest Supported Version", "Not Available");
602 break;
603
284604 default:
285605 return 0;
286606 }
2020
2121 struct dmi_header;
2222
23 void dmi_set_vendor(const char *s);
23 void dmi_set_vendor(const char *s, const char *p);
2424 int dmi_decode_oem(const struct dmi_header *h);