1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved.
24 * Copyright (c) 2017, Joyent, Inc.
25 * Copyright 2024 Oxide Computer Company
26 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
28 */
29
30 #include <sys/sysmacros.h>
31 #include <sys/param.h>
32 #include <sys/bitext.h>
33 #include <sys/hexdump.h>
34
35 #include <smbios.h>
36 #include <alloca.h>
37 #include <limits.h>
38 #include <unistd.h>
39 #include <strings.h>
40 #include <stdlib.h>
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <fcntl.h>
44 #include <errno.h>
45 #include <ctype.h>
46 #include <libjedec.h>
47
48 #define SMBIOS_SUCCESS 0
49 #define SMBIOS_ERROR 1
50 #define SMBIOS_USAGE 2
51
52 static const char *g_pname;
53 static int g_hdr;
54
55 static int opt_e;
56 static int opt_i = -1;
57 static int opt_O;
58 static int opt_s;
59 static int opt_t = -1;
60 static int opt_x;
61
62 static boolean_t
smbios_vergteq(smbios_version_t * v,uint_t major,uint_t minor)63 smbios_vergteq(smbios_version_t *v, uint_t major, uint_t minor)
64 {
65 if (v->smbv_major > major)
66 return (B_TRUE);
67 if (v->smbv_major == major &&
68 v->smbv_minor >= minor)
69 return (B_TRUE);
70 return (B_FALSE);
71 }
72
73 static void __PRINTFLIKE(2)
smbios_warn(smbios_hdl_t * shp,const char * format,...)74 smbios_warn(smbios_hdl_t *shp, const char *format, ...)
75 {
76 va_list ap;
77
78 va_start(ap, format);
79 (void) vfprintf(stderr, format, ap);
80 va_end(ap);
81
82 if (shp != NULL) {
83 (void) fprintf(stderr, ": %s",
84 smbios_errmsg(smbios_errno(shp)));
85 }
86
87 (void) fprintf(stderr, "\n");
88 }
89
90 static void __PRINTFLIKE(2)
oprintf(FILE * fp,const char * format,...)91 oprintf(FILE *fp, const char *format, ...)
92 {
93 va_list ap;
94
95 va_start(ap, format);
96 (void) vfprintf(fp, format, ap);
97 va_end(ap);
98 }
99
100 static void __PRINTFLIKE(3)
desc_printf(const char * d,FILE * fp,const char * format,...)101 desc_printf(const char *d, FILE *fp, const char *format, ...)
102 {
103 va_list ap;
104
105 va_start(ap, format);
106 (void) vfprintf(fp, format, ap);
107 va_end(ap);
108
109 if (d != NULL)
110 (void) fprintf(fp, " (%s)\n", d);
111 else
112 (void) fprintf(fp, "\n");
113 }
114
115 static void
flag_printf(FILE * fp,const char * s,uint_t flags,size_t bits,const char * (* flag_name)(uint_t),const char * (* flag_desc)(uint_t))116 flag_printf(FILE *fp, const char *s, uint_t flags, size_t bits,
117 const char *(*flag_name)(uint_t), const char *(*flag_desc)(uint_t))
118 {
119 size_t i;
120
121 oprintf(fp, " %s: 0x%x\n", s, flags);
122
123 for (i = 0; i < bits; i++) {
124 uint_t f = 1 << i;
125 const char *n;
126
127 if (!(flags & f))
128 continue;
129
130 if ((n = flag_name(f)) != NULL)
131 desc_printf(flag_desc(f), fp, "\t%s", n);
132 else
133 desc_printf(flag_desc(f), fp, "\t0x%x", f);
134 }
135 }
136
137 static void
flag64_printf(FILE * fp,const char * s,uint64_t flags,size_t bits,const char * (* flag_name)(uint64_t),const char * (* flag_desc)(uint64_t))138 flag64_printf(FILE *fp, const char *s, uint64_t flags, size_t bits,
139 const char *(*flag_name)(uint64_t), const char *(*flag_desc)(uint64_t))
140 {
141 size_t i;
142
143 oprintf(fp, " %s: 0x%llx\n", s, (u_longlong_t)flags);
144
145 for (i = 0; i < bits; i++) {
146 u_longlong_t f = 1ULL << i;
147 const char *n;
148
149 if (!(flags & f))
150 continue;
151
152 if ((n = flag_name(f)) != NULL)
153 desc_printf(flag_desc(f), fp, "\t%s", n);
154 else
155 desc_printf(flag_desc(f), fp, "\t0x%llx", f);
156 }
157 }
158
159 static void
id_printf(FILE * fp,const char * s,id_t id)160 id_printf(FILE *fp, const char *s, id_t id)
161 {
162 switch (id) {
163 case SMB_ID_NONE:
164 oprintf(fp, "%sNone\n", s);
165 break;
166 case SMB_ID_NOTSUP:
167 oprintf(fp, "%sNot Supported\n", s);
168 break;
169 default:
170 oprintf(fp, "%s%u\n", s, (uint_t)id);
171 }
172 }
173
174 static void
jedec_print(FILE * fp,const char * desc,uint_t id)175 jedec_print(FILE *fp, const char *desc, uint_t id)
176 {
177 const char *name;
178 uint_t cont, vendor;
179
180 /*
181 * SMBIOS encodes data in the way that the underlying memory standard
182 * does. In this case, the upper byte indicates the vendor that we care
183 * about while the lower byte indicates the number of continuations that
184 * are needed. libjedec indexes this based on zero (e.g. table 1 is zero
185 * continuations), which is how the spec encodes it. We add one so that
186 * we can match how the spec describes it.
187 */
188 vendor = id >> 8;
189 cont = id & 0x7f;
190 name = libjedec_vendor_string(cont, vendor);
191 if (name == NULL) {
192 oprintf(fp, " %s: Bank: 0x%x Vendor: 0x%x\n", desc, cont + 1,
193 vendor);
194 } else {
195 oprintf(fp, " %s: Bank: 0x%x Vendor: 0x%x (%s)\n", desc,
196 cont + 1, vendor, name);
197 }
198 }
199
200 /*
201 * Convert an SMBIOS encoded JEDEDC component revision into its actual form. In
202 * general, JEDEC revisions are single byte values; however, the SMBIOS fields
203 * are two bytes wide. The byte that we care about is the "first" byte which
204 * translates into the upper bits here. The revision is binary coded decimal
205 * (BCD) represented with each nibble as major.minor. The major is the upper
206 * nibble and the minor is the lower one.
207 */
208 static void
jedec_rev_print(FILE * fp,const char * desc,uint16_t raw_rev)209 jedec_rev_print(FILE *fp, const char *desc, uint16_t raw_rev)
210 {
211 uint8_t rev = (uint8_t)bitx16(raw_rev, 15, 8);
212 uint8_t maj = bitx8(rev, 7, 4);
213 uint8_t min = bitx8(rev, 3, 0);
214 oprintf(fp, " %s: %x.%x\n", desc, maj, min);
215 }
216
217 /*
218 * Print a 128-bit data as a series of 16 hex digits.
219 */
220 static void
u128_print(FILE * fp,const char * desc,const uint8_t * data)221 u128_print(FILE *fp, const char *desc, const uint8_t *data)
222 {
223 uint_t i;
224
225 oprintf(fp, "%s: ", desc);
226 for (i = 0; i < 16; i++) {
227 oprintf(fp, " %02x", data[i]);
228 }
229 oprintf(fp, "\n");
230 }
231
232 /*
233 * Print a string that came from an SMBIOS table. We do this character by
234 * character so we can potentially escape strings.
235 */
236 static void
str_print_label(FILE * fp,const char * header,const char * str,boolean_t label)237 str_print_label(FILE *fp, const char *header, const char *str, boolean_t label)
238 {
239 const char *c;
240
241 oprintf(fp, header);
242 if (label) {
243 oprintf(fp, ": ");
244 }
245
246 for (c = str; *c != '\0'; c++) {
247 if (isprint(*c)) {
248 oprintf(fp, "%c", *c);
249 } else {
250 oprintf(fp, "\\x%02x", *c);
251 }
252 }
253
254 oprintf(fp, "\n");
255 }
256
257 static void
str_print_nolabel(FILE * fp,const char * ws,const char * str)258 str_print_nolabel(FILE *fp, const char *ws, const char *str)
259 {
260 return (str_print_label(fp, ws, str, B_FALSE));
261 }
262
263 static void
str_print(FILE * fp,const char * header,const char * str)264 str_print(FILE *fp, const char *header, const char *str)
265 {
266 return (str_print_label(fp, header, str, B_TRUE));
267 }
268
269 static int
check_oem(smbios_hdl_t * shp)270 check_oem(smbios_hdl_t *shp)
271 {
272 int i;
273 int cnt;
274 int rv;
275 id_t oem_id;
276 smbios_struct_t s;
277 const char **oem_str;
278
279 rv = smbios_lookup_type(shp, SMB_TYPE_OEMSTR, &s);
280 if (rv != 0) {
281 return (-1);
282 }
283
284 oem_id = s.smbstr_id;
285
286 cnt = smbios_info_strtab(shp, oem_id, 0, NULL);
287 if (cnt > 0) {
288 oem_str = alloca(sizeof (char *) * cnt);
289 (void) smbios_info_strtab(shp, oem_id, cnt, oem_str);
290
291 for (i = 0; i < cnt; i++) {
292 if (strncmp(oem_str[i], SMB_PRMS1,
293 strlen(SMB_PRMS1) + 1) == 0) {
294 return (0);
295 }
296 }
297 }
298
299 return (-1);
300 }
301
302 static void
print_smbios_21(smbios_21_entry_t * ep,FILE * fp)303 print_smbios_21(smbios_21_entry_t *ep, FILE *fp)
304 {
305 int i;
306
307 oprintf(fp, "Entry Point Anchor Tag: %*.*s\n",
308 (int)sizeof (ep->smbe_eanchor), (int)sizeof (ep->smbe_eanchor),
309 ep->smbe_eanchor);
310
311 oprintf(fp, "Entry Point Checksum: 0x%x\n", ep->smbe_ecksum);
312 oprintf(fp, "Entry Point Length: %u\n", ep->smbe_elen);
313 oprintf(fp, "Entry Point Version: %u.%u\n",
314 ep->smbe_major, ep->smbe_minor);
315 oprintf(fp, "Max Structure Size: %u\n", ep->smbe_maxssize);
316 oprintf(fp, "Entry Point Revision: 0x%x\n", ep->smbe_revision);
317
318 oprintf(fp, "Entry Point Revision Data:");
319 for (i = 0; i < sizeof (ep->smbe_format); i++)
320 oprintf(fp, " 0x%02x", ep->smbe_format[i]);
321 oprintf(fp, "\n");
322
323 oprintf(fp, "Intermediate Anchor Tag: %*.*s\n",
324 (int)sizeof (ep->smbe_ianchor), (int)sizeof (ep->smbe_ianchor),
325 ep->smbe_ianchor);
326
327 oprintf(fp, "Intermediate Checksum: 0x%x\n", ep->smbe_icksum);
328 oprintf(fp, "Structure Table Length: %u\n", ep->smbe_stlen);
329 oprintf(fp, "Structure Table Address: 0x%x\n", ep->smbe_staddr);
330 oprintf(fp, "Structure Table Entries: %u\n", ep->smbe_stnum);
331 oprintf(fp, "DMI BCD Revision: 0x%x\n", ep->smbe_bcdrev);
332 }
333
334 static void
print_smbios_30(smbios_30_entry_t * ep,FILE * fp)335 print_smbios_30(smbios_30_entry_t *ep, FILE *fp)
336 {
337 oprintf(fp, "Entry Point Anchor Tag: %*.*s\n",
338 (int)sizeof (ep->smbe_eanchor), (int)sizeof (ep->smbe_eanchor),
339 ep->smbe_eanchor);
340
341 oprintf(fp, "Entry Point Checksum: 0x%x\n", ep->smbe_ecksum);
342 oprintf(fp, "Entry Point Length: %u\n", ep->smbe_elen);
343 oprintf(fp, "SMBIOS Version: %u.%u\n",
344 ep->smbe_major, ep->smbe_minor);
345 oprintf(fp, "SMBIOS DocRev: 0x%x\n", ep->smbe_docrev);
346 oprintf(fp, "Entry Point Revision: 0x%x\n", ep->smbe_revision);
347
348 oprintf(fp, "Structure Table Length: %u\n", ep->smbe_stlen);
349 oprintf(fp, "Structure Table Address: 0x%" PRIx64 "\n",
350 ep->smbe_staddr);
351 }
352
353 static void
print_smbios(smbios_hdl_t * shp,FILE * fp)354 print_smbios(smbios_hdl_t *shp, FILE *fp)
355 {
356 smbios_entry_t ep;
357
358 switch (smbios_info_smbios(shp, &ep)) {
359 case SMBIOS_ENTRY_POINT_21:
360 print_smbios_21(&ep.ep21, fp);
361 break;
362 case SMBIOS_ENTRY_POINT_30:
363 print_smbios_30(&ep.ep30, fp);
364 break;
365 }
366 }
367
368 static void
print_common(const smbios_info_t * ip,FILE * fp)369 print_common(const smbios_info_t *ip, FILE *fp)
370 {
371 if (ip->smbi_manufacturer[0] != '\0')
372 str_print(fp, " Manufacturer", ip->smbi_manufacturer);
373 if (ip->smbi_product[0] != '\0')
374 str_print(fp, " Product", ip->smbi_product);
375 if (ip->smbi_version[0] != '\0')
376 str_print(fp, " Version", ip->smbi_version);
377 if (ip->smbi_serial[0] != '\0')
378 str_print(fp, " Serial Number", ip->smbi_serial);
379 if (ip->smbi_asset[0] != '\0')
380 str_print(fp, " Asset Tag", ip->smbi_asset);
381 if (ip->smbi_location[0] != '\0')
382 str_print(fp, " Location Tag", ip->smbi_location);
383 if (ip->smbi_part[0] != '\0')
384 str_print(fp, " Part Number", ip->smbi_part);
385 }
386
387 static void
print_bios(smbios_hdl_t * shp,FILE * fp)388 print_bios(smbios_hdl_t *shp, FILE *fp)
389 {
390 smbios_bios_t b;
391
392 if (smbios_info_bios(shp, &b) == -1) {
393 smbios_warn(shp, "failed to read BIOS information");
394 return;
395 }
396
397 str_print(fp, " Vendor", b.smbb_vendor);
398 str_print(fp, " Version String", b.smbb_version);
399 str_print(fp, " Release Date", b.smbb_reldate);
400 oprintf(fp, " Address Segment: 0x%x\n", b.smbb_segment);
401 oprintf(fp, " ROM Size: %" PRIu64 " bytes\n", b.smbb_extromsize);
402 oprintf(fp, " Image Size: %u bytes\n", b.smbb_runsize);
403
404 flag64_printf(fp, "Characteristics",
405 b.smbb_cflags, sizeof (b.smbb_cflags) * NBBY,
406 smbios_bios_flag_name, smbios_bios_flag_desc);
407
408 if (b.smbb_nxcflags > SMB_BIOSXB_1) {
409 flag_printf(fp, "Characteristics Extension Byte 1",
410 b.smbb_xcflags[SMB_BIOSXB_1],
411 sizeof (b.smbb_xcflags[SMB_BIOSXB_1]) * NBBY,
412 smbios_bios_xb1_name, smbios_bios_xb1_desc);
413 }
414
415 if (b.smbb_nxcflags > SMB_BIOSXB_2) {
416 flag_printf(fp, "Characteristics Extension Byte 2",
417 b.smbb_xcflags[SMB_BIOSXB_2],
418 sizeof (b.smbb_xcflags[SMB_BIOSXB_2]) * NBBY,
419 smbios_bios_xb2_name, smbios_bios_xb2_desc);
420 }
421
422 if (b.smbb_nxcflags > SMB_BIOSXB_BIOS_MIN) {
423 oprintf(fp, " Version Number: %u.%u\n",
424 b.smbb_biosv.smbv_major, b.smbb_biosv.smbv_minor);
425 }
426
427 /*
428 * If the major and minor versions are 0xff then that indicates that the
429 * embedded controller does not exist.
430 */
431 if (b.smbb_nxcflags > SMB_BIOSXB_ECFW_MIN &&
432 b.smbb_ecfwv.smbv_major != 0xff &&
433 b.smbb_ecfwv.smbv_minor != 0xff) {
434 oprintf(fp, " Embedded Ctlr Firmware Version Number: %u.%u\n",
435 b.smbb_ecfwv.smbv_major, b.smbb_ecfwv.smbv_minor);
436 }
437 }
438
439 static void
print_system(smbios_hdl_t * shp,FILE * fp)440 print_system(smbios_hdl_t *shp, FILE *fp)
441 {
442 smbios_system_t s;
443 uint_t i;
444
445 if (smbios_info_system(shp, &s) == -1) {
446 smbios_warn(shp, "failed to read system information");
447 return;
448 }
449
450 oprintf(fp, " UUID: ");
451 for (i = 0; i < s.smbs_uuidlen; i++) {
452 oprintf(fp, "%02x", s.smbs_uuid[i]);
453 if (i == 3 || i == 5 || i == 7 || i == 9)
454 oprintf(fp, "-");
455 }
456 oprintf(fp, "\n");
457
458 desc_printf(smbios_system_wakeup_desc(s.smbs_wakeup),
459 fp, " Wake-Up Event: 0x%x", s.smbs_wakeup);
460
461 str_print(fp, " SKU Number", s.smbs_sku);
462 str_print(fp, " Family", s.smbs_family);
463 }
464
465 static void
print_bboard(smbios_hdl_t * shp,id_t id,FILE * fp)466 print_bboard(smbios_hdl_t *shp, id_t id, FILE *fp)
467 {
468 smbios_bboard_t b;
469 int chdl_cnt;
470
471 if (smbios_info_bboard(shp, id, &b) != 0) {
472 smbios_warn(shp, "failed to read baseboard information");
473 return;
474 }
475
476 oprintf(fp, " Chassis: %u\n", (uint_t)b.smbb_chassis);
477
478 flag_printf(fp, "Flags", b.smbb_flags, sizeof (b.smbb_flags) * NBBY,
479 smbios_bboard_flag_name, smbios_bboard_flag_desc);
480
481 desc_printf(smbios_bboard_type_desc(b.smbb_type),
482 fp, " Board Type: 0x%x", b.smbb_type);
483
484 chdl_cnt = b.smbb_contn;
485 if (chdl_cnt != 0) {
486 id_t *chdl;
487 uint16_t hdl;
488 int i, n, cnt;
489
490 chdl = alloca(chdl_cnt * sizeof (id_t));
491 cnt = smbios_info_contains(shp, id, chdl_cnt, chdl);
492 if (cnt > SMB_CONT_MAX)
493 return;
494 n = MIN(chdl_cnt, cnt);
495
496 oprintf(fp, "\n");
497 for (i = 0; i < n; i++) {
498 hdl = (uint16_t)chdl[i];
499 oprintf(fp, " Contained Handle: %u\n", hdl);
500 }
501 }
502 }
503
504 static void
print_chassis(smbios_hdl_t * shp,id_t id,FILE * fp)505 print_chassis(smbios_hdl_t *shp, id_t id, FILE *fp)
506 {
507 smbios_chassis_t c;
508 smbios_chassis_entry_t *elts;
509 uint_t nelts, i;
510
511 if (smbios_info_chassis(shp, id, &c) != 0) {
512 smbios_warn(shp, "failed to read chassis information");
513 return;
514 }
515
516 oprintf(fp, " OEM Data: 0x%x\n", c.smbc_oemdata);
517 str_print(fp, " SKU Number",
518 c.smbc_sku[0] == '\0' ? "<unknown>" : c.smbc_sku);
519 oprintf(fp, " Lock Present: %s\n", c.smbc_lock ? "Y" : "N");
520
521 desc_printf(smbios_chassis_type_desc(c.smbc_type),
522 fp, " Chassis Type: 0x%x", c.smbc_type);
523
524 desc_printf(smbios_chassis_state_desc(c.smbc_bustate),
525 fp, " Boot-Up State: 0x%x", c.smbc_bustate);
526
527 desc_printf(smbios_chassis_state_desc(c.smbc_psstate),
528 fp, " Power Supply State: 0x%x", c.smbc_psstate);
529
530 desc_printf(smbios_chassis_state_desc(c.smbc_thstate),
531 fp, " Thermal State: 0x%x", c.smbc_thstate);
532
533 oprintf(fp, " Chassis Height: %uu\n", c.smbc_uheight);
534 oprintf(fp, " Power Cords: %u\n", c.smbc_cords);
535
536 oprintf(fp, " Element Records: %u\n", c.smbc_elems);
537
538 if (c.smbc_elems == 0) {
539 return;
540 }
541
542 if (smbios_info_chassis_elts(shp, id, &nelts, &elts) != 0) {
543 smbios_warn(shp, "failed to read chassis elements");
544 return;
545 }
546
547 oprintf(fp, "\n");
548
549 for (i = 0; i < nelts; i++) {
550 switch (elts[i].smbce_type) {
551 case SMB_CELT_BBOARD:
552 desc_printf(smbios_bboard_type_desc(elts[i].smbce_elt),
553 fp, " Contained SMBIOS Base Board Type: 0x%x",
554 elts[i].smbce_elt);
555 break;
556 case SMB_CELT_SMBIOS:
557 desc_printf(smbios_type_name(elts[i].smbce_elt), fp,
558 " Contained SMBIOS structure Type: %u",
559 elts[i].smbce_elt);
560 break;
561 default:
562 oprintf(fp, " Unknown contained Type: %u/%u\n",
563 elts[i].smbce_type, elts[i].smbce_elt);
564 break;
565 }
566 oprintf(fp, " Minimum number: %u\n", elts[i].smbce_min);
567 oprintf(fp, " Maximum number: %u\n", elts[i].smbce_max);
568 }
569 }
570
571 static void
print_processor(smbios_hdl_t * shp,id_t id,FILE * fp)572 print_processor(smbios_hdl_t *shp, id_t id, FILE *fp)
573 {
574 smbios_processor_t p;
575 uint_t status;
576
577 if (smbios_info_processor(shp, id, &p) != 0) {
578 smbios_warn(shp, "failed to read processor information");
579 return;
580 }
581 status = SMB_PRSTATUS_STATUS(p.smbp_status);
582
583 desc_printf(smbios_processor_family_desc(p.smbp_family),
584 fp, " Family: %u", p.smbp_family);
585
586 oprintf(fp, " CPUID: 0x%llx\n", (u_longlong_t)p.smbp_cpuid);
587
588 desc_printf(smbios_processor_type_desc(p.smbp_type),
589 fp, " Type: %u", p.smbp_type);
590
591 desc_printf(smbios_processor_upgrade_desc(p.smbp_upgrade),
592 fp, " Socket Upgrade: %u", p.smbp_upgrade);
593
594 oprintf(fp, " Socket Status: %s\n",
595 SMB_PRSTATUS_PRESENT(p.smbp_status) ?
596 "Populated" : "Not Populated");
597
598 desc_printf(smbios_processor_status_desc(status),
599 fp, " Processor Status: %u", status);
600
601 if (SMB_PRV_LEGACY(p.smbp_voltage)) {
602 oprintf(fp, " Supported Voltages:");
603 switch (p.smbp_voltage) {
604 case SMB_PRV_5V:
605 oprintf(fp, " 5.0V");
606 break;
607 case SMB_PRV_33V:
608 oprintf(fp, " 3.3V");
609 break;
610 case SMB_PRV_29V:
611 oprintf(fp, " 2.9V");
612 break;
613 }
614 oprintf(fp, "\n");
615 } else {
616 oprintf(fp, " Supported Voltages: %.1fV\n",
617 (float)SMB_PRV_VOLTAGE(p.smbp_voltage) / 10);
618 }
619
620 if (p.smbp_corecount != 0) {
621 oprintf(fp, " Core Count: %u\n", p.smbp_corecount);
622 } else {
623 oprintf(fp, " Core Count: Unknown\n");
624 }
625
626 if (p.smbp_coresenabled != 0) {
627 oprintf(fp, " Cores Enabled: %u\n", p.smbp_coresenabled);
628 } else {
629 oprintf(fp, " Cores Enabled: Unknown\n");
630 }
631
632 if (p.smbp_threadcount != 0) {
633 oprintf(fp, " Thread Count: %u\n", p.smbp_threadcount);
634 } else {
635 oprintf(fp, " Thread Count: Unknown\n");
636 }
637
638 if (p.smbp_cflags) {
639 flag_printf(fp, "Processor Characteristics",
640 p.smbp_cflags, sizeof (p.smbp_cflags) * NBBY,
641 smbios_processor_core_flag_name,
642 smbios_processor_core_flag_desc);
643 }
644
645 if (p.smbp_clkspeed != 0)
646 oprintf(fp, " External Clock Speed: %uMHz\n", p.smbp_clkspeed);
647 else
648 oprintf(fp, " External Clock Speed: Unknown\n");
649
650 if (p.smbp_maxspeed != 0)
651 oprintf(fp, " Maximum Speed: %uMHz\n", p.smbp_maxspeed);
652 else
653 oprintf(fp, " Maximum Speed: Unknown\n");
654
655 if (p.smbp_curspeed != 0)
656 oprintf(fp, " Current Speed: %uMHz\n", p.smbp_curspeed);
657 else
658 oprintf(fp, " Current Speed: Unknown\n");
659
660 id_printf(fp, " L1 Cache Handle: ", p.smbp_l1cache);
661 id_printf(fp, " L2 Cache Handle: ", p.smbp_l2cache);
662 id_printf(fp, " L3 Cache Handle: ", p.smbp_l3cache);
663
664 if (p.smbp_threadsenabled != 0) {
665 oprintf(fp, " Threads Enabled: %u\n", p.smbp_threadsenabled);
666 } else {
667 oprintf(fp, " Threads Enabled: Unknown\n");
668 }
669
670 /*
671 * The Socket Type string overlaps with the upgrade string. Only print
672 * something if we have a valid value.
673 */
674 if (*p.smbp_socktype != '\0') {
675 str_print(fp, " Socket Type", p.smbp_socktype);
676 }
677 }
678
679 static void
print_cache(smbios_hdl_t * shp,id_t id,FILE * fp)680 print_cache(smbios_hdl_t *shp, id_t id, FILE *fp)
681 {
682 smbios_cache_t c;
683
684 if (smbios_info_cache(shp, id, &c) != 0) {
685 smbios_warn(shp, "failed to read cache information");
686 return;
687 }
688
689 oprintf(fp, " Level: %u\n", c.smba_level);
690 oprintf(fp, " Maximum Installed Size: %" PRIu64 " bytes\n",
691 c.smba_maxsize2);
692
693 if (c.smba_size2 != 0) {
694 oprintf(fp, " Installed Size: %" PRIu64 " bytes\n",
695 c.smba_size2);
696 } else {
697 oprintf(fp, " Installed Size: Not Installed\n");
698 }
699
700 if (c.smba_speed != 0)
701 oprintf(fp, " Speed: %uns\n", c.smba_speed);
702 else
703 oprintf(fp, " Speed: Unknown\n");
704
705 flag_printf(fp, "Supported SRAM Types",
706 c.smba_stype, sizeof (c.smba_stype) * NBBY,
707 smbios_cache_ctype_name, smbios_cache_ctype_desc);
708
709 desc_printf(smbios_cache_ctype_desc(c.smba_ctype),
710 fp, " Current SRAM Type: 0x%x", c.smba_ctype);
711
712 desc_printf(smbios_cache_ecc_desc(c.smba_etype),
713 fp, " Error Correction Type: %u", c.smba_etype);
714
715 desc_printf(smbios_cache_logical_desc(c.smba_ltype),
716 fp, " Logical Cache Type: %u", c.smba_ltype);
717
718 desc_printf(smbios_cache_assoc_desc(c.smba_assoc),
719 fp, " Associativity: %u", c.smba_assoc);
720
721 desc_printf(smbios_cache_mode_desc(c.smba_mode),
722 fp, " Mode: %u", c.smba_mode);
723
724 desc_printf(smbios_cache_loc_desc(c.smba_location),
725 fp, " Location: %u", c.smba_location);
726
727 flag_printf(fp, "Flags", c.smba_flags, sizeof (c.smba_flags) * NBBY,
728 smbios_cache_flag_name, smbios_cache_flag_desc);
729 }
730
731 static void
print_port(smbios_hdl_t * shp,id_t id,FILE * fp)732 print_port(smbios_hdl_t *shp, id_t id, FILE *fp)
733 {
734 smbios_port_t p;
735
736 if (smbios_info_port(shp, id, &p) != 0) {
737 smbios_warn(shp, "failed to read port information");
738 return;
739 }
740
741 str_print(fp, " Internal Reference Designator", p.smbo_iref);
742 str_print(fp, " External Reference Designator", p.smbo_eref);
743
744 desc_printf(smbios_port_conn_desc(p.smbo_itype),
745 fp, " Internal Connector Type: %u", p.smbo_itype);
746
747 desc_printf(smbios_port_conn_desc(p.smbo_etype),
748 fp, " External Connector Type: %u", p.smbo_etype);
749
750 desc_printf(smbios_port_type_desc(p.smbo_ptype),
751 fp, " Port Type: %u", p.smbo_ptype);
752 }
753
754 static void
print_slot(smbios_hdl_t * shp,id_t id,FILE * fp)755 print_slot(smbios_hdl_t *shp, id_t id, FILE *fp)
756 {
757 smbios_slot_t s;
758 smbios_version_t v;
759
760 if (smbios_info_slot(shp, id, &s) != 0) {
761 smbios_warn(shp, "failed to read slot information");
762 return;
763 }
764 smbios_info_smbios_version(shp, &v);
765
766 str_print(fp, " Reference Designator", s.smbl_name);
767 oprintf(fp, " Slot ID: 0x%x\n", s.smbl_id);
768
769 desc_printf(smbios_slot_type_desc(s.smbl_type),
770 fp, " Type: 0x%x", s.smbl_type);
771
772 desc_printf(smbios_slot_width_desc(s.smbl_width),
773 fp, " Width: 0x%x", s.smbl_width);
774
775 desc_printf(smbios_slot_usage_desc(s.smbl_usage),
776 fp, " Usage: 0x%x", s.smbl_usage);
777
778 desc_printf(smbios_slot_length_desc(s.smbl_length),
779 fp, " Length: 0x%x", s.smbl_length);
780
781 flag_printf(fp, "Slot Characteristics 1",
782 s.smbl_ch1, sizeof (s.smbl_ch1) * NBBY,
783 smbios_slot_ch1_name, smbios_slot_ch1_desc);
784
785 flag_printf(fp, "Slot Characteristics 2",
786 s.smbl_ch2, sizeof (s.smbl_ch2) * NBBY,
787 smbios_slot_ch2_name, smbios_slot_ch2_desc);
788
789 if (check_oem(shp) != 0 && !smbios_vergteq(&v, 2, 6))
790 return;
791
792 oprintf(fp, " Segment Group: %u\n", s.smbl_sg);
793 oprintf(fp, " Bus Number: %u\n", s.smbl_bus);
794 oprintf(fp, " Device/Function Number: %u/%u\n", s.smbl_df >> 3,
795 s.smbl_df & 0x7);
796
797 if (s.smbl_dbw != 0) {
798 oprintf(fp, " Data Bus Width: %d\n", s.smbl_dbw);
799 }
800
801 if (s.smbl_npeers > 0) {
802 smbios_slot_peer_t *peer;
803 uint_t i, npeers;
804
805 if (smbios_info_slot_peers(shp, id, &npeers, &peer) != 0) {
806 smbios_warn(shp, "failed to read slot peer "
807 "information");
808 return;
809 }
810
811 for (i = 0; i < npeers; i++) {
812 oprintf(fp, " Slot Peer %u:\n", i);
813 oprintf(fp, " Segment group: %u\n",
814 peer[i].smblp_group);
815 oprintf(fp, " Bus/Device/Function: %u/%u/%u\n",
816 peer[i].smblp_bus, peer[i].smblp_device,
817 peer[i].smblp_function);
818 oprintf(fp, " Electrical width: %u\n",
819 peer[i].smblp_data_width);
820 }
821
822 smbios_info_slot_peers_free(shp, npeers, peer);
823 }
824
825 if (s.smbl_info != 0) {
826 if (s.smbl_type >= SMB_SLT_PCIE &&
827 s.smbl_type <= SMB_SLT_PCIEG6P) {
828 oprintf(fp, " PCIe Generation: %d\n", s.smbl_info);
829 } else {
830 oprintf(fp, " Slot Type: 0x%x\n", s.smbl_info);
831 }
832 }
833
834 if (s.smbl_pwidth != 0) {
835 desc_printf(smbios_slot_width_desc(s.smbl_pwidth),
836 fp, " Physical Width: 0x%x", s.smbl_pwidth);
837 }
838
839 if (s.smbl_pitch != 0) {
840 oprintf(fp, " Slot Pitch: %u.%u mm\n", s.smbl_pitch / 100,
841 s.smbl_pitch % 100);
842 }
843
844 /*
845 * The slot height was introduced in SMBIOS 3.5. However, a value of
846 * zero here does not mean that it is unknown, but rather that the
847 * concept is not applicable. Therefore we cannot use a standard check
848 * against zero for this and instead use the version.
849 */
850 if (smbios_vergteq(&v, 3, 5)) {
851 desc_printf(smbios_slot_height_desc(s.smbl_height), fp,
852 " Height: 0x%x", s.smbl_height);
853 } else {
854 oprintf(fp, " Height: unknown\n");
855 }
856 }
857
858 static void
print_obdevs_ext(smbios_hdl_t * shp,id_t id,FILE * fp)859 print_obdevs_ext(smbios_hdl_t *shp, id_t id, FILE *fp)
860 {
861 boolean_t enabled;
862 smbios_obdev_ext_t oe;
863 const char *type;
864
865 if (smbios_info_obdevs_ext(shp, id, &oe) != 0) {
866 smbios_warn(shp, "failed to read extended on-board devices "
867 "information");
868 return;
869 }
870
871 /*
872 * Bit 7 is always whether or not the device is enabled while bits 0:6
873 * are the actual device type.
874 */
875 enabled = oe.smboe_dtype >> 7;
876 type = smbios_onboard_ext_type_desc(oe.smboe_dtype & 0x7f);
877
878 str_print(fp, " Reference Designator", oe.smboe_name);
879 oprintf(fp, " Device Enabled: %s\n", enabled == B_TRUE ? "true" :
880 "false");
881 oprintf(fp, " Device Type: %s\n", type);
882 oprintf(fp, " Device Type Instance: %u\n", oe.smboe_dti);
883 oprintf(fp, " Segment Group Number: %u\n", oe.smboe_sg);
884 oprintf(fp, " Bus Number: %u\n", oe.smboe_bus);
885 oprintf(fp, " Device/Function Number: %u\n", oe.smboe_df);
886 }
887
888 static void
print_obdevs(smbios_hdl_t * shp,id_t id,FILE * fp)889 print_obdevs(smbios_hdl_t *shp, id_t id, FILE *fp)
890 {
891 smbios_obdev_t *argv;
892 int i, argc;
893
894 if ((argc = smbios_info_obdevs(shp, id, 0, NULL)) > 0) {
895 argv = alloca(sizeof (smbios_obdev_t) * argc);
896 if (smbios_info_obdevs(shp, id, argc, argv) == -1) {
897 smbios_warn(shp, "failed to read on-board device "
898 "information");
899 return;
900 }
901 for (i = 0; i < argc; i++)
902 str_print_nolabel(fp, " ", argv[i].smbd_name);
903 }
904 }
905
906 static void
print_strtab(smbios_hdl_t * shp,id_t id,FILE * fp)907 print_strtab(smbios_hdl_t *shp, id_t id, FILE *fp)
908 {
909 const char **argv;
910 int i, argc;
911
912 if ((argc = smbios_info_strtab(shp, id, 0, NULL)) > 0) {
913 argv = alloca(sizeof (char *) * argc);
914 if (smbios_info_strtab(shp, id, argc, argv) == -1) {
915 smbios_warn(shp, "failed to read string table "
916 "information");
917 return;
918 }
919 for (i = 0; i < argc; i++)
920 str_print_nolabel(fp, " ", argv[i]);
921 }
922 }
923
924 static void
print_lang(smbios_hdl_t * shp,id_t id,FILE * fp)925 print_lang(smbios_hdl_t *shp, id_t id, FILE *fp)
926 {
927 smbios_lang_t l;
928
929 if (smbios_info_lang(shp, &l) == -1) {
930 smbios_warn(shp, "failed to read language information");
931 return;
932 }
933
934 str_print(fp, " Current Language", l.smbla_cur);
935 oprintf(fp, " Language String Format: %u\n", l.smbla_fmt);
936 oprintf(fp, " Number of Installed Languages: %u\n", l.smbla_num);
937 oprintf(fp, " Installed Languages:\n");
938
939 print_strtab(shp, id, fp);
940 }
941
942 /*ARGSUSED*/
943 static void
print_evlog(smbios_hdl_t * shp,id_t id,FILE * fp)944 print_evlog(smbios_hdl_t *shp, id_t id, FILE *fp)
945 {
946 smbios_evlog_t ev;
947 uint32_t i;
948
949 if (smbios_info_eventlog(shp, &ev) == -1) {
950 smbios_warn(shp, "failed to read event log information");
951 return;
952 }
953
954 oprintf(fp, " Log Area Size: %lu bytes\n", (ulong_t)ev.smbev_size);
955 oprintf(fp, " Header Offset: %lu\n", (ulong_t)ev.smbev_hdr);
956 oprintf(fp, " Data Offset: %lu\n", (ulong_t)ev.smbev_data);
957
958 desc_printf(smbios_evlog_method_desc(ev.smbev_method),
959 fp, " Data Access Method: %u", ev.smbev_method);
960
961 flag_printf(fp, "Log Flags",
962 ev.smbev_flags, sizeof (ev.smbev_flags) * NBBY,
963 smbios_evlog_flag_name, smbios_evlog_flag_desc);
964
965 desc_printf(smbios_evlog_format_desc(ev.smbev_format),
966 fp, " Log Header Format: %u", ev.smbev_format);
967
968 oprintf(fp, " Update Token: 0x%x\n", ev.smbev_token);
969 oprintf(fp, " Data Access Address: ");
970
971 switch (ev.smbev_method) {
972 case SMB_EVM_1x1i_1x1d:
973 case SMB_EVM_2x1i_1x1d:
974 case SMB_EVM_1x2i_1x1d:
975 oprintf(fp, "Index Address 0x%x, Data Address 0x%x\n",
976 ev.smbev_addr.eva_io.evi_iaddr,
977 ev.smbev_addr.eva_io.evi_daddr);
978 break;
979 case SMB_EVM_GPNV:
980 oprintf(fp, "0x%x\n", ev.smbev_addr.eva_gpnv);
981 break;
982 default:
983 oprintf(fp, "0x%x\n", ev.smbev_addr.eva_addr);
984 }
985
986 oprintf(fp, " Type Descriptors:\n");
987
988 for (i = 0; i < ev.smbev_typec; i++) {
989 oprintf(fp, " %u: Log Type 0x%x, Data Type 0x%x\n", i,
990 ev.smbev_typev[i].smbevt_ltype,
991 ev.smbev_typev[i].smbevt_dtype);
992 }
993 }
994
995 static void
print_bytes(const uint8_t * data,size_t size,FILE * fp)996 print_bytes(const uint8_t *data, size_t size, FILE *fp)
997 {
998 hexdump_t h;
999
1000 hexdump_init(&h);
1001 hexdump_set_grouping(&h, 4);
1002 hexdump_set_indent(&h, 2);
1003
1004 (void) fprintf(fp, "\n");
1005 (void) hexdump_fileh(&h, data, size, HDF_DEFAULT, fp);
1006 (void) fprintf(fp, "\n");
1007
1008 hexdump_fini(&h);
1009 }
1010
1011 static void
print_memarray(smbios_hdl_t * shp,id_t id,FILE * fp)1012 print_memarray(smbios_hdl_t *shp, id_t id, FILE *fp)
1013 {
1014 smbios_memarray_t ma;
1015
1016 if (smbios_info_memarray(shp, id, &ma) != 0) {
1017 smbios_warn(shp, "failed to read memarray information");
1018 return;
1019 }
1020
1021 desc_printf(smbios_memarray_loc_desc(ma.smbma_location),
1022 fp, " Location: %u", ma.smbma_location);
1023
1024 desc_printf(smbios_memarray_use_desc(ma.smbma_use),
1025 fp, " Use: %u", ma.smbma_use);
1026
1027 desc_printf(smbios_memarray_ecc_desc(ma.smbma_ecc),
1028 fp, " ECC: %u", ma.smbma_ecc);
1029
1030 oprintf(fp, " Number of Slots/Sockets: %u\n", ma.smbma_ndevs);
1031 id_printf(fp, " Memory Error Data: ", ma.smbma_err);
1032 oprintf(fp, " Max Capacity: %llu bytes\n",
1033 (u_longlong_t)ma.smbma_size);
1034 }
1035
1036 static void
print_memdevice(smbios_hdl_t * shp,id_t id,FILE * fp)1037 print_memdevice(smbios_hdl_t *shp, id_t id, FILE *fp)
1038 {
1039 smbios_memdevice_t md;
1040
1041 if (smbios_info_memdevice(shp, id, &md) != 0) {
1042 smbios_warn(shp, "failed to read memory device information");
1043 return;
1044 }
1045
1046 id_printf(fp, " Physical Memory Array: ", md.smbmd_array);
1047 id_printf(fp, " Memory Error Data: ", md.smbmd_error);
1048
1049 if (md.smbmd_twidth != -1u)
1050 oprintf(fp, " Total Width: %u bits\n", md.smbmd_twidth);
1051 else
1052 oprintf(fp, " Total Width: Unknown\n");
1053
1054 if (md.smbmd_dwidth != -1u)
1055 oprintf(fp, " Data Width: %u bits\n", md.smbmd_dwidth);
1056 else
1057 oprintf(fp, " Data Width: Unknown\n");
1058
1059 switch (md.smbmd_size) {
1060 case -1ull:
1061 oprintf(fp, " Size: Unknown\n");
1062 break;
1063 case 0:
1064 oprintf(fp, " Size: Not Populated\n");
1065 break;
1066 default:
1067 oprintf(fp, " Size: %llu bytes\n",
1068 (u_longlong_t)md.smbmd_size);
1069 }
1070
1071 desc_printf(smbios_memdevice_form_desc(md.smbmd_form),
1072 fp, " Form Factor: %u", md.smbmd_form);
1073
1074 if (md.smbmd_set == 0)
1075 oprintf(fp, " Set: None\n");
1076 else if (md.smbmd_set == (uint8_t)-1u)
1077 oprintf(fp, " Set: Unknown\n");
1078 else
1079 oprintf(fp, " Set: %u\n", md.smbmd_set);
1080
1081 if (md.smbmd_rank != 0) {
1082 desc_printf(smbios_memdevice_rank_desc(md.smbmd_rank),
1083 fp, " Rank: %u", md.smbmd_rank);
1084 } else {
1085 oprintf(fp, " Rank: Unknown\n");
1086 }
1087
1088 desc_printf(smbios_memdevice_type_desc(md.smbmd_type),
1089 fp, " Memory Type: %u", md.smbmd_type);
1090
1091 flag_printf(fp, "Flags", md.smbmd_flags, sizeof (md.smbmd_flags) * NBBY,
1092 smbios_memdevice_flag_name, smbios_memdevice_flag_desc);
1093
1094 if (md.smbmd_extspeed != 0) {
1095 oprintf(fp, " Speed: %" PRIu64 " MT/s\n", md.smbmd_extspeed);
1096 } else {
1097 oprintf(fp, " Speed: Unknown\n");
1098 }
1099
1100 if (md.smbmd_extclkspeed != 0) {
1101 oprintf(fp, " Configured Speed: %" PRIu64 " MT/s\n",
1102 md.smbmd_extclkspeed);
1103 } else {
1104 oprintf(fp, " Configured Speed: Unknown\n");
1105 }
1106
1107 str_print(fp, " Device Locator", md.smbmd_dloc);
1108 str_print(fp, " Bank Locator", md.smbmd_bloc);
1109
1110 if (md.smbmd_minvolt != 0) {
1111 oprintf(fp, " Minimum Voltage: %.2fV\n",
1112 md.smbmd_minvolt / 1000.0);
1113 } else {
1114 oprintf(fp, " Minimum Voltage: Unknown\n");
1115 }
1116
1117 if (md.smbmd_maxvolt != 0) {
1118 oprintf(fp, " Maximum Voltage: %.2fV\n",
1119 md.smbmd_maxvolt / 1000.0);
1120 } else {
1121 oprintf(fp, " Maximum Voltage: Unknown\n");
1122 }
1123
1124 if (md.smbmd_confvolt != 0) {
1125 oprintf(fp, " Configured Voltage: %.2fV\n",
1126 md.smbmd_confvolt / 1000.0);
1127 } else {
1128 oprintf(fp, " Configured Voltage: Unknown\n");
1129 }
1130
1131 if (md.smbmd_memtech != 0) {
1132 desc_printf(smbios_memdevice_memtech_desc(md.smbmd_memtech),
1133 fp, " Memory Technology: %u", md.smbmd_memtech);
1134 }
1135
1136 if (md.smbmd_opcap_flags != 0) {
1137 flag_printf(fp, "Operating Mode Capabilities",
1138 md.smbmd_opcap_flags, sizeof (md.smbmd_opcap_flags) * NBBY,
1139 smbios_memdevice_op_capab_name,
1140 smbios_memdevice_op_capab_desc);
1141 }
1142
1143 if (md.smbmd_firmware_rev[0] != '\0') {
1144 str_print(fp, " Firmware Revision", md.smbmd_firmware_rev);
1145 }
1146
1147 if (md.smbmd_modmfg_id != SMB_MD_MFG_UNKNOWN) {
1148 jedec_print(fp, "Module Manufacturer ID", md.smbmd_modmfg_id);
1149 }
1150
1151 if (md.smbmd_modprod_id != 0) {
1152 jedec_print(fp, "Module Product ID", md.smbmd_modprod_id);
1153 }
1154
1155 if (md.smbmd_cntrlmfg_id != SMB_MD_MFG_UNKNOWN) {
1156 jedec_print(fp, "Memory Subsystem Controller Manufacturer ID",
1157 md.smbmd_cntrlmfg_id);
1158 }
1159
1160 if (md.smbmd_cntrlprod_id != 0) {
1161 jedec_print(fp, "Memory Subsystem Controller Product ID",
1162 md.smbmd_cntrlprod_id);
1163 }
1164
1165 if (md.smbmd_nvsize == UINT64_MAX) {
1166 oprintf(fp, " Non-volatile Size: Unknown\n");
1167 } else if (md.smbmd_nvsize != 0) {
1168 oprintf(fp, " Non-volatile Size: %llu bytes\n",
1169 (u_longlong_t)md.smbmd_nvsize);
1170 }
1171
1172 if (md.smbmd_volatile_size == UINT64_MAX) {
1173 oprintf(fp, " Volatile Size: Unknown\n");
1174 } else if (md.smbmd_volatile_size != 0) {
1175 oprintf(fp, " Volatile Size: %llu bytes\n",
1176 (u_longlong_t)md.smbmd_volatile_size);
1177 }
1178
1179 if (md.smbmd_cache_size == UINT64_MAX) {
1180 oprintf(fp, " Cache Size: Unknown\n");
1181 } else if (md.smbmd_cache_size != 0) {
1182 oprintf(fp, " Cache Size: %llu bytes\n",
1183 (u_longlong_t)md.smbmd_cache_size);
1184 }
1185
1186 if (md.smbmd_logical_size == UINT64_MAX) {
1187 oprintf(fp, " Logical Size: Unknown\n");
1188 } else if (md.smbmd_logical_size != 0) {
1189 oprintf(fp, " Logical Size: %llu bytes\n",
1190 (u_longlong_t)md.smbmd_logical_size);
1191 }
1192
1193 if (md.smbmd_pmic0_mfgid != SMB_MD_MFG_UNKNOWN) {
1194 jedec_print(fp, "PMIC0 Manufacturer ID", md.smbmd_pmic0_mfgid);
1195 }
1196
1197 if (md.smbmd_pmic0_rev != SMB_MD_REV_UNKNOWN) {
1198 jedec_rev_print(fp, "PMIC0 Revision", md.smbmd_pmic0_rev);
1199 }
1200
1201 if (md.smbmd_rcd_mfgid != SMB_MD_MFG_UNKNOWN) {
1202 jedec_print(fp, "RCD Manufacturer ID", md.smbmd_rcd_mfgid);
1203 }
1204
1205 if (md.smbmd_rcd_rev != SMB_MD_REV_UNKNOWN) {
1206 jedec_rev_print(fp, "RCD Revision", md.smbmd_rcd_rev);
1207 }
1208 }
1209
1210 static void
print_memarrmap(smbios_hdl_t * shp,id_t id,FILE * fp)1211 print_memarrmap(smbios_hdl_t *shp, id_t id, FILE *fp)
1212 {
1213 smbios_memarrmap_t ma;
1214
1215 if (smbios_info_memarrmap(shp, id, &ma) != 0) {
1216 smbios_warn(shp, "failed to read memory array map information");
1217 return;
1218 }
1219
1220 id_printf(fp, " Physical Memory Array: ", ma.smbmam_array);
1221 oprintf(fp, " Devices per Row: %u\n", ma.smbmam_width);
1222
1223 oprintf(fp, " Physical Address: 0x%llx\n Size: %llu bytes\n",
1224 (u_longlong_t)ma.smbmam_addr, (u_longlong_t)ma.smbmam_size);
1225 }
1226
1227 static void
print_memdevmap(smbios_hdl_t * shp,id_t id,FILE * fp)1228 print_memdevmap(smbios_hdl_t *shp, id_t id, FILE *fp)
1229 {
1230 smbios_memdevmap_t md;
1231
1232 if (smbios_info_memdevmap(shp, id, &md) != 0) {
1233 smbios_warn(shp, "failed to read memory device map "
1234 "information");
1235 return;
1236 }
1237
1238 id_printf(fp, " Memory Device: ", md.smbmdm_device);
1239 id_printf(fp, " Memory Array Mapped Address: ", md.smbmdm_arrmap);
1240
1241 oprintf(fp, " Physical Address: 0x%llx\n Size: %llu bytes\n",
1242 (u_longlong_t)md.smbmdm_addr, (u_longlong_t)md.smbmdm_size);
1243
1244 oprintf(fp, " Partition Row Position: %u\n", md.smbmdm_rpos);
1245 oprintf(fp, " Interleave Position: %u\n", md.smbmdm_ipos);
1246 oprintf(fp, " Interleave Data Depth: %u\n", md.smbmdm_idepth);
1247 }
1248
1249 static void
print_hwsec(smbios_hdl_t * shp,FILE * fp)1250 print_hwsec(smbios_hdl_t *shp, FILE *fp)
1251 {
1252 smbios_hwsec_t h;
1253
1254 if (smbios_info_hwsec(shp, &h) == -1) {
1255 smbios_warn(shp, "failed to read hwsec information");
1256 return;
1257 }
1258
1259 desc_printf(smbios_hwsec_desc(h.smbh_pwr_ps),
1260 fp, " Power-On Password Status: %u", h.smbh_pwr_ps);
1261 desc_printf(smbios_hwsec_desc(h.smbh_kbd_ps),
1262 fp, " Keyboard Password Status: %u", h.smbh_kbd_ps);
1263 desc_printf(smbios_hwsec_desc(h.smbh_adm_ps),
1264 fp, " Administrator Password Status: %u", h.smbh_adm_ps);
1265 desc_printf(smbios_hwsec_desc(h.smbh_pan_ps),
1266 fp, " Front Panel Reset Status: %u", h.smbh_pan_ps);
1267 }
1268
1269 static void
print_vprobe(smbios_hdl_t * shp,id_t id,FILE * fp)1270 print_vprobe(smbios_hdl_t *shp, id_t id, FILE *fp)
1271 {
1272 smbios_vprobe_t vp;
1273
1274 if (smbios_info_vprobe(shp, id, &vp) != 0) {
1275 smbios_warn(shp, "failed to read voltage probe information");
1276 return;
1277 }
1278
1279 str_print(fp, " Description", vp.smbvp_description != NULL ?
1280 vp.smbvp_description : "unknown");
1281 desc_printf(smbios_vprobe_loc_desc(vp.smbvp_location),
1282 fp, " Location: %u", vp.smbvp_location);
1283 desc_printf(smbios_vprobe_status_desc(vp.smbvp_status),
1284 fp, " Status: %u", vp.smbvp_status);
1285
1286 if (vp.smbvp_maxval != SMB_PROBE_UNKNOWN_VALUE) {
1287 oprintf(fp, " Maximum Possible Voltage: %u mV\n",
1288 vp.smbvp_maxval);
1289 } else {
1290 oprintf(fp, " Maximum Possible Voltage: unknown\n");
1291 }
1292
1293 if (vp.smbvp_minval != SMB_PROBE_UNKNOWN_VALUE) {
1294 oprintf(fp, " Minimum Possible Voltage: %u mV\n",
1295 vp.smbvp_minval);
1296 } else {
1297 oprintf(fp, " Minimum Possible Voltage: unknown\n");
1298 }
1299
1300 if (vp.smbvp_resolution != SMB_PROBE_UNKNOWN_VALUE) {
1301 oprintf(fp, " Probe Resolution: %u.%u mV\n",
1302 vp.smbvp_resolution / 10,
1303 vp.smbvp_resolution % 10);
1304 } else {
1305 oprintf(fp, " Probe Resolution: unknown\n");
1306 }
1307
1308 if (vp.smbvp_tolerance != SMB_PROBE_UNKNOWN_VALUE) {
1309 oprintf(fp, " Probe Tolerance: +/-%u mV\n",
1310 vp.smbvp_tolerance);
1311 } else {
1312 oprintf(fp, " Probe Tolerance: unknown\n");
1313 }
1314
1315 if (vp.smbvp_accuracy != SMB_PROBE_UNKNOWN_VALUE) {
1316 oprintf(fp, " Probe Accuracy: +/-%u.%02u%%\n",
1317 vp.smbvp_accuracy / 100,
1318 vp.smbvp_accuracy % 100);
1319 } else {
1320 oprintf(fp, " Probe Accuracy: unknown\n");
1321 }
1322
1323 oprintf(fp, " OEM- or BIOS- defined value: 0x%x\n", vp.smbvp_oem);
1324
1325 if (vp.smbvp_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1326 oprintf(fp, " Probe Nominal Value: %u mV\n", vp.smbvp_nominal);
1327 } else {
1328 oprintf(fp, " Probe Nominal Value: unknown\n");
1329 }
1330 }
1331
1332 static void
print_cooldev(smbios_hdl_t * shp,id_t id,FILE * fp)1333 print_cooldev(smbios_hdl_t *shp, id_t id, FILE *fp)
1334 {
1335 smbios_cooldev_t cd;
1336
1337 if (smbios_info_cooldev(shp, id, &cd) != 0) {
1338 smbios_warn(shp, "failed to read cooling device "
1339 "information");
1340 return;
1341 }
1342
1343 id_printf(fp, " Temperature Probe Handle: ", cd.smbcd_tprobe);
1344 desc_printf(smbios_cooldev_type_desc(cd.smbcd_type),
1345 fp, " Device Type: %u", cd.smbcd_type);
1346 desc_printf(smbios_cooldev_status_desc(cd.smbcd_status),
1347 fp, " Status: %u", cd.smbcd_status);
1348 oprintf(fp, " Cooling Unit Group: %u\n", cd.smbcd_group);
1349 oprintf(fp, " OEM- or BIOS- defined data: 0x%x\n", cd.smbcd_oem);
1350 if (cd.smbcd_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1351 oprintf(fp, " Nominal Speed: %u RPM\n", cd.smbcd_nominal);
1352 } else {
1353 oprintf(fp, " Nominal Speed: unknown\n");
1354 }
1355
1356 if (cd.smbcd_descr != NULL && cd.smbcd_descr[0] != '\0') {
1357 str_print(fp, " Description", cd.smbcd_descr);
1358 }
1359 }
1360
1361 static void
print_tprobe(smbios_hdl_t * shp,id_t id,FILE * fp)1362 print_tprobe(smbios_hdl_t *shp, id_t id, FILE *fp)
1363 {
1364 smbios_tprobe_t tp;
1365
1366 if (smbios_info_tprobe(shp, id, &tp) != 0) {
1367 smbios_warn(shp, "failed to read temperature probe "
1368 "information");
1369 return;
1370 }
1371
1372 str_print(fp, " Description", tp.smbtp_description != NULL ?
1373 tp.smbtp_description : "unknown");
1374 desc_printf(smbios_tprobe_loc_desc(tp.smbtp_location),
1375 fp, " Location: %u", tp.smbtp_location);
1376 desc_printf(smbios_tprobe_status_desc(tp.smbtp_status),
1377 fp, " Status: %u", tp.smbtp_status);
1378
1379 if (tp.smbtp_maxval != SMB_PROBE_UNKNOWN_VALUE) {
1380 oprintf(fp, " Maximum Possible Temperature: %u.%u C\n",
1381 tp.smbtp_maxval / 10, tp.smbtp_maxval % 10);
1382 } else {
1383 oprintf(fp, " Maximum Possible Temperature: unknown\n");
1384 }
1385
1386 if (tp.smbtp_minval != SMB_PROBE_UNKNOWN_VALUE) {
1387 oprintf(fp, " Minimum Possible Temperature: %u.%u C\n",
1388 tp.smbtp_minval / 10, tp.smbtp_minval % 10);
1389 } else {
1390 oprintf(fp, " Minimum Possible Temperature: unknown\n");
1391 }
1392
1393 if (tp.smbtp_resolution != SMB_PROBE_UNKNOWN_VALUE) {
1394 oprintf(fp, " Probe Resolution: %u.%03u C\n",
1395 tp.smbtp_resolution / 1000,
1396 tp.smbtp_resolution % 1000);
1397 } else {
1398 oprintf(fp, " Probe Resolution: unknown\n");
1399 }
1400
1401 if (tp.smbtp_tolerance != SMB_PROBE_UNKNOWN_VALUE) {
1402 oprintf(fp, " Probe Tolerance: +/-%u.%u C\n",
1403 tp.smbtp_tolerance / 10, tp.smbtp_tolerance % 10);
1404 } else {
1405 oprintf(fp, " Probe Tolerance: unknown\n");
1406 }
1407
1408 if (tp.smbtp_accuracy != SMB_PROBE_UNKNOWN_VALUE) {
1409 oprintf(fp, " Probe Accuracy: +/-%u.%02u%%\n",
1410 tp.smbtp_accuracy / 100,
1411 tp.smbtp_accuracy % 100);
1412 } else {
1413 oprintf(fp, " Probe Accuracy: unknown\n");
1414 }
1415
1416 oprintf(fp, " OEM- or BIOS- defined value: 0x%x\n", tp.smbtp_oem);
1417
1418 if (tp.smbtp_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1419 oprintf(fp, " Probe Nominal Value: %u.%u C\n",
1420 tp.smbtp_nominal / 10, tp.smbtp_nominal % 10);
1421 } else {
1422 oprintf(fp, " Probe Nominal Value: unknown\n");
1423 }
1424 }
1425
1426 static void
print_iprobe(smbios_hdl_t * shp,id_t id,FILE * fp)1427 print_iprobe(smbios_hdl_t *shp, id_t id, FILE *fp)
1428 {
1429 smbios_iprobe_t ip;
1430
1431 if (smbios_info_iprobe(shp, id, &ip) != 0) {
1432 smbios_warn(shp, "failed to read current probe information");
1433 return;
1434 }
1435
1436 str_print(fp, " Description", ip.smbip_description != NULL ?
1437 ip.smbip_description : "unknown");
1438 desc_printf(smbios_iprobe_loc_desc(ip.smbip_location),
1439 fp, " Location: %u", ip.smbip_location);
1440 desc_printf(smbios_iprobe_status_desc(ip.smbip_status),
1441 fp, " Status: %u", ip.smbip_status);
1442
1443 if (ip.smbip_maxval != SMB_PROBE_UNKNOWN_VALUE) {
1444 oprintf(fp, " Maximum Possible Current: %u mA\n",
1445 ip.smbip_maxval);
1446 } else {
1447 oprintf(fp, " Maximum Possible Current: unknown\n");
1448 }
1449
1450 if (ip.smbip_minval != SMB_PROBE_UNKNOWN_VALUE) {
1451 oprintf(fp, " Minimum Possible Current: %u mA\n",
1452 ip.smbip_minval);
1453 } else {
1454 oprintf(fp, " Minimum Possible Current: unknown\n");
1455 }
1456
1457 if (ip.smbip_resolution != SMB_PROBE_UNKNOWN_VALUE) {
1458 oprintf(fp, " Probe Resolution: %u.%u mA\n",
1459 ip.smbip_resolution / 10,
1460 ip.smbip_resolution % 10);
1461 } else {
1462 oprintf(fp, " Probe Resolution: unknown\n");
1463 }
1464
1465 if (ip.smbip_tolerance != SMB_PROBE_UNKNOWN_VALUE) {
1466 oprintf(fp, " Probe Tolerance: +/-%u mA\n",
1467 ip.smbip_tolerance);
1468 } else {
1469 oprintf(fp, " Probe Tolerance: unknown\n");
1470 }
1471
1472 if (ip.smbip_accuracy != SMB_PROBE_UNKNOWN_VALUE) {
1473 oprintf(fp, " Probe Accuracy: +/-%u.%02u%%\n",
1474 ip.smbip_accuracy / 100,
1475 ip.smbip_accuracy % 100);
1476 } else {
1477 oprintf(fp, " Probe Accuracy: unknown\n");
1478 }
1479
1480 oprintf(fp, " OEM- or BIOS- defined value: 0x%x\n", ip.smbip_oem);
1481
1482 if (ip.smbip_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1483 oprintf(fp, " Probe Nominal Value: %u mA\n", ip.smbip_nominal);
1484 } else {
1485 oprintf(fp, " Probe Nominal Value: unknown\n");
1486 }
1487 }
1488
1489 static void
print_boot(smbios_hdl_t * shp,FILE * fp)1490 print_boot(smbios_hdl_t *shp, FILE *fp)
1491 {
1492 smbios_boot_t b;
1493
1494 if (smbios_info_boot(shp, &b) == -1) {
1495 smbios_warn(shp, "failed to read boot information");
1496 return;
1497 }
1498
1499 desc_printf(smbios_boot_desc(b.smbt_status),
1500 fp, " Boot Status Code: 0x%x", b.smbt_status);
1501
1502 if (b.smbt_size != 0) {
1503 oprintf(fp, " Boot Data (%lu bytes):\n", (ulong_t)b.smbt_size);
1504 print_bytes(b.smbt_data, b.smbt_size, fp);
1505 }
1506 }
1507
1508 static void
print_ipmi(smbios_hdl_t * shp,FILE * fp)1509 print_ipmi(smbios_hdl_t *shp, FILE *fp)
1510 {
1511 smbios_ipmi_t i;
1512
1513 if (smbios_info_ipmi(shp, &i) == -1) {
1514 smbios_warn(shp, "failed to read ipmi information");
1515 return;
1516 }
1517
1518 desc_printf(smbios_ipmi_type_desc(i.smbip_type),
1519 fp, " Type: %u", i.smbip_type);
1520
1521 oprintf(fp, " BMC IPMI Version: %u.%u\n",
1522 i.smbip_vers.smbv_major, i.smbip_vers.smbv_minor);
1523
1524 oprintf(fp, " i2c Bus Slave Address: 0x%x\n", i.smbip_i2c);
1525 oprintf(fp, " NV Storage Device Bus ID: 0x%x\n", i.smbip_bus);
1526 oprintf(fp, " BMC Base Address: 0x%llx\n", (u_longlong_t)i.smbip_addr);
1527 oprintf(fp, " Interrupt Number: %u\n", i.smbip_intr);
1528 oprintf(fp, " Register Spacing: %u\n", i.smbip_regspacing);
1529
1530 flag_printf(fp, "Flags", i.smbip_flags, sizeof (i.smbip_flags) * NBBY,
1531 smbios_ipmi_flag_name, smbios_ipmi_flag_desc);
1532 }
1533
1534 static void
print_powersup(smbios_hdl_t * shp,id_t id,FILE * fp)1535 print_powersup(smbios_hdl_t *shp, id_t id, FILE *fp)
1536 {
1537 smbios_powersup_t p;
1538
1539 if (smbios_info_powersup(shp, id, &p) != 0) {
1540 smbios_warn(shp, "failed to read power supply information");
1541 return;
1542 }
1543
1544 oprintf(fp, " Power Supply Group: %u\n", p.smbps_group);
1545 if (p.smbps_maxout != 0x8000) {
1546 oprintf(fp, " Maximum Output: %" PRIu64 " mW\n",
1547 p.smbps_maxout);
1548 } else {
1549 oprintf(fp, " Maximum Output: unknown\n");
1550 }
1551
1552 flag_printf(fp, "Characteristics", p.smbps_flags,
1553 sizeof (p.smbps_flags) * NBBY, smbios_powersup_flag_name,
1554 smbios_powersup_flag_desc);
1555
1556 desc_printf(smbios_powersup_input_desc(p.smbps_ivrs),
1557 fp, " Input Voltage Range Switching: %u", p.smbps_ivrs);
1558 desc_printf(smbios_powersup_status_desc(p.smbps_status),
1559 fp, " Status: %u", p.smbps_status);
1560 desc_printf(smbios_powersup_type_desc(p.smbps_pstype),
1561 fp, " Type: %u", p.smbps_pstype);
1562
1563 if (p.smbps_vprobe != 0xffff) {
1564 oprintf(fp, " Voltage Probe Handle: %" _PRIuID "\n",
1565 p.smbps_vprobe);
1566 }
1567
1568 if (p.smbps_cooldev != 0xffff) {
1569 oprintf(fp, " Cooling Device Handle: %" _PRIuID "\n",
1570 p.smbps_cooldev);
1571 }
1572
1573 if (p.smbps_iprobe != 0xffff) {
1574 oprintf(fp, " Current Probe Handle: %" _PRIuID "\n",
1575 p.smbps_iprobe);
1576 }
1577 }
1578
1579 static void
print_addinfo(smbios_hdl_t * shp,id_t id,FILE * fp)1580 print_addinfo(smbios_hdl_t *shp, id_t id, FILE *fp)
1581 {
1582 uint_t nents, i;
1583
1584 if (smbios_info_addinfo_nents(shp, id, &nents) != 0) {
1585 smbios_warn(shp, "failed to read additional information");
1586 return;
1587 }
1588
1589 oprintf(fp, " Number of Additional Information Entries: %u\n", nents);
1590 for (i = 0; i < nents; i++) {
1591 smbios_addinfo_ent_t *ent;
1592
1593 oprintf(fp, " Additional Information Entry %u\n", i);
1594 if (smbios_info_addinfo_ent(shp, id, i, &ent) != 0) {
1595 smbios_warn(shp, "failed to read additional "
1596 "information entry %u", i);
1597 continue;
1598 }
1599
1600 oprintf(fp, " Referenced handle: %" _PRIuID "\n",
1601 ent->smbai_ref);
1602 oprintf(fp, " Handle offset: %u\n", ent->smbai_ref_off);
1603 if (ent->smbai_str != NULL) {
1604 str_print(fp, " Information String", ent->smbai_str);
1605 }
1606
1607 /*
1608 * As of SMBIOS 3.7, there are no extra data entries strictly
1609 * defined in the spec, but there may be something. If we find
1610 * something that's a standard integer size, then we'll
1611 * interpret it and print it as a hex value. In theory this is
1612 * supposed to refer back to some field, but hard to say how
1613 * this'll actually be used. The first time we encountered it
1614 * was just an additional string entry.
1615 */
1616 if (ent->smbai_dlen > 0) {
1617 oprintf(fp, " Data Length: %u\n", ent->smbai_dlen);
1618 switch (ent->smbai_dlen) {
1619 case 1:
1620 oprintf(fp, " Data: 0x%x\n",
1621 *(uint8_t *)ent->smbai_data);
1622 break;
1623 case 2:
1624 oprintf(fp, " Data: 0x%x\n",
1625 *(uint16_t *)ent->smbai_data);
1626 break;
1627 case 4:
1628 oprintf(fp, " Data: 0x%x\n",
1629 *(uint32_t *)ent->smbai_data);
1630 break;
1631 case 8:
1632 oprintf(fp, " Data: 0x%" PRIx64 "\n",
1633 *(uint64_t *)ent->smbai_data);
1634 break;
1635 default:
1636 break;
1637 }
1638 }
1639
1640 smbios_info_addinfo_ent_free(shp, ent);
1641 }
1642 }
1643
1644
1645 static void
print_processor_info_riscv(smbios_hdl_t * shp,id_t id,FILE * fp)1646 print_processor_info_riscv(smbios_hdl_t *shp, id_t id, FILE *fp)
1647 {
1648 smbios_processor_info_riscv_t rv;
1649
1650 if (smbios_info_processor_riscv(shp, id, &rv) != 0) {
1651 smbios_warn(shp, "failed to read RISC-V specific processor "
1652 "information");
1653 return;
1654 }
1655
1656 if (rv.smbpirv_boothart != 0) {
1657 oprintf(fp, " Boot Hart\n");
1658 }
1659 u128_print(fp, " Hart ID", rv.smbpirv_hartid);
1660 u128_print(fp, " Vendor ID", rv.smbpirv_vendid);
1661 u128_print(fp, " Architecture ID", rv.smbpirv_archid);
1662 u128_print(fp, " Implementation ID", rv.smbpirv_machid);
1663 flag64_printf(fp, " ISA", rv.smbpirv_isa,
1664 sizeof (rv.smbpirv_isa) * NBBY, smbios_riscv_isa_name,
1665 smbios_riscv_isa_desc);
1666 flag_printf(fp, " Privilege Levels", rv.smbpirv_privlvl,
1667 sizeof (rv.smbpirv_privlvl) * NBBY, smbios_riscv_priv_name,
1668 smbios_riscv_priv_desc);
1669 u128_print(fp, " Machine Exception Trap Delegation",
1670 rv.smbpirv_metdi);
1671 u128_print(fp, " Machine Interrupt Trap Delegation",
1672 rv.smbpirv_mitdi);
1673 desc_printf(smbios_riscv_width_desc(rv.smbpirv_xlen),
1674 fp, " Register Width: 0x%x", rv.smbpirv_xlen);
1675 desc_printf(smbios_riscv_width_desc(rv.smbpirv_mxlen),
1676 fp, " M-Mode Register Width: 0x%x", rv.smbpirv_mxlen);
1677 desc_printf(smbios_riscv_width_desc(rv.smbpirv_sxlen),
1678 fp, " S-Mode Register Width: 0x%x", rv.smbpirv_sxlen);
1679 desc_printf(smbios_riscv_width_desc(rv.smbpirv_uxlen),
1680 fp, " U-Mode Register Width: 0x%x", rv.smbpirv_uxlen);
1681 }
1682
1683 static void
print_processor_info(smbios_hdl_t * shp,id_t id,FILE * fp)1684 print_processor_info(smbios_hdl_t *shp, id_t id, FILE *fp)
1685 {
1686 smbios_processor_info_t p;
1687
1688 if (smbios_info_processor_info(shp, id, &p) != 0) {
1689 smbios_warn(shp, "failed to read processor additional "
1690 "information");
1691 return;
1692 }
1693
1694 id_printf(fp, " Processor Handle: ", p.smbpi_processor);
1695 desc_printf(smbios_processor_info_type_desc(p.smbpi_ptype),
1696 fp, " Processor Type: %u", p.smbpi_ptype);
1697
1698 switch (p.smbpi_ptype) {
1699 case SMB_PROCINFO_T_RV32:
1700 case SMB_PROCINFO_T_RV64:
1701 case SMB_PROCINFO_T_RV128:
1702 oprintf(fp, " RISC-V Additional Processor Information:\n");
1703 print_processor_info_riscv(shp, id, fp);
1704 break;
1705 default:
1706 break;
1707 }
1708 }
1709
1710 static void
print_battery(smbios_hdl_t * shp,id_t id,FILE * fp)1711 print_battery(smbios_hdl_t *shp, id_t id, FILE *fp)
1712 {
1713 smbios_battery_t bat;
1714
1715 if (smbios_info_battery(shp, id, &bat) != 0) {
1716 smbios_warn(shp, "failed to read battery information");
1717 return;
1718 }
1719
1720 if (bat.smbb_date != NULL) {
1721 str_print(fp, " Manufacture Date", bat.smbb_date);
1722 }
1723
1724 if (bat.smbb_serial != NULL) {
1725 str_print(fp, " Serial Number", bat.smbb_serial);
1726 }
1727
1728 if (bat.smbb_chem != SMB_BDC_UNKNOWN) {
1729 desc_printf(smbios_battery_chem_desc(bat.smbb_chem),
1730 fp, " Battery Chemistry: 0x%x", bat.smbb_chem);
1731 }
1732
1733 if (bat.smbb_cap != 0) {
1734 oprintf(fp, " Design Capacity: %u mWh\n", bat.smbb_cap);
1735 } else {
1736 oprintf(fp, " Design Capacity: unknown\n");
1737 }
1738
1739 if (bat.smbb_volt != 0) {
1740 oprintf(fp, " Design Voltage: %u mV\n", bat.smbb_volt);
1741 } else {
1742 oprintf(fp, " Design Voltage: unknown\n");
1743 }
1744
1745 str_print(fp, " SBDS Version Number", bat.smbb_version);
1746 if (bat.smbb_err != UINT8_MAX) {
1747 oprintf(fp, " Maximum Error: %u\n", bat.smbb_err);
1748 } else {
1749 oprintf(fp, " Maximum Error: unknown\n");
1750 }
1751 oprintf(fp, " SBDS Serial Number: %04x\n", bat.smbb_ssn);
1752 oprintf(fp, " SBDS Manufacture Date: %u-%02u-%02u\n", bat.smbb_syear,
1753 bat.smbb_smonth, bat.smbb_sday);
1754 str_print(fp, " SBDS Device Chemistry", bat.smbb_schem);
1755 oprintf(fp, " OEM-specific Information: 0x%08x\n", bat.smbb_oemdata);
1756 }
1757
1758 static void
print_pointdev(smbios_hdl_t * shp,id_t id,FILE * fp)1759 print_pointdev(smbios_hdl_t *shp, id_t id, FILE *fp)
1760 {
1761 smbios_pointdev_t pd;
1762
1763 if (smbios_info_pointdev(shp, id, &pd) != 0) {
1764 smbios_warn(shp, "failed to read pointer device information");
1765 return;
1766 }
1767
1768 desc_printf(smbios_pointdev_type_desc(pd.smbpd_type),
1769 fp, " Type: %u", pd.smbpd_type);
1770 desc_printf(smbios_pointdev_iface_desc(pd.smbpd_iface),
1771 fp, " Interface: %u", pd.smbpd_iface);
1772 oprintf(fp, " Buttons: %u\n", pd.smbpd_nbuttons);
1773 }
1774
1775 static void
print_extprocessor(smbios_hdl_t * shp,id_t id,FILE * fp)1776 print_extprocessor(smbios_hdl_t *shp, id_t id, FILE *fp)
1777 {
1778 int i;
1779 smbios_processor_ext_t ep;
1780
1781 if (check_oem(shp) != 0)
1782 return;
1783
1784 if (smbios_info_extprocessor(shp, id, &ep) != 0) {
1785 smbios_warn(shp, "failed to read extended processor "
1786 "information");
1787 return;
1788 }
1789
1790 oprintf(fp, " Processor: %u\n", ep.smbpe_processor);
1791 oprintf(fp, " FRU: %u\n", ep.smbpe_fru);
1792 oprintf(fp, " Initial APIC ID count: %u\n\n", ep.smbpe_n);
1793
1794 for (i = 0; i < ep.smbpe_n; i++) {
1795 oprintf(fp, " Logical Strand %u: Initial APIC ID: %u\n", i,
1796 ep.smbpe_apicid[i]);
1797 }
1798 }
1799
1800 static void
print_extport(smbios_hdl_t * shp,id_t id,FILE * fp)1801 print_extport(smbios_hdl_t *shp, id_t id, FILE *fp)
1802 {
1803 smbios_port_ext_t epo;
1804
1805 if (check_oem(shp) != 0)
1806 return;
1807
1808 if (smbios_info_extport(shp, id, &epo) != 0) {
1809 smbios_warn(shp, "failed to read extended port information");
1810 return;
1811 }
1812
1813 oprintf(fp, " Chassis Handle: %u\n", epo.smbporte_chassis);
1814 oprintf(fp, " Port Connector Handle: %u\n", epo.smbporte_port);
1815 oprintf(fp, " Device Type: %u\n", epo.smbporte_dtype);
1816 oprintf(fp, " Device Handle: %u\n", epo.smbporte_devhdl);
1817 oprintf(fp, " PHY: %u\n", epo.smbporte_phy);
1818 }
1819
1820 static void
print_pciexrc(smbios_hdl_t * shp,id_t id,FILE * fp)1821 print_pciexrc(smbios_hdl_t *shp, id_t id, FILE *fp)
1822 {
1823 smbios_pciexrc_t pcie;
1824
1825 if (check_oem(shp) != 0)
1826 return;
1827
1828 if (smbios_info_pciexrc(shp, id, &pcie) != 0) {
1829 smbios_warn(shp, "failed to read pciexrc information");
1830 return;
1831 }
1832
1833 oprintf(fp, " Component ID: %u\n", pcie.smbpcie_bb);
1834 oprintf(fp, " BDF: 0x%x\n", pcie.smbpcie_bdf);
1835 }
1836
1837 static void
print_extmemarray(smbios_hdl_t * shp,id_t id,FILE * fp)1838 print_extmemarray(smbios_hdl_t *shp, id_t id, FILE *fp)
1839 {
1840 smbios_memarray_ext_t em;
1841
1842 if (check_oem(shp) != 0)
1843 return;
1844
1845 if (smbios_info_extmemarray(shp, id, &em) != 0) {
1846 smbios_warn(shp, "failed to read extmemarray information");
1847 return;
1848 }
1849
1850 oprintf(fp, " Physical Memory Array Handle: %u\n", em.smbmae_ma);
1851 oprintf(fp, " Component Parent Handle: %u\n", em.smbmae_comp);
1852 oprintf(fp, " BDF: 0x%x\n", em.smbmae_bdf);
1853 }
1854
1855 static void
print_extmemdevice(smbios_hdl_t * shp,id_t id,FILE * fp)1856 print_extmemdevice(smbios_hdl_t *shp, id_t id, FILE *fp)
1857 {
1858 uint_t i, ncs;
1859 uint8_t *cs;
1860 smbios_memdevice_ext_t emd;
1861
1862 if (check_oem(shp) != 0)
1863 return;
1864
1865 if (smbios_info_extmemdevice(shp, id, &emd) != 0) {
1866 smbios_warn(shp, "failed to read extmemdevice information");
1867 return;
1868 }
1869
1870 oprintf(fp, " Memory Device Handle: %u\n", emd.smbmdeve_md);
1871 oprintf(fp, " DRAM Channel: %u\n", emd.smbmdeve_drch);
1872 oprintf(fp, " Number of Chip Selects: %u\n", emd.smbmdeve_ncs);
1873
1874 if (emd.smbmdeve_ncs == 0)
1875 return;
1876
1877 if (smbios_info_extmemdevice_cs(shp, id, &ncs, &cs) != 0) {
1878 smbios_warn(shp, "failed to read extmemdevice cs information");
1879 return;
1880 }
1881
1882 for (i = 0; i < ncs; i++) {
1883 oprintf(fp, " Chip Select: %u\n", cs[i]);
1884 }
1885 smbios_info_extmemdevice_cs_free(shp, ncs, cs);
1886 }
1887
1888 static void
print_strprop_info(smbios_hdl_t * shp,id_t id,FILE * fp)1889 print_strprop_info(smbios_hdl_t *shp, id_t id, FILE *fp)
1890 {
1891 smbios_strprop_t prop;
1892
1893 if (smbios_info_strprop(shp, id, &prop) != 0) {
1894 smbios_warn(shp, "failed to read string property information");
1895 return;
1896 }
1897
1898 desc_printf(smbios_strprop_id_desc(prop.smbsp_prop_id), fp,
1899 " Property ID: %u", prop.smbsp_prop_id);
1900 if (prop.smbsp_prop_val != NULL) {
1901 str_print(fp, " Property Value", prop.smbsp_prop_val);
1902 }
1903 id_printf(fp, " Parent Handle: ", prop.smbsp_parent);
1904 }
1905
1906 static void
print_fwinfo(smbios_hdl_t * shp,id_t id,FILE * fp)1907 print_fwinfo(smbios_hdl_t *shp, id_t id, FILE *fp)
1908 {
1909 smbios_fwinfo_t fw;
1910 smbios_fwinfo_comp_t *comps;
1911 uint_t ncomps, i;
1912
1913 if (smbios_info_fwinfo(shp, id, &fw) != 0) {
1914 smbios_warn(shp, "failed to read firmware inventory");
1915 return;
1916 }
1917
1918 str_print(fp, " Component Name", fw.smbfw_name);
1919 str_print(fp, " ID", fw.smbfw_id);
1920 str_print(fp, " Release Date", fw.smbfw_reldate);
1921 str_print(fp, " Lowest Supported Version", fw.smbfw_lsv);
1922 desc_printf(smbios_fwinfo_vers_desc(fw.smbfw_vers_fmt), fp,
1923 " Version Format: %u", fw.smbfw_vers_fmt);
1924 desc_printf(smbios_fwinfo_id_desc(fw.smbfw_id_fmt), fp,
1925 " ID Format: %u", fw.smbfw_id_fmt);
1926 if (fw.smbfw_imgsz != UINT64_MAX) {
1927 oprintf(fp, " Image Size: %" PRIu64 "\n", fw.smbfw_imgsz);
1928 } else {
1929 oprintf(fp, " Image Size: unknown\n");
1930 }
1931
1932 flag_printf(fp, "Characteristics", fw.smbfw_chars,
1933 sizeof (fw.smbfw_chars) * NBBY, smbios_fwinfo_ch_name,
1934 smbios_fwinfo_ch_desc);
1935
1936 desc_printf(smbios_fwinfo_state_desc(fw.smbfw_state), fp, " State: %u",
1937 fw.smbfw_state);
1938 oprintf(fp, " Number of Associated Components: %u\n",
1939 fw.smbfw_ncomps);
1940
1941 if (fw.smbfw_ncomps == 0)
1942 return;
1943
1944 if (smbios_info_fwinfo_comps(shp, id, &ncomps, &comps) == -1) {
1945 smbios_warn(shp, "failed to read firmware inventory "
1946 "components");
1947 return;
1948 }
1949
1950 oprintf(fp, "\n Component Handles:\n");
1951 for (i = 0; i < ncomps; i++) {
1952 oprintf(fp, " %" _PRIdID "\n", comps[i].smbfwe_id);
1953 }
1954 }
1955
1956 static int
print_struct(smbios_hdl_t * shp,const smbios_struct_t * sp,void * fp)1957 print_struct(smbios_hdl_t *shp, const smbios_struct_t *sp, void *fp)
1958 {
1959 smbios_info_t info;
1960 int hex = opt_x;
1961 const char *s;
1962
1963 if (opt_t != -1 && opt_t != sp->smbstr_type)
1964 return (0); /* skip struct if type doesn't match -t */
1965
1966 if (!opt_O && (sp->smbstr_type == SMB_TYPE_MEMCTL ||
1967 sp->smbstr_type == SMB_TYPE_MEMMOD))
1968 return (0); /* skip struct if type is obsolete */
1969
1970 if (g_hdr++ == 0 || !opt_s)
1971 oprintf(fp, "%-5s %-4s %s\n", "ID", "SIZE", "TYPE");
1972
1973 oprintf(fp, "%-5u %-4lu",
1974 (uint_t)sp->smbstr_id, (ulong_t)sp->smbstr_size);
1975
1976 if ((s = smbios_type_name(sp->smbstr_type)) != NULL)
1977 oprintf(fp, " %s (type %u)", s, sp->smbstr_type);
1978 else if (sp->smbstr_type > SMB_TYPE_OEM_LO &&
1979 sp->smbstr_type < SMB_TYPE_OEM_HI)
1980 oprintf(fp, " %s+%u (type %u)", "SMB_TYPE_OEM_LO",
1981 sp->smbstr_type - SMB_TYPE_OEM_LO, sp->smbstr_type);
1982 else
1983 oprintf(fp, " %u", sp->smbstr_type);
1984
1985 if ((s = smbios_type_desc(sp->smbstr_type)) != NULL)
1986 oprintf(fp, " (%s)\n", s);
1987 else
1988 oprintf(fp, "\n");
1989
1990 if (opt_s)
1991 return (0); /* only print header line if -s specified */
1992
1993 if (smbios_info_common(shp, sp->smbstr_id, &info) == 0) {
1994 oprintf(fp, "\n");
1995 print_common(&info, fp);
1996 }
1997
1998 switch (sp->smbstr_type) {
1999 case SMB_TYPE_BIOS:
2000 oprintf(fp, "\n");
2001 print_bios(shp, fp);
2002 break;
2003 case SMB_TYPE_SYSTEM:
2004 oprintf(fp, "\n");
2005 print_system(shp, fp);
2006 break;
2007 case SMB_TYPE_BASEBOARD:
2008 oprintf(fp, "\n");
2009 print_bboard(shp, sp->smbstr_id, fp);
2010 break;
2011 case SMB_TYPE_CHASSIS:
2012 oprintf(fp, "\n");
2013 print_chassis(shp, sp->smbstr_id, fp);
2014 break;
2015 case SMB_TYPE_PROCESSOR:
2016 oprintf(fp, "\n");
2017 print_processor(shp, sp->smbstr_id, fp);
2018 break;
2019 case SMB_TYPE_CACHE:
2020 oprintf(fp, "\n");
2021 print_cache(shp, sp->smbstr_id, fp);
2022 break;
2023 case SMB_TYPE_PORT:
2024 oprintf(fp, "\n");
2025 print_port(shp, sp->smbstr_id, fp);
2026 break;
2027 case SMB_TYPE_SLOT:
2028 oprintf(fp, "\n");
2029 print_slot(shp, sp->smbstr_id, fp);
2030 break;
2031 case SMB_TYPE_OBDEVS:
2032 oprintf(fp, "\n");
2033 print_obdevs(shp, sp->smbstr_id, fp);
2034 break;
2035 case SMB_TYPE_OEMSTR:
2036 case SMB_TYPE_SYSCONFSTR:
2037 oprintf(fp, "\n");
2038 print_strtab(shp, sp->smbstr_id, fp);
2039 break;
2040 case SMB_TYPE_LANG:
2041 oprintf(fp, "\n");
2042 print_lang(shp, sp->smbstr_id, fp);
2043 break;
2044 case SMB_TYPE_EVENTLOG:
2045 oprintf(fp, "\n");
2046 print_evlog(shp, sp->smbstr_id, fp);
2047 break;
2048 case SMB_TYPE_MEMARRAY:
2049 oprintf(fp, "\n");
2050 print_memarray(shp, sp->smbstr_id, fp);
2051 break;
2052 case SMB_TYPE_MEMDEVICE:
2053 oprintf(fp, "\n");
2054 print_memdevice(shp, sp->smbstr_id, fp);
2055 break;
2056 case SMB_TYPE_MEMARRAYMAP:
2057 oprintf(fp, "\n");
2058 print_memarrmap(shp, sp->smbstr_id, fp);
2059 break;
2060 case SMB_TYPE_MEMDEVICEMAP:
2061 oprintf(fp, "\n");
2062 print_memdevmap(shp, sp->smbstr_id, fp);
2063 break;
2064 case SMB_TYPE_BATTERY:
2065 oprintf(fp, "\n");
2066 print_battery(shp, sp->smbstr_id, fp);
2067 break;
2068 case SMB_TYPE_POINTDEV:
2069 oprintf(fp, "\n");
2070 print_pointdev(shp, sp->smbstr_id, fp);
2071 break;
2072 case SMB_TYPE_SECURITY:
2073 oprintf(fp, "\n");
2074 print_hwsec(shp, fp);
2075 break;
2076 case SMB_TYPE_VPROBE:
2077 oprintf(fp, "\n");
2078 print_vprobe(shp, sp->smbstr_id, fp);
2079 break;
2080 case SMB_TYPE_COOLDEV:
2081 oprintf(fp, "\n");
2082 print_cooldev(shp, sp->smbstr_id, fp);
2083 break;
2084 case SMB_TYPE_TPROBE:
2085 oprintf(fp, "\n");
2086 print_tprobe(shp, sp->smbstr_id, fp);
2087 break;
2088 case SMB_TYPE_IPROBE:
2089 oprintf(fp, "\n");
2090 print_iprobe(shp, sp->smbstr_id, fp);
2091 break;
2092 case SMB_TYPE_BOOT:
2093 oprintf(fp, "\n");
2094 print_boot(shp, fp);
2095 break;
2096 case SMB_TYPE_IPMIDEV:
2097 oprintf(fp, "\n");
2098 print_ipmi(shp, fp);
2099 break;
2100 case SMB_TYPE_POWERSUP:
2101 oprintf(fp, "\n");
2102 print_powersup(shp, sp->smbstr_id, fp);
2103 break;
2104 case SMB_TYPE_ADDINFO:
2105 oprintf(fp, "\n");
2106 print_addinfo(shp, sp->smbstr_id, fp);
2107 break;
2108 case SMB_TYPE_OBDEVEXT:
2109 oprintf(fp, "\n");
2110 print_obdevs_ext(shp, sp->smbstr_id, fp);
2111 break;
2112 case SMB_TYPE_PROCESSOR_INFO:
2113 oprintf(fp, "\n");
2114 print_processor_info(shp, sp->smbstr_id, fp);
2115 break;
2116 case SMB_TYPE_STRPROP:
2117 oprintf(fp, "\n");
2118 print_strprop_info(shp, sp->smbstr_id, fp);
2119 break;
2120 case SMB_TYPE_FWINFO:
2121 oprintf(fp, "\n");
2122 print_fwinfo(shp, sp->smbstr_id, fp);
2123 break;
2124 case SUN_OEM_EXT_PROCESSOR:
2125 oprintf(fp, "\n");
2126 print_extprocessor(shp, sp->smbstr_id, fp);
2127 break;
2128 case SUN_OEM_EXT_PORT:
2129 oprintf(fp, "\n");
2130 print_extport(shp, sp->smbstr_id, fp);
2131 break;
2132 case SUN_OEM_PCIEXRC:
2133 oprintf(fp, "\n");
2134 print_pciexrc(shp, sp->smbstr_id, fp);
2135 break;
2136 case SUN_OEM_EXT_MEMARRAY:
2137 oprintf(fp, "\n");
2138 print_extmemarray(shp, sp->smbstr_id, fp);
2139 break;
2140 case SUN_OEM_EXT_MEMDEVICE:
2141 oprintf(fp, "\n");
2142 print_extmemdevice(shp, sp->smbstr_id, fp);
2143 break;
2144 default:
2145 hex++;
2146 }
2147
2148 if (hex)
2149 print_bytes(sp->smbstr_data, sp->smbstr_size, fp);
2150 else
2151 oprintf(fp, "\n");
2152
2153 return (0);
2154 }
2155
2156 static uint16_t
getu16(const char * name,const char * s)2157 getu16(const char *name, const char *s)
2158 {
2159 u_longlong_t val;
2160 char *p;
2161
2162 errno = 0;
2163 val = strtoull(s, &p, 0);
2164
2165 if (errno != 0 || p == s || *p != '\0' || val > UINT16_MAX) {
2166 (void) fprintf(stderr, "%s: invalid %s argument -- %s\n",
2167 g_pname, name, s);
2168 exit(SMBIOS_USAGE);
2169 }
2170
2171 return ((uint16_t)val);
2172 }
2173
2174 static uint16_t
getstype(const char * name,const char * s)2175 getstype(const char *name, const char *s)
2176 {
2177 const char *ts;
2178 uint16_t t;
2179
2180 for (t = 0; t < SMB_TYPE_OEM_LO; t++) {
2181 if ((ts = smbios_type_name(t)) != NULL && strcmp(s, ts) == 0)
2182 return (t);
2183 }
2184
2185 (void) fprintf(stderr, "%s: invalid %s argument -- %s\n",
2186 g_pname, name, s);
2187
2188 exit(SMBIOS_USAGE);
2189 /*NOTREACHED*/
2190 }
2191
2192 static int
usage(FILE * fp)2193 usage(FILE *fp)
2194 {
2195 (void) fprintf(fp, "Usage: %s "
2196 "[-BeOsx] [-i id] [-t type] [-w file] [file]\n\n", g_pname);
2197
2198 (void) fprintf(fp,
2199 "\t-B disable header validation for broken BIOSes\n"
2200 "\t-e display SMBIOS entry point information\n"
2201 "\t-i display only the specified structure\n"
2202 "\t-O display obsolete structure types\n"
2203 "\t-s display only a summary of structure identifiers and types\n"
2204 "\t-t display only the specified structure type\n"
2205 "\t-w write the raw data to the specified file\n"
2206 "\t-x display raw data for structures\n");
2207
2208 return (SMBIOS_USAGE);
2209 }
2210
2211 int
main(int argc,char * argv[])2212 main(int argc, char *argv[])
2213 {
2214 const char *ifile = NULL;
2215 const char *ofile = NULL;
2216 int oflags = 0;
2217
2218 smbios_hdl_t *shp;
2219 smbios_struct_t s;
2220 int err, fd, c;
2221 char *p;
2222
2223 if ((p = strrchr(argv[0], '/')) == NULL)
2224 g_pname = argv[0];
2225 else
2226 g_pname = p + 1;
2227
2228 while (optind < argc) {
2229 while ((c = getopt(argc, argv, "Bei:Ost:w:xZ")) != EOF) {
2230 switch (c) {
2231 case 'B':
2232 oflags |= SMB_O_NOCKSUM | SMB_O_NOVERS;
2233 break;
2234 case 'e':
2235 opt_e++;
2236 break;
2237 case 'i':
2238 opt_i = getu16("struct ID", optarg);
2239 break;
2240 case 'O':
2241 opt_O++;
2242 break;
2243 case 's':
2244 opt_s++;
2245 break;
2246 case 't':
2247 if (isdigit(optarg[0]))
2248 opt_t = getu16("struct type", optarg);
2249 else
2250 opt_t = getstype("struct type", optarg);
2251 break;
2252 case 'w':
2253 ofile = optarg;
2254 break;
2255 case 'x':
2256 opt_x++;
2257 break;
2258 case 'Z':
2259 oflags |= SMB_O_ZIDS; /* undocumented */
2260 break;
2261 default:
2262 return (usage(stderr));
2263 }
2264 }
2265
2266 if (optind < argc) {
2267 if (ifile != NULL) {
2268 (void) fprintf(stderr, "%s: illegal "
2269 "argument -- %s\n", g_pname, argv[optind]);
2270 return (SMBIOS_USAGE);
2271 }
2272 ifile = argv[optind++];
2273 }
2274 }
2275
2276 if ((shp = smbios_open(ifile, SMB_VERSION, oflags, &err)) == NULL) {
2277 (void) fprintf(stderr, "%s: failed to load SMBIOS: %s\n",
2278 g_pname, smbios_errmsg(err));
2279 return (SMBIOS_ERROR);
2280 }
2281
2282 if (opt_i == -1 && opt_t == -1 && opt_e == 0 &&
2283 smbios_truncated(shp))
2284 (void) fprintf(stderr, "%s: SMBIOS table is truncated\n",
2285 g_pname);
2286
2287 if (ofile != NULL) {
2288 if ((fd = open(ofile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1) {
2289 (void) fprintf(stderr, "%s: failed to open %s: %s\n",
2290 g_pname, ofile, strerror(errno));
2291 err = SMBIOS_ERROR;
2292 } else if (smbios_write(shp, fd) != 0) {
2293 (void) fprintf(stderr, "%s: failed to write %s: %s\n",
2294 g_pname, ofile, smbios_errmsg(smbios_errno(shp)));
2295 err = SMBIOS_ERROR;
2296 }
2297 smbios_close(shp);
2298 return (err);
2299 }
2300
2301 if (opt_e) {
2302 print_smbios(shp, stdout);
2303 smbios_close(shp);
2304 return (SMBIOS_SUCCESS);
2305 }
2306
2307 if (opt_O && (opt_i != -1 || opt_t != -1))
2308 opt_O++; /* -i or -t imply displaying obsolete records */
2309
2310 if (opt_i != -1)
2311 err = smbios_lookup_id(shp, opt_i, &s);
2312 else
2313 err = smbios_iter(shp, print_struct, stdout);
2314
2315 if (err != 0) {
2316 (void) fprintf(stderr, "%s: failed to access SMBIOS: %s\n",
2317 g_pname, smbios_errmsg(smbios_errno(shp)));
2318 smbios_close(shp);
2319 return (SMBIOS_ERROR);
2320 }
2321
2322 if (opt_i != -1)
2323 (void) print_struct(shp, &s, stdout);
2324
2325 smbios_close(shp);
2326 return (SMBIOS_SUCCESS);
2327 }
2328