xref: /illumos-gate/usr/src/cmd/smbios/smbios.c (revision 1d111dc8a7b0c978fa8cafbedf00eefa9768061e)
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 2025 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
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)
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)
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)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 	/*
534 	 * SMBIOS 3.9 states that if the value is 0xff, that means that the
535 	 * height is specified by the rack height field. This means that the
536 	 * rack type also matters. We don't normalize this in the library so
537 	 * that way someone can tell what unit actually is supposed to be
538 	 * applied here. Otherwise in a future version of the library we could
539 	 * add a height unit in addition to rack type (but would need to define
540 	 * U as that doesn't exist today).
541 	 */
542 	const char *rtype = smbios_chassis_rack_type_desc(c.smbc_rtype);
543 	if (rtype == NULL) {
544 		rtype = " unknown unit";
545 	}
546 
547 	if (c.smbc_uheight == 0xff) {
548 		oprintf(fp, "  Chassis Height: %u%s\n", c.smbc_rheight, rtype);
549 	} else {
550 		oprintf(fp, "  Chassis Height: %uu\n", c.smbc_uheight);
551 	}
552 	oprintf(fp, "  Power Cords: %u\n", c.smbc_cords);
553 
554 	oprintf(fp, "  Element Records: %u\n", c.smbc_elems);
555 
556 	if (c.smbc_rtype == 0) {
557 		oprintf(fp, "  Rack Type: unspecified\n");
558 	} else {
559 		desc_printf(smbios_chassis_rack_type_desc(c.smbc_rtype),
560 		    fp, "  Rack Type: 0x%x", c.smbc_rtype);
561 	}
562 	if (c.smbc_rheight != 0) {
563 		oprintf(fp, "  Rack Height: %u%s\n", c.smbc_rheight, rtype);
564 	}
565 
566 	if (c.smbc_elems == 0) {
567 		return;
568 	}
569 
570 	if (smbios_info_chassis_elts(shp, id, &nelts, &elts) != 0) {
571 		smbios_warn(shp, "failed to read chassis elements");
572 		return;
573 	}
574 
575 	oprintf(fp, "\n");
576 
577 	for (i = 0; i < nelts; i++) {
578 		switch (elts[i].smbce_type) {
579 		case SMB_CELT_BBOARD:
580 			desc_printf(smbios_bboard_type_desc(elts[i].smbce_elt),
581 			    fp, "  Contained SMBIOS Base Board Type: 0x%x",
582 			    elts[i].smbce_elt);
583 			break;
584 		case SMB_CELT_SMBIOS:
585 			desc_printf(smbios_type_name(elts[i].smbce_elt), fp,
586 			    "  Contained SMBIOS structure Type: %u",
587 			    elts[i].smbce_elt);
588 			break;
589 		default:
590 			oprintf(fp, "  Unknown contained Type: %u/%u\n",
591 			    elts[i].smbce_type, elts[i].smbce_elt);
592 			break;
593 		}
594 		oprintf(fp, "    Minimum number: %u\n", elts[i].smbce_min);
595 		oprintf(fp, "    Maximum number: %u\n", elts[i].smbce_max);
596 	}
597 }
598 
599 static void
600 print_processor(smbios_hdl_t *shp, id_t id, FILE *fp)
601 {
602 	smbios_processor_t p;
603 	uint_t status;
604 
605 	if (smbios_info_processor(shp, id, &p) != 0) {
606 		smbios_warn(shp, "failed to read processor information");
607 		return;
608 	}
609 	status = SMB_PRSTATUS_STATUS(p.smbp_status);
610 
611 	desc_printf(smbios_processor_family_desc(p.smbp_family),
612 	    fp, "  Family: %u", p.smbp_family);
613 
614 	oprintf(fp, "  CPUID: 0x%llx\n", (u_longlong_t)p.smbp_cpuid);
615 
616 	desc_printf(smbios_processor_type_desc(p.smbp_type),
617 	    fp, "  Type: %u", p.smbp_type);
618 
619 	desc_printf(smbios_processor_upgrade_desc(p.smbp_upgrade),
620 	    fp, "  Socket Upgrade: %u", p.smbp_upgrade);
621 
622 	oprintf(fp, "  Socket Status: %s\n",
623 	    SMB_PRSTATUS_PRESENT(p.smbp_status) ?
624 	    "Populated" : "Not Populated");
625 
626 	desc_printf(smbios_processor_status_desc(status),
627 	    fp, "  Processor Status: %u", status);
628 
629 	if (SMB_PRV_LEGACY(p.smbp_voltage)) {
630 		oprintf(fp, "  Supported Voltages:");
631 		switch (p.smbp_voltage) {
632 		case SMB_PRV_5V:
633 			oprintf(fp, " 5.0V");
634 			break;
635 		case SMB_PRV_33V:
636 			oprintf(fp, " 3.3V");
637 			break;
638 		case SMB_PRV_29V:
639 			oprintf(fp, " 2.9V");
640 			break;
641 		}
642 		oprintf(fp, "\n");
643 	} else {
644 		oprintf(fp, "  Supported Voltages: %.1fV\n",
645 		    (float)SMB_PRV_VOLTAGE(p.smbp_voltage) / 10);
646 	}
647 
648 	if (p.smbp_corecount != 0) {
649 		oprintf(fp, "  Core Count: %u\n", p.smbp_corecount);
650 	} else {
651 		oprintf(fp, "  Core Count: Unknown\n");
652 	}
653 
654 	if (p.smbp_coresenabled != 0) {
655 		oprintf(fp, "  Cores Enabled: %u\n", p.smbp_coresenabled);
656 	} else {
657 		oprintf(fp, "  Cores Enabled: Unknown\n");
658 	}
659 
660 	if (p.smbp_threadcount != 0) {
661 		oprintf(fp, "  Thread Count: %u\n", p.smbp_threadcount);
662 	} else {
663 		oprintf(fp, "  Thread Count: Unknown\n");
664 	}
665 
666 	if (p.smbp_cflags) {
667 		flag_printf(fp, "Processor Characteristics",
668 		    p.smbp_cflags, sizeof (p.smbp_cflags) * NBBY,
669 		    smbios_processor_core_flag_name,
670 		    smbios_processor_core_flag_desc);
671 	}
672 
673 	if (p.smbp_clkspeed != 0)
674 		oprintf(fp, "  External Clock Speed: %uMHz\n", p.smbp_clkspeed);
675 	else
676 		oprintf(fp, "  External Clock Speed: Unknown\n");
677 
678 	if (p.smbp_maxspeed != 0)
679 		oprintf(fp, "  Maximum Speed: %uMHz\n", p.smbp_maxspeed);
680 	else
681 		oprintf(fp, "  Maximum Speed: Unknown\n");
682 
683 	if (p.smbp_curspeed != 0)
684 		oprintf(fp, "  Current Speed: %uMHz\n", p.smbp_curspeed);
685 	else
686 		oprintf(fp, "  Current Speed: Unknown\n");
687 
688 	id_printf(fp, "  L1 Cache Handle: ", p.smbp_l1cache);
689 	id_printf(fp, "  L2 Cache Handle: ", p.smbp_l2cache);
690 	id_printf(fp, "  L3 Cache Handle: ", p.smbp_l3cache);
691 
692 	if (p.smbp_threadsenabled != 0) {
693 		oprintf(fp, "  Threads Enabled: %u\n", p.smbp_threadsenabled);
694 	} else {
695 		oprintf(fp, "  Threads Enabled: Unknown\n");
696 	}
697 
698 	/*
699 	 * The Socket Type string overlaps with the upgrade string. Only print
700 	 * something if we have a valid value.
701 	 */
702 	if (*p.smbp_socktype != '\0') {
703 		str_print(fp, "  Socket Type", p.smbp_socktype);
704 	}
705 }
706 
707 static void
708 print_cache(smbios_hdl_t *shp, id_t id, FILE *fp)
709 {
710 	smbios_cache_t c;
711 
712 	if (smbios_info_cache(shp, id, &c) != 0) {
713 		smbios_warn(shp, "failed to read cache information");
714 		return;
715 	}
716 
717 	oprintf(fp, "  Level: %u\n", c.smba_level);
718 	oprintf(fp, "  Maximum Installed Size: %" PRIu64 " bytes\n",
719 	    c.smba_maxsize2);
720 
721 	if (c.smba_size2 != 0) {
722 		oprintf(fp, "  Installed Size: %" PRIu64 " bytes\n",
723 		    c.smba_size2);
724 	} else {
725 		oprintf(fp, "  Installed Size: Not Installed\n");
726 	}
727 
728 	if (c.smba_speed != 0)
729 		oprintf(fp, "  Speed: %uns\n", c.smba_speed);
730 	else
731 		oprintf(fp, "  Speed: Unknown\n");
732 
733 	flag_printf(fp, "Supported SRAM Types",
734 	    c.smba_stype, sizeof (c.smba_stype) * NBBY,
735 	    smbios_cache_ctype_name, smbios_cache_ctype_desc);
736 
737 	desc_printf(smbios_cache_ctype_desc(c.smba_ctype),
738 	    fp, "  Current SRAM Type: 0x%x", c.smba_ctype);
739 
740 	desc_printf(smbios_cache_ecc_desc(c.smba_etype),
741 	    fp, "  Error Correction Type: %u", c.smba_etype);
742 
743 	desc_printf(smbios_cache_logical_desc(c.smba_ltype),
744 	    fp, "  Logical Cache Type: %u", c.smba_ltype);
745 
746 	desc_printf(smbios_cache_assoc_desc(c.smba_assoc),
747 	    fp, "  Associativity: %u", c.smba_assoc);
748 
749 	desc_printf(smbios_cache_mode_desc(c.smba_mode),
750 	    fp, "  Mode: %u", c.smba_mode);
751 
752 	desc_printf(smbios_cache_loc_desc(c.smba_location),
753 	    fp, "  Location: %u", c.smba_location);
754 
755 	flag_printf(fp, "Flags", c.smba_flags, sizeof (c.smba_flags) * NBBY,
756 	    smbios_cache_flag_name, smbios_cache_flag_desc);
757 }
758 
759 static void
760 print_port(smbios_hdl_t *shp, id_t id, FILE *fp)
761 {
762 	smbios_port_t p;
763 
764 	if (smbios_info_port(shp, id, &p) != 0) {
765 		smbios_warn(shp, "failed to read port information");
766 		return;
767 	}
768 
769 	str_print(fp, "  Internal Reference Designator", p.smbo_iref);
770 	str_print(fp, "  External Reference Designator", p.smbo_eref);
771 
772 	desc_printf(smbios_port_conn_desc(p.smbo_itype),
773 	    fp, "  Internal Connector Type: %u", p.smbo_itype);
774 
775 	desc_printf(smbios_port_conn_desc(p.smbo_etype),
776 	    fp, "  External Connector Type: %u", p.smbo_etype);
777 
778 	desc_printf(smbios_port_type_desc(p.smbo_ptype),
779 	    fp, "  Port Type: %u", p.smbo_ptype);
780 }
781 
782 static void
783 print_slot(smbios_hdl_t *shp, id_t id, FILE *fp)
784 {
785 	smbios_slot_t s;
786 	smbios_version_t v;
787 
788 	if (smbios_info_slot(shp, id, &s) != 0) {
789 		smbios_warn(shp, "failed to read slot information");
790 		return;
791 	}
792 	smbios_info_smbios_version(shp, &v);
793 
794 	str_print(fp, "  Reference Designator", s.smbl_name);
795 	oprintf(fp, "  Slot ID: 0x%x\n", s.smbl_id);
796 
797 	desc_printf(smbios_slot_type_desc(s.smbl_type),
798 	    fp, "  Type: 0x%x", s.smbl_type);
799 
800 	desc_printf(smbios_slot_width_desc(s.smbl_width),
801 	    fp, "  Width: 0x%x", s.smbl_width);
802 
803 	desc_printf(smbios_slot_usage_desc(s.smbl_usage),
804 	    fp, "  Usage: 0x%x", s.smbl_usage);
805 
806 	desc_printf(smbios_slot_length_desc(s.smbl_length),
807 	    fp, "  Length: 0x%x", s.smbl_length);
808 
809 	flag_printf(fp, "Slot Characteristics 1",
810 	    s.smbl_ch1, sizeof (s.smbl_ch1) * NBBY,
811 	    smbios_slot_ch1_name, smbios_slot_ch1_desc);
812 
813 	flag_printf(fp, "Slot Characteristics 2",
814 	    s.smbl_ch2, sizeof (s.smbl_ch2) * NBBY,
815 	    smbios_slot_ch2_name, smbios_slot_ch2_desc);
816 
817 	if (check_oem(shp) != 0 && !smbios_vergteq(&v, 2, 6))
818 		return;
819 
820 	oprintf(fp, "  Segment Group: %u\n", s.smbl_sg);
821 	oprintf(fp, "  Bus Number: %u\n", s.smbl_bus);
822 	oprintf(fp, "  Device/Function Number: %u/%u\n", s.smbl_df >> 3,
823 	    s.smbl_df & 0x7);
824 
825 	if (s.smbl_dbw != 0) {
826 		oprintf(fp, "  Data Bus Width: %d\n", s.smbl_dbw);
827 	}
828 
829 	if (s.smbl_npeers > 0) {
830 		smbios_slot_peer_t *peer;
831 		uint_t i, npeers;
832 
833 		if (smbios_info_slot_peers(shp, id, &npeers, &peer) != 0) {
834 			smbios_warn(shp, "failed to read slot peer "
835 			    "information");
836 			return;
837 		}
838 
839 		for (i = 0; i < npeers; i++) {
840 			oprintf(fp, "  Slot Peer %u:\n", i);
841 			oprintf(fp, "    Segment group: %u\n",
842 			    peer[i].smblp_group);
843 			oprintf(fp, "    Bus/Device/Function: %u/%u/%u\n",
844 			    peer[i].smblp_bus, peer[i].smblp_device,
845 			    peer[i].smblp_function);
846 			oprintf(fp, "    Electrical width: %u\n",
847 			    peer[i].smblp_data_width);
848 		}
849 
850 		smbios_info_slot_peers_free(shp, npeers, peer);
851 	}
852 
853 	if (s.smbl_info != 0) {
854 		if (s.smbl_type >= SMB_SLT_PCIE &&
855 		    s.smbl_type <= SMB_SLT_PCIEG6P) {
856 			oprintf(fp, "  PCIe Generation: %d\n", s.smbl_info);
857 		} else {
858 			oprintf(fp, "  Slot Type: 0x%x\n", s.smbl_info);
859 		}
860 	}
861 
862 	if (s.smbl_pwidth != 0) {
863 		desc_printf(smbios_slot_width_desc(s.smbl_pwidth),
864 		    fp, "  Physical Width: 0x%x", s.smbl_pwidth);
865 	}
866 
867 	if (s.smbl_pitch != 0) {
868 		oprintf(fp, "  Slot Pitch: %u.%u mm\n", s.smbl_pitch / 100,
869 		    s.smbl_pitch % 100);
870 	}
871 
872 	/*
873 	 * The slot height was introduced in SMBIOS 3.5. However, a value of
874 	 * zero here does not mean that it is unknown, but rather that the
875 	 * concept is not applicable. Therefore we cannot use a standard check
876 	 * against zero for this and instead use the version.
877 	 */
878 	if (smbios_vergteq(&v, 3, 5)) {
879 		desc_printf(smbios_slot_height_desc(s.smbl_height), fp,
880 		    "  Height: 0x%x", s.smbl_height);
881 	} else {
882 		oprintf(fp, "  Height:  unknown\n");
883 	}
884 }
885 
886 static void
887 print_obdevs_ext(smbios_hdl_t *shp, id_t id, FILE *fp)
888 {
889 	boolean_t enabled;
890 	smbios_obdev_ext_t oe;
891 	const char *type;
892 
893 	if (smbios_info_obdevs_ext(shp, id, &oe) != 0) {
894 		smbios_warn(shp, "failed to read extended on-board devices "
895 		    "information");
896 		return;
897 	}
898 
899 	/*
900 	 * Bit 7 is always whether or not the device is enabled while bits 0:6
901 	 * are the actual device type.
902 	 */
903 	enabled = oe.smboe_dtype >> 7;
904 	type = smbios_onboard_ext_type_desc(oe.smboe_dtype & 0x7f);
905 
906 	str_print(fp, "  Reference Designator", oe.smboe_name);
907 	oprintf(fp, "  Device Enabled: %s\n", enabled == B_TRUE ? "true" :
908 	    "false");
909 	oprintf(fp, "  Device Type: %s\n", type);
910 	oprintf(fp, "  Device Type Instance: %u\n", oe.smboe_dti);
911 	oprintf(fp, "  Segment Group Number: %u\n", oe.smboe_sg);
912 	oprintf(fp, "  Bus Number: %u\n", oe.smboe_bus);
913 	oprintf(fp, "  Device/Function Number: %u\n", oe.smboe_df);
914 }
915 
916 static void
917 print_obdevs(smbios_hdl_t *shp, id_t id, FILE *fp)
918 {
919 	smbios_obdev_t *argv;
920 	int i, argc;
921 
922 	if ((argc = smbios_info_obdevs(shp, id, 0, NULL)) > 0) {
923 		argv = alloca(sizeof (smbios_obdev_t) * argc);
924 		if (smbios_info_obdevs(shp, id, argc, argv) == -1) {
925 			smbios_warn(shp, "failed to read on-board device "
926 			    "information");
927 			return;
928 		}
929 		for (i = 0; i < argc; i++)
930 			str_print_nolabel(fp, "  ", argv[i].smbd_name);
931 	}
932 }
933 
934 static void
935 print_strtab(smbios_hdl_t *shp, id_t id, FILE *fp)
936 {
937 	const char **argv;
938 	int i, argc;
939 
940 	if ((argc = smbios_info_strtab(shp, id, 0, NULL)) > 0) {
941 		argv = alloca(sizeof (char *) * argc);
942 		if (smbios_info_strtab(shp, id, argc, argv) == -1) {
943 			smbios_warn(shp, "failed to read string table "
944 			    "information");
945 			return;
946 		}
947 		for (i = 0; i < argc; i++)
948 			str_print_nolabel(fp, "  ", argv[i]);
949 	}
950 }
951 
952 static void
953 print_lang(smbios_hdl_t *shp, id_t id, FILE *fp)
954 {
955 	smbios_lang_t l;
956 
957 	if (smbios_info_lang(shp, &l) == -1) {
958 		smbios_warn(shp, "failed to read language information");
959 		return;
960 	}
961 
962 	str_print(fp, "  Current Language", l.smbla_cur);
963 	oprintf(fp, "  Language String Format: %u\n", l.smbla_fmt);
964 	oprintf(fp, "  Number of Installed Languages: %u\n", l.smbla_num);
965 	oprintf(fp, "  Installed Languages:\n");
966 
967 	print_strtab(shp, id, fp);
968 }
969 
970 /*ARGSUSED*/
971 static void
972 print_evlog(smbios_hdl_t *shp, id_t id, FILE *fp)
973 {
974 	smbios_evlog_t ev;
975 	uint32_t i;
976 
977 	if (smbios_info_eventlog(shp, &ev) == -1) {
978 		smbios_warn(shp, "failed to read event log information");
979 		return;
980 	}
981 
982 	oprintf(fp, "  Log Area Size: %lu bytes\n", (ulong_t)ev.smbev_size);
983 	oprintf(fp, "  Header Offset: %lu\n", (ulong_t)ev.smbev_hdr);
984 	oprintf(fp, "  Data Offset: %lu\n", (ulong_t)ev.smbev_data);
985 
986 	desc_printf(smbios_evlog_method_desc(ev.smbev_method),
987 	    fp, "  Data Access Method: %u", ev.smbev_method);
988 
989 	flag_printf(fp, "Log Flags",
990 	    ev.smbev_flags, sizeof (ev.smbev_flags) * NBBY,
991 	    smbios_evlog_flag_name, smbios_evlog_flag_desc);
992 
993 	desc_printf(smbios_evlog_format_desc(ev.smbev_format),
994 	    fp, "  Log Header Format: %u", ev.smbev_format);
995 
996 	oprintf(fp, "  Update Token: 0x%x\n", ev.smbev_token);
997 	oprintf(fp, "  Data Access Address: ");
998 
999 	switch (ev.smbev_method) {
1000 	case SMB_EVM_1x1i_1x1d:
1001 	case SMB_EVM_2x1i_1x1d:
1002 	case SMB_EVM_1x2i_1x1d:
1003 		oprintf(fp, "Index Address 0x%x, Data Address 0x%x\n",
1004 		    ev.smbev_addr.eva_io.evi_iaddr,
1005 		    ev.smbev_addr.eva_io.evi_daddr);
1006 		break;
1007 	case SMB_EVM_GPNV:
1008 		oprintf(fp, "0x%x\n", ev.smbev_addr.eva_gpnv);
1009 		break;
1010 	default:
1011 		oprintf(fp, "0x%x\n", ev.smbev_addr.eva_addr);
1012 	}
1013 
1014 	oprintf(fp, "  Type Descriptors:\n");
1015 
1016 	for (i = 0; i < ev.smbev_typec; i++) {
1017 		oprintf(fp, "  %u: Log Type 0x%x, Data Type 0x%x\n", i,
1018 		    ev.smbev_typev[i].smbevt_ltype,
1019 		    ev.smbev_typev[i].smbevt_dtype);
1020 	}
1021 }
1022 
1023 static void
1024 print_bytes(const uint8_t *data, size_t size, FILE *fp)
1025 {
1026 	hexdump_t h;
1027 
1028 	hexdump_init(&h);
1029 	hexdump_set_grouping(&h, 4);
1030 	hexdump_set_indent(&h, 2);
1031 
1032 	(void) fprintf(fp, "\n");
1033 	(void) hexdump_fileh(&h, data, size, HDF_DEFAULT, fp);
1034 	(void) fprintf(fp, "\n");
1035 
1036 	hexdump_fini(&h);
1037 }
1038 
1039 static void
1040 print_memarray(smbios_hdl_t *shp, id_t id, FILE *fp)
1041 {
1042 	smbios_memarray_t ma;
1043 
1044 	if (smbios_info_memarray(shp, id, &ma) != 0) {
1045 		smbios_warn(shp, "failed to read memarray information");
1046 		return;
1047 	}
1048 
1049 	desc_printf(smbios_memarray_loc_desc(ma.smbma_location),
1050 	    fp, "  Location: %u", ma.smbma_location);
1051 
1052 	desc_printf(smbios_memarray_use_desc(ma.smbma_use),
1053 	    fp, "  Use: %u", ma.smbma_use);
1054 
1055 	desc_printf(smbios_memarray_ecc_desc(ma.smbma_ecc),
1056 	    fp, "  ECC: %u", ma.smbma_ecc);
1057 
1058 	oprintf(fp, "  Number of Slots/Sockets: %u\n", ma.smbma_ndevs);
1059 	id_printf(fp, "  Memory Error Data: ", ma.smbma_err);
1060 	oprintf(fp, "  Max Capacity: %llu bytes\n",
1061 	    (u_longlong_t)ma.smbma_size);
1062 }
1063 
1064 static void
1065 print_memdevice(smbios_hdl_t *shp, id_t id, FILE *fp)
1066 {
1067 	smbios_memdevice_t md;
1068 
1069 	if (smbios_info_memdevice(shp, id, &md) != 0) {
1070 		smbios_warn(shp, "failed to read memory device information");
1071 		return;
1072 	}
1073 
1074 	id_printf(fp, "  Physical Memory Array: ", md.smbmd_array);
1075 	id_printf(fp, "  Memory Error Data: ", md.smbmd_error);
1076 
1077 	if (md.smbmd_twidth != -1u)
1078 		oprintf(fp, "  Total Width: %u bits\n", md.smbmd_twidth);
1079 	else
1080 		oprintf(fp, "  Total Width: Unknown\n");
1081 
1082 	if (md.smbmd_dwidth != -1u)
1083 		oprintf(fp, "  Data Width: %u bits\n", md.smbmd_dwidth);
1084 	else
1085 		oprintf(fp, "  Data Width: Unknown\n");
1086 
1087 	switch (md.smbmd_size) {
1088 	case -1ull:
1089 		oprintf(fp, "  Size: Unknown\n");
1090 		break;
1091 	case 0:
1092 		oprintf(fp, "  Size: Not Populated\n");
1093 		break;
1094 	default:
1095 		oprintf(fp, "  Size: %llu bytes\n",
1096 		    (u_longlong_t)md.smbmd_size);
1097 	}
1098 
1099 	desc_printf(smbios_memdevice_form_desc(md.smbmd_form),
1100 	    fp, "  Form Factor: %u", md.smbmd_form);
1101 
1102 	if (md.smbmd_set == 0)
1103 		oprintf(fp, "  Set: None\n");
1104 	else if (md.smbmd_set == (uint8_t)-1u)
1105 		oprintf(fp, "  Set: Unknown\n");
1106 	else
1107 		oprintf(fp, "  Set: %u\n", md.smbmd_set);
1108 
1109 	if (md.smbmd_rank != 0) {
1110 		desc_printf(smbios_memdevice_rank_desc(md.smbmd_rank),
1111 		    fp, "  Rank: %u", md.smbmd_rank);
1112 	} else {
1113 		oprintf(fp, "  Rank: Unknown\n");
1114 	}
1115 
1116 	desc_printf(smbios_memdevice_type_desc(md.smbmd_type),
1117 	    fp, "  Memory Type: %u", md.smbmd_type);
1118 
1119 	flag_printf(fp, "Flags", md.smbmd_flags, sizeof (md.smbmd_flags) * NBBY,
1120 	    smbios_memdevice_flag_name, smbios_memdevice_flag_desc);
1121 
1122 	if (md.smbmd_extspeed != 0) {
1123 		oprintf(fp, "  Speed: %" PRIu64 " MT/s\n", md.smbmd_extspeed);
1124 	} else {
1125 		oprintf(fp, "  Speed: Unknown\n");
1126 	}
1127 
1128 	if (md.smbmd_extclkspeed != 0) {
1129 		oprintf(fp, "  Configured Speed: %" PRIu64 " MT/s\n",
1130 		    md.smbmd_extclkspeed);
1131 	} else {
1132 		oprintf(fp, "  Configured Speed: Unknown\n");
1133 	}
1134 
1135 	str_print(fp, "  Device Locator", md.smbmd_dloc);
1136 	str_print(fp, "  Bank Locator", md.smbmd_bloc);
1137 
1138 	if (md.smbmd_minvolt != 0) {
1139 		oprintf(fp, "  Minimum Voltage: %.2fV\n",
1140 		    md.smbmd_minvolt / 1000.0);
1141 	} else {
1142 		oprintf(fp, "  Minimum Voltage: Unknown\n");
1143 	}
1144 
1145 	if (md.smbmd_maxvolt != 0) {
1146 		oprintf(fp, "  Maximum Voltage: %.2fV\n",
1147 		    md.smbmd_maxvolt / 1000.0);
1148 	} else {
1149 		oprintf(fp, "  Maximum Voltage: Unknown\n");
1150 	}
1151 
1152 	if (md.smbmd_confvolt != 0) {
1153 		oprintf(fp, "  Configured Voltage: %.2fV\n",
1154 		    md.smbmd_confvolt / 1000.0);
1155 	} else {
1156 		oprintf(fp, "  Configured Voltage: Unknown\n");
1157 	}
1158 
1159 	if (md.smbmd_memtech != 0) {
1160 		desc_printf(smbios_memdevice_memtech_desc(md.smbmd_memtech),
1161 		    fp, "  Memory Technology: %u", md.smbmd_memtech);
1162 	}
1163 
1164 	if (md.smbmd_opcap_flags != 0) {
1165 		flag_printf(fp, "Operating Mode Capabilities",
1166 		    md.smbmd_opcap_flags, sizeof (md.smbmd_opcap_flags) * NBBY,
1167 		    smbios_memdevice_op_capab_name,
1168 		    smbios_memdevice_op_capab_desc);
1169 	}
1170 
1171 	if (md.smbmd_firmware_rev[0] != '\0') {
1172 		str_print(fp, "  Firmware Revision", md.smbmd_firmware_rev);
1173 	}
1174 
1175 	if (md.smbmd_modmfg_id != SMB_MD_MFG_UNKNOWN) {
1176 		jedec_print(fp, "Module Manufacturer ID", md.smbmd_modmfg_id);
1177 	}
1178 
1179 	if (md.smbmd_modprod_id  != 0) {
1180 		jedec_print(fp, "Module Product ID", md.smbmd_modprod_id);
1181 	}
1182 
1183 	if (md.smbmd_cntrlmfg_id != SMB_MD_MFG_UNKNOWN) {
1184 		jedec_print(fp, "Memory Subsystem Controller Manufacturer ID",
1185 		    md.smbmd_cntrlmfg_id);
1186 	}
1187 
1188 	if (md.smbmd_cntrlprod_id != 0) {
1189 		jedec_print(fp, "Memory Subsystem Controller Product ID",
1190 		    md.smbmd_cntrlprod_id);
1191 	}
1192 
1193 	if (md.smbmd_nvsize == UINT64_MAX) {
1194 		oprintf(fp, "  Non-volatile Size: Unknown\n");
1195 	} else if (md.smbmd_nvsize != 0) {
1196 		oprintf(fp, "  Non-volatile Size: %llu bytes\n",
1197 		    (u_longlong_t)md.smbmd_nvsize);
1198 	}
1199 
1200 	if (md.smbmd_volatile_size == UINT64_MAX) {
1201 		oprintf(fp, "  Volatile Size: Unknown\n");
1202 	} else if (md.smbmd_volatile_size != 0) {
1203 		oprintf(fp, "  Volatile Size: %llu bytes\n",
1204 		    (u_longlong_t)md.smbmd_volatile_size);
1205 	}
1206 
1207 	if (md.smbmd_cache_size == UINT64_MAX) {
1208 		oprintf(fp, "  Cache Size: Unknown\n");
1209 	} else if (md.smbmd_cache_size != 0) {
1210 		oprintf(fp, "  Cache Size: %llu bytes\n",
1211 		    (u_longlong_t)md.smbmd_cache_size);
1212 	}
1213 
1214 	if (md.smbmd_logical_size == UINT64_MAX) {
1215 		oprintf(fp, "  Logical Size: Unknown\n");
1216 	} else if (md.smbmd_logical_size != 0) {
1217 		oprintf(fp, "  Logical Size: %llu bytes\n",
1218 		    (u_longlong_t)md.smbmd_logical_size);
1219 	}
1220 
1221 	if (md.smbmd_pmic0_mfgid != SMB_MD_MFG_UNKNOWN) {
1222 		jedec_print(fp, "PMIC0 Manufacturer ID", md.smbmd_pmic0_mfgid);
1223 	}
1224 
1225 	if (md.smbmd_pmic0_rev != SMB_MD_REV_UNKNOWN) {
1226 		jedec_rev_print(fp, "PMIC0 Revision", md.smbmd_pmic0_rev);
1227 	}
1228 
1229 	if (md.smbmd_rcd_mfgid != SMB_MD_MFG_UNKNOWN) {
1230 		jedec_print(fp, "RCD Manufacturer ID", md.smbmd_rcd_mfgid);
1231 	}
1232 
1233 	if (md.smbmd_rcd_rev != SMB_MD_REV_UNKNOWN) {
1234 		jedec_rev_print(fp, "RCD Revision", md.smbmd_rcd_rev);
1235 	}
1236 }
1237 
1238 static void
1239 print_memarrmap(smbios_hdl_t *shp, id_t id, FILE *fp)
1240 {
1241 	smbios_memarrmap_t ma;
1242 
1243 	if (smbios_info_memarrmap(shp, id, &ma) != 0) {
1244 		smbios_warn(shp, "failed to read memory array map information");
1245 		return;
1246 	}
1247 
1248 	id_printf(fp, "  Physical Memory Array: ", ma.smbmam_array);
1249 	oprintf(fp, "  Devices per Row: %u\n", ma.smbmam_width);
1250 
1251 	oprintf(fp, "  Physical Address: 0x%llx\n  Size: %llu bytes\n",
1252 	    (u_longlong_t)ma.smbmam_addr, (u_longlong_t)ma.smbmam_size);
1253 }
1254 
1255 static void
1256 print_memdevmap(smbios_hdl_t *shp, id_t id, FILE *fp)
1257 {
1258 	smbios_memdevmap_t md;
1259 
1260 	if (smbios_info_memdevmap(shp, id, &md) != 0) {
1261 		smbios_warn(shp, "failed to read memory device map "
1262 		    "information");
1263 		return;
1264 	}
1265 
1266 	id_printf(fp, "  Memory Device: ", md.smbmdm_device);
1267 	id_printf(fp, "  Memory Array Mapped Address: ", md.smbmdm_arrmap);
1268 
1269 	oprintf(fp, "  Physical Address: 0x%llx\n  Size: %llu bytes\n",
1270 	    (u_longlong_t)md.smbmdm_addr, (u_longlong_t)md.smbmdm_size);
1271 
1272 	oprintf(fp, "  Partition Row Position: %u\n", md.smbmdm_rpos);
1273 	oprintf(fp, "  Interleave Position: %u\n", md.smbmdm_ipos);
1274 	oprintf(fp, "  Interleave Data Depth: %u\n", md.smbmdm_idepth);
1275 }
1276 
1277 static void
1278 print_hwsec(smbios_hdl_t *shp, FILE *fp)
1279 {
1280 	smbios_hwsec_t h;
1281 
1282 	if (smbios_info_hwsec(shp, &h) == -1) {
1283 		smbios_warn(shp, "failed to read hwsec information");
1284 		return;
1285 	}
1286 
1287 	desc_printf(smbios_hwsec_desc(h.smbh_pwr_ps),
1288 	    fp, "  Power-On Password Status: %u", h.smbh_pwr_ps);
1289 	desc_printf(smbios_hwsec_desc(h.smbh_kbd_ps),
1290 	    fp, "  Keyboard Password Status: %u", h.smbh_kbd_ps);
1291 	desc_printf(smbios_hwsec_desc(h.smbh_adm_ps),
1292 	    fp, "  Administrator Password Status: %u", h.smbh_adm_ps);
1293 	desc_printf(smbios_hwsec_desc(h.smbh_pan_ps),
1294 	    fp, "  Front Panel Reset Status: %u", h.smbh_pan_ps);
1295 }
1296 
1297 static void
1298 print_vprobe(smbios_hdl_t *shp, id_t id, FILE *fp)
1299 {
1300 	smbios_vprobe_t vp;
1301 
1302 	if (smbios_info_vprobe(shp, id, &vp) != 0) {
1303 		smbios_warn(shp, "failed to read voltage probe information");
1304 		return;
1305 	}
1306 
1307 	str_print(fp, "  Description", vp.smbvp_description != NULL ?
1308 	    vp.smbvp_description : "unknown");
1309 	desc_printf(smbios_vprobe_loc_desc(vp.smbvp_location),
1310 	    fp, "  Location: %u", vp.smbvp_location);
1311 	desc_printf(smbios_vprobe_status_desc(vp.smbvp_status),
1312 	    fp, "  Status: %u", vp.smbvp_status);
1313 
1314 	if (vp.smbvp_maxval != SMB_PROBE_UNKNOWN_VALUE) {
1315 		oprintf(fp, "  Maximum Possible Voltage: %u mV\n",
1316 		    vp.smbvp_maxval);
1317 	} else {
1318 		oprintf(fp, "  Maximum Possible Voltage: unknown\n");
1319 	}
1320 
1321 	if (vp.smbvp_minval != SMB_PROBE_UNKNOWN_VALUE) {
1322 		oprintf(fp, "  Minimum Possible Voltage: %u mV\n",
1323 		    vp.smbvp_minval);
1324 	} else {
1325 		oprintf(fp, "  Minimum Possible Voltage: unknown\n");
1326 	}
1327 
1328 	if (vp.smbvp_resolution != SMB_PROBE_UNKNOWN_VALUE) {
1329 		oprintf(fp, "  Probe Resolution: %u.%u mV\n",
1330 		    vp.smbvp_resolution / 10,
1331 		    vp.smbvp_resolution % 10);
1332 	} else {
1333 		oprintf(fp, "  Probe Resolution: unknown\n");
1334 	}
1335 
1336 	if (vp.smbvp_tolerance != SMB_PROBE_UNKNOWN_VALUE) {
1337 		oprintf(fp, "  Probe Tolerance: +/-%u mV\n",
1338 		    vp.smbvp_tolerance);
1339 	} else {
1340 		oprintf(fp, "  Probe Tolerance: unknown\n");
1341 	}
1342 
1343 	if (vp.smbvp_accuracy != SMB_PROBE_UNKNOWN_VALUE) {
1344 		oprintf(fp, "  Probe Accuracy: +/-%u.%02u%%\n",
1345 		    vp.smbvp_accuracy / 100,
1346 		    vp.smbvp_accuracy % 100);
1347 	} else {
1348 		oprintf(fp, "  Probe Accuracy: unknown\n");
1349 	}
1350 
1351 	oprintf(fp, "  OEM- or BIOS- defined value: 0x%x\n", vp.smbvp_oem);
1352 
1353 	if (vp.smbvp_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1354 		oprintf(fp, "  Probe Nominal Value: %u mV\n", vp.smbvp_nominal);
1355 	} else {
1356 		oprintf(fp, "  Probe Nominal Value: unknown\n");
1357 	}
1358 }
1359 
1360 static void
1361 print_cooldev(smbios_hdl_t *shp, id_t id, FILE *fp)
1362 {
1363 	smbios_cooldev_t cd;
1364 
1365 	if (smbios_info_cooldev(shp, id, &cd) != 0) {
1366 		smbios_warn(shp, "failed to read cooling device "
1367 		    "information");
1368 		return;
1369 	}
1370 
1371 	id_printf(fp, "  Temperature Probe Handle: ", cd.smbcd_tprobe);
1372 	desc_printf(smbios_cooldev_type_desc(cd.smbcd_type),
1373 	    fp, "  Device Type: %u", cd.smbcd_type);
1374 	desc_printf(smbios_cooldev_status_desc(cd.smbcd_status),
1375 	    fp, "  Status: %u", cd.smbcd_status);
1376 	oprintf(fp, "  Cooling Unit Group: %u\n", cd.smbcd_group);
1377 	oprintf(fp, "  OEM- or BIOS- defined data: 0x%x\n", cd.smbcd_oem);
1378 	if (cd.smbcd_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1379 		oprintf(fp, "  Nominal Speed: %u RPM\n", cd.smbcd_nominal);
1380 	} else {
1381 		oprintf(fp, "  Nominal Speed: unknown\n");
1382 	}
1383 
1384 	if (cd.smbcd_descr != NULL && cd.smbcd_descr[0] != '\0') {
1385 		str_print(fp, "  Description", cd.smbcd_descr);
1386 	}
1387 }
1388 
1389 static void
1390 print_tprobe(smbios_hdl_t *shp, id_t id, FILE *fp)
1391 {
1392 	smbios_tprobe_t tp;
1393 
1394 	if (smbios_info_tprobe(shp, id, &tp) != 0) {
1395 		smbios_warn(shp, "failed to read temperature probe "
1396 		    "information");
1397 		return;
1398 	}
1399 
1400 	str_print(fp, "  Description", tp.smbtp_description != NULL ?
1401 	    tp.smbtp_description : "unknown");
1402 	desc_printf(smbios_tprobe_loc_desc(tp.smbtp_location),
1403 	    fp, "  Location: %u", tp.smbtp_location);
1404 	desc_printf(smbios_tprobe_status_desc(tp.smbtp_status),
1405 	    fp, "  Status: %u", tp.smbtp_status);
1406 
1407 	if (tp.smbtp_maxval != SMB_PROBE_UNKNOWN_VALUE) {
1408 		oprintf(fp, "  Maximum Possible Temperature: %u.%u C\n",
1409 		    tp.smbtp_maxval / 10, tp.smbtp_maxval % 10);
1410 	} else {
1411 		oprintf(fp, "  Maximum Possible Temperature: unknown\n");
1412 	}
1413 
1414 	if (tp.smbtp_minval != SMB_PROBE_UNKNOWN_VALUE) {
1415 		oprintf(fp, "  Minimum Possible Temperature: %u.%u C\n",
1416 		    tp.smbtp_minval / 10, tp.smbtp_minval % 10);
1417 	} else {
1418 		oprintf(fp, "  Minimum Possible Temperature: unknown\n");
1419 	}
1420 
1421 	if (tp.smbtp_resolution != SMB_PROBE_UNKNOWN_VALUE) {
1422 		oprintf(fp, "  Probe Resolution: %u.%03u C\n",
1423 		    tp.smbtp_resolution / 1000,
1424 		    tp.smbtp_resolution % 1000);
1425 	} else {
1426 		oprintf(fp, "  Probe Resolution: unknown\n");
1427 	}
1428 
1429 	if (tp.smbtp_tolerance != SMB_PROBE_UNKNOWN_VALUE) {
1430 		oprintf(fp, "  Probe Tolerance: +/-%u.%u C\n",
1431 		    tp.smbtp_tolerance / 10, tp.smbtp_tolerance % 10);
1432 	} else {
1433 		oprintf(fp, "  Probe Tolerance: unknown\n");
1434 	}
1435 
1436 	if (tp.smbtp_accuracy != SMB_PROBE_UNKNOWN_VALUE) {
1437 		oprintf(fp, "  Probe Accuracy: +/-%u.%02u%%\n",
1438 		    tp.smbtp_accuracy / 100,
1439 		    tp.smbtp_accuracy % 100);
1440 	} else {
1441 		oprintf(fp, "  Probe Accuracy: unknown\n");
1442 	}
1443 
1444 	oprintf(fp, "  OEM- or BIOS- defined value: 0x%x\n", tp.smbtp_oem);
1445 
1446 	if (tp.smbtp_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1447 		oprintf(fp, "  Probe Nominal Value: %u.%u C\n",
1448 		    tp.smbtp_nominal / 10, tp.smbtp_nominal % 10);
1449 	} else {
1450 		oprintf(fp, "  Probe Nominal Value: unknown\n");
1451 	}
1452 }
1453 
1454 static void
1455 print_iprobe(smbios_hdl_t *shp, id_t id, FILE *fp)
1456 {
1457 	smbios_iprobe_t ip;
1458 
1459 	if (smbios_info_iprobe(shp, id, &ip) != 0) {
1460 		smbios_warn(shp, "failed to read current probe information");
1461 		return;
1462 	}
1463 
1464 	str_print(fp, "  Description", ip.smbip_description != NULL ?
1465 	    ip.smbip_description : "unknown");
1466 	desc_printf(smbios_iprobe_loc_desc(ip.smbip_location),
1467 	    fp, "  Location: %u", ip.smbip_location);
1468 	desc_printf(smbios_iprobe_status_desc(ip.smbip_status),
1469 	    fp, "  Status: %u", ip.smbip_status);
1470 
1471 	if (ip.smbip_maxval != SMB_PROBE_UNKNOWN_VALUE) {
1472 		oprintf(fp, "  Maximum Possible Current: %u mA\n",
1473 		    ip.smbip_maxval);
1474 	} else {
1475 		oprintf(fp, "  Maximum Possible Current: unknown\n");
1476 	}
1477 
1478 	if (ip.smbip_minval != SMB_PROBE_UNKNOWN_VALUE) {
1479 		oprintf(fp, "  Minimum Possible Current: %u mA\n",
1480 		    ip.smbip_minval);
1481 	} else {
1482 		oprintf(fp, "  Minimum Possible Current: unknown\n");
1483 	}
1484 
1485 	if (ip.smbip_resolution != SMB_PROBE_UNKNOWN_VALUE) {
1486 		oprintf(fp, "  Probe Resolution: %u.%u mA\n",
1487 		    ip.smbip_resolution / 10,
1488 		    ip.smbip_resolution % 10);
1489 	} else {
1490 		oprintf(fp, "  Probe Resolution: unknown\n");
1491 	}
1492 
1493 	if (ip.smbip_tolerance != SMB_PROBE_UNKNOWN_VALUE) {
1494 		oprintf(fp, "  Probe Tolerance: +/-%u mA\n",
1495 		    ip.smbip_tolerance);
1496 	} else {
1497 		oprintf(fp, "  Probe Tolerance: unknown\n");
1498 	}
1499 
1500 	if (ip.smbip_accuracy != SMB_PROBE_UNKNOWN_VALUE) {
1501 		oprintf(fp, "  Probe Accuracy: +/-%u.%02u%%\n",
1502 		    ip.smbip_accuracy / 100,
1503 		    ip.smbip_accuracy % 100);
1504 	} else {
1505 		oprintf(fp, "  Probe Accuracy: unknown\n");
1506 	}
1507 
1508 	oprintf(fp, "  OEM- or BIOS- defined value: 0x%x\n", ip.smbip_oem);
1509 
1510 	if (ip.smbip_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1511 		oprintf(fp, "  Probe Nominal Value: %u mA\n", ip.smbip_nominal);
1512 	} else {
1513 		oprintf(fp, "  Probe Nominal Value: unknown\n");
1514 	}
1515 }
1516 
1517 static void
1518 print_boot(smbios_hdl_t *shp, FILE *fp)
1519 {
1520 	smbios_boot_t b;
1521 
1522 	if (smbios_info_boot(shp, &b) == -1) {
1523 		smbios_warn(shp, "failed to read boot information");
1524 		return;
1525 	}
1526 
1527 	desc_printf(smbios_boot_desc(b.smbt_status),
1528 	    fp, "  Boot Status Code: 0x%x", b.smbt_status);
1529 
1530 	if (b.smbt_size != 0) {
1531 		oprintf(fp, "  Boot Data (%lu bytes):\n", (ulong_t)b.smbt_size);
1532 		print_bytes(b.smbt_data, b.smbt_size, fp);
1533 	}
1534 }
1535 
1536 static void
1537 print_mgmtdev(smbios_hdl_t *shp, id_t id, FILE *fp)
1538 {
1539 	smbios_mgmtdev_t md;
1540 
1541 	if (smbios_info_mgmtdev(shp, id, &md) == -1) {
1542 		smbios_warn(shp, "failed to read management device");
1543 		return;
1544 	}
1545 
1546 	str_print(fp, "  Description", md.smbmd_desc);
1547 	desc_printf(smbios_mgmtdev_dtype_desc(md.smbmd_dtype), fp,
1548 	    "  Device Type: 0x%x", md.smbmd_dtype);
1549 	oprintf(fp, "  Address: 0x%x\n", md.smbmd_addr);
1550 	desc_printf(smbios_mgmtdev_atype_desc(md.smbmd_atype), fp,
1551 	    "  Address Type: 0x%x", md.smbmd_atype);
1552 }
1553 
1554 static void
1555 print_mgmtcomp(smbios_hdl_t *shp, id_t id, FILE *fp)
1556 {
1557 	smbios_mgmtcomp_t mc;
1558 
1559 	if (smbios_info_mgmtcomp(shp, id, &mc) == -1) {
1560 		smbios_warn(shp, "failed to read management device component");
1561 		return;
1562 	}
1563 
1564 	str_print(fp, "  Description", mc.smbmc_desc);
1565 	id_printf(fp, "  Management Device Handle: ", mc.smbmc_mgmtdev);
1566 	id_printf(fp, "  Component Handle: ", mc.smbmc_comp);
1567 	id_printf(fp, "  Threshold Handle: ", mc.smbmc_thresh);
1568 }
1569 
1570 static void
1571 print_ipmi(smbios_hdl_t *shp, FILE *fp)
1572 {
1573 	smbios_ipmi_t i;
1574 
1575 	if (smbios_info_ipmi(shp, &i) == -1) {
1576 		smbios_warn(shp, "failed to read ipmi information");
1577 		return;
1578 	}
1579 
1580 	desc_printf(smbios_ipmi_type_desc(i.smbip_type),
1581 	    fp, "  Type: %u", i.smbip_type);
1582 
1583 	oprintf(fp, "  BMC IPMI Version: %u.%u\n",
1584 	    i.smbip_vers.smbv_major, i.smbip_vers.smbv_minor);
1585 
1586 	oprintf(fp, "  i2c Bus Slave Address: 0x%x\n", i.smbip_i2c);
1587 	oprintf(fp, "  NV Storage Device Bus ID: 0x%x\n", i.smbip_bus);
1588 	oprintf(fp, "  BMC Base Address: 0x%llx\n", (u_longlong_t)i.smbip_addr);
1589 	oprintf(fp, "  Interrupt Number: %u\n", i.smbip_intr);
1590 	oprintf(fp, "  Register Spacing: %u\n", i.smbip_regspacing);
1591 
1592 	flag_printf(fp, "Flags", i.smbip_flags, sizeof (i.smbip_flags) * NBBY,
1593 	    smbios_ipmi_flag_name, smbios_ipmi_flag_desc);
1594 }
1595 
1596 static void
1597 print_powersup(smbios_hdl_t *shp, id_t id, FILE *fp)
1598 {
1599 	smbios_powersup_t p;
1600 
1601 	if (smbios_info_powersup(shp, id, &p) != 0) {
1602 		smbios_warn(shp, "failed to read power supply information");
1603 		return;
1604 	}
1605 
1606 	oprintf(fp, "  Power Supply Group: %u\n", p.smbps_group);
1607 	if (p.smbps_maxout != 0x8000) {
1608 		oprintf(fp, "  Maximum Output: %" PRIu64 " mW\n",
1609 		    p.smbps_maxout);
1610 	} else {
1611 		oprintf(fp, "  Maximum Output: unknown\n");
1612 	}
1613 
1614 	flag_printf(fp, "Characteristics", p.smbps_flags,
1615 	    sizeof (p.smbps_flags) * NBBY, smbios_powersup_flag_name,
1616 	    smbios_powersup_flag_desc);
1617 
1618 	desc_printf(smbios_powersup_input_desc(p.smbps_ivrs),
1619 	    fp, "  Input Voltage Range Switching: %u", p.smbps_ivrs);
1620 	desc_printf(smbios_powersup_status_desc(p.smbps_status),
1621 	    fp, "  Status: %u", p.smbps_status);
1622 	desc_printf(smbios_powersup_type_desc(p.smbps_pstype),
1623 	    fp, "  Type: %u", p.smbps_pstype);
1624 
1625 	if (p.smbps_vprobe != 0xffff) {
1626 		oprintf(fp, "  Voltage Probe Handle: %" _PRIuID "\n",
1627 		    p.smbps_vprobe);
1628 	}
1629 
1630 	if (p.smbps_cooldev != 0xffff) {
1631 		oprintf(fp, "  Cooling Device Handle: %" _PRIuID "\n",
1632 		    p.smbps_cooldev);
1633 	}
1634 
1635 	if (p.smbps_iprobe != 0xffff) {
1636 		oprintf(fp, "  Current Probe Handle: %" _PRIuID "\n",
1637 		    p.smbps_iprobe);
1638 	}
1639 }
1640 
1641 static void
1642 print_addinfo(smbios_hdl_t *shp, id_t id, FILE *fp)
1643 {
1644 	uint_t nents, i;
1645 
1646 	if (smbios_info_addinfo_nents(shp, id, &nents) != 0) {
1647 		smbios_warn(shp, "failed to read additional information");
1648 		return;
1649 	}
1650 
1651 	oprintf(fp, "  Number of Additional Information Entries: %u\n", nents);
1652 	for (i = 0; i < nents; i++) {
1653 		smbios_addinfo_ent_t *ent;
1654 
1655 		oprintf(fp, "  Additional Information Entry %u\n", i);
1656 		if (smbios_info_addinfo_ent(shp, id, i, &ent) != 0) {
1657 			smbios_warn(shp, "failed to read additional "
1658 			    "information entry %u", i);
1659 			continue;
1660 		}
1661 
1662 		oprintf(fp, "    Referenced handle: %" _PRIuID "\n",
1663 		    ent->smbai_ref);
1664 		oprintf(fp, "    Handle offset: %u\n", ent->smbai_ref_off);
1665 		if (ent->smbai_str != NULL) {
1666 			str_print(fp, "    Information String", ent->smbai_str);
1667 		}
1668 
1669 		/*
1670 		 * As of SMBIOS 3.7, there are no extra data entries strictly
1671 		 * defined in the spec, but there may be something. If we find
1672 		 * something that's a standard integer size, then we'll
1673 		 * interpret it and print it as a hex value. In theory this is
1674 		 * supposed to refer back to some field, but hard to say how
1675 		 * this'll actually be used. The first time we encountered it
1676 		 * was just an additional string entry.
1677 		 */
1678 		if (ent->smbai_dlen > 0) {
1679 			oprintf(fp, "    Data Length: %u\n", ent->smbai_dlen);
1680 			switch (ent->smbai_dlen) {
1681 			case 1:
1682 				oprintf(fp, "    Data: 0x%x\n",
1683 				    *(uint8_t *)ent->smbai_data);
1684 				break;
1685 			case 2:
1686 				oprintf(fp, "    Data: 0x%x\n",
1687 				    *(uint16_t *)ent->smbai_data);
1688 				break;
1689 			case 4:
1690 				oprintf(fp, "    Data: 0x%x\n",
1691 				    *(uint32_t *)ent->smbai_data);
1692 				break;
1693 			case 8:
1694 				oprintf(fp, "    Data: 0x%" PRIx64 "\n",
1695 				    *(uint64_t *)ent->smbai_data);
1696 				break;
1697 			default:
1698 				break;
1699 			}
1700 		}
1701 
1702 		smbios_info_addinfo_ent_free(shp, ent);
1703 	}
1704 }
1705 
1706 
1707 static void
1708 print_processor_info_riscv(smbios_hdl_t *shp, id_t id, FILE *fp)
1709 {
1710 	smbios_processor_info_riscv_t rv;
1711 
1712 	if (smbios_info_processor_riscv(shp, id, &rv) != 0) {
1713 		smbios_warn(shp, "failed to read RISC-V specific processor "
1714 		    "information");
1715 		return;
1716 	}
1717 
1718 	if (rv.smbpirv_boothart != 0) {
1719 		oprintf(fp, "    Boot Hart\n");
1720 	}
1721 	u128_print(fp, "    Hart ID", rv.smbpirv_hartid);
1722 	u128_print(fp, "    Vendor ID", rv.smbpirv_vendid);
1723 	u128_print(fp, "    Architecture ID", rv.smbpirv_archid);
1724 	u128_print(fp, "    Implementation ID", rv.smbpirv_machid);
1725 	flag64_printf(fp, "  ISA", rv.smbpirv_isa,
1726 	    sizeof (rv.smbpirv_isa) * NBBY, smbios_riscv_isa_name,
1727 	    smbios_riscv_isa_desc);
1728 	flag_printf(fp, "  Privilege Levels", rv.smbpirv_privlvl,
1729 	    sizeof (rv.smbpirv_privlvl) * NBBY, smbios_riscv_priv_name,
1730 	    smbios_riscv_priv_desc);
1731 	u128_print(fp, "    Machine Exception Trap Delegation",
1732 	    rv.smbpirv_metdi);
1733 	u128_print(fp, "    Machine Interrupt Trap Delegation",
1734 	    rv.smbpirv_mitdi);
1735 	desc_printf(smbios_riscv_width_desc(rv.smbpirv_xlen),
1736 	    fp, "    Register Width: 0x%x", rv.smbpirv_xlen);
1737 	desc_printf(smbios_riscv_width_desc(rv.smbpirv_mxlen),
1738 	    fp, "    M-Mode Register Width: 0x%x", rv.smbpirv_mxlen);
1739 	desc_printf(smbios_riscv_width_desc(rv.smbpirv_sxlen),
1740 	    fp, "    S-Mode Register Width: 0x%x", rv.smbpirv_sxlen);
1741 	desc_printf(smbios_riscv_width_desc(rv.smbpirv_uxlen),
1742 	    fp, "    U-Mode Register Width: 0x%x", rv.smbpirv_uxlen);
1743 }
1744 
1745 static void
1746 print_processor_info(smbios_hdl_t *shp, id_t id, FILE *fp)
1747 {
1748 	smbios_processor_info_t p;
1749 
1750 	if (smbios_info_processor_info(shp, id, &p) != 0) {
1751 		smbios_warn(shp, "failed to read processor additional "
1752 		    "information");
1753 		return;
1754 	}
1755 
1756 	id_printf(fp, "  Processor Handle: ", p.smbpi_processor);
1757 	desc_printf(smbios_processor_info_type_desc(p.smbpi_ptype),
1758 	    fp, "  Processor Type: %u", p.smbpi_ptype);
1759 
1760 	switch (p.smbpi_ptype) {
1761 	case SMB_PROCINFO_T_RV32:
1762 	case SMB_PROCINFO_T_RV64:
1763 	case SMB_PROCINFO_T_RV128:
1764 		oprintf(fp, "  RISC-V Additional Processor Information:\n");
1765 		print_processor_info_riscv(shp, id, fp);
1766 		break;
1767 	default:
1768 		break;
1769 	}
1770 }
1771 
1772 static void
1773 print_battery(smbios_hdl_t *shp, id_t id, FILE *fp)
1774 {
1775 	smbios_battery_t bat;
1776 
1777 	if (smbios_info_battery(shp, id, &bat) != 0) {
1778 		smbios_warn(shp, "failed to read battery information");
1779 		return;
1780 	}
1781 
1782 	if (bat.smbb_date != NULL) {
1783 		str_print(fp, "  Manufacture Date", bat.smbb_date);
1784 	}
1785 
1786 	if (bat.smbb_serial != NULL) {
1787 		str_print(fp, "  Serial Number", bat.smbb_serial);
1788 	}
1789 
1790 	if (bat.smbb_chem != SMB_BDC_UNKNOWN) {
1791 		desc_printf(smbios_battery_chem_desc(bat.smbb_chem),
1792 		    fp, "  Battery Chemistry: 0x%x", bat.smbb_chem);
1793 	}
1794 
1795 	if (bat.smbb_cap != 0) {
1796 		oprintf(fp, "  Design Capacity: %u mWh\n", bat.smbb_cap);
1797 	} else {
1798 		oprintf(fp, "  Design Capacity: unknown\n");
1799 	}
1800 
1801 	if (bat.smbb_volt != 0) {
1802 		oprintf(fp, "  Design Voltage: %u mV\n", bat.smbb_volt);
1803 	} else {
1804 		oprintf(fp, "  Design Voltage: unknown\n");
1805 	}
1806 
1807 	str_print(fp, "  SBDS Version Number", bat.smbb_version);
1808 	if (bat.smbb_err != UINT8_MAX) {
1809 		oprintf(fp, "  Maximum Error: %u\n", bat.smbb_err);
1810 	} else {
1811 		oprintf(fp, "  Maximum Error: unknown\n");
1812 	}
1813 	oprintf(fp, "  SBDS Serial Number: %04x\n", bat.smbb_ssn);
1814 	oprintf(fp, "  SBDS Manufacture Date: %u-%02u-%02u\n", bat.smbb_syear,
1815 	    bat.smbb_smonth, bat.smbb_sday);
1816 	str_print(fp, "  SBDS Device Chemistry", bat.smbb_schem);
1817 	oprintf(fp, "  OEM-specific Information: 0x%08x\n", bat.smbb_oemdata);
1818 }
1819 
1820 static void
1821 print_pointdev(smbios_hdl_t *shp, id_t id, FILE *fp)
1822 {
1823 	smbios_pointdev_t pd;
1824 
1825 	if (smbios_info_pointdev(shp, id, &pd) != 0) {
1826 		smbios_warn(shp, "failed to read pointer device information");
1827 		return;
1828 	}
1829 
1830 	desc_printf(smbios_pointdev_type_desc(pd.smbpd_type),
1831 	    fp, "  Type: %u", pd.smbpd_type);
1832 	desc_printf(smbios_pointdev_iface_desc(pd.smbpd_iface),
1833 	    fp, "  Interface: %u", pd.smbpd_iface);
1834 	oprintf(fp, "  Buttons: %u\n", pd.smbpd_nbuttons);
1835 }
1836 
1837 static void
1838 print_extprocessor(smbios_hdl_t *shp, id_t id, FILE *fp)
1839 {
1840 	int i;
1841 	smbios_processor_ext_t ep;
1842 
1843 	if (check_oem(shp) != 0)
1844 		return;
1845 
1846 	if (smbios_info_extprocessor(shp, id, &ep) != 0) {
1847 		smbios_warn(shp, "failed to read extended processor "
1848 		    "information");
1849 		return;
1850 	}
1851 
1852 	oprintf(fp, "  Processor: %u\n", ep.smbpe_processor);
1853 	oprintf(fp, "  FRU: %u\n", ep.smbpe_fru);
1854 	oprintf(fp, "  Initial APIC ID count: %u\n\n", ep.smbpe_n);
1855 
1856 	for (i = 0; i < ep.smbpe_n; i++) {
1857 		oprintf(fp, "  Logical Strand %u: Initial APIC ID: %u\n", i,
1858 		    ep.smbpe_apicid[i]);
1859 	}
1860 }
1861 
1862 static void
1863 print_extport(smbios_hdl_t *shp, id_t id, FILE *fp)
1864 {
1865 	smbios_port_ext_t epo;
1866 
1867 	if (check_oem(shp) != 0)
1868 		return;
1869 
1870 	if (smbios_info_extport(shp, id, &epo) != 0) {
1871 		smbios_warn(shp, "failed to read extended port information");
1872 		return;
1873 	}
1874 
1875 	oprintf(fp, "  Chassis Handle: %u\n", epo.smbporte_chassis);
1876 	oprintf(fp, "  Port Connector Handle: %u\n", epo.smbporte_port);
1877 	oprintf(fp, "  Device Type: %u\n", epo.smbporte_dtype);
1878 	oprintf(fp, "  Device Handle: %u\n", epo.smbporte_devhdl);
1879 	oprintf(fp, "  PHY: %u\n", epo.smbporte_phy);
1880 }
1881 
1882 static void
1883 print_pciexrc(smbios_hdl_t *shp, id_t id, FILE *fp)
1884 {
1885 	smbios_pciexrc_t pcie;
1886 
1887 	if (check_oem(shp) != 0)
1888 		return;
1889 
1890 	if (smbios_info_pciexrc(shp, id, &pcie) != 0) {
1891 		smbios_warn(shp, "failed to read pciexrc information");
1892 		return;
1893 	}
1894 
1895 	oprintf(fp, "  Component ID: %u\n", pcie.smbpcie_bb);
1896 	oprintf(fp, "  BDF: 0x%x\n", pcie.smbpcie_bdf);
1897 }
1898 
1899 static void
1900 print_extmemarray(smbios_hdl_t *shp, id_t id, FILE *fp)
1901 {
1902 	smbios_memarray_ext_t em;
1903 
1904 	if (check_oem(shp) != 0)
1905 		return;
1906 
1907 	if (smbios_info_extmemarray(shp, id, &em) != 0) {
1908 		smbios_warn(shp, "failed to read extmemarray information");
1909 		return;
1910 	}
1911 
1912 	oprintf(fp, "  Physical Memory Array Handle: %u\n", em.smbmae_ma);
1913 	oprintf(fp, "  Component Parent Handle: %u\n", em.smbmae_comp);
1914 	oprintf(fp, "  BDF: 0x%x\n", em.smbmae_bdf);
1915 }
1916 
1917 static void
1918 print_extmemdevice(smbios_hdl_t *shp, id_t id, FILE *fp)
1919 {
1920 	uint_t i, ncs;
1921 	uint8_t *cs;
1922 	smbios_memdevice_ext_t emd;
1923 
1924 	if (check_oem(shp) != 0)
1925 		return;
1926 
1927 	if (smbios_info_extmemdevice(shp, id, &emd) != 0) {
1928 		smbios_warn(shp, "failed to read extmemdevice information");
1929 		return;
1930 	}
1931 
1932 	oprintf(fp, "  Memory Device Handle: %u\n", emd.smbmdeve_md);
1933 	oprintf(fp, "  DRAM Channel: %u\n", emd.smbmdeve_drch);
1934 	oprintf(fp, "  Number of Chip Selects: %u\n", emd.smbmdeve_ncs);
1935 
1936 	if (emd.smbmdeve_ncs == 0)
1937 		return;
1938 
1939 	if (smbios_info_extmemdevice_cs(shp, id, &ncs, &cs) != 0) {
1940 		smbios_warn(shp, "failed to read extmemdevice cs information");
1941 		return;
1942 	}
1943 
1944 	for (i = 0; i < ncs; i++) {
1945 		oprintf(fp, "  Chip Select: %u\n", cs[i]);
1946 	}
1947 	smbios_info_extmemdevice_cs_free(shp, ncs, cs);
1948 }
1949 
1950 static void
1951 print_strprop_info(smbios_hdl_t *shp, id_t id, FILE *fp)
1952 {
1953 	smbios_strprop_t prop;
1954 
1955 	if (smbios_info_strprop(shp, id, &prop) != 0) {
1956 		smbios_warn(shp, "failed to read string property information");
1957 		return;
1958 	}
1959 
1960 	desc_printf(smbios_strprop_id_desc(prop.smbsp_prop_id), fp,
1961 	    "  Property ID: %u", prop.smbsp_prop_id);
1962 	if (prop.smbsp_prop_val != NULL) {
1963 		str_print(fp, "  Property Value", prop.smbsp_prop_val);
1964 	}
1965 	id_printf(fp, "  Parent Handle: ", prop.smbsp_parent);
1966 }
1967 
1968 static void
1969 print_tpm(smbios_hdl_t *shp, id_t id, FILE *fp)
1970 {
1971 	size_t i;
1972 	smbios_tpm_t tpm;
1973 
1974 	if (smbios_info_tpm(shp, id, &tpm) != 0) {
1975 		smbios_warn(shp, "failed to read TPM information");
1976 		return;
1977 	}
1978 
1979 	oprintf(fp, "  Vendor ID: ");
1980 	for (i = 0; i < ARRAY_SIZE(tpm.smbtpm_vid); i++) {
1981 		/*
1982 		 * We've found some vendors terminate this with a NUL. If we
1983 		 * find that, then we consider that the end and stop printing.
1984 		 */
1985 		if (tpm.smbtpm_vid[i] == '\0')
1986 			break;
1987 
1988 		if (isascii(tpm.smbtpm_vid[i]) && isprint(tpm.smbtpm_vid[i])) {
1989 			(void) oprintf(fp, "%c", tpm.smbtpm_vid[i]);
1990 		} else {
1991 			oprintf(fp, "\\x%02x", tpm.smbtpm_vid[i]);
1992 		}
1993 	}
1994 	oprintf(fp, "\n");
1995 	oprintf(fp, "  Spec Version: %u.%u\n", tpm.smbtpm_major,
1996 	    tpm.smbtpm_minor);
1997 	oprintf(fp, "  Firmware Version 1: 0x%x\n", tpm.smbtpm_fwv1);
1998 	oprintf(fp, "  Firmware Version 2: 0x%x\n", tpm.smbtpm_fwv2);
1999 	str_print(fp, "  Description", tpm.smbtpm_desc);
2000 	flag64_printf(fp, "Characteristics",
2001 	    tpm.smbtpm_chars, sizeof (tpm.smbtpm_chars) * NBBY,
2002 	    smbios_tpm_char_name, smbios_tpm_char_desc);
2003 	oprintf(fp, "  OEM-defined: 0x%x", tpm.smbtpm_oem);
2004 }
2005 
2006 static void
2007 print_fwinfo(smbios_hdl_t *shp, id_t id, FILE *fp)
2008 {
2009 	smbios_fwinfo_t fw;
2010 	smbios_fwinfo_comp_t *comps;
2011 	uint_t ncomps, i;
2012 
2013 	if (smbios_info_fwinfo(shp, id, &fw) != 0) {
2014 		smbios_warn(shp, "failed to read firmware inventory");
2015 		return;
2016 	}
2017 
2018 	str_print(fp, "  Component Name", fw.smbfw_name);
2019 	str_print(fp, "  ID", fw.smbfw_id);
2020 	str_print(fp, "  Release Date", fw.smbfw_reldate);
2021 	str_print(fp, "  Lowest Supported Version", fw.smbfw_lsv);
2022 	desc_printf(smbios_fwinfo_vers_desc(fw.smbfw_vers_fmt), fp,
2023 	    "  Version Format: %u", fw.smbfw_vers_fmt);
2024 	desc_printf(smbios_fwinfo_id_desc(fw.smbfw_id_fmt), fp,
2025 	    "  ID Format: %u", fw.smbfw_id_fmt);
2026 	if (fw.smbfw_imgsz != UINT64_MAX) {
2027 		oprintf(fp, "  Image Size: %" PRIu64 "\n", fw.smbfw_imgsz);
2028 	} else {
2029 		oprintf(fp, "  Image Size: unknown\n");
2030 	}
2031 
2032 	flag_printf(fp, "Characteristics", fw.smbfw_chars,
2033 	    sizeof (fw.smbfw_chars) * NBBY, smbios_fwinfo_ch_name,
2034 	    smbios_fwinfo_ch_desc);
2035 
2036 	desc_printf(smbios_fwinfo_state_desc(fw.smbfw_state), fp, "  State: %u",
2037 	    fw.smbfw_state);
2038 	oprintf(fp, "  Number of Associated Components: %u\n",
2039 	    fw.smbfw_ncomps);
2040 
2041 	if (fw.smbfw_ncomps == 0)
2042 		return;
2043 
2044 	if (smbios_info_fwinfo_comps(shp, id, &ncomps, &comps) == -1) {
2045 		smbios_warn(shp, "failed to read firmware inventory "
2046 		    "components");
2047 		return;
2048 	}
2049 
2050 	oprintf(fp, "\n  Component Handles:\n");
2051 	for (i = 0; i < ncomps; i++) {
2052 		oprintf(fp, "    %" _PRIdID "\n", comps[i].smbfwe_id);
2053 	}
2054 }
2055 
2056 static int
2057 print_struct(smbios_hdl_t *shp, const smbios_struct_t *sp, void *fp)
2058 {
2059 	smbios_info_t info;
2060 	int hex = opt_x;
2061 	const char *s;
2062 
2063 	if (opt_t != -1 && opt_t != sp->smbstr_type)
2064 		return (0); /* skip struct if type doesn't match -t */
2065 
2066 	if (!opt_O && (sp->smbstr_type == SMB_TYPE_MEMCTL ||
2067 	    sp->smbstr_type == SMB_TYPE_MEMMOD))
2068 		return (0); /* skip struct if type is obsolete */
2069 
2070 	if (g_hdr++ == 0 || !opt_s)
2071 		oprintf(fp, "%-5s %-4s %s\n", "ID", "SIZE", "TYPE");
2072 
2073 	oprintf(fp, "%-5u %-4lu",
2074 	    (uint_t)sp->smbstr_id, (ulong_t)sp->smbstr_size);
2075 
2076 	if ((s = smbios_type_name(sp->smbstr_type)) != NULL)
2077 		oprintf(fp, " %s (type %u)", s, sp->smbstr_type);
2078 	else if (sp->smbstr_type > SMB_TYPE_OEM_LO &&
2079 	    sp->smbstr_type < SMB_TYPE_OEM_HI)
2080 		oprintf(fp, " %s+%u (type %u)", "SMB_TYPE_OEM_LO",
2081 		    sp->smbstr_type - SMB_TYPE_OEM_LO, sp->smbstr_type);
2082 	else
2083 		oprintf(fp, " %u", sp->smbstr_type);
2084 
2085 	if ((s = smbios_type_desc(sp->smbstr_type)) != NULL)
2086 		oprintf(fp, " (%s)\n", s);
2087 	else
2088 		oprintf(fp, "\n");
2089 
2090 	if (opt_s)
2091 		return (0); /* only print header line if -s specified */
2092 
2093 	if (smbios_info_common(shp, sp->smbstr_id, &info) == 0) {
2094 		oprintf(fp, "\n");
2095 		print_common(&info, fp);
2096 	}
2097 
2098 	switch (sp->smbstr_type) {
2099 	case SMB_TYPE_BIOS:
2100 		oprintf(fp, "\n");
2101 		print_bios(shp, fp);
2102 		break;
2103 	case SMB_TYPE_SYSTEM:
2104 		oprintf(fp, "\n");
2105 		print_system(shp, fp);
2106 		break;
2107 	case SMB_TYPE_BASEBOARD:
2108 		oprintf(fp, "\n");
2109 		print_bboard(shp, sp->smbstr_id, fp);
2110 		break;
2111 	case SMB_TYPE_CHASSIS:
2112 		oprintf(fp, "\n");
2113 		print_chassis(shp, sp->smbstr_id, fp);
2114 		break;
2115 	case SMB_TYPE_PROCESSOR:
2116 		oprintf(fp, "\n");
2117 		print_processor(shp, sp->smbstr_id, fp);
2118 		break;
2119 	case SMB_TYPE_CACHE:
2120 		oprintf(fp, "\n");
2121 		print_cache(shp, sp->smbstr_id, fp);
2122 		break;
2123 	case SMB_TYPE_PORT:
2124 		oprintf(fp, "\n");
2125 		print_port(shp, sp->smbstr_id, fp);
2126 		break;
2127 	case SMB_TYPE_SLOT:
2128 		oprintf(fp, "\n");
2129 		print_slot(shp, sp->smbstr_id, fp);
2130 		break;
2131 	case SMB_TYPE_OBDEVS:
2132 		oprintf(fp, "\n");
2133 		print_obdevs(shp, sp->smbstr_id, fp);
2134 		break;
2135 	case SMB_TYPE_OEMSTR:
2136 	case SMB_TYPE_SYSCONFSTR:
2137 		oprintf(fp, "\n");
2138 		print_strtab(shp, sp->smbstr_id, fp);
2139 		break;
2140 	case SMB_TYPE_LANG:
2141 		oprintf(fp, "\n");
2142 		print_lang(shp, sp->smbstr_id, fp);
2143 		break;
2144 	case SMB_TYPE_EVENTLOG:
2145 		oprintf(fp, "\n");
2146 		print_evlog(shp, sp->smbstr_id, fp);
2147 		break;
2148 	case SMB_TYPE_MEMARRAY:
2149 		oprintf(fp, "\n");
2150 		print_memarray(shp, sp->smbstr_id, fp);
2151 		break;
2152 	case SMB_TYPE_MEMDEVICE:
2153 		oprintf(fp, "\n");
2154 		print_memdevice(shp, sp->smbstr_id, fp);
2155 		break;
2156 	case SMB_TYPE_MEMARRAYMAP:
2157 		oprintf(fp, "\n");
2158 		print_memarrmap(shp, sp->smbstr_id, fp);
2159 		break;
2160 	case SMB_TYPE_MEMDEVICEMAP:
2161 		oprintf(fp, "\n");
2162 		print_memdevmap(shp, sp->smbstr_id, fp);
2163 		break;
2164 	case SMB_TYPE_BATTERY:
2165 		oprintf(fp, "\n");
2166 		print_battery(shp, sp->smbstr_id, fp);
2167 		break;
2168 	case SMB_TYPE_POINTDEV:
2169 		oprintf(fp, "\n");
2170 		print_pointdev(shp, sp->smbstr_id, fp);
2171 		break;
2172 	case SMB_TYPE_SECURITY:
2173 		oprintf(fp, "\n");
2174 		print_hwsec(shp, fp);
2175 		break;
2176 	case SMB_TYPE_VPROBE:
2177 		oprintf(fp, "\n");
2178 		print_vprobe(shp, sp->smbstr_id, fp);
2179 		break;
2180 	case SMB_TYPE_COOLDEV:
2181 		oprintf(fp, "\n");
2182 		print_cooldev(shp, sp->smbstr_id, fp);
2183 		break;
2184 	case SMB_TYPE_TPROBE:
2185 		oprintf(fp, "\n");
2186 		print_tprobe(shp, sp->smbstr_id, fp);
2187 		break;
2188 	case SMB_TYPE_IPROBE:
2189 		oprintf(fp, "\n");
2190 		print_iprobe(shp, sp->smbstr_id, fp);
2191 		break;
2192 	case SMB_TYPE_BOOT:
2193 		oprintf(fp, "\n");
2194 		print_boot(shp, fp);
2195 		break;
2196 	case SMB_TYPE_MGMTDEV:
2197 		oprintf(fp, "\n");
2198 		print_mgmtdev(shp, sp->smbstr_id, fp);
2199 		break;
2200 	case SMB_TYPE_MGMTDEVCP:
2201 		oprintf(fp, "\n");
2202 		print_mgmtcomp(shp, sp->smbstr_id, fp);
2203 		break;
2204 	case SMB_TYPE_IPMIDEV:
2205 		oprintf(fp, "\n");
2206 		print_ipmi(shp, fp);
2207 		break;
2208 	case SMB_TYPE_POWERSUP:
2209 		oprintf(fp, "\n");
2210 		print_powersup(shp, sp->smbstr_id, fp);
2211 		break;
2212 	case SMB_TYPE_ADDINFO:
2213 		oprintf(fp, "\n");
2214 		print_addinfo(shp, sp->smbstr_id, fp);
2215 		break;
2216 	case SMB_TYPE_OBDEVEXT:
2217 		oprintf(fp, "\n");
2218 		print_obdevs_ext(shp, sp->smbstr_id, fp);
2219 		break;
2220 	case SMB_TYPE_PROCESSOR_INFO:
2221 		oprintf(fp, "\n");
2222 		print_processor_info(shp, sp->smbstr_id, fp);
2223 		break;
2224 	case SMB_TYPE_TPM:
2225 		oprintf(fp, "\n");
2226 		print_tpm(shp, sp->smbstr_id, fp);
2227 		break;
2228 	case SMB_TYPE_STRPROP:
2229 		oprintf(fp, "\n");
2230 		print_strprop_info(shp, sp->smbstr_id, fp);
2231 		break;
2232 	case SMB_TYPE_FWINFO:
2233 		oprintf(fp, "\n");
2234 		print_fwinfo(shp, sp->smbstr_id, fp);
2235 		break;
2236 	case SUN_OEM_EXT_PROCESSOR:
2237 		oprintf(fp, "\n");
2238 		print_extprocessor(shp, sp->smbstr_id, fp);
2239 		break;
2240 	case SUN_OEM_EXT_PORT:
2241 		oprintf(fp, "\n");
2242 		print_extport(shp, sp->smbstr_id, fp);
2243 		break;
2244 	case SUN_OEM_PCIEXRC:
2245 		oprintf(fp, "\n");
2246 		print_pciexrc(shp, sp->smbstr_id, fp);
2247 		break;
2248 	case SUN_OEM_EXT_MEMARRAY:
2249 		oprintf(fp, "\n");
2250 		print_extmemarray(shp, sp->smbstr_id, fp);
2251 		break;
2252 	case SUN_OEM_EXT_MEMDEVICE:
2253 		oprintf(fp, "\n");
2254 		print_extmemdevice(shp, sp->smbstr_id, fp);
2255 		break;
2256 	default:
2257 		hex++;
2258 	}
2259 
2260 	if (hex)
2261 		print_bytes(sp->smbstr_data, sp->smbstr_size, fp);
2262 	else
2263 		oprintf(fp, "\n");
2264 
2265 	return (0);
2266 }
2267 
2268 static uint16_t
2269 getu16(const char *name, const char *s)
2270 {
2271 	u_longlong_t val;
2272 	char *p;
2273 
2274 	errno = 0;
2275 	val = strtoull(s, &p, 0);
2276 
2277 	if (errno != 0 || p == s || *p != '\0' || val > UINT16_MAX) {
2278 		(void) fprintf(stderr, "%s: invalid %s argument -- %s\n",
2279 		    g_pname, name, s);
2280 		exit(SMBIOS_USAGE);
2281 	}
2282 
2283 	return ((uint16_t)val);
2284 }
2285 
2286 static uint16_t
2287 getstype(const char *name, const char *s)
2288 {
2289 	const char *ts;
2290 	uint16_t t;
2291 
2292 	for (t = 0; t < SMB_TYPE_OEM_LO; t++) {
2293 		if ((ts = smbios_type_name(t)) != NULL && strcmp(s, ts) == 0)
2294 			return (t);
2295 	}
2296 
2297 	(void) fprintf(stderr, "%s: invalid %s argument -- %s\n",
2298 	    g_pname, name, s);
2299 
2300 	exit(SMBIOS_USAGE);
2301 	/*NOTREACHED*/
2302 }
2303 
2304 static int
2305 usage(FILE *fp)
2306 {
2307 	(void) fprintf(fp, "Usage: %s "
2308 	    "[-BeOsx] [-i id] [-t type] [-w file] [file]\n\n", g_pname);
2309 
2310 	(void) fprintf(fp,
2311 	    "\t-B disable header validation for broken BIOSes\n"
2312 	    "\t-e display SMBIOS entry point information\n"
2313 	    "\t-i display only the specified structure\n"
2314 	    "\t-O display obsolete structure types\n"
2315 	    "\t-s display only a summary of structure identifiers and types\n"
2316 	    "\t-t display only the specified structure type\n"
2317 	    "\t-w write the raw data to the specified file\n"
2318 	    "\t-x display raw data for structures\n");
2319 
2320 	return (SMBIOS_USAGE);
2321 }
2322 
2323 int
2324 main(int argc, char *argv[])
2325 {
2326 	const char *ifile = NULL;
2327 	const char *ofile = NULL;
2328 	int oflags = 0;
2329 
2330 	smbios_hdl_t *shp;
2331 	smbios_struct_t s;
2332 	int err, fd, c;
2333 	char *p;
2334 
2335 	if ((p = strrchr(argv[0], '/')) == NULL)
2336 		g_pname = argv[0];
2337 	else
2338 		g_pname = p + 1;
2339 
2340 	while (optind < argc) {
2341 		while ((c = getopt(argc, argv, "Bei:Ost:w:xZ")) != EOF) {
2342 			switch (c) {
2343 			case 'B':
2344 				oflags |= SMB_O_NOCKSUM | SMB_O_NOVERS;
2345 				break;
2346 			case 'e':
2347 				opt_e++;
2348 				break;
2349 			case 'i':
2350 				opt_i = getu16("struct ID", optarg);
2351 				break;
2352 			case 'O':
2353 				opt_O++;
2354 				break;
2355 			case 's':
2356 				opt_s++;
2357 				break;
2358 			case 't':
2359 				if (isdigit(optarg[0]))
2360 					opt_t = getu16("struct type", optarg);
2361 				else
2362 					opt_t = getstype("struct type", optarg);
2363 				break;
2364 			case 'w':
2365 				ofile = optarg;
2366 				break;
2367 			case 'x':
2368 				opt_x++;
2369 				break;
2370 			case 'Z':
2371 				oflags |= SMB_O_ZIDS; /* undocumented */
2372 				break;
2373 			default:
2374 				return (usage(stderr));
2375 			}
2376 		}
2377 
2378 		if (optind < argc) {
2379 			if (ifile != NULL) {
2380 				(void) fprintf(stderr, "%s: illegal "
2381 				    "argument -- %s\n", g_pname, argv[optind]);
2382 				return (SMBIOS_USAGE);
2383 			}
2384 			ifile = argv[optind++];
2385 		}
2386 	}
2387 
2388 	if ((shp = smbios_open(ifile, SMB_VERSION, oflags, &err)) == NULL) {
2389 		(void) fprintf(stderr, "%s: failed to load SMBIOS: %s\n",
2390 		    g_pname, smbios_errmsg(err));
2391 		return (SMBIOS_ERROR);
2392 	}
2393 
2394 	if (opt_i == -1 && opt_t == -1 && opt_e == 0 &&
2395 	    smbios_truncated(shp))
2396 		(void) fprintf(stderr, "%s: SMBIOS table is truncated\n",
2397 		    g_pname);
2398 
2399 	if (ofile != NULL) {
2400 		if ((fd = open(ofile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1) {
2401 			(void) fprintf(stderr, "%s: failed to open %s: %s\n",
2402 			    g_pname, ofile, strerror(errno));
2403 			err = SMBIOS_ERROR;
2404 		} else if (smbios_write(shp, fd) != 0) {
2405 			(void) fprintf(stderr, "%s: failed to write %s: %s\n",
2406 			    g_pname, ofile, smbios_errmsg(smbios_errno(shp)));
2407 			err = SMBIOS_ERROR;
2408 		}
2409 		smbios_close(shp);
2410 		return (err);
2411 	}
2412 
2413 	if (opt_e) {
2414 		print_smbios(shp, stdout);
2415 		smbios_close(shp);
2416 		return (SMBIOS_SUCCESS);
2417 	}
2418 
2419 	if (opt_O && (opt_i != -1 || opt_t != -1))
2420 		opt_O++; /* -i or -t imply displaying obsolete records */
2421 
2422 	if (opt_i != -1)
2423 		err = smbios_lookup_id(shp, opt_i, &s);
2424 	else
2425 		err = smbios_iter(shp, print_struct, stdout);
2426 
2427 	if (err != 0) {
2428 		(void) fprintf(stderr, "%s: failed to access SMBIOS: %s\n",
2429 		    g_pname, smbios_errmsg(smbios_errno(shp)));
2430 		smbios_close(shp);
2431 		return (SMBIOS_ERROR);
2432 	}
2433 
2434 	if (opt_i != -1)
2435 		(void) print_struct(shp, &s, stdout);
2436 
2437 	smbios_close(shp);
2438 	return (SMBIOS_SUCCESS);
2439 }
2440