xref: /illumos-gate/usr/src/cmd/smbios/smbios.c (revision ba2b435afc094312a669141557d7db936139fcb7)
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
smbios_vergteq(smbios_version_t * v,uint_t major,uint_t minor)63 smbios_vergteq(smbios_version_t *v, uint_t major, uint_t minor)
64 {
65 	if (v->smbv_major > major)
66 		return (B_TRUE);
67 	if (v->smbv_major == major &&
68 	    v->smbv_minor >= minor)
69 		return (B_TRUE);
70 	return (B_FALSE);
71 }
72 
73 static void __PRINTFLIKE(2)
smbios_warn(smbios_hdl_t * shp,const char * format,...)74 smbios_warn(smbios_hdl_t *shp, const char *format, ...)
75 {
76 	va_list ap;
77 
78 	va_start(ap, format);
79 	(void) vfprintf(stderr, format, ap);
80 	va_end(ap);
81 
82 	if (shp != NULL) {
83 		(void) fprintf(stderr, ": %s",
84 		    smbios_errmsg(smbios_errno(shp)));
85 	}
86 
87 	(void) fprintf(stderr, "\n");
88 }
89 
90 static void __PRINTFLIKE(2)
oprintf(FILE * fp,const char * format,...)91 oprintf(FILE *fp, const char *format, ...)
92 {
93 	va_list ap;
94 
95 	va_start(ap, format);
96 	(void) vfprintf(fp, format, ap);
97 	va_end(ap);
98 }
99 
100 static void __PRINTFLIKE(3)
desc_printf(const char * d,FILE * fp,const char * format,...)101 desc_printf(const char *d, FILE *fp, const char *format, ...)
102 {
103 	va_list ap;
104 
105 	va_start(ap, format);
106 	(void) vfprintf(fp, format, ap);
107 	va_end(ap);
108 
109 	if (d != NULL)
110 		(void) fprintf(fp, " (%s)\n", d);
111 	else
112 		(void) fprintf(fp, "\n");
113 }
114 
115 static void
flag_printf(FILE * fp,const char * s,uint_t flags,size_t bits,const char * (* flag_name)(uint_t),const char * (* flag_desc)(uint_t))116 flag_printf(FILE *fp, const char *s, uint_t flags, size_t bits,
117     const char *(*flag_name)(uint_t), const char *(*flag_desc)(uint_t))
118 {
119 	size_t i;
120 
121 	oprintf(fp, "  %s: 0x%x\n", s, flags);
122 
123 	for (i = 0; i < bits; i++) {
124 		uint_t f = 1 << i;
125 		const char *n;
126 
127 		if (!(flags & f))
128 			continue;
129 
130 		if ((n = flag_name(f)) != NULL)
131 			desc_printf(flag_desc(f), fp, "\t%s", n);
132 		else
133 			desc_printf(flag_desc(f), fp, "\t0x%x", f);
134 	}
135 }
136 
137 static void
flag64_printf(FILE * fp,const char * s,uint64_t flags,size_t bits,const char * (* flag_name)(uint64_t),const char * (* flag_desc)(uint64_t))138 flag64_printf(FILE *fp, const char *s, uint64_t flags, size_t bits,
139     const char *(*flag_name)(uint64_t), const char *(*flag_desc)(uint64_t))
140 {
141 	size_t i;
142 
143 	oprintf(fp, "  %s: 0x%llx\n", s, (u_longlong_t)flags);
144 
145 	for (i = 0; i < bits; i++) {
146 		u_longlong_t f = 1ULL << i;
147 		const char *n;
148 
149 		if (!(flags & f))
150 			continue;
151 
152 		if ((n = flag_name(f)) != NULL)
153 			desc_printf(flag_desc(f), fp, "\t%s", n);
154 		else
155 			desc_printf(flag_desc(f), fp, "\t0x%llx", f);
156 	}
157 }
158 
159 static void
id_printf(FILE * fp,const char * s,id_t id)160 id_printf(FILE *fp, const char *s, id_t id)
161 {
162 	switch (id) {
163 	case SMB_ID_NONE:
164 		oprintf(fp, "%sNone\n", s);
165 		break;
166 	case SMB_ID_NOTSUP:
167 		oprintf(fp, "%sNot Supported\n", s);
168 		break;
169 	default:
170 		oprintf(fp, "%s%u\n", s, (uint_t)id);
171 	}
172 }
173 
174 static void
jedec_print(FILE * fp,const char * desc,uint_t id)175 jedec_print(FILE *fp, const char *desc, uint_t id)
176 {
177 	const char *name;
178 	uint_t cont, vendor;
179 
180 	/*
181 	 * SMBIOS encodes data in the way that the underlying memory standard
182 	 * does. In this case, the upper byte indicates the vendor that we care
183 	 * about while the lower byte indicates the number of continuations that
184 	 * are needed. libjedec indexes this based on zero (e.g. table 1 is zero
185 	 * continuations), which is how the spec encodes it. We add one so that
186 	 * we can match how the spec describes it.
187 	 */
188 	vendor = id >> 8;
189 	cont = id & 0x7f;
190 	name = libjedec_vendor_string(cont, vendor);
191 	if (name == NULL) {
192 		oprintf(fp, "  %s: Bank: 0x%x Vendor: 0x%x\n", desc, cont + 1,
193 		    vendor);
194 	} else {
195 		oprintf(fp, "  %s: Bank: 0x%x Vendor: 0x%x (%s)\n", desc,
196 		    cont + 1, vendor, name);
197 	}
198 }
199 
200 /*
201  * Convert an SMBIOS encoded JEDEDC component revision into its actual form. In
202  * general, JEDEC revisions are single byte values; however, the SMBIOS fields
203  * are two bytes wide. The byte that we care about is the "first" byte which
204  * translates into the upper bits here. The revision is binary coded decimal
205  * (BCD) represented with each nibble as major.minor. The major is the upper
206  * nibble and the minor is the lower one.
207  */
208 static void
jedec_rev_print(FILE * fp,const char * desc,uint16_t raw_rev)209 jedec_rev_print(FILE *fp, const char *desc, uint16_t raw_rev)
210 {
211 	uint8_t rev = (uint8_t)bitx16(raw_rev, 15, 8);
212 	uint8_t maj = bitx8(rev, 7, 4);
213 	uint8_t min = bitx8(rev, 3, 0);
214 	oprintf(fp, "  %s: %x.%x\n", desc, maj, min);
215 }
216 
217 /*
218  * Print a 128-bit data as a series of 16 hex digits.
219  */
220 static void
u128_print(FILE * fp,const char * desc,const uint8_t * data)221 u128_print(FILE *fp, const char *desc, const uint8_t *data)
222 {
223 	uint_t i;
224 
225 	oprintf(fp, "%s: ", desc);
226 	for (i = 0; i < 16; i++) {
227 		oprintf(fp, " %02x", data[i]);
228 	}
229 	oprintf(fp, "\n");
230 }
231 
232 /*
233  * Print a string that came from an SMBIOS table. We do this character by
234  * character so we can potentially escape strings.
235  */
236 static void
str_print_label(FILE * fp,const char * header,const char * str,boolean_t label)237 str_print_label(FILE *fp, const char *header, const char *str, boolean_t label)
238 {
239 	const char *c;
240 
241 	oprintf(fp, header);
242 	if (label) {
243 		oprintf(fp, ": ");
244 	}
245 
246 	for (c = str; *c != '\0'; c++) {
247 		if (isprint(*c)) {
248 			oprintf(fp, "%c", *c);
249 		} else {
250 			oprintf(fp, "\\x%02x", *c);
251 		}
252 	}
253 
254 	oprintf(fp, "\n");
255 }
256 
257 static void
str_print_nolabel(FILE * fp,const char * ws,const char * str)258 str_print_nolabel(FILE *fp, const char *ws, const char *str)
259 {
260 	return (str_print_label(fp, ws, str, B_FALSE));
261 }
262 
263 static void
str_print(FILE * fp,const char * header,const char * str)264 str_print(FILE *fp, const char *header, const char *str)
265 {
266 	return (str_print_label(fp, header, str, B_TRUE));
267 }
268 
269 static int
check_oem(smbios_hdl_t * shp)270 check_oem(smbios_hdl_t *shp)
271 {
272 	int i;
273 	int cnt;
274 	int rv;
275 	id_t oem_id;
276 	smbios_struct_t s;
277 	const char **oem_str;
278 
279 	rv = smbios_lookup_type(shp, SMB_TYPE_OEMSTR, &s);
280 	if (rv != 0) {
281 		return (-1);
282 	}
283 
284 	oem_id = s.smbstr_id;
285 
286 	cnt = smbios_info_strtab(shp, oem_id, 0, NULL);
287 	if (cnt > 0) {
288 		oem_str =  alloca(sizeof (char *) * cnt);
289 		(void) smbios_info_strtab(shp, oem_id, cnt, oem_str);
290 
291 		for (i = 0; i < cnt; i++) {
292 			if (strncmp(oem_str[i], SMB_PRMS1,
293 			    strlen(SMB_PRMS1) + 1) == 0) {
294 				return (0);
295 			}
296 		}
297 	}
298 
299 	return (-1);
300 }
301 
302 static void
print_smbios_21(smbios_21_entry_t * ep,FILE * fp)303 print_smbios_21(smbios_21_entry_t *ep, FILE *fp)
304 {
305 	int i;
306 
307 	oprintf(fp, "Entry Point Anchor Tag: %*.*s\n",
308 	    (int)sizeof (ep->smbe_eanchor), (int)sizeof (ep->smbe_eanchor),
309 	    ep->smbe_eanchor);
310 
311 	oprintf(fp, "Entry Point Checksum: 0x%x\n", ep->smbe_ecksum);
312 	oprintf(fp, "Entry Point Length: %u\n", ep->smbe_elen);
313 	oprintf(fp, "Entry Point Version: %u.%u\n",
314 	    ep->smbe_major, ep->smbe_minor);
315 	oprintf(fp, "Max Structure Size: %u\n", ep->smbe_maxssize);
316 	oprintf(fp, "Entry Point Revision: 0x%x\n", ep->smbe_revision);
317 
318 	oprintf(fp, "Entry Point Revision Data:");
319 	for (i = 0; i < sizeof (ep->smbe_format); i++)
320 		oprintf(fp, " 0x%02x", ep->smbe_format[i]);
321 	oprintf(fp, "\n");
322 
323 	oprintf(fp, "Intermediate Anchor Tag: %*.*s\n",
324 	    (int)sizeof (ep->smbe_ianchor), (int)sizeof (ep->smbe_ianchor),
325 	    ep->smbe_ianchor);
326 
327 	oprintf(fp, "Intermediate Checksum: 0x%x\n", ep->smbe_icksum);
328 	oprintf(fp, "Structure Table Length: %u\n", ep->smbe_stlen);
329 	oprintf(fp, "Structure Table Address: 0x%x\n", ep->smbe_staddr);
330 	oprintf(fp, "Structure Table Entries: %u\n", ep->smbe_stnum);
331 	oprintf(fp, "DMI BCD Revision: 0x%x\n", ep->smbe_bcdrev);
332 }
333 
334 static void
print_smbios_30(smbios_30_entry_t * ep,FILE * fp)335 print_smbios_30(smbios_30_entry_t *ep, FILE *fp)
336 {
337 	oprintf(fp, "Entry Point Anchor Tag: %*.*s\n",
338 	    (int)sizeof (ep->smbe_eanchor), (int)sizeof (ep->smbe_eanchor),
339 	    ep->smbe_eanchor);
340 
341 	oprintf(fp, "Entry Point Checksum: 0x%x\n", ep->smbe_ecksum);
342 	oprintf(fp, "Entry Point Length: %u\n", ep->smbe_elen);
343 	oprintf(fp, "SMBIOS Version: %u.%u\n",
344 	    ep->smbe_major, ep->smbe_minor);
345 	oprintf(fp, "SMBIOS DocRev: 0x%x\n", ep->smbe_docrev);
346 	oprintf(fp, "Entry Point Revision: 0x%x\n", ep->smbe_revision);
347 
348 	oprintf(fp, "Structure Table Length: %u\n", ep->smbe_stlen);
349 	oprintf(fp, "Structure Table Address: 0x%" PRIx64 "\n",
350 	    ep->smbe_staddr);
351 }
352 
353 static void
print_smbios(smbios_hdl_t * shp,FILE * fp)354 print_smbios(smbios_hdl_t *shp, FILE *fp)
355 {
356 	smbios_entry_t ep;
357 
358 	switch (smbios_info_smbios(shp, &ep)) {
359 	case SMBIOS_ENTRY_POINT_21:
360 		print_smbios_21(&ep.ep21, fp);
361 		break;
362 	case SMBIOS_ENTRY_POINT_30:
363 		print_smbios_30(&ep.ep30, fp);
364 		break;
365 	}
366 }
367 
368 static void
print_common(const smbios_info_t * ip,FILE * fp)369 print_common(const smbios_info_t *ip, FILE *fp)
370 {
371 	if (ip->smbi_manufacturer[0] != '\0')
372 		str_print(fp, "  Manufacturer", ip->smbi_manufacturer);
373 	if (ip->smbi_product[0] != '\0')
374 		str_print(fp, "  Product", ip->smbi_product);
375 	if (ip->smbi_version[0] != '\0')
376 		str_print(fp, "  Version", ip->smbi_version);
377 	if (ip->smbi_serial[0] != '\0')
378 		str_print(fp, "  Serial Number", ip->smbi_serial);
379 	if (ip->smbi_asset[0] != '\0')
380 		str_print(fp, "  Asset Tag", ip->smbi_asset);
381 	if (ip->smbi_location[0] != '\0')
382 		str_print(fp, "  Location Tag", ip->smbi_location);
383 	if (ip->smbi_part[0] != '\0')
384 		str_print(fp, "  Part Number", ip->smbi_part);
385 }
386 
387 static void
print_bios(smbios_hdl_t * shp,FILE * fp)388 print_bios(smbios_hdl_t *shp, FILE *fp)
389 {
390 	smbios_bios_t b;
391 
392 	if (smbios_info_bios(shp, &b) == -1) {
393 		smbios_warn(shp, "failed to read BIOS information");
394 		return;
395 	}
396 
397 	str_print(fp, "  Vendor", b.smbb_vendor);
398 	str_print(fp, "  Version String", b.smbb_version);
399 	str_print(fp, "  Release Date", b.smbb_reldate);
400 	oprintf(fp, "  Address Segment: 0x%x\n", b.smbb_segment);
401 	oprintf(fp, "  ROM Size: %" PRIu64 " bytes\n", b.smbb_extromsize);
402 	oprintf(fp, "  Image Size: %u bytes\n", b.smbb_runsize);
403 
404 	flag64_printf(fp, "Characteristics",
405 	    b.smbb_cflags, sizeof (b.smbb_cflags) * NBBY,
406 	    smbios_bios_flag_name, smbios_bios_flag_desc);
407 
408 	if (b.smbb_nxcflags > SMB_BIOSXB_1) {
409 		flag_printf(fp, "Characteristics Extension Byte 1",
410 		    b.smbb_xcflags[SMB_BIOSXB_1],
411 		    sizeof (b.smbb_xcflags[SMB_BIOSXB_1]) * NBBY,
412 		    smbios_bios_xb1_name, smbios_bios_xb1_desc);
413 	}
414 
415 	if (b.smbb_nxcflags > SMB_BIOSXB_2) {
416 		flag_printf(fp, "Characteristics Extension Byte 2",
417 		    b.smbb_xcflags[SMB_BIOSXB_2],
418 		    sizeof (b.smbb_xcflags[SMB_BIOSXB_2]) * NBBY,
419 		    smbios_bios_xb2_name, smbios_bios_xb2_desc);
420 	}
421 
422 	if (b.smbb_nxcflags > SMB_BIOSXB_BIOS_MIN) {
423 		oprintf(fp, "  Version Number: %u.%u\n",
424 		    b.smbb_biosv.smbv_major, b.smbb_biosv.smbv_minor);
425 	}
426 
427 	/*
428 	 * If the major and minor versions are 0xff then that indicates that the
429 	 * embedded controller does not exist.
430 	 */
431 	if (b.smbb_nxcflags > SMB_BIOSXB_ECFW_MIN &&
432 	    b.smbb_ecfwv.smbv_major != 0xff &&
433 	    b.smbb_ecfwv.smbv_minor != 0xff) {
434 		oprintf(fp, "  Embedded Ctlr Firmware Version Number: %u.%u\n",
435 		    b.smbb_ecfwv.smbv_major, b.smbb_ecfwv.smbv_minor);
436 	}
437 }
438 
439 static void
print_system(smbios_hdl_t * shp,FILE * fp)440 print_system(smbios_hdl_t *shp, FILE *fp)
441 {
442 	smbios_system_t s;
443 	uint_t i;
444 
445 	if (smbios_info_system(shp, &s) == -1) {
446 		smbios_warn(shp, "failed to read system information");
447 		return;
448 	}
449 
450 	oprintf(fp, "  UUID: ");
451 	for (i = 0; i < s.smbs_uuidlen; i++) {
452 		oprintf(fp, "%02x", s.smbs_uuid[i]);
453 		if (i == 3 || i == 5 || i == 7 || i == 9)
454 			oprintf(fp, "-");
455 	}
456 	oprintf(fp, "\n");
457 
458 	desc_printf(smbios_system_wakeup_desc(s.smbs_wakeup),
459 	    fp, "  Wake-Up Event: 0x%x", s.smbs_wakeup);
460 
461 	str_print(fp, "  SKU Number", s.smbs_sku);
462 	str_print(fp, "  Family", s.smbs_family);
463 }
464 
465 static void
print_bboard(smbios_hdl_t * shp,id_t id,FILE * fp)466 print_bboard(smbios_hdl_t *shp, id_t id, FILE *fp)
467 {
468 	smbios_bboard_t b;
469 	int chdl_cnt;
470 
471 	if (smbios_info_bboard(shp, id, &b) != 0) {
472 		smbios_warn(shp, "failed to read baseboard information");
473 		return;
474 	}
475 
476 	oprintf(fp, "  Chassis: %u\n", (uint_t)b.smbb_chassis);
477 
478 	flag_printf(fp, "Flags", b.smbb_flags, sizeof (b.smbb_flags) * NBBY,
479 	    smbios_bboard_flag_name, smbios_bboard_flag_desc);
480 
481 	desc_printf(smbios_bboard_type_desc(b.smbb_type),
482 	    fp, "  Board Type: 0x%x", b.smbb_type);
483 
484 	chdl_cnt = b.smbb_contn;
485 	if (chdl_cnt != 0) {
486 		id_t *chdl;
487 		uint16_t hdl;
488 		int i, n, cnt;
489 
490 		chdl = alloca(chdl_cnt * sizeof (id_t));
491 		cnt = smbios_info_contains(shp, id, chdl_cnt, chdl);
492 		if (cnt > SMB_CONT_MAX)
493 			return;
494 		n = MIN(chdl_cnt, cnt);
495 
496 		oprintf(fp, "\n");
497 		for (i = 0; i < n; i++) {
498 			hdl = (uint16_t)chdl[i];
499 			oprintf(fp, "  Contained Handle: %u\n", hdl);
500 		}
501 	}
502 }
503 
504 static void
print_chassis(smbios_hdl_t * shp,id_t id,FILE * fp)505 print_chassis(smbios_hdl_t *shp, id_t id, FILE *fp)
506 {
507 	smbios_chassis_t c;
508 	smbios_chassis_entry_t *elts;
509 	uint_t nelts, i;
510 
511 	if (smbios_info_chassis(shp, id, &c) != 0) {
512 		smbios_warn(shp, "failed to read chassis information");
513 		return;
514 	}
515 
516 	oprintf(fp, "  OEM Data: 0x%x\n", c.smbc_oemdata);
517 	str_print(fp, "  SKU Number",
518 	    c.smbc_sku[0] == '\0' ? "<unknown>" : c.smbc_sku);
519 	oprintf(fp, "  Lock Present: %s\n", c.smbc_lock ? "Y" : "N");
520 
521 	desc_printf(smbios_chassis_type_desc(c.smbc_type),
522 	    fp, "  Chassis Type: 0x%x", c.smbc_type);
523 
524 	desc_printf(smbios_chassis_state_desc(c.smbc_bustate),
525 	    fp, "  Boot-Up State: 0x%x", c.smbc_bustate);
526 
527 	desc_printf(smbios_chassis_state_desc(c.smbc_psstate),
528 	    fp, "  Power Supply State: 0x%x", c.smbc_psstate);
529 
530 	desc_printf(smbios_chassis_state_desc(c.smbc_thstate),
531 	    fp, "  Thermal State: 0x%x", c.smbc_thstate);
532 
533 	/*
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
print_processor(smbios_hdl_t * shp,id_t id,FILE * fp)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
print_cache(smbios_hdl_t * shp,id_t id,FILE * fp)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
print_port(smbios_hdl_t * shp,id_t id,FILE * fp)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
print_slot(smbios_hdl_t * shp,id_t id,FILE * fp)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
print_obdevs_ext(smbios_hdl_t * shp,id_t id,FILE * fp)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
print_obdevs(smbios_hdl_t * shp,id_t id,FILE * fp)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
print_strtab(smbios_hdl_t * shp,id_t id,FILE * fp)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
print_lang(smbios_hdl_t * shp,id_t id,FILE * fp)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
print_evlog(smbios_hdl_t * shp,id_t id,FILE * fp)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
print_bytes(const uint8_t * data,size_t size,FILE * fp)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
print_memarray(smbios_hdl_t * shp,id_t id,FILE * fp)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
print_memdevice(smbios_hdl_t * shp,id_t id,FILE * fp)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
print_memarrmap(smbios_hdl_t * shp,id_t id,FILE * fp)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
print_memdevmap(smbios_hdl_t * shp,id_t id,FILE * fp)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
print_hwsec(smbios_hdl_t * shp,FILE * fp)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
print_vprobe(smbios_hdl_t * shp,id_t id,FILE * fp)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
print_cooldev(smbios_hdl_t * shp,id_t id,FILE * fp)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
print_tprobe(smbios_hdl_t * shp,id_t id,FILE * fp)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
print_iprobe(smbios_hdl_t * shp,id_t id,FILE * fp)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
print_boot(smbios_hdl_t * shp,FILE * fp)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
print_ipmi(smbios_hdl_t * shp,FILE * fp)1537 print_ipmi(smbios_hdl_t *shp, FILE *fp)
1538 {
1539 	smbios_ipmi_t i;
1540 
1541 	if (smbios_info_ipmi(shp, &i) == -1) {
1542 		smbios_warn(shp, "failed to read ipmi information");
1543 		return;
1544 	}
1545 
1546 	desc_printf(smbios_ipmi_type_desc(i.smbip_type),
1547 	    fp, "  Type: %u", i.smbip_type);
1548 
1549 	oprintf(fp, "  BMC IPMI Version: %u.%u\n",
1550 	    i.smbip_vers.smbv_major, i.smbip_vers.smbv_minor);
1551 
1552 	oprintf(fp, "  i2c Bus Slave Address: 0x%x\n", i.smbip_i2c);
1553 	oprintf(fp, "  NV Storage Device Bus ID: 0x%x\n", i.smbip_bus);
1554 	oprintf(fp, "  BMC Base Address: 0x%llx\n", (u_longlong_t)i.smbip_addr);
1555 	oprintf(fp, "  Interrupt Number: %u\n", i.smbip_intr);
1556 	oprintf(fp, "  Register Spacing: %u\n", i.smbip_regspacing);
1557 
1558 	flag_printf(fp, "Flags", i.smbip_flags, sizeof (i.smbip_flags) * NBBY,
1559 	    smbios_ipmi_flag_name, smbios_ipmi_flag_desc);
1560 }
1561 
1562 static void
print_powersup(smbios_hdl_t * shp,id_t id,FILE * fp)1563 print_powersup(smbios_hdl_t *shp, id_t id, FILE *fp)
1564 {
1565 	smbios_powersup_t p;
1566 
1567 	if (smbios_info_powersup(shp, id, &p) != 0) {
1568 		smbios_warn(shp, "failed to read power supply information");
1569 		return;
1570 	}
1571 
1572 	oprintf(fp, "  Power Supply Group: %u\n", p.smbps_group);
1573 	if (p.smbps_maxout != 0x8000) {
1574 		oprintf(fp, "  Maximum Output: %" PRIu64 " mW\n",
1575 		    p.smbps_maxout);
1576 	} else {
1577 		oprintf(fp, "  Maximum Output: unknown\n");
1578 	}
1579 
1580 	flag_printf(fp, "Characteristics", p.smbps_flags,
1581 	    sizeof (p.smbps_flags) * NBBY, smbios_powersup_flag_name,
1582 	    smbios_powersup_flag_desc);
1583 
1584 	desc_printf(smbios_powersup_input_desc(p.smbps_ivrs),
1585 	    fp, "  Input Voltage Range Switching: %u", p.smbps_ivrs);
1586 	desc_printf(smbios_powersup_status_desc(p.smbps_status),
1587 	    fp, "  Status: %u", p.smbps_status);
1588 	desc_printf(smbios_powersup_type_desc(p.smbps_pstype),
1589 	    fp, "  Type: %u", p.smbps_pstype);
1590 
1591 	if (p.smbps_vprobe != 0xffff) {
1592 		oprintf(fp, "  Voltage Probe Handle: %" _PRIuID "\n",
1593 		    p.smbps_vprobe);
1594 	}
1595 
1596 	if (p.smbps_cooldev != 0xffff) {
1597 		oprintf(fp, "  Cooling Device Handle: %" _PRIuID "\n",
1598 		    p.smbps_cooldev);
1599 	}
1600 
1601 	if (p.smbps_iprobe != 0xffff) {
1602 		oprintf(fp, "  Current Probe Handle: %" _PRIuID "\n",
1603 		    p.smbps_iprobe);
1604 	}
1605 }
1606 
1607 static void
print_addinfo(smbios_hdl_t * shp,id_t id,FILE * fp)1608 print_addinfo(smbios_hdl_t *shp, id_t id, FILE *fp)
1609 {
1610 	uint_t nents, i;
1611 
1612 	if (smbios_info_addinfo_nents(shp, id, &nents) != 0) {
1613 		smbios_warn(shp, "failed to read additional information");
1614 		return;
1615 	}
1616 
1617 	oprintf(fp, "  Number of Additional Information Entries: %u\n", nents);
1618 	for (i = 0; i < nents; i++) {
1619 		smbios_addinfo_ent_t *ent;
1620 
1621 		oprintf(fp, "  Additional Information Entry %u\n", i);
1622 		if (smbios_info_addinfo_ent(shp, id, i, &ent) != 0) {
1623 			smbios_warn(shp, "failed to read additional "
1624 			    "information entry %u", i);
1625 			continue;
1626 		}
1627 
1628 		oprintf(fp, "    Referenced handle: %" _PRIuID "\n",
1629 		    ent->smbai_ref);
1630 		oprintf(fp, "    Handle offset: %u\n", ent->smbai_ref_off);
1631 		if (ent->smbai_str != NULL) {
1632 			str_print(fp, "    Information String", ent->smbai_str);
1633 		}
1634 
1635 		/*
1636 		 * As of SMBIOS 3.7, there are no extra data entries strictly
1637 		 * defined in the spec, but there may be something. If we find
1638 		 * something that's a standard integer size, then we'll
1639 		 * interpret it and print it as a hex value. In theory this is
1640 		 * supposed to refer back to some field, but hard to say how
1641 		 * this'll actually be used. The first time we encountered it
1642 		 * was just an additional string entry.
1643 		 */
1644 		if (ent->smbai_dlen > 0) {
1645 			oprintf(fp, "    Data Length: %u\n", ent->smbai_dlen);
1646 			switch (ent->smbai_dlen) {
1647 			case 1:
1648 				oprintf(fp, "    Data: 0x%x\n",
1649 				    *(uint8_t *)ent->smbai_data);
1650 				break;
1651 			case 2:
1652 				oprintf(fp, "    Data: 0x%x\n",
1653 				    *(uint16_t *)ent->smbai_data);
1654 				break;
1655 			case 4:
1656 				oprintf(fp, "    Data: 0x%x\n",
1657 				    *(uint32_t *)ent->smbai_data);
1658 				break;
1659 			case 8:
1660 				oprintf(fp, "    Data: 0x%" PRIx64 "\n",
1661 				    *(uint64_t *)ent->smbai_data);
1662 				break;
1663 			default:
1664 				break;
1665 			}
1666 		}
1667 
1668 		smbios_info_addinfo_ent_free(shp, ent);
1669 	}
1670 }
1671 
1672 
1673 static void
print_processor_info_riscv(smbios_hdl_t * shp,id_t id,FILE * fp)1674 print_processor_info_riscv(smbios_hdl_t *shp, id_t id, FILE *fp)
1675 {
1676 	smbios_processor_info_riscv_t rv;
1677 
1678 	if (smbios_info_processor_riscv(shp, id, &rv) != 0) {
1679 		smbios_warn(shp, "failed to read RISC-V specific processor "
1680 		    "information");
1681 		return;
1682 	}
1683 
1684 	if (rv.smbpirv_boothart != 0) {
1685 		oprintf(fp, "    Boot Hart\n");
1686 	}
1687 	u128_print(fp, "    Hart ID", rv.smbpirv_hartid);
1688 	u128_print(fp, "    Vendor ID", rv.smbpirv_vendid);
1689 	u128_print(fp, "    Architecture ID", rv.smbpirv_archid);
1690 	u128_print(fp, "    Implementation ID", rv.smbpirv_machid);
1691 	flag64_printf(fp, "  ISA", rv.smbpirv_isa,
1692 	    sizeof (rv.smbpirv_isa) * NBBY, smbios_riscv_isa_name,
1693 	    smbios_riscv_isa_desc);
1694 	flag_printf(fp, "  Privilege Levels", rv.smbpirv_privlvl,
1695 	    sizeof (rv.smbpirv_privlvl) * NBBY, smbios_riscv_priv_name,
1696 	    smbios_riscv_priv_desc);
1697 	u128_print(fp, "    Machine Exception Trap Delegation",
1698 	    rv.smbpirv_metdi);
1699 	u128_print(fp, "    Machine Interrupt Trap Delegation",
1700 	    rv.smbpirv_mitdi);
1701 	desc_printf(smbios_riscv_width_desc(rv.smbpirv_xlen),
1702 	    fp, "    Register Width: 0x%x", rv.smbpirv_xlen);
1703 	desc_printf(smbios_riscv_width_desc(rv.smbpirv_mxlen),
1704 	    fp, "    M-Mode Register Width: 0x%x", rv.smbpirv_mxlen);
1705 	desc_printf(smbios_riscv_width_desc(rv.smbpirv_sxlen),
1706 	    fp, "    S-Mode Register Width: 0x%x", rv.smbpirv_sxlen);
1707 	desc_printf(smbios_riscv_width_desc(rv.smbpirv_uxlen),
1708 	    fp, "    U-Mode Register Width: 0x%x", rv.smbpirv_uxlen);
1709 }
1710 
1711 static void
print_processor_info(smbios_hdl_t * shp,id_t id,FILE * fp)1712 print_processor_info(smbios_hdl_t *shp, id_t id, FILE *fp)
1713 {
1714 	smbios_processor_info_t p;
1715 
1716 	if (smbios_info_processor_info(shp, id, &p) != 0) {
1717 		smbios_warn(shp, "failed to read processor additional "
1718 		    "information");
1719 		return;
1720 	}
1721 
1722 	id_printf(fp, "  Processor Handle: ", p.smbpi_processor);
1723 	desc_printf(smbios_processor_info_type_desc(p.smbpi_ptype),
1724 	    fp, "  Processor Type: %u", p.smbpi_ptype);
1725 
1726 	switch (p.smbpi_ptype) {
1727 	case SMB_PROCINFO_T_RV32:
1728 	case SMB_PROCINFO_T_RV64:
1729 	case SMB_PROCINFO_T_RV128:
1730 		oprintf(fp, "  RISC-V Additional Processor Information:\n");
1731 		print_processor_info_riscv(shp, id, fp);
1732 		break;
1733 	default:
1734 		break;
1735 	}
1736 }
1737 
1738 static void
print_battery(smbios_hdl_t * shp,id_t id,FILE * fp)1739 print_battery(smbios_hdl_t *shp, id_t id, FILE *fp)
1740 {
1741 	smbios_battery_t bat;
1742 
1743 	if (smbios_info_battery(shp, id, &bat) != 0) {
1744 		smbios_warn(shp, "failed to read battery information");
1745 		return;
1746 	}
1747 
1748 	if (bat.smbb_date != NULL) {
1749 		str_print(fp, "  Manufacture Date", bat.smbb_date);
1750 	}
1751 
1752 	if (bat.smbb_serial != NULL) {
1753 		str_print(fp, "  Serial Number", bat.smbb_serial);
1754 	}
1755 
1756 	if (bat.smbb_chem != SMB_BDC_UNKNOWN) {
1757 		desc_printf(smbios_battery_chem_desc(bat.smbb_chem),
1758 		    fp, "  Battery Chemistry: 0x%x", bat.smbb_chem);
1759 	}
1760 
1761 	if (bat.smbb_cap != 0) {
1762 		oprintf(fp, "  Design Capacity: %u mWh\n", bat.smbb_cap);
1763 	} else {
1764 		oprintf(fp, "  Design Capacity: unknown\n");
1765 	}
1766 
1767 	if (bat.smbb_volt != 0) {
1768 		oprintf(fp, "  Design Voltage: %u mV\n", bat.smbb_volt);
1769 	} else {
1770 		oprintf(fp, "  Design Voltage: unknown\n");
1771 	}
1772 
1773 	str_print(fp, "  SBDS Version Number", bat.smbb_version);
1774 	if (bat.smbb_err != UINT8_MAX) {
1775 		oprintf(fp, "  Maximum Error: %u\n", bat.smbb_err);
1776 	} else {
1777 		oprintf(fp, "  Maximum Error: unknown\n");
1778 	}
1779 	oprintf(fp, "  SBDS Serial Number: %04x\n", bat.smbb_ssn);
1780 	oprintf(fp, "  SBDS Manufacture Date: %u-%02u-%02u\n", bat.smbb_syear,
1781 	    bat.smbb_smonth, bat.smbb_sday);
1782 	str_print(fp, "  SBDS Device Chemistry", bat.smbb_schem);
1783 	oprintf(fp, "  OEM-specific Information: 0x%08x\n", bat.smbb_oemdata);
1784 }
1785 
1786 static void
print_pointdev(smbios_hdl_t * shp,id_t id,FILE * fp)1787 print_pointdev(smbios_hdl_t *shp, id_t id, FILE *fp)
1788 {
1789 	smbios_pointdev_t pd;
1790 
1791 	if (smbios_info_pointdev(shp, id, &pd) != 0) {
1792 		smbios_warn(shp, "failed to read pointer device information");
1793 		return;
1794 	}
1795 
1796 	desc_printf(smbios_pointdev_type_desc(pd.smbpd_type),
1797 	    fp, "  Type: %u", pd.smbpd_type);
1798 	desc_printf(smbios_pointdev_iface_desc(pd.smbpd_iface),
1799 	    fp, "  Interface: %u", pd.smbpd_iface);
1800 	oprintf(fp, "  Buttons: %u\n", pd.smbpd_nbuttons);
1801 }
1802 
1803 static void
print_extprocessor(smbios_hdl_t * shp,id_t id,FILE * fp)1804 print_extprocessor(smbios_hdl_t *shp, id_t id, FILE *fp)
1805 {
1806 	int i;
1807 	smbios_processor_ext_t ep;
1808 
1809 	if (check_oem(shp) != 0)
1810 		return;
1811 
1812 	if (smbios_info_extprocessor(shp, id, &ep) != 0) {
1813 		smbios_warn(shp, "failed to read extended processor "
1814 		    "information");
1815 		return;
1816 	}
1817 
1818 	oprintf(fp, "  Processor: %u\n", ep.smbpe_processor);
1819 	oprintf(fp, "  FRU: %u\n", ep.smbpe_fru);
1820 	oprintf(fp, "  Initial APIC ID count: %u\n\n", ep.smbpe_n);
1821 
1822 	for (i = 0; i < ep.smbpe_n; i++) {
1823 		oprintf(fp, "  Logical Strand %u: Initial APIC ID: %u\n", i,
1824 		    ep.smbpe_apicid[i]);
1825 	}
1826 }
1827 
1828 static void
print_extport(smbios_hdl_t * shp,id_t id,FILE * fp)1829 print_extport(smbios_hdl_t *shp, id_t id, FILE *fp)
1830 {
1831 	smbios_port_ext_t epo;
1832 
1833 	if (check_oem(shp) != 0)
1834 		return;
1835 
1836 	if (smbios_info_extport(shp, id, &epo) != 0) {
1837 		smbios_warn(shp, "failed to read extended port information");
1838 		return;
1839 	}
1840 
1841 	oprintf(fp, "  Chassis Handle: %u\n", epo.smbporte_chassis);
1842 	oprintf(fp, "  Port Connector Handle: %u\n", epo.smbporte_port);
1843 	oprintf(fp, "  Device Type: %u\n", epo.smbporte_dtype);
1844 	oprintf(fp, "  Device Handle: %u\n", epo.smbporte_devhdl);
1845 	oprintf(fp, "  PHY: %u\n", epo.smbporte_phy);
1846 }
1847 
1848 static void
print_pciexrc(smbios_hdl_t * shp,id_t id,FILE * fp)1849 print_pciexrc(smbios_hdl_t *shp, id_t id, FILE *fp)
1850 {
1851 	smbios_pciexrc_t pcie;
1852 
1853 	if (check_oem(shp) != 0)
1854 		return;
1855 
1856 	if (smbios_info_pciexrc(shp, id, &pcie) != 0) {
1857 		smbios_warn(shp, "failed to read pciexrc information");
1858 		return;
1859 	}
1860 
1861 	oprintf(fp, "  Component ID: %u\n", pcie.smbpcie_bb);
1862 	oprintf(fp, "  BDF: 0x%x\n", pcie.smbpcie_bdf);
1863 }
1864 
1865 static void
print_extmemarray(smbios_hdl_t * shp,id_t id,FILE * fp)1866 print_extmemarray(smbios_hdl_t *shp, id_t id, FILE *fp)
1867 {
1868 	smbios_memarray_ext_t em;
1869 
1870 	if (check_oem(shp) != 0)
1871 		return;
1872 
1873 	if (smbios_info_extmemarray(shp, id, &em) != 0) {
1874 		smbios_warn(shp, "failed to read extmemarray information");
1875 		return;
1876 	}
1877 
1878 	oprintf(fp, "  Physical Memory Array Handle: %u\n", em.smbmae_ma);
1879 	oprintf(fp, "  Component Parent Handle: %u\n", em.smbmae_comp);
1880 	oprintf(fp, "  BDF: 0x%x\n", em.smbmae_bdf);
1881 }
1882 
1883 static void
print_extmemdevice(smbios_hdl_t * shp,id_t id,FILE * fp)1884 print_extmemdevice(smbios_hdl_t *shp, id_t id, FILE *fp)
1885 {
1886 	uint_t i, ncs;
1887 	uint8_t *cs;
1888 	smbios_memdevice_ext_t emd;
1889 
1890 	if (check_oem(shp) != 0)
1891 		return;
1892 
1893 	if (smbios_info_extmemdevice(shp, id, &emd) != 0) {
1894 		smbios_warn(shp, "failed to read extmemdevice information");
1895 		return;
1896 	}
1897 
1898 	oprintf(fp, "  Memory Device Handle: %u\n", emd.smbmdeve_md);
1899 	oprintf(fp, "  DRAM Channel: %u\n", emd.smbmdeve_drch);
1900 	oprintf(fp, "  Number of Chip Selects: %u\n", emd.smbmdeve_ncs);
1901 
1902 	if (emd.smbmdeve_ncs == 0)
1903 		return;
1904 
1905 	if (smbios_info_extmemdevice_cs(shp, id, &ncs, &cs) != 0) {
1906 		smbios_warn(shp, "failed to read extmemdevice cs information");
1907 		return;
1908 	}
1909 
1910 	for (i = 0; i < ncs; i++) {
1911 		oprintf(fp, "  Chip Select: %u\n", cs[i]);
1912 	}
1913 	smbios_info_extmemdevice_cs_free(shp, ncs, cs);
1914 }
1915 
1916 static void
print_strprop_info(smbios_hdl_t * shp,id_t id,FILE * fp)1917 print_strprop_info(smbios_hdl_t *shp, id_t id, FILE *fp)
1918 {
1919 	smbios_strprop_t prop;
1920 
1921 	if (smbios_info_strprop(shp, id, &prop) != 0) {
1922 		smbios_warn(shp, "failed to read string property information");
1923 		return;
1924 	}
1925 
1926 	desc_printf(smbios_strprop_id_desc(prop.smbsp_prop_id), fp,
1927 	    "  Property ID: %u", prop.smbsp_prop_id);
1928 	if (prop.smbsp_prop_val != NULL) {
1929 		str_print(fp, "  Property Value", prop.smbsp_prop_val);
1930 	}
1931 	id_printf(fp, "  Parent Handle: ", prop.smbsp_parent);
1932 }
1933 
1934 static void
print_fwinfo(smbios_hdl_t * shp,id_t id,FILE * fp)1935 print_fwinfo(smbios_hdl_t *shp, id_t id, FILE *fp)
1936 {
1937 	smbios_fwinfo_t fw;
1938 	smbios_fwinfo_comp_t *comps;
1939 	uint_t ncomps, i;
1940 
1941 	if (smbios_info_fwinfo(shp, id, &fw) != 0) {
1942 		smbios_warn(shp, "failed to read firmware inventory");
1943 		return;
1944 	}
1945 
1946 	str_print(fp, "  Component Name", fw.smbfw_name);
1947 	str_print(fp, "  ID", fw.smbfw_id);
1948 	str_print(fp, "  Release Date", fw.smbfw_reldate);
1949 	str_print(fp, "  Lowest Supported Version", fw.smbfw_lsv);
1950 	desc_printf(smbios_fwinfo_vers_desc(fw.smbfw_vers_fmt), fp,
1951 	    "  Version Format: %u", fw.smbfw_vers_fmt);
1952 	desc_printf(smbios_fwinfo_id_desc(fw.smbfw_id_fmt), fp,
1953 	    "  ID Format: %u", fw.smbfw_id_fmt);
1954 	if (fw.smbfw_imgsz != UINT64_MAX) {
1955 		oprintf(fp, "  Image Size: %" PRIu64 "\n", fw.smbfw_imgsz);
1956 	} else {
1957 		oprintf(fp, "  Image Size: unknown\n");
1958 	}
1959 
1960 	flag_printf(fp, "Characteristics", fw.smbfw_chars,
1961 	    sizeof (fw.smbfw_chars) * NBBY, smbios_fwinfo_ch_name,
1962 	    smbios_fwinfo_ch_desc);
1963 
1964 	desc_printf(smbios_fwinfo_state_desc(fw.smbfw_state), fp, "  State: %u",
1965 	    fw.smbfw_state);
1966 	oprintf(fp, "  Number of Associated Components: %u\n",
1967 	    fw.smbfw_ncomps);
1968 
1969 	if (fw.smbfw_ncomps == 0)
1970 		return;
1971 
1972 	if (smbios_info_fwinfo_comps(shp, id, &ncomps, &comps) == -1) {
1973 		smbios_warn(shp, "failed to read firmware inventory "
1974 		    "components");
1975 		return;
1976 	}
1977 
1978 	oprintf(fp, "\n  Component Handles:\n");
1979 	for (i = 0; i < ncomps; i++) {
1980 		oprintf(fp, "    %" _PRIdID "\n", comps[i].smbfwe_id);
1981 	}
1982 }
1983 
1984 static int
print_struct(smbios_hdl_t * shp,const smbios_struct_t * sp,void * fp)1985 print_struct(smbios_hdl_t *shp, const smbios_struct_t *sp, void *fp)
1986 {
1987 	smbios_info_t info;
1988 	int hex = opt_x;
1989 	const char *s;
1990 
1991 	if (opt_t != -1 && opt_t != sp->smbstr_type)
1992 		return (0); /* skip struct if type doesn't match -t */
1993 
1994 	if (!opt_O && (sp->smbstr_type == SMB_TYPE_MEMCTL ||
1995 	    sp->smbstr_type == SMB_TYPE_MEMMOD))
1996 		return (0); /* skip struct if type is obsolete */
1997 
1998 	if (g_hdr++ == 0 || !opt_s)
1999 		oprintf(fp, "%-5s %-4s %s\n", "ID", "SIZE", "TYPE");
2000 
2001 	oprintf(fp, "%-5u %-4lu",
2002 	    (uint_t)sp->smbstr_id, (ulong_t)sp->smbstr_size);
2003 
2004 	if ((s = smbios_type_name(sp->smbstr_type)) != NULL)
2005 		oprintf(fp, " %s (type %u)", s, sp->smbstr_type);
2006 	else if (sp->smbstr_type > SMB_TYPE_OEM_LO &&
2007 	    sp->smbstr_type < SMB_TYPE_OEM_HI)
2008 		oprintf(fp, " %s+%u (type %u)", "SMB_TYPE_OEM_LO",
2009 		    sp->smbstr_type - SMB_TYPE_OEM_LO, sp->smbstr_type);
2010 	else
2011 		oprintf(fp, " %u", sp->smbstr_type);
2012 
2013 	if ((s = smbios_type_desc(sp->smbstr_type)) != NULL)
2014 		oprintf(fp, " (%s)\n", s);
2015 	else
2016 		oprintf(fp, "\n");
2017 
2018 	if (opt_s)
2019 		return (0); /* only print header line if -s specified */
2020 
2021 	if (smbios_info_common(shp, sp->smbstr_id, &info) == 0) {
2022 		oprintf(fp, "\n");
2023 		print_common(&info, fp);
2024 	}
2025 
2026 	switch (sp->smbstr_type) {
2027 	case SMB_TYPE_BIOS:
2028 		oprintf(fp, "\n");
2029 		print_bios(shp, fp);
2030 		break;
2031 	case SMB_TYPE_SYSTEM:
2032 		oprintf(fp, "\n");
2033 		print_system(shp, fp);
2034 		break;
2035 	case SMB_TYPE_BASEBOARD:
2036 		oprintf(fp, "\n");
2037 		print_bboard(shp, sp->smbstr_id, fp);
2038 		break;
2039 	case SMB_TYPE_CHASSIS:
2040 		oprintf(fp, "\n");
2041 		print_chassis(shp, sp->smbstr_id, fp);
2042 		break;
2043 	case SMB_TYPE_PROCESSOR:
2044 		oprintf(fp, "\n");
2045 		print_processor(shp, sp->smbstr_id, fp);
2046 		break;
2047 	case SMB_TYPE_CACHE:
2048 		oprintf(fp, "\n");
2049 		print_cache(shp, sp->smbstr_id, fp);
2050 		break;
2051 	case SMB_TYPE_PORT:
2052 		oprintf(fp, "\n");
2053 		print_port(shp, sp->smbstr_id, fp);
2054 		break;
2055 	case SMB_TYPE_SLOT:
2056 		oprintf(fp, "\n");
2057 		print_slot(shp, sp->smbstr_id, fp);
2058 		break;
2059 	case SMB_TYPE_OBDEVS:
2060 		oprintf(fp, "\n");
2061 		print_obdevs(shp, sp->smbstr_id, fp);
2062 		break;
2063 	case SMB_TYPE_OEMSTR:
2064 	case SMB_TYPE_SYSCONFSTR:
2065 		oprintf(fp, "\n");
2066 		print_strtab(shp, sp->smbstr_id, fp);
2067 		break;
2068 	case SMB_TYPE_LANG:
2069 		oprintf(fp, "\n");
2070 		print_lang(shp, sp->smbstr_id, fp);
2071 		break;
2072 	case SMB_TYPE_EVENTLOG:
2073 		oprintf(fp, "\n");
2074 		print_evlog(shp, sp->smbstr_id, fp);
2075 		break;
2076 	case SMB_TYPE_MEMARRAY:
2077 		oprintf(fp, "\n");
2078 		print_memarray(shp, sp->smbstr_id, fp);
2079 		break;
2080 	case SMB_TYPE_MEMDEVICE:
2081 		oprintf(fp, "\n");
2082 		print_memdevice(shp, sp->smbstr_id, fp);
2083 		break;
2084 	case SMB_TYPE_MEMARRAYMAP:
2085 		oprintf(fp, "\n");
2086 		print_memarrmap(shp, sp->smbstr_id, fp);
2087 		break;
2088 	case SMB_TYPE_MEMDEVICEMAP:
2089 		oprintf(fp, "\n");
2090 		print_memdevmap(shp, sp->smbstr_id, fp);
2091 		break;
2092 	case SMB_TYPE_BATTERY:
2093 		oprintf(fp, "\n");
2094 		print_battery(shp, sp->smbstr_id, fp);
2095 		break;
2096 	case SMB_TYPE_POINTDEV:
2097 		oprintf(fp, "\n");
2098 		print_pointdev(shp, sp->smbstr_id, fp);
2099 		break;
2100 	case SMB_TYPE_SECURITY:
2101 		oprintf(fp, "\n");
2102 		print_hwsec(shp, fp);
2103 		break;
2104 	case SMB_TYPE_VPROBE:
2105 		oprintf(fp, "\n");
2106 		print_vprobe(shp, sp->smbstr_id, fp);
2107 		break;
2108 	case SMB_TYPE_COOLDEV:
2109 		oprintf(fp, "\n");
2110 		print_cooldev(shp, sp->smbstr_id, fp);
2111 		break;
2112 	case SMB_TYPE_TPROBE:
2113 		oprintf(fp, "\n");
2114 		print_tprobe(shp, sp->smbstr_id, fp);
2115 		break;
2116 	case SMB_TYPE_IPROBE:
2117 		oprintf(fp, "\n");
2118 		print_iprobe(shp, sp->smbstr_id, fp);
2119 		break;
2120 	case SMB_TYPE_BOOT:
2121 		oprintf(fp, "\n");
2122 		print_boot(shp, fp);
2123 		break;
2124 	case SMB_TYPE_IPMIDEV:
2125 		oprintf(fp, "\n");
2126 		print_ipmi(shp, fp);
2127 		break;
2128 	case SMB_TYPE_POWERSUP:
2129 		oprintf(fp, "\n");
2130 		print_powersup(shp, sp->smbstr_id, fp);
2131 		break;
2132 	case SMB_TYPE_ADDINFO:
2133 		oprintf(fp, "\n");
2134 		print_addinfo(shp, sp->smbstr_id, fp);
2135 		break;
2136 	case SMB_TYPE_OBDEVEXT:
2137 		oprintf(fp, "\n");
2138 		print_obdevs_ext(shp, sp->smbstr_id, fp);
2139 		break;
2140 	case SMB_TYPE_PROCESSOR_INFO:
2141 		oprintf(fp, "\n");
2142 		print_processor_info(shp, sp->smbstr_id, fp);
2143 		break;
2144 	case SMB_TYPE_STRPROP:
2145 		oprintf(fp, "\n");
2146 		print_strprop_info(shp, sp->smbstr_id, fp);
2147 		break;
2148 	case SMB_TYPE_FWINFO:
2149 		oprintf(fp, "\n");
2150 		print_fwinfo(shp, sp->smbstr_id, fp);
2151 		break;
2152 	case SUN_OEM_EXT_PROCESSOR:
2153 		oprintf(fp, "\n");
2154 		print_extprocessor(shp, sp->smbstr_id, fp);
2155 		break;
2156 	case SUN_OEM_EXT_PORT:
2157 		oprintf(fp, "\n");
2158 		print_extport(shp, sp->smbstr_id, fp);
2159 		break;
2160 	case SUN_OEM_PCIEXRC:
2161 		oprintf(fp, "\n");
2162 		print_pciexrc(shp, sp->smbstr_id, fp);
2163 		break;
2164 	case SUN_OEM_EXT_MEMARRAY:
2165 		oprintf(fp, "\n");
2166 		print_extmemarray(shp, sp->smbstr_id, fp);
2167 		break;
2168 	case SUN_OEM_EXT_MEMDEVICE:
2169 		oprintf(fp, "\n");
2170 		print_extmemdevice(shp, sp->smbstr_id, fp);
2171 		break;
2172 	default:
2173 		hex++;
2174 	}
2175 
2176 	if (hex)
2177 		print_bytes(sp->smbstr_data, sp->smbstr_size, fp);
2178 	else
2179 		oprintf(fp, "\n");
2180 
2181 	return (0);
2182 }
2183 
2184 static uint16_t
getu16(const char * name,const char * s)2185 getu16(const char *name, const char *s)
2186 {
2187 	u_longlong_t val;
2188 	char *p;
2189 
2190 	errno = 0;
2191 	val = strtoull(s, &p, 0);
2192 
2193 	if (errno != 0 || p == s || *p != '\0' || val > UINT16_MAX) {
2194 		(void) fprintf(stderr, "%s: invalid %s argument -- %s\n",
2195 		    g_pname, name, s);
2196 		exit(SMBIOS_USAGE);
2197 	}
2198 
2199 	return ((uint16_t)val);
2200 }
2201 
2202 static uint16_t
getstype(const char * name,const char * s)2203 getstype(const char *name, const char *s)
2204 {
2205 	const char *ts;
2206 	uint16_t t;
2207 
2208 	for (t = 0; t < SMB_TYPE_OEM_LO; t++) {
2209 		if ((ts = smbios_type_name(t)) != NULL && strcmp(s, ts) == 0)
2210 			return (t);
2211 	}
2212 
2213 	(void) fprintf(stderr, "%s: invalid %s argument -- %s\n",
2214 	    g_pname, name, s);
2215 
2216 	exit(SMBIOS_USAGE);
2217 	/*NOTREACHED*/
2218 }
2219 
2220 static int
usage(FILE * fp)2221 usage(FILE *fp)
2222 {
2223 	(void) fprintf(fp, "Usage: %s "
2224 	    "[-BeOsx] [-i id] [-t type] [-w file] [file]\n\n", g_pname);
2225 
2226 	(void) fprintf(fp,
2227 	    "\t-B disable header validation for broken BIOSes\n"
2228 	    "\t-e display SMBIOS entry point information\n"
2229 	    "\t-i display only the specified structure\n"
2230 	    "\t-O display obsolete structure types\n"
2231 	    "\t-s display only a summary of structure identifiers and types\n"
2232 	    "\t-t display only the specified structure type\n"
2233 	    "\t-w write the raw data to the specified file\n"
2234 	    "\t-x display raw data for structures\n");
2235 
2236 	return (SMBIOS_USAGE);
2237 }
2238 
2239 int
main(int argc,char * argv[])2240 main(int argc, char *argv[])
2241 {
2242 	const char *ifile = NULL;
2243 	const char *ofile = NULL;
2244 	int oflags = 0;
2245 
2246 	smbios_hdl_t *shp;
2247 	smbios_struct_t s;
2248 	int err, fd, c;
2249 	char *p;
2250 
2251 	if ((p = strrchr(argv[0], '/')) == NULL)
2252 		g_pname = argv[0];
2253 	else
2254 		g_pname = p + 1;
2255 
2256 	while (optind < argc) {
2257 		while ((c = getopt(argc, argv, "Bei:Ost:w:xZ")) != EOF) {
2258 			switch (c) {
2259 			case 'B':
2260 				oflags |= SMB_O_NOCKSUM | SMB_O_NOVERS;
2261 				break;
2262 			case 'e':
2263 				opt_e++;
2264 				break;
2265 			case 'i':
2266 				opt_i = getu16("struct ID", optarg);
2267 				break;
2268 			case 'O':
2269 				opt_O++;
2270 				break;
2271 			case 's':
2272 				opt_s++;
2273 				break;
2274 			case 't':
2275 				if (isdigit(optarg[0]))
2276 					opt_t = getu16("struct type", optarg);
2277 				else
2278 					opt_t = getstype("struct type", optarg);
2279 				break;
2280 			case 'w':
2281 				ofile = optarg;
2282 				break;
2283 			case 'x':
2284 				opt_x++;
2285 				break;
2286 			case 'Z':
2287 				oflags |= SMB_O_ZIDS; /* undocumented */
2288 				break;
2289 			default:
2290 				return (usage(stderr));
2291 			}
2292 		}
2293 
2294 		if (optind < argc) {
2295 			if (ifile != NULL) {
2296 				(void) fprintf(stderr, "%s: illegal "
2297 				    "argument -- %s\n", g_pname, argv[optind]);
2298 				return (SMBIOS_USAGE);
2299 			}
2300 			ifile = argv[optind++];
2301 		}
2302 	}
2303 
2304 	if ((shp = smbios_open(ifile, SMB_VERSION, oflags, &err)) == NULL) {
2305 		(void) fprintf(stderr, "%s: failed to load SMBIOS: %s\n",
2306 		    g_pname, smbios_errmsg(err));
2307 		return (SMBIOS_ERROR);
2308 	}
2309 
2310 	if (opt_i == -1 && opt_t == -1 && opt_e == 0 &&
2311 	    smbios_truncated(shp))
2312 		(void) fprintf(stderr, "%s: SMBIOS table is truncated\n",
2313 		    g_pname);
2314 
2315 	if (ofile != NULL) {
2316 		if ((fd = open(ofile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1) {
2317 			(void) fprintf(stderr, "%s: failed to open %s: %s\n",
2318 			    g_pname, ofile, strerror(errno));
2319 			err = SMBIOS_ERROR;
2320 		} else if (smbios_write(shp, fd) != 0) {
2321 			(void) fprintf(stderr, "%s: failed to write %s: %s\n",
2322 			    g_pname, ofile, smbios_errmsg(smbios_errno(shp)));
2323 			err = SMBIOS_ERROR;
2324 		}
2325 		smbios_close(shp);
2326 		return (err);
2327 	}
2328 
2329 	if (opt_e) {
2330 		print_smbios(shp, stdout);
2331 		smbios_close(shp);
2332 		return (SMBIOS_SUCCESS);
2333 	}
2334 
2335 	if (opt_O && (opt_i != -1 || opt_t != -1))
2336 		opt_O++; /* -i or -t imply displaying obsolete records */
2337 
2338 	if (opt_i != -1)
2339 		err = smbios_lookup_id(shp, opt_i, &s);
2340 	else
2341 		err = smbios_iter(shp, print_struct, stdout);
2342 
2343 	if (err != 0) {
2344 		(void) fprintf(stderr, "%s: failed to access SMBIOS: %s\n",
2345 		    g_pname, smbios_errmsg(smbios_errno(shp)));
2346 		smbios_close(shp);
2347 		return (SMBIOS_ERROR);
2348 	}
2349 
2350 	if (opt_i != -1)
2351 		(void) print_struct(shp, &s, stdout);
2352 
2353 	smbios_close(shp);
2354 	return (SMBIOS_SUCCESS);
2355 }
2356