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