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