xref: /illumos-gate/usr/src/cmd/smbios/smbios.c (revision a7aaa513)
184ab085aSmws /*
284ab085aSmws  * CDDL HEADER START
384ab085aSmws  *
484ab085aSmws  * The contents of this file are subject to the terms of the
5074bb90dSTom Pothier  * Common Development and Distribution License (the "License").
6074bb90dSTom Pothier  * You may not use this file except in compliance with the License.
784ab085aSmws  *
884ab085aSmws  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
984ab085aSmws  * or http://www.opensolaris.org/os/licensing.
1084ab085aSmws  * See the License for the specific language governing permissions
1184ab085aSmws  * and limitations under the License.
1284ab085aSmws  *
1384ab085aSmws  * When distributing Covered Code, include this CDDL HEADER in each
1484ab085aSmws  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1584ab085aSmws  * If applicable, add the following below this CDDL HEADER, with the
1684ab085aSmws  * fields enclosed by brackets "[]" replaced with your own identifying
1784ab085aSmws  * information: Portions Copyright [yyyy] [name of copyright owner]
1884ab085aSmws  *
1984ab085aSmws  * CDDL HEADER END
2084ab085aSmws  */
2284ab085aSmws /*
234e901881SDale Ghent  * Copyright 2015 OmniTI Computer Consulting, Inc.  All rights reserved.
24e9cac61dSRobert Mustacchi  * Copyright (c) 2017, Joyent, Inc.
250f56e145SRobert Mustacchi  * Copyright 2021 Oxide Computer Company
2603f9f63dSTom Pothier  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2784ab085aSmws  * Use is subject to license terms.
2884ab085aSmws  */
3084ab085aSmws #include <sys/sysmacros.h>
3184ab085aSmws #include <sys/param.h>
3384ab085aSmws #include <smbios.h>
3484ab085aSmws #include <alloca.h>
3584ab085aSmws #include <limits.h>
3684ab085aSmws #include <unistd.h>
3784ab085aSmws #include <strings.h>
3884ab085aSmws #include <stdlib.h>
3984ab085aSmws #include <stdarg.h>
4084ab085aSmws #include <stdio.h>
4184ab085aSmws #include <fcntl.h>
4284ab085aSmws #include <errno.h>
4384ab085aSmws #include <ctype.h>
441566bc34SRobert Mustacchi #include <libjedec.h>
4684ab085aSmws #define	SMBIOS_SUCCESS	0
4784ab085aSmws #define	SMBIOS_ERROR	1
4884ab085aSmws #define	SMBIOS_USAGE	2
5084ab085aSmws static const char *g_pname;
5184ab085aSmws static int g_hdr;
5384ab085aSmws static int opt_e;
5484ab085aSmws static int opt_i = -1;
5584ab085aSmws static int opt_O;
5684ab085aSmws static int opt_s;
5784ab085aSmws static int opt_t = -1;
5884ab085aSmws static int opt_x;
601566bc34SRobert Mustacchi static boolean_t
smbios_vergteq(smbios_version_t * v,uint_t major,uint_t minor)611566bc34SRobert Mustacchi smbios_vergteq(smbios_version_t *v, uint_t major, uint_t minor)
621566bc34SRobert Mustacchi {
631566bc34SRobert Mustacchi 	if (v->smbv_major > major)
641566bc34SRobert Mustacchi 		return (B_TRUE);
651566bc34SRobert Mustacchi 	if (v->smbv_major == major &&
661566bc34SRobert Mustacchi 	    v->smbv_minor >= minor)
671566bc34SRobert Mustacchi 		return (B_TRUE);
681566bc34SRobert Mustacchi 	return (B_FALSE);
691566bc34SRobert Mustacchi }
701566bc34SRobert Mustacchi 
7132ece1f9SRobert Mustacchi /*PRINTFLIKE2*/
7232ece1f9SRobert Mustacchi static void
smbios_warn(smbios_hdl_t * shp,const char * format,...)7332ece1f9SRobert Mustacchi smbios_warn(smbios_hdl_t *shp, const char *format, ...)
7432ece1f9SRobert Mustacchi {
7532ece1f9SRobert Mustacchi 	va_list ap;
7632ece1f9SRobert Mustacchi 
7732ece1f9SRobert Mustacchi 	va_start(ap, format);
7832ece1f9SRobert Mustacchi 	(void) vfprintf(stderr, format, ap);
7932ece1f9SRobert Mustacchi 	va_end(ap);
8032ece1f9SRobert Mustacchi 
8132ece1f9SRobert Mustacchi 	if (shp != NULL) {
8232ece1f9SRobert Mustacchi 		(void) fprintf(stderr, ": %s",
8332ece1f9SRobert Mustacchi 		    smbios_errmsg(smbios_errno(shp)));
8432ece1f9SRobert Mustacchi 	}
8532ece1f9SRobert Mustacchi 
8632ece1f9SRobert Mustacchi 	(void) fprintf(stderr, "\n");
8732ece1f9SRobert Mustacchi }
8832ece1f9SRobert Mustacchi 
8984ab085aSmws /*PRINTFLIKE2*/
9084ab085aSmws static void
oprintf(FILE * fp,const char * format,...)9184ab085aSmws oprintf(FILE *fp, const char *format, ...)
9284ab085aSmws {
9384ab085aSmws 	va_list ap;
9584ab085aSmws 	va_start(ap, format);
9684ab085aSmws 	(void) vfprintf(fp, format, ap);
9784ab085aSmws 	va_end(ap);
9884ab085aSmws }
10084ab085aSmws /*PRINTFLIKE3*/
10184ab085aSmws static void
desc_printf(const char * d,FILE * fp,const char * format,...)10284ab085aSmws desc_printf(const char *d, FILE *fp, const char *format, ...)
10384ab085aSmws {
10484ab085aSmws 	va_list ap;
10684ab085aSmws 	va_start(ap, format);
10784ab085aSmws 	(void) vfprintf(fp, format, ap);
10884ab085aSmws 	va_end(ap);
11084ab085aSmws 	if (d != NULL)
11184ab085aSmws 		(void) fprintf(fp, " (%s)\n", d);
11284ab085aSmws 	else
11384ab085aSmws 		(void) fprintf(fp, "\n");
11484ab085aSmws }
11684ab085aSmws 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))11784ab085aSmws flag_printf(FILE *fp, const char *s, uint_t flags, size_t bits,
11884ab085aSmws     const char *(*flag_name)(uint_t), const char *(*flag_desc)(uint_t))
11984ab085aSmws {
12084ab085aSmws 	size_t i;
12284ab085aSmws 	oprintf(fp, "  %s: 0x%x\n", s, flags);
12484ab085aSmws 	for (i = 0; i < bits; i++) {
12584ab085aSmws 		uint_t f = 1 << i;
12684ab085aSmws 		const char *n;
12884ab085aSmws 		if (!(flags & f))
12984ab085aSmws 			continue;
13184ab085aSmws 		if ((n = flag_name(f)) != NULL)
13284ab085aSmws 			desc_printf(flag_desc(f), fp, "\t%s", n);
13384ab085aSmws 		else
13484ab085aSmws 			desc_printf(flag_desc(f), fp, "\t0x%x", f);
13584ab085aSmws 	}
13684ab085aSmws }
13884ab085aSmws 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))13984ab085aSmws flag64_printf(FILE *fp, const char *s, uint64_t flags, size_t bits,
14084ab085aSmws     const char *(*flag_name)(uint64_t), const char *(*flag_desc)(uint64_t))
14184ab085aSmws {
14284ab085aSmws 	size_t i;
14484ab085aSmws 	oprintf(fp, "  %s: 0x%llx\n", s, (u_longlong_t)flags);
14684ab085aSmws 	for (i = 0; i < bits; i++) {
14784ab085aSmws 		u_longlong_t f = 1ULL << i;
14884ab085aSmws 		const char *n;
15084ab085aSmws 		if (!(flags & f))
15184ab085aSmws 			continue;
15384ab085aSmws 		if ((n = flag_name(f)) != NULL)
15484ab085aSmws 			desc_printf(flag_desc(f), fp, "\t%s", n);
15584ab085aSmws 		else
15684ab085aSmws 			desc_printf(flag_desc(f), fp, "\t0x%llx", f);
15784ab085aSmws 	}
15884ab085aSmws }
16084ab085aSmws static void
id_printf(FILE * fp,const char * s,id_t id)16184ab085aSmws id_printf(FILE *fp, const char *s, id_t id)
16284ab085aSmws {
16384ab085aSmws 	switch (id) {
16484ab085aSmws 	case SMB_ID_NONE:
16584ab085aSmws 		oprintf(fp, "%sNone\n", s);
16684ab085aSmws 		break;
16784ab085aSmws 	case SMB_ID_NOTSUP:
16884ab085aSmws 		oprintf(fp, "%sNot Supported\n", s);
16984ab085aSmws 		break;
17084ab085aSmws 	default:
17184ab085aSmws 		oprintf(fp, "%s%u\n", s, (uint_t)id);
17284ab085aSmws 	}
17384ab085aSmws }
1751566bc34SRobert Mustacchi static void
jedec_print(FILE * fp,const char * desc,uint_t id)1761566bc34SRobert Mustacchi jedec_print(FILE *fp, const char *desc, uint_t id)
1771566bc34SRobert Mustacchi {
1781566bc34SRobert Mustacchi 	const char *name;
1791566bc34SRobert Mustacchi 	uint_t cont, vendor;
1801566bc34SRobert Mustacchi 
1819f9cceb6SRobert Mustacchi 	/*
1829f9cceb6SRobert Mustacchi 	 * SMBIOS encodes data in the way that the underlying memory standard
1839f9cceb6SRobert Mustacchi 	 * does. In this case, the upper byte indicates the vendor that we care
1849f9cceb6SRobert Mustacchi 	 * about while the lower byte indicates the number of continuations that
1859f9cceb6SRobert Mustacchi 	 * are needed. libjedec indexes this based on zero (e.g. table 1 is zero
1869f9cceb6SRobert Mustacchi 	 * continuations), which is how the spec encodes it. We add one so that
1879f9cceb6SRobert Mustacchi 	 * we can match how the spec describes it.
1889f9cceb6SRobert Mustacchi 	 */
1899f9cceb6SRobert Mustacchi 	vendor = id >> 8;
1909f9cceb6SRobert Mustacchi 	cont = id & 0x7f;
1911566bc34SRobert Mustacchi 	name = libjedec_vendor_string(cont, vendor);
1921566bc34SRobert Mustacchi 	if (name == NULL) {
1939f9cceb6SRobert Mustacchi 		oprintf(fp, "  %s: Bank: 0x%x Vendor: 0x%x\n", desc, cont + 1,
1949f9cceb6SRobert Mustacchi 		    vendor);
1951566bc34SRobert Mustacchi 	} else {
1969f9cceb6SRobert Mustacchi 		oprintf(fp, "  %s: Bank: 0x%x Vendor: 0x%x (%s)\n", desc,
1979f9cceb6SRobert Mustacchi 		    cont + 1, vendor, name);
1981566bc34SRobert Mustacchi 	}
1991566bc34SRobert Mustacchi }
2001566bc34SRobert Mustacchi 
201176a9270SRobert Mustacchi /*
202176a9270SRobert Mustacchi  * Print a 128-bit data as a series of 16 hex digits.
203176a9270SRobert Mustacchi  */
204176a9270SRobert Mustacchi static void
u128_print(FILE * fp,const char * desc,const uint8_t * data)205176a9270SRobert Mustacchi u128_print(FILE *fp, const char *desc, const uint8_t *data)
206176a9270SRobert Mustacchi {
207176a9270SRobert Mustacchi 	uint_t i;
208176a9270SRobert Mustacchi 
209176a9270SRobert Mustacchi 	oprintf(fp, "%s: ", desc);
210176a9270SRobert Mustacchi 	for (i = 0; i < 16; i++) {
211176a9270SRobert Mustacchi 		oprintf(fp, " %02x", data[i]);
212176a9270SRobert Mustacchi 	}
213176a9270SRobert Mustacchi 	oprintf(fp, "\n");
214176a9270SRobert Mustacchi }
215176a9270SRobert Mustacchi 
2160f56e145SRobert Mustacchi /*
2170f56e145SRobert Mustacchi  * Print a string that came from an SMBIOS table. We do this character by
2180f56e145SRobert Mustacchi  * character so we can potentially escape strings.
2190f56e145SRobert Mustacchi  */
2200f56e145SRobert Mustacchi static void
str_print_label(FILE * fp,const char * header,const char * str,boolean_t label)2210f56e145SRobert Mustacchi str_print_label(FILE *fp, const char *header, const char *str, boolean_t label)
2220f56e145SRobert Mustacchi {
2230f56e145SRobert Mustacchi 	const char *c;
2240f56e145SRobert Mustacchi 
2250f56e145SRobert Mustacchi 	oprintf(fp, header);
2260f56e145SRobert Mustacchi 	if (label) {
2270f56e145SRobert Mustacchi 		oprintf(fp, ": ");
2280f56e145SRobert Mustacchi 	}
2290f56e145SRobert Mustacchi 
2300f56e145SRobert Mustacchi 	for (c = str; *c != '\0'; c++) {
2310f56e145SRobert Mustacchi 		if (isprint(*c)) {
2320f56e145SRobert Mustacchi 			oprintf(fp, "%c", *c);
2330f56e145SRobert Mustacchi 		} else {
2340f56e145SRobert Mustacchi 			oprintf(fp, "\\x%02x", *c);
2350f56e145SRobert Mustacchi 		}
2360f56e145SRobert Mustacchi 	}
2370f56e145SRobert Mustacchi 
2380f56e145SRobert Mustacchi 	oprintf(fp, "\n");
2390f56e145SRobert Mustacchi }
2400f56e145SRobert Mustacchi 
2410f56e145SRobert Mustacchi static void
str_print_nolabel(FILE * fp,const char * ws,const char * str)2420f56e145SRobert Mustacchi str_print_nolabel(FILE *fp, const char *ws, const char *str)
2430f56e145SRobert Mustacchi {
2440f56e145SRobert Mustacchi 	return (str_print_label(fp, ws, str, B_FALSE));
2450f56e145SRobert Mustacchi }
2460f56e145SRobert Mustacchi 
2470f56e145SRobert Mustacchi static void
str_print(FILE * fp,const char * header,const char * str)2480f56e145SRobert Mustacchi str_print(FILE *fp, const char *header, const char *str)
2490f56e145SRobert Mustacchi {
2500f56e145SRobert Mustacchi 	return (str_print_label(fp, header, str, B_TRUE));
2510f56e145SRobert Mustacchi }
2520f56e145SRobert Mustacchi 
25303f9f63dSTom Pothier static int
check_oem(smbios_hdl_t * shp)25403f9f63dSTom Pothier check_oem(smbios_hdl_t *shp)
25503f9f63dSTom Pothier {
25603f9f63dSTom Pothier 	int i;
25703f9f63dSTom Pothier 	int cnt;
25803f9f63dSTom Pothier 	int rv;
25903f9f63dSTom Pothier 	id_t oem_id;
26003f9f63dSTom Pothier 	smbios_struct_t s;
26103f9f63dSTom Pothier 	const char **oem_str;
26203f9f63dSTom Pothier 
26303f9f63dSTom Pothier 	rv = smbios_lookup_type(shp, SMB_TYPE_OEMSTR, &s);
26403f9f63dSTom Pothier 	if (rv != 0) {
26503f9f63dSTom Pothier 		return (-1);
26603f9f63dSTom Pothier 	}
26703f9f63dSTom Pothier 
26803f9f63dSTom Pothier 	oem_id = s.smbstr_id;
26903f9f63dSTom Pothier 
27003f9f63dSTom Pothier 	cnt = smbios_info_strtab(shp, oem_id, 0, NULL);
27103f9f63dSTom Pothier 	if (cnt > 0) {
27203f9f63dSTom Pothier 		oem_str =  alloca(sizeof (char *) * cnt);
27303f9f63dSTom Pothier 		(void) smbios_info_strtab(shp, oem_id, cnt, oem_str);
27403f9f63dSTom Pothier 
27503f9f63dSTom Pothier 		for (i = 0; i < cnt; i++) {
27603f9f63dSTom Pothier 			if (strncmp(oem_str[i], SMB_PRMS1,
27703f9f63dSTom Pothier 			    strlen(SMB_PRMS1) + 1) == 0) {
27803f9f63dSTom Pothier 				return (0);
27903f9f63dSTom Pothier 			}
28003f9f63dSTom Pothier 		}
28103f9f63dSTom Pothier 	}
28203f9f63dSTom Pothier 
28303f9f63dSTom Pothier 	return (-1);
28403f9f63dSTom Pothier }
28503f9f63dSTom Pothier 
28684ab085aSmws static void
print_smbios_21(smbios_21_entry_t * ep,FILE * fp)2871951a933SToomas Soome print_smbios_21(smbios_21_entry_t *ep, FILE *fp)
28884ab085aSmws {
28984ab085aSmws 	int i;
29184ab085aSmws 	oprintf(fp, "Entry Point Anchor Tag: %*.*s\n",
2921951a933SToomas Soome 	    (int)sizeof (ep->smbe_eanchor), (int)sizeof (ep->smbe_eanchor),
2931951a933SToomas Soome 	    ep->smbe_eanchor);
2951951a933SToomas Soome 	oprintf(fp, "Entry Point Checksum: 0x%x\n", ep->smbe_ecksum);
2961951a933SToomas Soome 	oprintf(fp, "Entry Point Length: %u\n", ep->smbe_elen);
29784ab085aSmws 	oprintf(fp, "Entry Point Version: %u.%u\n",
2981951a933SToomas Soome 	    ep->smbe_major, ep->smbe_minor);
2991951a933SToomas Soome 	oprintf(fp, "Max Structure Size: %u\n", ep->smbe_maxssize);
3001951a933SToomas Soome 	oprintf(fp, "Entry Point Revision: 0x%x\n", ep->smbe_revision);
30284ab085aSmws 	oprintf(fp, "Entry Point Revision Data:");
3031951a933SToomas Soome 	for (i = 0; i < sizeof (ep->smbe_format); i++)
3041951a933SToomas Soome 		oprintf(fp, " 0x%02x", ep->smbe_format[i]);
30584ab085aSmws 	oprintf(fp, "\n");
30784ab085aSmws 	oprintf(fp, "Intermediate Anchor Tag: %*.*s\n",
3081951a933SToomas Soome 	    (int)sizeof (ep->smbe_ianchor), (int)sizeof (ep->smbe_ianchor),
3091951a933SToomas Soome 	    ep->smbe_ianchor);
3101951a933SToomas Soome 
3111951a933SToomas Soome 	oprintf(fp, "Intermediate Checksum: 0x%x\n", ep->smbe_icksum);
3121951a933SToomas Soome 	oprintf(fp, "Structure Table Length: %u\n", ep->smbe_stlen);
3131951a933SToomas Soome 	oprintf(fp, "Structure Table Address: 0x%x\n", ep->smbe_staddr);
3141951a933SToomas Soome 	oprintf(fp, "Structure Table Entries: %u\n", ep->smbe_stnum);
3151951a933SToomas Soome 	oprintf(fp, "DMI BCD Revision: 0x%x\n", ep->smbe_bcdrev);
3161951a933SToomas Soome }
3171951a933SToomas Soome 
3181951a933SToomas Soome static void
print_smbios_30(smbios_30_entry_t * ep,FILE * fp)3191951a933SToomas Soome print_smbios_30(smbios_30_entry_t *ep, FILE *fp)
3201951a933SToomas Soome {
3211951a933SToomas Soome 	oprintf(fp, "Entry Point Anchor Tag: %*.*s\n",
3221951a933SToomas Soome 	    (int)sizeof (ep->smbe_eanchor), (int)sizeof (ep->smbe_eanchor),
3231951a933SToomas Soome 	    ep->smbe_eanchor);
3241951a933SToomas Soome 
3251951a933SToomas Soome 	oprintf(fp, "Entry Point Checksum: 0x%x\n", ep->smbe_ecksum);
3261951a933SToomas Soome 	oprintf(fp, "Entry Point Length: %u\n", ep->smbe_elen);
3271951a933SToomas Soome 	oprintf(fp, "SMBIOS Version: %u.%u\n",
3281951a933SToomas Soome 	    ep->smbe_major, ep->smbe_minor);
3291951a933SToomas Soome 	oprintf(fp, "SMBIOS DocRev: 0x%x\n", ep->smbe_docrev);
3301951a933SToomas Soome 	oprintf(fp, "Entry Point Revision: 0x%x\n", ep->smbe_revision);
3311951a933SToomas Soome 
3321951a933SToomas Soome 	oprintf(fp, "Structure Table Length: %u\n", ep->smbe_stlen);
3331951a933SToomas Soome 	oprintf(fp, "Structure Table Address: 0x%" PRIx64 "\n",
3341951a933SToomas Soome 	    ep->smbe_staddr);
3351951a933SToomas Soome }
3361951a933SToomas Soome 
3371951a933SToomas Soome static void
print_smbios(smbios_hdl_t * shp,FILE * fp)3381951a933SToomas Soome print_smbios(smbios_hdl_t *shp, FILE *fp)
3391951a933SToomas Soome {
3401951a933SToomas Soome 	smbios_entry_t ep;
3411951a933SToomas Soome 
3421951a933SToomas Soome 	switch (smbios_info_smbios(shp, &ep)) {
3431951a933SToomas Soome 	case SMBIOS_ENTRY_POINT_21:
3441951a933SToomas Soome 		print_smbios_21(&ep.ep21, fp);
3451951a933SToomas Soome 		break;
3461951a933SToomas Soome 	case SMBIOS_ENTRY_POINT_30:
3471951a933SToomas Soome 		print_smbios_30(&ep.ep30, fp);
3481951a933SToomas Soome 		break;
3491951a933SToomas Soome 	}
35084ab085aSmws }
35284ab085aSmws static void
print_common(const smbios_info_t * ip,FILE * fp)35384ab085aSmws print_common(const smbios_info_t *ip, FILE *fp)
35484ab085aSmws {
35584ab085aSmws 	if (ip->smbi_manufacturer[0] != '\0')
3560f56e145SRobert Mustacchi 		str_print(fp, "  Manufacturer", ip->smbi_manufacturer);
35784ab085aSmws 	if (ip->smbi_product[0] != '\0')
3580f56e145SRobert Mustacchi 		str_print(fp, "  Product", ip->smbi_product);
35984ab085aSmws 	if (ip->smbi_version[0] != '\0')
3600f56e145SRobert Mustacchi 		str_print(fp, "  Version", ip->smbi_version);
36184ab085aSmws 	if (ip->smbi_serial[0] != '\0')
3620f56e145SRobert Mustacchi 		str_print(fp, "  Serial Number", ip->smbi_serial);
36384ab085aSmws 	if (ip->smbi_asset[0] != '\0')
3640f56e145SRobert Mustacchi 		str_print(fp, "  Asset Tag", ip->smbi_asset);
36584ab085aSmws 	if (ip->smbi_location[0] != '\0')
3660f56e145SRobert Mustacchi 		str_print(fp, "  Location Tag", ip->smbi_location);
36784ab085aSmws 	if (ip->smbi_part[0] != '\0')
3680f56e145SRobert Mustacchi 		str_print(fp, "  Part Number", ip->smbi_part);
36984ab085aSmws }
37184ab085aSmws static void
print_bios(smbios_hdl_t * shp,FILE * fp)37284ab085aSmws print_bios(smbios_hdl_t *shp, FILE *fp)
37384ab085aSmws {
37484ab085aSmws 	smbios_bios_t b;
376*a7aaa513SRobert Mustacchi 	if (smbios_info_bios(shp, &b) == -1) {
377*a7aaa513SRobert Mustacchi 		smbios_warn(shp, "failed to read BIOS information");
378*a7aaa513SRobert Mustacchi 		return;
379*a7aaa513SRobert Mustacchi 	}
3810f56e145SRobert Mustacchi 	str_print(fp, "  Vendor", b.smbb_vendor);
3820f56e145SRobert Mustacchi 	str_print(fp, "  Version String", b.smbb_version);
3830f56e145SRobert Mustacchi 	str_print(fp, "  Release Date", b.smbb_reldate);
38484ab085aSmws 	oprintf(fp, "  Address Segment: 0x%x\n", b.smbb_segment);
385e5cce96fSRobert Mustacchi 	oprintf(fp, "  ROM Size: %" PRIu64 " bytes\n", b.smbb_extromsize);
38684ab085aSmws 	oprintf(fp, "  Image Size: %u bytes\n", b.smbb_runsize);
38884ab085aSmws 	flag64_printf(fp, "Characteristics",
38984ab085aSmws 	    b.smbb_cflags, sizeof (b.smbb_cflags) * NBBY,
39084ab085aSmws 	    smbios_bios_flag_name, smbios_bios_flag_desc);
39284ab085aSmws 	if (b.smbb_nxcflags > SMB_BIOSXB_1) {
39384ab085aSmws 		flag_printf(fp, "Characteristics Extension Byte 1",
39484ab085aSmws 		    b.smbb_xcflags[SMB_BIOSXB_1],
39584ab085aSmws 		    sizeof (b.smbb_xcflags[SMB_BIOSXB_1]) * NBBY,
39684ab085aSmws 		    smbios_bios_xb1_name, smbios_bios_xb1_desc);
39784ab085aSmws 	}
39984ab085aSmws 	if (b.smbb_nxcflags > SMB_BIOSXB_2) {
40084ab085aSmws 		flag_printf(fp, "Characteristics Extension Byte 2",
40184ab085aSmws 		    b.smbb_xcflags[SMB_BIOSXB_2],
40284ab085aSmws 		    sizeof (b.smbb_xcflags[SMB_BIOSXB_2]) * NBBY,
40384ab085aSmws 		    smbios_bios_xb2_name, smbios_bios_xb2_desc);
40484ab085aSmws 	}
40684ab085aSmws 	if (b.smbb_nxcflags > SMB_BIOSXB_BIOS_MIN) {
40784ab085aSmws 		oprintf(fp, "  Version Number: %u.%u\n",
40884ab085aSmws 		    b.smbb_biosv.smbv_major, b.smbb_biosv.smbv_minor);
40984ab085aSmws 	}
411f44a1392SRobert Mustacchi 	/*
412f44a1392SRobert Mustacchi 	 * If the major and minor versions are 0xff then that indicates that the
413f44a1392SRobert Mustacchi 	 * embedded controller does not exist.
414f44a1392SRobert Mustacchi 	 */
415f44a1392SRobert Mustacchi 	if (b.smbb_nxcflags > SMB_BIOSXB_ECFW_MIN &&
416f44a1392SRobert Mustacchi 	    b.smbb_ecfwv.smbv_major != 0xff &&
417f44a1392SRobert Mustacchi 	    b.smbb_ecfwv.smbv_minor != 0xff) {
41884ab085aSmws 		oprintf(fp, "  Embedded Ctlr Firmware Version Number: %u.%u\n",
41984ab085aSmws 		    b.smbb_ecfwv.smbv_major, b.smbb_ecfwv.smbv_minor);
42084ab085aSmws 	}
42184ab085aSmws }
42384ab085aSmws static void
print_system(smbios_hdl_t * shp,FILE * fp)42484ab085aSmws print_system(smbios_hdl_t *shp, FILE *fp)
42584ab085aSmws {
42684ab085aSmws 	smbios_system_t s;
42784ab085aSmws 	uint_t i;
429*a7aaa513SRobert Mustacchi 	if (smbios_info_system(shp, &s) == -1) {
430*a7aaa513SRobert Mustacchi 		smbios_warn(shp, "failed to read system information");
431*a7aaa513SRobert Mustacchi 		return;
432*a7aaa513SRobert Mustacchi 	}
43484ab085aSmws 	oprintf(fp, "  UUID: ");
43584ab085aSmws 	for (i = 0; i < s.smbs_uuidlen; i++) {
43684ab085aSmws 		oprintf(fp, "%02x", s.smbs_uuid[i]);
43784ab085aSmws 		if (i == 3 || i == 5 || i == 7 || i == 9)
43884ab085aSmws 			oprintf(fp, "-");
43984ab085aSmws 	}
44084ab085aSmws 	oprintf(fp, "\n");
44284ab085aSmws 	desc_printf(smbios_system_wakeup_desc(s.smbs_wakeup),
44384ab085aSmws 	    fp, "  Wake-Up Event: 0x%x", s.smbs_wakeup);
4450f56e145SRobert Mustacchi 	str_print(fp, "  SKU Number", s.smbs_sku);
4460f56e145SRobert Mustacchi 	str_print(fp, "  Family", s.smbs_family);
44784ab085aSmws }
44984ab085aSmws static void
print_bboard(smbios_hdl_t * shp,id_t id,FILE * fp)45084ab085aSmws print_bboard(smbios_hdl_t *shp, id_t id, FILE *fp)
45184ab085aSmws {
45284ab085aSmws 	smbios_bboard_t b;
453074bb90dSTom Pothier 	int chdl_cnt;
455*a7aaa513SRobert Mustacchi 	if (smbios_info_bboard(shp, id, &b) != 0) {
456*a7aaa513SRobert Mustacchi 		smbios_warn(shp, "failed to read baseboard information");
457*a7aaa513SRobert Mustacchi 		return;
458*a7aaa513SRobert Mustacchi 	}
46084ab085aSmws 	oprintf(fp, "  Chassis: %u\n", (uint_t)b.smbb_chassis);
46284ab085aSmws 	flag_printf(fp, "Flags", b.smbb_flags, sizeof (b.smbb_flags) * NBBY,
46384ab085aSmws 	    smbios_bboard_flag_name, smbios_bboard_flag_desc);
46584ab085aSmws 	desc_printf(smbios_bboard_type_desc(b.smbb_type),
46684ab085aSmws 	    fp, "  Board Type: 0x%x", b.smbb_type);
467074bb90dSTom Pothier 
468074bb90dSTom Pothier 	chdl_cnt = b.smbb_contn;
469074bb90dSTom Pothier 	if (chdl_cnt != 0) {
470074bb90dSTom Pothier 		id_t *chdl;
471074bb90dSTom Pothier 		uint16_t hdl;
472074bb90dSTom Pothier 		int i, n, cnt;
473074bb90dSTom Pothier 
474074bb90dSTom Pothier 		chdl = alloca(chdl_cnt * sizeof (id_t));
475074bb90dSTom Pothier 		cnt = smbios_info_contains(shp, id, chdl_cnt, chdl);
476074bb90dSTom Pothier 		if (cnt > SMB_CONT_MAX)
477074bb90dSTom Pothier 			return;
478074bb90dSTom Pothier 		n = MIN(chdl_cnt, cnt);
479074bb90dSTom Pothier 
480074bb90dSTom Pothier 		oprintf(fp, "\n");
481074bb90dSTom Pothier 		for (i = 0; i < n; i++) {
482074bb90dSTom Pothier 			hdl = (uint16_t)chdl[i];
483074bb90dSTom Pothier 			oprintf(fp, "  Contained Handle: %u\n", hdl);
484074bb90dSTom Pothier 		}
485074bb90dSTom Pothier 	}
48684ab085aSmws }
48884ab085aSmws static void
print_chassis(smbios_hdl_t * shp,id_t id,FILE * fp)48984ab085aSmws print_chassis(smbios_hdl_t *shp, id_t id, FILE *fp)
49084ab085aSmws {
49184ab085aSmws 	smbios_chassis_t c;
492d53cdfabSRobert Mustacchi 	smbios_chassis_entry_t *elts;
493d53cdfabSRobert Mustacchi 	uint_t nelts, i;
495*a7aaa513SRobert Mustacchi 	if (smbios_info_chassis(shp, id, &c) != 0) {
496*a7aaa513SRobert Mustacchi 		smbios_warn(shp, "failed to read chassis information");
497*a7aaa513SRobert Mustacchi 		return;
498*a7aaa513SRobert Mustacchi 	}
50084ab085aSmws 	oprintf(fp, "  OEM Data: 0x%x\n", c.smbc_oemdata);
5010f56e145SRobert Mustacchi 	str_print(fp, "  SKU Number",
502d54e4739SYuri Pankov 	    c.smbc_sku[0] == '\0' ? "<unknown>" : c.smbc_sku);
50384ab085aSmws 	oprintf(fp, "  Lock Present: %s\n", c.smbc_lock ? "Y" : "N");
50584ab085aSmws 	desc_printf(smbios_chassis_type_desc(c.smbc_type),
50684ab085aSmws 	    fp, "  Chassis Type: 0x%x", c.smbc_type);
50884ab085aSmws 	desc_printf(smbios_chassis_state_desc(c.smbc_bustate),
50984ab085aSmws 	    fp, "  Boot-Up State: 0x%x", c.smbc_bustate);
51184ab085aSmws 	desc_printf(smbios_chassis_state_desc(c.smbc_psstate),
51284ab085aSmws 	    fp, "  Power Supply State: 0x%x", c.smbc_psstate);
51484ab085aSmws 	desc_printf(smbios_chassis_state_desc(c.smbc_thstate),
51584ab085aSmws 	    fp, "  Thermal State: 0x%x", c.smbc_thstate);
51784ab085aSmws 	oprintf(fp, "  Chassis Height: %uu\n", c.smbc_uheight);
51884ab085aSmws 	oprintf(fp, "  Power Cords: %u\n", c.smbc_cords);
519074bb90dSTom Pothier 
520d53cdfabSRobert Mustacchi 	oprintf(fp, "  Element Records: %u\n", c.smbc_elems);
521074bb90dSTom Pothier 
522d53cdfabSRobert Mustacchi 	if (c.smbc_elems == 0) {
523d53cdfabSRobert Mustacchi 		return;
524d53cdfabSRobert Mustacchi 	}
525074bb90dSTom Pothier 
526d53cdfabSRobert Mustacchi 	if (smbios_info_chassis_elts(shp, id, &nelts, &elts) != 0) {
527d53cdfabSRobert Mustacchi 		smbios_warn(shp, "failed to read chassis elements");
528d53cdfabSRobert Mustacchi 		return;
529d53cdfabSRobert Mustacchi 	}
530074bb90dSTom Pothier 
531d53cdfabSRobert Mustacchi 	oprintf(fp, "\n");
532d53cdfabSRobert Mustacchi 
533d53cdfabSRobert Mustacchi 	for (i = 0; i < nelts; i++) {
534d53cdfabSRobert Mustacchi 		switch (elts[i].smbce_type) {
535d53cdfabSRobert Mustacchi 		case SMB_CELT_BBOARD:
536d53cdfabSRobert Mustacchi 			desc_printf(smbios_bboard_type_desc(elts[i].smbce_elt),
537d53cdfabSRobert Mustacchi 			    fp, "  Contained SMBIOS Base Board Type: 0x%x",
538d53cdfabSRobert Mustacchi 			    elts[i].smbce_elt);
539d53cdfabSRobert Mustacchi 			break;
540d53cdfabSRobert Mustacchi 		case SMB_CELT_SMBIOS:
541d53cdfabSRobert Mustacchi 			desc_printf(smbios_type_name(elts[i].smbce_elt), fp,
542d53cdfabSRobert Mustacchi 			    "  Contained SMBIOS structure Type: %u",
543d53cdfabSRobert Mustacchi 			    elts[i].smbce_elt);
544d53cdfabSRobert Mustacchi 			break;
545d53cdfabSRobert Mustacchi 		default:
546d53cdfabSRobert Mustacchi 			oprintf(fp, "  Unknown contained Type: %u/%u\n",
547d53cdfabSRobert Mustacchi 			    elts[i].smbce_type, elts[i].smbce_elt);
548d53cdfabSRobert Mustacchi 			break;
549074bb90dSTom Pothier 		}
550d53cdfabSRobert Mustacchi 		oprintf(fp, "    Minimum number: %u\n", elts[i].smbce_min);
551d53cdfabSRobert Mustacchi 		oprintf(fp, "    Maximum number: %u\n", elts[i].smbce_max);
552074bb90dSTom Pothier 	}
55384ab085aSmws }
55584ab085aSmws static void
print_processor(smbios_hdl_t * shp,id_t id,FILE * fp)55684ab085aSmws print_processor(smbios_hdl_t *shp, id_t id, FILE *fp)
55784ab085aSmws {
55884ab085aSmws 	smbios_processor_t p;
55984ab085aSmws 	uint_t status;
561*a7aaa513SRobert Mustacchi 	if (smbios_info_processor(shp, id, &p) != 0) {
562*a7aaa513SRobert Mustacchi 		smbios_warn(shp, "failed to read processor information");
563*a7aaa513SRobert Mustacchi 		return;
564*a7aaa513SRobert Mustacchi 	}
56584ab085aSmws 	status = SMB_PRSTATUS_STATUS(p.smbp_status);
56784ab085aSmws 	desc_printf(smbios_processor_family_desc(p.smbp_family),
56884ab085aSmws 	    fp, "  Family: %u", p.smbp_family);
57084ab085aSmws 	oprintf(fp, "  CPUID: 0x%llx\n", (u_longlong_t)p.smbp_cpuid);
57284ab085aSmws 	desc_printf(smbios_processor_type_desc(p.smbp_type),
57384ab085aSmws 	    fp, "  Type: %u", p.smbp_type);
57584ab085aSmws 	desc_printf(smbios_processor_upgrade_desc(p.smbp_upgrade),
57684ab085aSmws 	    fp, "  Socket Upgrade: %u", p.smbp_upgrade);
57884ab085aSmws 	oprintf(fp, "  Socket Status: %s\n",
57984ab085aSmws 	    SMB_PRSTATUS_PRESENT(p.smbp_status) ?
58084ab085aSmws 	    "Populated" : "Not Populated");
58284ab085aSmws 	desc_printf(smbios_processor_status_desc(status),
58384ab085aSmws 	    fp, "  Processor Status: %u", status);
58584ab085aSmws 	if (SMB_PRV_LEGACY(p.smbp_voltage)) {
58684ab085aSmws 		oprintf(fp, "  Supported Voltages:");
58784ab085aSmws 		switch (p.smbp_voltage) {
58884ab085aSmws 		case SMB_PRV_5V:
58984ab085aSmws 			oprintf(fp, " 5.0V");
59084ab085aSmws 			break;
59184ab085aSmws 		case SMB_PRV_33V:
59284ab085aSmws 			oprintf(fp, " 3.3V");
59384ab085aSmws 			break;
59484ab085aSmws 		case SMB_PRV_29V:
59584ab085aSmws 			oprintf(fp, " 2.9V");
59684ab085aSmws 			break;
59784ab085aSmws 		}
59884ab085aSmws 		oprintf(fp, "\n");
59984ab085aSmws 	} else {
60084ab085aSmws 		oprintf(fp, "  Supported Voltages: %.1fV\n",
60184ab085aSmws 		    (float)SMB_PRV_VOLTAGE(p.smbp_voltage) / 10);
60284ab085aSmws 	}
6046734c4b0SRobert Mustacchi 	if (p.smbp_corecount != 0) {
605176a9270SRobert Mustacchi 		oprintf(fp, "  Core Count: %u\n", p.smbp_corecount);
6066734c4b0SRobert Mustacchi 	} else {
6074e901881SDale Ghent 		oprintf(fp, "  Core Count: Unknown\n");
6086734c4b0SRobert Mustacchi 	}
6094e901881SDale Ghent 
6106734c4b0SRobert Mustacchi 	if (p.smbp_coresenabled != 0) {
611176a9270SRobert Mustacchi 		oprintf(fp, "  Cores Enabled: %u\n", p.smbp_coresenabled);
6126734c4b0SRobert Mustacchi 	} else {
6134e901881SDale Ghent 		oprintf(fp, "  Cores Enabled: Unknown\n");
6146734c4b0SRobert Mustacchi 	}
6154e901881SDale Ghent 
6166734c4b0SRobert Mustacchi 	if (p.smbp_threadcount != 0) {
617176a9270SRobert Mustacchi 		oprintf(fp, "  Thread Count: %u\n", p.smbp_threadcount);
6186734c4b0SRobert Mustacchi 	} else {
6194e901881SDale Ghent 		oprintf(fp, "  Thread Count: Unknown\n");
6206734c4b0SRobert Mustacchi 	}
6214e901881SDale Ghent 
6224e901881SDale Ghent 	if (p.smbp_cflags) {
6234e901881SDale Ghent 		flag_printf(fp, "Processor Characteristics",
6244e901881SDale Ghent 		    p.smbp_cflags, sizeof (p.smbp_cflags) * NBBY,
6254e901881SDale Ghent 		    smbios_processor_core_flag_name,
6264e901881SDale Ghent 		    smbios_processor_core_flag_desc);
6274e901881SDale Ghent 	}
6284e901881SDale Ghent 
62984ab085aSmws 	if (p.smbp_clkspeed != 0)
63084ab085aSmws 		oprintf(fp, "  External Clock Speed: %uMHz\n", p.smbp_clkspeed);
63184ab085aSmws 	else
63284ab085aSmws 		oprintf(fp, "  External Clock Speed: Unknown\n");
63484ab085aSmws 	if (p.smbp_maxspeed != 0)
63584ab085aSmws 		oprintf(fp, "  Maximum Speed: %uMHz\n", p.smbp_maxspeed);
63684ab085aSmws 	else
63784ab085aSmws 		oprintf(fp, "  Maximum Speed: Unknown\n");
63984ab085aSmws 	if (p.smbp_curspeed != 0)
64084ab085aSmws 		oprintf(fp, "  Current Speed: %uMHz\n", p.smbp_curspeed);
64184ab085aSmws 	else
64284ab085aSmws 		oprintf(fp, "  Current Speed: Unknown\n");
64432ece1f9SRobert Mustacchi 	id_printf(fp, "  L1 Cache Handle: ", p.smbp_l1cache);
64532ece1f9SRobert Mustacchi 	id_printf(fp, "  L2 Cache Handle: ", p.smbp_l2cache);
64632ece1f9SRobert Mustacchi 	id_printf(fp, "  L3 Cache Handle: ", p.smbp_l3cache);
64784ab085aSmws }
64984ab085aSmws static void
print_cache(smbios_hdl_t * shp,id_t id,FILE * fp)65084ab085aSmws print_cache(smbios_hdl_t *shp, id_t id, FILE *fp)
65184ab085aSmws {
65284ab085aSmws 	smbios_cache_t c;
654*a7aaa513SRobert Mustacchi 	if (smbios_info_cache(shp, id, &c) != 0) {
655*a7aaa513SRobert Mustacchi 		smbios_warn(shp, "failed to read cache information");
656*a7aaa513SRobert Mustacchi 		return;
657*a7aaa513SRobert Mustacchi 	}
65984ab085aSmws 	oprintf(fp, "  Level: %u\n", c.smba_level);
660e5cce96fSRobert Mustacchi 	oprintf(fp, "  Maximum Installed Size: %" PRIu64 " bytes\n",
661e5cce96fSRobert Mustacchi 	    c.smba_maxsize2);
663e5cce96fSRobert Mustacchi 	if (c.smba_size2 != 0) {
664e5cce96fSRobert Mustacchi 		oprintf(fp, "  Installed Size: %" PRIu64 " bytes\n",
665e5cce96fSRobert Mustacchi 		    c.smba_size2);
666e5cce96fSRobert Mustacchi 	} else {
66784ab085aSmws 		oprintf(fp, "  Installed Size: Not Installed\n");
668e5cce96fSRobert Mustacchi 	}
67084ab085aSmws 	if (c.smba_speed != 0)
67184ab085aSmws 		oprintf(fp, "  Speed: %uns\n", c.smba_speed);
67284ab085aSmws 	else
67384ab085aSmws 		oprintf(fp, "  Speed: Unknown\n");
67584ab085aSmws 	flag_printf(fp, "Supported SRAM Types",
67684ab085aSmws 	    c.smba_stype, sizeof (c.smba_stype) * NBBY,
67784ab085aSmws 	    smbios_cache_ctype_name, smbios_cache_ctype_desc);
67984ab085aSmws 	desc_printf(smbios_cache_ctype_desc(c.smba_ctype),
68084ab085aSmws 	    fp, "  Current SRAM Type: 0x%x", c.smba_ctype);
68284ab085aSmws 	desc_printf(smbios_cache_ecc_desc(c.smba_etype),
68384ab085aSmws 	    fp, "  Error Correction Type: %u", c.smba_etype);
68584ab085aSmws 	desc_printf(smbios_cache_logical_desc(c.smba_ltype),
68684ab085aSmws 	    fp, "  Logical Cache Type: %u", c.smba_ltype);
68884ab085aSmws 	desc_printf(smbios_cache_assoc_desc(c.smba_assoc),
68984ab085aSmws 	    fp, "  Associativity: %u", c.smba_assoc);
69184ab085aSmws 	desc_printf(smbios_cache_mode_desc(c.smba_mode),
69284ab085aSmws 	    fp, "  Mode: %u", c.smba_mode);
69484ab085aSmws 	desc_printf(smbios_cache_loc_desc(c.smba_location),
69584ab085aSmws 	    fp, "  Location: %u", c.smba_location);