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