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