summaryrefslogtreecommitdiff
path: root/usr/src/common
diff options
context:
space:
mode:
authormws <none@none>2005-08-27 15:17:06 -0700
committermws <none@none>2005-08-27 15:17:06 -0700
commit84ab085a13f931bc78e7415e7ce921dbaa14fcb3 (patch)
tree7e11d8ecfa91e3947c8c99dbe116ae10a8e8076f /usr/src/common
parent89518a1cfe5021ecf5ad8d04c40f53cf947e95d9 (diff)
downloadillumos-joyent-84ab085a13f931bc78e7415e7ce921dbaa14fcb3.tar.gz
PSARC 2005/483 SMBIOS Support for Solaris
6313638 SMBIOS Support for Solaris 6230033 prtdiag should be implemented for Solaris x86 6313668 bmc driver should not have its own private smbios reader 6313670 post_startup_mmu_initialization() is useless and can be deleted
Diffstat (limited to 'usr/src/common')
-rw-r--r--usr/src/common/smbios/mktables.sh145
-rw-r--r--usr/src/common/smbios/smb_error.c79
-rw-r--r--usr/src/common/smbios/smb_info.c785
-rw-r--r--usr/src/common/smbios/smb_open.c370
4 files changed, 1379 insertions, 0 deletions
diff --git a/usr/src/common/smbios/mktables.sh b/usr/src/common/smbios/mktables.sh
new file mode 100644
index 0000000000..2cb4db46fa
--- /dev/null
+++ b/usr/src/common/smbios/mktables.sh
@@ -0,0 +1,145 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+#
+# The SMBIOS interfaces defined in <sys/smbios.h> include a set of integer-to-
+# string conversion routines for the various constants defined in the SMBIOS
+# spec. These functions are used by smbios(1M) and prtdiag(1M) and can be
+# leveraged by other clients as well. To simplify maintenance of the source
+# base, this shell script automatically generates the source code for all of
+# these functions from the <sys/smbios.h> header file and its comments. Each
+# set of constants should be given a unique #define prefix, listed in the
+# tables below. The smbios_*_name() functions return the identifier of the
+# cpp define, and the smbios_*_desc() functions return the text of the comment.
+#
+
+name_funcs='
+SMB_BBFL_ smbios_bboard_flag_name uint_t
+SMB_BIOSFL_ smbios_bios_flag_name uint64_t
+SMB_BIOSXB1_ smbios_bios_xb1_name uint_t
+SMB_BIOSXB2_ smbios_bios_xb2_name uint_t
+SMB_CAT_ smbios_cache_ctype_name uint_t
+SMB_CAF_ smbios_cache_flag_name uint_t
+SMB_EVFL_ smbios_evlog_flag_name uint_t
+SMB_IPMI_F_ smbios_ipmi_flag_name uint_t
+SMB_MDF_ smbios_memdevice_flag_name uint_t
+SMB_TYPE_ smbios_type_name uint_t
+SMB_SLCH1_ smbios_slot_ch1_name uint_t
+SMB_SLCH2_ smbios_slot_ch2_name uint_t
+'
+
+desc_funcs='
+SMB_BBFL_ smbios_bboard_flag_desc uint_t
+SMB_BBT_ smbios_bboard_type_desc uint_t
+SMB_BIOSFL_ smbios_bios_flag_desc uint64_t
+SMB_BIOSXB1_ smbios_bios_xb1_desc uint_t
+SMB_BIOSXB2_ smbios_bios_xb2_desc uint_t
+SMB_BOOT_ smbios_boot_desc uint_t
+SMB_CAA_ smbios_cache_assoc_desc uint_t
+SMB_CAT_ smbios_cache_ctype_desc uint_t
+SMB_CAE_ smbios_cache_ecc_desc uint_t
+SMB_CAF_ smbios_cache_flag_desc uint_t
+SMB_CAL_ smbios_cache_loc_desc uint_t
+SMB_CAG_ smbios_cache_logical_desc uint_t
+SMB_CAM_ smbios_cache_mode_desc uint_t
+SMB_CHST_ smbios_chassis_state_desc uint_t
+SMB_CHT_ smbios_chassis_type_desc uint_t
+SMB_EVFL_ smbios_evlog_flag_desc uint_t
+SMB_EVHF_ smbios_evlog_format_desc uint_t
+SMB_EVM_ smbios_evlog_method_desc uint_t
+SMB_HWSEC_PS_ smbios_hwsec_desc uint_t
+SMB_IPMI_F_ smbios_ipmi_flag_desc uint_t
+SMB_IPMI_T_ smbios_ipmi_type_desc uint_t
+SMB_MAL_ smbios_memarray_loc_desc uint_t
+SMB_MAU_ smbios_memarray_use_desc uint_t
+SMB_MAE_ smbios_memarray_ecc_desc uint_t
+SMB_MDF_ smbios_memdevice_flag_desc uint_t
+SMB_MDFF_ smbios_memdevice_form_desc uint_t
+SMB_MDT_ smbios_memdevice_type_desc uint_t
+SMB_POC_ smbios_port_conn_desc uint_t
+SMB_POT_ smbios_port_type_desc uint_t
+SMB_PRF_ smbios_processor_family_desc uint_t
+SMB_PRS_ smbios_processor_status_desc uint_t
+SMB_PRT_ smbios_processor_type_desc uint_t
+SMB_PRU_ smbios_processor_upgrade_desc uint_t
+SMB_SLCH1_ smbios_slot_ch1_desc uint_t
+SMB_SLCH2_ smbios_slot_ch2_desc uint_t
+SMB_SLL_ smbios_slot_length_desc uint_t
+SMB_SLT_ smbios_slot_type_desc uint_t
+SMB_SLU_ smbios_slot_usage_desc uint_t
+SMB_SLW_ smbios_slot_width_desc uint_t
+SMB_TYPE_ smbios_type_desc uint_t
+SMB_WAKEUP_ smbios_system_wakeup_desc uint_t
+'
+
+if [ $# -ne 1 ]; then
+ echo "Usage: $0 file.h > file.c" >&2
+ exit 2
+fi
+
+echo "\
+/*\n\
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.\n\
+ * Use is subject to license terms.\n\
+ */\n\
+\n\
+#pragma ident\t\"%Z%%M%\t%I%\t%E% SMI\"\n\
+\n\
+#include <smbios.h>"
+
+echo "$name_funcs" | while read p name type; do
+ [ -z "$p" ] && continue
+ pattern="^#define[ ]\($p[A-Za-z0-9_]*\)[ ]*[A-Z0-9]*.*$"
+ replace=' case \1: return ("\1");'
+
+ echo "\nconst char *\n$name($type x)\n{\n\tswitch (x) {"
+ sed -n "s@$pattern@$replace@p" < $1 || exit 1
+ echo "\t}\n\treturn (NULL);\n}"
+done
+
+#
+# Generate the description functions based on the comment next to a #define.
+# The transformations for descriptive comments are slightly more complicated
+# than those used for the identifier->name functions above:
+#
+# (1) strip any [RO] suffix from the comment (a header file convention)
+# (2) replace any " with \" so it is escaped for the final output string
+# (3) replace return (...); with return ("..."); to finish the code
+#
+echo "$desc_funcs" | while read p name type; do
+ [ -z "$p" ] && continue
+ pattern="^#define[ ]\($p[A-Za-z0-9_]*\)[ ]*.*/\\* \(.*\) \\*/$"
+ replace=' case \1: return (\2);'
+
+ echo "\nconst char *\n$name($type x)\n{\n\tswitch (x) {"
+ sed -n "s@$pattern@$replace@p" < $1 | sed 's/ ([RO]))/)/' | \
+ sed 's/"/\\"/g' | sed 's/(/("/;s/);$/");/' || exit 1
+ echo "\t}\n\treturn (NULL);\n}"
+done
+
+exit 0
diff --git a/usr/src/common/smbios/smb_error.c b/usr/src/common/smbios/smb_error.c
new file mode 100644
index 0000000000..7c0ad4ddbf
--- /dev/null
+++ b/usr/src/common/smbios/smb_error.c
@@ -0,0 +1,79 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/smbios_impl.h>
+
+static const char *const _smb_errlist[] = {
+ "System does not export an SMBIOS table", /* ESMB_NOTFOUND */
+ "Failed to map SMBIOS table", /* ESMB_MAPDEV */
+ "Failed to locate specified structure", /* ESMB_NOENT */
+ "Failed to allocate memory", /* ESMB_NOMEM */
+ "Failed to read SMBIOS entry point", /* ESMB_NOHDR */
+ "Failed to read SMBIOS structure table", /* ESMB_NOSTAB */
+ "Generic info not available for structure", /* ESMB_NOINFO */
+ "Structure table is shorter than expected", /* ESMB_SHORT */
+ "SMBIOS data structure is corrupted", /* ESMB_CORRUPT */
+ "Requested library version is not supported", /* ESMB_VERSION */
+ "Structure type is not supported by this BIOS", /* ESMB_NOTSUP */
+ "Header is not a valid SMBIOS entry point", /* ESMB_HEADER */
+ "SMBIOS format is too old for processing", /* ESMB_OLD */
+ "SMBIOS format is new and not yet supported", /* ESMB_NEW */
+ "SMBIOS header checksum mismatch", /* ESMB_CKSUM */
+ "Invalid argument specified in library call", /* ESMB_INVAL */
+ "Structure is not of the expected type", /* ESMB_TYPE */
+ "Unknown SMBIOS error" /* ESMB_UNKNOWN */
+};
+
+static const int _smb_nerr = sizeof (_smb_errlist) / sizeof (_smb_errlist[0]);
+
+const char *
+smbios_errmsg(int error)
+{
+ const char *str;
+
+ if (error >= ESMB_BASE && (error - ESMB_BASE) < _smb_nerr)
+ str = _smb_errlist[error - ESMB_BASE];
+ else
+ str = smb_strerror(error);
+
+ return (str ? str : "Unknown error");
+}
+
+int
+smbios_errno(smbios_hdl_t *shp)
+{
+ return (shp->sh_err);
+}
+
+int
+smb_set_errno(smbios_hdl_t *shp, int error)
+{
+ shp->sh_err = error;
+ return (SMB_ERR);
+}
diff --git a/usr/src/common/smbios/smb_info.c b/usr/src/common/smbios/smb_info.c
new file mode 100644
index 0000000000..ae0be44c72
--- /dev/null
+++ b/usr/src/common/smbios/smb_info.c
@@ -0,0 +1,785 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMBIOS Information Routines
+ *
+ * The routines in this file are used to convert from the SMBIOS data format to
+ * a more reasonable and stable set of structures offered as part of our ABI.
+ * These functions take the general form:
+ *
+ * stp = smb_lookup_type(shp, foo);
+ * smb_foo_t foo;
+ *
+ * smb_info_bcopy(stp->smbst_hdr, &foo, sizeof (foo));
+ * bzero(caller's struct);
+ *
+ * copy/convert foo members into caller's struct
+ *
+ * We copy the internal structure on to an automatic variable so as to avoid
+ * checks everywhere for structures that the BIOS has improperly truncated, and
+ * also to automatically handle the case of a structure that has been extended.
+ * When necessary, this code can use smb_gteq() to determine whether the SMBIOS
+ * data is of a particular revision that is supposed to contain a new field.
+ */
+
+#include <sys/smbios_impl.h>
+
+/*
+ * A large number of SMBIOS structures contain a set of common strings used to
+ * describe a h/w component's serial number, manufacturer, etc. These fields
+ * helpfully have different names and offsets and sometimes aren't consistent.
+ * To simplify life for our clients, we factor these common things out into
+ * smbios_info_t, which can be retrieved for any structure. The following
+ * table describes the mapping from a given structure to the smbios_info_t.
+ */
+static const struct smb_infospec {
+ uint8_t is_type; /* structure type */
+ uint8_t is_manu; /* manufacturer offset */
+ uint8_t is_product; /* product name offset */
+ uint8_t is_version; /* version offset */
+ uint8_t is_serial; /* serial number offset */
+ uint8_t is_asset; /* asset tag offset */
+ uint8_t is_location; /* location string offset */
+ uint8_t is_part; /* part number offset */
+} _smb_infospecs[] = {
+ { SMB_TYPE_SYSTEM,
+ offsetof(smb_system_t, smbsi_manufacturer),
+ offsetof(smb_system_t, smbsi_product),
+ offsetof(smb_system_t, smbsi_version),
+ offsetof(smb_system_t, smbsi_serial),
+ 0,
+ 0,
+ 0 },
+ { SMB_TYPE_BASEBOARD,
+ offsetof(smb_bboard_t, smbbb_manufacturer),
+ offsetof(smb_bboard_t, smbbb_product),
+ offsetof(smb_bboard_t, smbbb_version),
+ offsetof(smb_bboard_t, smbbb_serial),
+ offsetof(smb_bboard_t, smbbb_asset),
+ offsetof(smb_bboard_t, smbbb_location),
+ 0 },
+ { SMB_TYPE_CHASSIS,
+ offsetof(smb_chassis_t, smbch_manufacturer),
+ 0,
+ offsetof(smb_chassis_t, smbch_version),
+ offsetof(smb_chassis_t, smbch_serial),
+ offsetof(smb_chassis_t, smbch_asset),
+ 0,
+ 0 },
+ { SMB_TYPE_PROCESSOR,
+ offsetof(smb_processor_t, smbpr_manufacturer),
+ 0,
+ offsetof(smb_processor_t, smbpr_version),
+ offsetof(smb_processor_t, smbpr_serial),
+ offsetof(smb_processor_t, smbpr_asset),
+ offsetof(smb_processor_t, smbpr_socket),
+ offsetof(smb_processor_t, smbpr_part) },
+ { SMB_TYPE_CACHE,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ offsetof(smb_cache_t, smbca_socket),
+ 0 },
+ { SMB_TYPE_PORT,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ offsetof(smb_port_t, smbpo_iref),
+ 0 },
+ { SMB_TYPE_SLOT,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ offsetof(smb_slot_t, smbsl_name),
+ 0 },
+ { SMB_TYPE_MEMDEVICE,
+ offsetof(smb_memdevice_t, smbmdev_manufacturer),
+ 0,
+ 0,
+ offsetof(smb_memdevice_t, smbmdev_serial),
+ offsetof(smb_memdevice_t, smbmdev_asset),
+ offsetof(smb_memdevice_t, smbmdev_dloc),
+ offsetof(smb_memdevice_t, smbmdev_part) },
+ { SMB_TYPE_POWERSUP,
+ offsetof(smb_powersup_t, smbpsup_manufacturer),
+ offsetof(smb_powersup_t, smbpsup_devname),
+ offsetof(smb_powersup_t, smbpsup_rev),
+ offsetof(smb_powersup_t, smbpsup_serial),
+ offsetof(smb_powersup_t, smbpsup_asset),
+ offsetof(smb_powersup_t, smbpsup_loc),
+ offsetof(smb_powersup_t, smbpsup_part) },
+ { SMB_TYPE_EOT }
+};
+
+static const char *
+smb_info_strptr(const smb_struct_t *stp, uint8_t off, int *n)
+{
+ const uint8_t *sp = (const uint8_t *)(uintptr_t)stp->smbst_hdr;
+
+ if (off != 0 && sp + off < stp->smbst_end) {
+ (*n)++; /* indicate success for caller */
+ return (smb_strptr(stp, sp[off]));
+ }
+
+ return (smb_strptr(stp, 0));
+}
+
+static void
+smb_info_bcopy(const smb_header_t *hp, void *dst, size_t dstlen)
+{
+ if (dstlen > hp->smbh_len) {
+ bcopy(hp, dst, hp->smbh_len);
+ bzero((char *)dst + hp->smbh_len, dstlen - hp->smbh_len);
+ } else
+ bcopy(hp, dst, dstlen);
+}
+
+void
+smbios_info_smbios(smbios_hdl_t *shp, smbios_entry_t *ep)
+{
+ bcopy(&shp->sh_ent, ep, sizeof (smbios_entry_t));
+}
+
+int
+smbios_info_common(smbios_hdl_t *shp, id_t id, smbios_info_t *ip)
+{
+ const smb_struct_t *stp = smb_lookup_id(shp, id);
+ const struct smb_infospec *isp;
+ int n = 0;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ for (isp = _smb_infospecs; isp->is_type != SMB_TYPE_EOT; isp++) {
+ if (isp->is_type == stp->smbst_hdr->smbh_type)
+ break;
+ }
+
+ ip->smbi_manufacturer = smb_info_strptr(stp, isp->is_manu, &n);
+ ip->smbi_product = smb_info_strptr(stp, isp->is_product, &n);
+ ip->smbi_version = smb_info_strptr(stp, isp->is_version, &n);
+ ip->smbi_serial = smb_info_strptr(stp, isp->is_serial, &n);
+ ip->smbi_asset = smb_info_strptr(stp, isp->is_asset, &n);
+ ip->smbi_location = smb_info_strptr(stp, isp->is_location, &n);
+ ip->smbi_part = smb_info_strptr(stp, isp->is_part, &n);
+
+ /*
+ * If we have a port with an empty internal reference designator string
+ * try using the external reference designator string instead.
+ */
+ if (isp->is_type == SMB_TYPE_PORT && ip->smbi_location[0] == '\0') {
+ ip->smbi_location = smb_info_strptr(stp,
+ offsetof(smb_port_t, smbpo_eref), &n);
+ }
+
+ return (n ? 0 : smb_set_errno(shp, ESMB_NOINFO));
+}
+
+id_t
+smbios_info_bios(smbios_hdl_t *shp, smbios_bios_t *bp)
+{
+ const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_BIOS);
+ const smb_bios_t *bip;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ if (stp->smbst_hdr->smbh_len < sizeof (smb_bios_t) - sizeof (uint8_t))
+ return (smb_set_errno(shp, ESMB_CORRUPT));
+
+ bip = (smb_bios_t *)(uintptr_t)stp->smbst_hdr;
+ bzero(bp, sizeof (smbios_bios_t));
+
+ bp->smbb_vendor = smb_strptr(stp, bip->smbbi_vendor);
+ bp->smbb_version = smb_strptr(stp, bip->smbbi_version);
+ bp->smbb_segment = bip->smbbi_segment;
+ bp->smbb_reldate = smb_strptr(stp, bip->smbbi_reldate);
+ bp->smbb_romsize = 64 * 1024 * ((uint32_t)bip->smbbi_romsize + 1);
+ bp->smbb_runsize = 16 * (0x10000 - (uint32_t)bip->smbbi_segment);
+ bp->smbb_cflags = bip->smbbi_cflags;
+
+ /*
+ * If one or more extension bytes are present, reset smbb_xcflags to
+ * point to them. Otherwise leave this member set to NULL.
+ */
+ if (stp->smbst_hdr->smbh_len >= sizeof (smb_bios_t)) {
+ bp->smbb_xcflags = bip->smbbi_xcflags;
+ bp->smbb_nxcflags = stp->smbst_hdr->smbh_len -
+ sizeof (smb_bios_t) + 1;
+
+ if (bp->smbb_nxcflags > SMB_BIOSXB_ECFW_MIN &&
+ smb_gteq(shp, SMB_VERSION_24)) {
+ bp->smbb_biosv.smbv_major =
+ bip->smbbi_xcflags[SMB_BIOSXB_BIOS_MAJ];
+ bp->smbb_biosv.smbv_minor =
+ bip->smbbi_xcflags[SMB_BIOSXB_BIOS_MIN];
+ bp->smbb_ecfwv.smbv_major =
+ bip->smbbi_xcflags[SMB_BIOSXB_ECFW_MAJ];
+ bp->smbb_ecfwv.smbv_minor =
+ bip->smbbi_xcflags[SMB_BIOSXB_ECFW_MIN];
+ }
+ }
+
+ return (stp->smbst_hdr->smbh_hdl);
+}
+
+id_t
+smbios_info_system(smbios_hdl_t *shp, smbios_system_t *sip)
+{
+ const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_SYSTEM);
+ smb_system_t si;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ smb_info_bcopy(stp->smbst_hdr, &si, sizeof (si));
+ bzero(sip, sizeof (smbios_system_t));
+
+ sip->smbs_uuid = ((smb_system_t *)stp->smbst_hdr)->smbsi_uuid;
+ sip->smbs_uuidlen = sizeof (si.smbsi_uuid);
+ sip->smbs_wakeup = si.smbsi_wakeup;
+ sip->smbs_sku = smb_strptr(stp, si.smbsi_sku);
+ sip->smbs_family = smb_strptr(stp, si.smbsi_family);
+
+ return (stp->smbst_hdr->smbh_hdl);
+}
+
+int
+smbios_info_bboard(smbios_hdl_t *shp, id_t id, smbios_bboard_t *bbp)
+{
+ const smb_struct_t *stp = smb_lookup_id(shp, id);
+ smb_bboard_t bb;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ if (stp->smbst_hdr->smbh_type != SMB_TYPE_BASEBOARD)
+ return (smb_set_errno(shp, ESMB_TYPE));
+
+ smb_info_bcopy(stp->smbst_hdr, &bb, sizeof (bb));
+ bzero(bbp, sizeof (smbios_bboard_t));
+
+ /*
+ * At present, we do not provide support for the contained object
+ * handles portion of the Base Board structure, as none of the 2.3+
+ * BIOSes commonly in use appear to implement it at present.
+ */
+ bbp->smbb_chassis = bb.smbbb_chassis;
+ bbp->smbb_flags = bb.smbbb_flags;
+ bbp->smbb_type = bb.smbbb_type;
+
+ return (0);
+}
+
+int
+smbios_info_chassis(smbios_hdl_t *shp, id_t id, smbios_chassis_t *chp)
+{
+ const smb_struct_t *stp = smb_lookup_id(shp, id);
+ smb_chassis_t ch;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ if (stp->smbst_hdr->smbh_type != SMB_TYPE_CHASSIS)
+ return (smb_set_errno(shp, ESMB_TYPE));
+
+ smb_info_bcopy(stp->smbst_hdr, &ch, sizeof (ch));
+ bzero(chp, sizeof (smbios_chassis_t));
+
+ /*
+ * At present, we do not provide support for the contained object
+ * handles portion of the Chassis structure, as none of the 2.3+
+ * BIOSes commonly in use appear to implement it at present.
+ */
+ chp->smbc_oemdata = ch.smbch_oemdata;
+ chp->smbc_lock = (ch.smbch_type & SMB_CHT_LOCK) != 0;
+ chp->smbc_type = ch.smbch_type & ~SMB_CHT_LOCK;
+ chp->smbc_bustate = ch.smbch_bustate;
+ chp->smbc_psstate = ch.smbch_psstate;
+ chp->smbc_thstate = ch.smbch_thstate;
+ chp->smbc_security = ch.smbch_security;
+ chp->smbc_uheight = ch.smbch_uheight;
+ chp->smbc_cords = ch.smbch_cords;
+ chp->smbc_elems = ch.smbch_cn;
+
+ return (0);
+}
+
+int
+smbios_info_processor(smbios_hdl_t *shp, id_t id, smbios_processor_t *pp)
+{
+ const smb_struct_t *stp = smb_lookup_id(shp, id);
+ smb_processor_t p;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ if (stp->smbst_hdr->smbh_type != SMB_TYPE_PROCESSOR)
+ return (smb_set_errno(shp, ESMB_TYPE));
+
+ smb_info_bcopy(stp->smbst_hdr, &p, sizeof (p));
+ bzero(pp, sizeof (smbios_processor_t));
+
+ pp->smbp_cpuid = p.smbpr_cpuid;
+ pp->smbp_type = p.smbpr_type;
+ pp->smbp_family = p.smbpr_family;
+ pp->smbp_voltage = p.smbpr_voltage;
+ pp->smbp_maxspeed = p.smbpr_maxspeed;
+ pp->smbp_curspeed = p.smbpr_curspeed;
+ pp->smbp_status = p.smbpr_status;
+ pp->smbp_upgrade = p.smbpr_upgrade;
+ pp->smbp_l1cache = p.smbpr_l1cache;
+ pp->smbp_l2cache = p.smbpr_l2cache;
+ pp->smbp_l3cache = p.smbpr_l3cache;
+
+ return (0);
+}
+
+int
+smbios_info_cache(smbios_hdl_t *shp, id_t id, smbios_cache_t *cap)
+{
+ const smb_struct_t *stp = smb_lookup_id(shp, id);
+ smb_cache_t c;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ if (stp->smbst_hdr->smbh_type != SMB_TYPE_CACHE)
+ return (smb_set_errno(shp, ESMB_TYPE));
+
+ smb_info_bcopy(stp->smbst_hdr, &c, sizeof (c));
+ bzero(cap, sizeof (smbios_cache_t));
+
+ cap->smba_maxsize = SMB_CACHE_SIZE(c.smbca_maxsize);
+ cap->smba_size = SMB_CACHE_SIZE(c.smbca_size);
+ cap->smba_stype = c.smbca_stype;
+ cap->smba_ctype = c.smbca_ctype;
+ cap->smba_speed = c.smbca_speed;
+ cap->smba_etype = c.smbca_etype;
+ cap->smba_ltype = c.smbca_ltype;
+ cap->smba_assoc = c.smbca_assoc;
+ cap->smba_level = SMB_CACHE_CFG_LEVEL(c.smbca_config);
+ cap->smba_mode = SMB_CACHE_CFG_MODE(c.smbca_config);
+ cap->smba_location = SMB_CACHE_CFG_LOCATION(c.smbca_config);
+
+ if (SMB_CACHE_CFG_ENABLED(c.smbca_config))
+ cap->smba_flags |= SMB_CAF_ENABLED;
+
+ if (SMB_CACHE_CFG_SOCKETED(c.smbca_config))
+ cap->smba_flags |= SMB_CAF_SOCKETED;
+
+ return (0);
+}
+
+int
+smbios_info_port(smbios_hdl_t *shp, id_t id, smbios_port_t *pop)
+{
+ const smb_struct_t *stp = smb_lookup_id(shp, id);
+ smb_port_t p;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ if (stp->smbst_hdr->smbh_type != SMB_TYPE_PORT)
+ return (smb_set_errno(shp, ESMB_TYPE));
+
+ smb_info_bcopy(stp->smbst_hdr, &p, sizeof (p));
+ bzero(pop, sizeof (smbios_port_t));
+
+ pop->smbo_iref = smb_strptr(stp, p.smbpo_iref);
+ pop->smbo_eref = smb_strptr(stp, p.smbpo_eref);
+
+ pop->smbo_itype = p.smbpo_itype;
+ pop->smbo_etype = p.smbpo_etype;
+ pop->smbo_ptype = p.smbpo_ptype;
+
+ return (0);
+}
+
+int
+smbios_info_slot(smbios_hdl_t *shp, id_t id, smbios_slot_t *sp)
+{
+ const smb_struct_t *stp = smb_lookup_id(shp, id);
+ smb_slot_t s;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ if (stp->smbst_hdr->smbh_type != SMB_TYPE_SLOT)
+ return (smb_set_errno(shp, ESMB_TYPE));
+
+ smb_info_bcopy(stp->smbst_hdr, &s, sizeof (s));
+ bzero(sp, sizeof (smbios_slot_t));
+
+ sp->smbl_name = smb_strptr(stp, s.smbsl_name);
+ sp->smbl_type = s.smbsl_type;
+ sp->smbl_width = s.smbsl_width;
+ sp->smbl_usage = s.smbsl_usage;
+ sp->smbl_length = s.smbsl_length;
+ sp->smbl_id = s.smbsl_id;
+ sp->smbl_ch1 = s.smbsl_ch1;
+ sp->smbl_ch2 = s.smbsl_ch2;
+
+ return (0);
+}
+
+int
+smbios_info_obdevs(smbios_hdl_t *shp, id_t id, int obc, smbios_obdev_t *obp)
+{
+ const smb_struct_t *stp = smb_lookup_id(shp, id);
+ const smb_obdev_t *op;
+ int i, m, n;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ if (stp->smbst_hdr->smbh_type != SMB_TYPE_OBDEVS)
+ return (smb_set_errno(shp, ESMB_TYPE));
+
+ op = (smb_obdev_t *)((uintptr_t)stp->smbst_hdr + sizeof (smb_header_t));
+ m = (stp->smbst_hdr->smbh_len - sizeof (smb_header_t)) / sizeof (*op);
+ n = MIN(m, obc);
+
+ for (i = 0; i < n; i++, op++, obp++) {
+ obp->smbd_name = smb_strptr(stp, op->smbob_name);
+ obp->smbd_type = op->smbob_type & ~SMB_OBT_ENABLED;
+ obp->smbd_enabled = (op->smbob_type & SMB_OBT_ENABLED) != 0;
+ }
+
+ return (m);
+}
+
+/*
+ * The implementation structures for OEMSTR, SYSCONFSTR, and LANG all use the
+ * first byte to indicate the size of a string table at the end of the record.
+ * Therefore, smbios_info_strtab() can be used to retrieve the table size and
+ * strings for any of these underlying record types.
+ */
+int
+smbios_info_strtab(smbios_hdl_t *shp, id_t id, int argc, const char *argv[])
+{
+ const smb_struct_t *stp = smb_lookup_id(shp, id);
+ smb_strtab_t s;
+ int i, n;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ if (stp->smbst_hdr->smbh_type != SMB_TYPE_OEMSTR &&
+ stp->smbst_hdr->smbh_type != SMB_TYPE_SYSCONFSTR &&
+ stp->smbst_hdr->smbh_type != SMB_TYPE_LANG)
+ return (smb_set_errno(shp, ESMB_TYPE));
+
+ smb_info_bcopy(stp->smbst_hdr, &s, sizeof (s));
+ n = MIN(s.smbtb_count, argc);
+
+ for (i = 0; i < n; i++)
+ argv[i] = smb_strptr(stp, i + 1);
+
+ return (s.smbtb_count);
+}
+
+id_t
+smbios_info_lang(smbios_hdl_t *shp, smbios_lang_t *lp)
+{
+ const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_LANG);
+ smb_lang_t l;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ smb_info_bcopy(stp->smbst_hdr, &l, sizeof (l));
+ bzero(lp, sizeof (smbios_lang_t));
+
+ lp->smbla_cur = smb_strptr(stp, l.smblang_cur);
+ lp->smbla_fmt = l.smblang_flags & 1;
+ lp->smbla_num = l.smblang_num;
+
+ return (stp->smbst_hdr->smbh_hdl);
+}
+
+id_t
+smbios_info_eventlog(smbios_hdl_t *shp, smbios_evlog_t *evp)
+{
+ const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_EVENTLOG);
+ const smb_sel_t *sel;
+ size_t len;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ if (stp->smbst_hdr->smbh_len < sizeof (smb_sel_t) - sizeof (uint8_t))
+ return (smb_set_errno(shp, ESMB_CORRUPT));
+
+ sel = (smb_sel_t *)(uintptr_t)stp->smbst_hdr;
+ len = stp->smbst_hdr->smbh_len - sizeof (smb_sel_t) + sizeof (uint8_t);
+ bzero(evp, sizeof (smbios_evlog_t));
+
+ if (len < sel->smbsel_typec * sel->smbsel_typesz)
+ return (smb_set_errno(shp, ESMB_CORRUPT));
+
+ evp->smbev_size = sel->smbsel_len;
+ evp->smbev_hdr = sel->smbsel_hdroff;
+ evp->smbev_data = sel->smbsel_dataoff;
+ evp->smbev_method = sel->smbsel_method;
+ evp->smbev_flags = sel->smbsel_status;
+ evp->smbev_format = sel->smbsel_format;
+ evp->smbev_token = sel->smbsel_token;
+ evp->smbev_addr.eva_addr = sel->smbsel_addr;
+
+ if (sel->smbsel_typesz == sizeof (smbios_evtype_t)) {
+ evp->smbev_typec = sel->smbsel_typec;
+ evp->smbev_typev = (void *)(uintptr_t)sel->smbsel_typev;
+ }
+
+ return (stp->smbst_hdr->smbh_hdl);
+}
+
+int
+smbios_info_memarray(smbios_hdl_t *shp, id_t id, smbios_memarray_t *map)
+{
+ const smb_struct_t *stp = smb_lookup_id(shp, id);
+ smb_memarray_t m;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ if (stp->smbst_hdr->smbh_type != SMB_TYPE_MEMARRAY)
+ return (smb_set_errno(shp, ESMB_TYPE));
+
+ smb_info_bcopy(stp->smbst_hdr, &m, sizeof (m));
+ bzero(map, sizeof (smbios_memarray_t));
+
+ map->smbma_location = m.smbmarr_loc;
+ map->smbma_use = m.smbmarr_use;
+ map->smbma_ecc = m.smbmarr_ecc;
+ map->smbma_ndevs = m.smbmarr_ndevs;
+ map->smbma_err = m.smbmarr_err;
+
+ if (m.smbmarr_cap != 0x80000000)
+ map->smbma_size = (uint64_t)m.smbmarr_cap * 1024;
+ else
+ map->smbma_size = 0; /* unknown */
+
+ return (0);
+}
+
+int
+smbios_info_memarrmap(smbios_hdl_t *shp, id_t id, smbios_memarrmap_t *map)
+{
+ const smb_struct_t *stp = smb_lookup_id(shp, id);
+ smb_memarrmap_t m;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ if (stp->smbst_hdr->smbh_type != SMB_TYPE_MEMARRAYMAP)
+ return (smb_set_errno(shp, ESMB_TYPE));
+
+ smb_info_bcopy(stp->smbst_hdr, &m, sizeof (m));
+ bzero(map, sizeof (smbios_memarrmap_t));
+
+ map->smbmam_array = m.smbamap_array;
+ map->smbmam_width = m.smbamap_width;
+ map->smbmam_addr = (uint64_t)m.smbamap_start * 1024;
+ map->smbmam_size = (uint64_t)
+ (m.smbamap_end - m.smbamap_start + 1) * 1024;
+
+ return (0);
+}
+
+int
+smbios_info_memdevice(smbios_hdl_t *shp, id_t id, smbios_memdevice_t *mdp)
+{
+ const smb_struct_t *stp = smb_lookup_id(shp, id);
+ smb_memdevice_t m;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ if (stp->smbst_hdr->smbh_type != SMB_TYPE_MEMDEVICE)
+ return (smb_set_errno(shp, ESMB_TYPE));
+
+ smb_info_bcopy(stp->smbst_hdr, &m, sizeof (m));
+ bzero(mdp, sizeof (smbios_memdevice_t));
+
+ mdp->smbmd_array = m.smbmdev_array;
+ mdp->smbmd_error = m.smbmdev_error;
+ mdp->smbmd_twidth = m.smbmdev_twidth == 0xFFFF ? -1U : m.smbmdev_twidth;
+ mdp->smbmd_dwidth = m.smbmdev_dwidth == 0xFFFF ? -1U : m.smbmdev_dwidth;
+
+ if (mdp->smbmd_size != 0xFFFF) {
+ mdp->smbmd_size = (uint64_t)(m.smbmdev_size & ~SMB_MDS_KBYTES);
+ if (m.smbmdev_size & SMB_MDS_KBYTES)
+ mdp->smbmd_size *= 1024;
+ else
+ mdp->smbmd_size *= 1024 * 1024;
+ } else
+ mdp->smbmd_size = -1ULL; /* size unknown */
+
+ mdp->smbmd_form = m.smbmdev_form;
+ mdp->smbmd_set = m.smbmdev_set;
+ mdp->smbmd_type = m.smbmdev_type;
+ mdp->smbmd_flags = m.smbmdev_flags;
+ mdp->smbmd_dloc = smb_strptr(stp, m.smbmdev_dloc);
+ mdp->smbmd_bloc = smb_strptr(stp, m.smbmdev_bloc);
+
+ if (m.smbmdev_speed != 0)
+ mdp->smbmd_speed = 1000 / m.smbmdev_speed; /* MHz -> nsec */
+
+ return (0);
+}
+
+int
+smbios_info_memdevmap(smbios_hdl_t *shp, id_t id, smbios_memdevmap_t *mdp)
+{
+ const smb_struct_t *stp = smb_lookup_id(shp, id);
+ smb_memdevmap_t m;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ if (stp->smbst_hdr->smbh_type != SMB_TYPE_MEMDEVICEMAP)
+ return (smb_set_errno(shp, ESMB_TYPE));
+
+ smb_info_bcopy(stp->smbst_hdr, &m, sizeof (m));
+ bzero(mdp, sizeof (smbios_memdevmap_t));
+
+ mdp->smbmdm_device = m.smbdmap_device;
+ mdp->smbmdm_arrmap = m.smbdmap_array;
+ mdp->smbmdm_addr = (uint64_t)m.smbdmap_start * 1024;
+ mdp->smbmdm_size = (uint64_t)
+ (m.smbdmap_end - m.smbdmap_start + 1) * 1024;
+ mdp->smbmdm_rpos = m.smbdmap_rpos;
+ mdp->smbmdm_ipos = m.smbdmap_ipos;
+ mdp->smbmdm_idepth = m.smbdmap_idepth;
+
+ return (0);
+}
+
+id_t
+smbios_info_hwsec(smbios_hdl_t *shp, smbios_hwsec_t *hsp)
+{
+ const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_SECURITY);
+ smb_hwsec_t hs;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ smb_info_bcopy(stp->smbst_hdr, &hs, sizeof (hs));
+ bzero(hsp, sizeof (smbios_hwsec_t));
+
+ hsp->smbh_pwr_ps = SMB_HWS_PWR_PS(hs.smbhs_settings);
+ hsp->smbh_kbd_ps = SMB_HWS_KBD_PS(hs.smbhs_settings);
+ hsp->smbh_adm_ps = SMB_HWS_ADM_PS(hs.smbhs_settings);
+ hsp->smbh_pan_ps = SMB_HWS_PAN_PS(hs.smbhs_settings);
+
+ return (stp->smbst_hdr->smbh_hdl);
+}
+
+id_t
+smbios_info_boot(smbios_hdl_t *shp, smbios_boot_t *bp)
+{
+ const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_BOOT);
+ const smb_boot_t *b = (smb_boot_t *)(uintptr_t)stp->smbst_hdr;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ bzero(bp, sizeof (smbios_boot_t));
+
+ bp->smbt_status = b->smbbo_status[0];
+ bp->smbt_size = stp->smbst_hdr->smbh_len - sizeof (smb_boot_t);
+ bp->smbt_data = bp->smbt_size ? &b->smbbo_status[1] : NULL;
+
+ return (stp->smbst_hdr->smbh_hdl);
+}
+
+id_t
+smbios_info_ipmi(smbios_hdl_t *shp, smbios_ipmi_t *ip)
+{
+ const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_IPMIDEV);
+ smb_ipmi_t i;
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ smb_info_bcopy(stp->smbst_hdr, &i, sizeof (i));
+ bzero(ip, sizeof (smbios_ipmi_t));
+
+ ip->smbip_type = i.smbipm_type;
+ ip->smbip_vers.smbv_major = SMB_IPM_SPEC_MAJOR(i.smbipm_spec);
+ ip->smbip_vers.smbv_minor = SMB_IPM_SPEC_MINOR(i.smbipm_spec);
+ ip->smbip_i2c = i.smbipm_i2c;
+ ip->smbip_addr = i.smbipm_addr & ~SMB_IPM_ADDR_IO;
+ ip->smbip_intr = i.smbipm_intr;
+
+ if (i.smbipm_bus != (uint8_t)-1)
+ ip->smbip_bus = i.smbipm_bus;
+ else
+ ip->smbip_bus = -1u;
+
+ if (SMB_IPM_INFO_LSB(i.smbipm_info))
+ ip->smbip_addr |= 1; /* turn on least-significant bit of addr */
+
+ if (i.smbipm_addr & SMB_IPM_ADDR_IO) {
+ switch (SMB_IPM_INFO_REGS(i.smbipm_info)) {
+ case SMB_IPM_REGS_1B:
+ ip->smbip_regspacing = 1;
+ break;
+ case SMB_IPM_REGS_4B:
+ ip->smbip_regspacing = 4;
+ break;
+ case SMB_IPM_REGS_16B:
+ ip->smbip_regspacing = 16;
+ break;
+ default:
+ ip->smbip_regspacing = 1;
+ }
+ ip->smbip_flags |= SMB_IPMI_F_IOADDR;
+ }
+
+ if (SMB_IPM_INFO_ISPEC(i.smbipm_info))
+ ip->smbip_flags |= SMB_IPMI_F_INTRSPEC;
+
+ if (SMB_IPM_INFO_IPOL(i.smbipm_info) == SMB_IPM_IPOL_HI)
+ ip->smbip_flags |= SMB_IPMI_F_INTRHIGH;
+
+ if (SMB_IPM_INFO_IMODE(i.smbipm_info) == SMB_IPM_IMODE_EDGE)
+ ip->smbip_flags |= SMB_IPMI_F_INTREDGE;
+
+ return (stp->smbst_hdr->smbh_hdl);
+}
diff --git a/usr/src/common/smbios/smb_open.c b/usr/src/common/smbios/smb_open.c
new file mode 100644
index 0000000000..c7c3fb666d
--- /dev/null
+++ b/usr/src/common/smbios/smb_open.c
@@ -0,0 +1,370 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/smbios_impl.h>
+
+static const uint_t _smb_hashlen = 64; /* hash length (must be Pof2) */
+static const char _smb_emptystr[] = ""; /* empty string to return */
+int _smb_debug = 0; /* default debug mode */
+
+/*
+ * Strip out identification information for you privacy weenies. This is quite
+ * simple using our smbios_info_common() abstraction: we just locate any serial
+ * numbers and asset tags for each record, and then zero out those strings.
+ * Then we must handle two special cases: SMB_TYPE_SYSTEM holds a 16-byte UUID
+ * and SMB_TYPE_BATTERY stores a Smart Battery Data Spec 16-bit serial number.
+ * We use a literal '0' rather than '\0' for zeroing strings because \0\0 in
+ * the SMBIOS string table has a special meaning (denotes end-of-record).
+ */
+static void
+smb_strip(smbios_hdl_t *shp)
+{
+ uint_t i;
+
+ for (i = 0; i < shp->sh_nstructs; i++) {
+ const smb_header_t *hp = shp->sh_structs[i].smbst_hdr;
+ smbios_info_t info;
+ char *p;
+
+ if (hp->smbh_type == SMB_TYPE_SYSTEM &&
+ hp->smbh_len >= offsetof(smb_system_t, smbsi_wakeup)) {
+ smb_system_t *sp = (smb_system_t *)(uintptr_t)hp;
+ bzero(sp->smbsi_uuid, sizeof (sp->smbsi_uuid));
+ }
+
+ if (hp->smbh_type == SMB_TYPE_BATTERY &&
+ hp->smbh_len >= offsetof(smb_battery_t, smbbat_sdate)) {
+ smb_battery_t *bp = (smb_battery_t *)(uintptr_t)hp;
+ bp->smbbat_ssn = 0;
+ }
+
+ if (smbios_info_common(shp, hp->smbh_hdl, &info) != SMB_ERR) {
+ for (p = (char *)info.smbi_serial; *p != '\0'; p++)
+ *p = '0';
+ for (p = (char *)info.smbi_asset; *p != '\0'; p++)
+ *p = '0';
+ }
+ }
+}
+
+smbios_hdl_t *
+smbios_bufopen(const smbios_entry_t *ep, const void *buf, size_t len,
+ int version, int flags, int *errp)
+{
+ smbios_hdl_t *shp = smb_zalloc(sizeof (smbios_hdl_t));
+ const smb_header_t *hp, *nhp;
+ const uchar_t *p, *q, *s;
+ uint_t i, h;
+
+ switch (version) {
+ case SMB_VERSION_23:
+ case SMB_VERSION_24:
+ break;
+ default:
+ return (smb_open_error(shp, errp, ESMB_VERSION));
+ }
+
+ if (ep == NULL || buf == NULL || len == 0 || (flags & ~SMB_O_MASK))
+ return (smb_open_error(shp, errp, ESMB_INVAL));
+
+ if (shp == NULL)
+ return (smb_open_error(shp, errp, ESMB_NOMEM));
+
+ if (_smb_debug)
+ shp->sh_flags |= SMB_FL_DEBUG;
+
+ if (strncmp(ep->smbe_eanchor, SMB_ENTRY_EANCHOR, SMB_ENTRY_EANCHORLEN))
+ return (smb_open_error(shp, errp, ESMB_HEADER));
+
+ if (strncmp(ep->smbe_ianchor, SMB_ENTRY_IANCHOR, SMB_ENTRY_IANCHORLEN))
+ return (smb_open_error(shp, errp, ESMB_HEADER));
+
+ smb_dprintf(shp, "opening SMBIOS version %u.%u bcdrev 0x%x\n",
+ ep->smbe_major, ep->smbe_minor, ep->smbe_bcdrev);
+
+ if (!(flags & SMB_O_NOVERS)) {
+ if (ep->smbe_major > SMB_MAJOR(SMB_VERSION))
+ return (smb_open_error(shp, errp, ESMB_NEW));
+
+ if (ep->smbe_major < SMB_MAJOR(SMB_VERSION_23) || (
+ ep->smbe_major == SMB_MAJOR(SMB_VERSION_23) &&
+ ep->smbe_minor < SMB_MINOR(SMB_VERSION_23)))
+ return (smb_open_error(shp, errp, ESMB_OLD));
+ }
+
+ if (len < sizeof (smb_header_t) ||
+ ep->smbe_stlen < sizeof (smb_header_t) || len < ep->smbe_stlen)
+ return (smb_open_error(shp, errp, ESMB_SHORT));
+
+ if (!(flags & SMB_O_NOCKSUM)) {
+ uint8_t esum = 0, isum = 0;
+ q = (uchar_t *)ep;
+
+ for (p = q; p < q + ep->smbe_elen; p++)
+ esum += *p;
+
+ for (p = (uchar_t *)ep->smbe_ianchor; p < q + sizeof (*ep); p++)
+ isum += *p;
+
+ if (esum != 0 || isum != 0) {
+ smb_dprintf(shp, "bad cksum: e=%x i=%x\n", esum, isum);
+ return (smb_open_error(shp, errp, ESMB_CKSUM));
+ }
+ }
+
+ bcopy(ep, &shp->sh_ent, sizeof (smbios_entry_t));
+ shp->sh_buf = buf;
+ shp->sh_buflen = len;
+ shp->sh_structs = smb_alloc(sizeof (smb_struct_t) * ep->smbe_stnum);
+ shp->sh_nstructs = 0;
+ shp->sh_hashlen = _smb_hashlen;
+ shp->sh_hash = smb_zalloc(sizeof (smb_struct_t *) * shp->sh_hashlen);
+ shp->sh_libvers = version;
+ shp->sh_smbvers = SMB_MAJMIN(ep->smbe_major, ep->smbe_minor);
+
+ if (shp->sh_structs == NULL || shp->sh_hash == NULL)
+ return (smb_open_error(shp, errp, ESMB_NOMEM));
+
+ hp = shp->sh_buf;
+ q = (const uchar_t *)buf + MIN(ep->smbe_stlen, len);
+
+ for (i = 0; i < ep->smbe_stnum; i++, hp = nhp) {
+ smb_struct_t *stp = &shp->sh_structs[i];
+ uint_t n = 0;
+
+ if ((const uchar_t *)hp + sizeof (smb_header_t) > q)
+ return (smb_open_error(shp, errp, ESMB_CORRUPT));
+
+ smb_dprintf(shp, "struct [%u] type %u len %u hdl %u at %p\n",
+ i, hp->smbh_type, hp->smbh_len, hp->smbh_hdl, (void *)hp);
+
+ if ((const uchar_t *)hp + hp->smbh_len > q - 2)
+ return (smb_open_error(shp, errp, ESMB_CORRUPT));
+
+ if (hp->smbh_type == SMB_TYPE_EOT)
+ break; /* ignore any entries beyond end-of-table */
+
+ h = hp->smbh_hdl & (shp->sh_hashlen - 1);
+ p = s = (const uchar_t *)hp + hp->smbh_len;
+
+ while (p <= q - 2 && (p[0] != '\0' || p[1] != '\0')) {
+ if (*p++ == '\0')
+ n++; /* count strings until \0\0 delimiter */
+ }
+
+ if (p > q - 2)
+ return (smb_open_error(shp, errp, ESMB_CORRUPT));
+
+ if (p > s)
+ n++; /* add one for final string in string table */
+
+ stp->smbst_hdr = hp;
+ stp->smbst_str = s;
+ stp->smbst_end = p;
+ stp->smbst_next = shp->sh_hash[h];
+ stp->smbst_strtab = smb_alloc(sizeof (uint16_t) * n);
+ stp->smbst_strtablen = n;
+
+ if (n != 0 && stp->smbst_strtab == NULL)
+ return (smb_open_error(shp, errp, ESMB_NOMEM));
+
+ shp->sh_hash[h] = stp;
+ nhp = (void *)(p + 2);
+ shp->sh_nstructs++;
+
+ for (n = 0, p = s; n < stp->smbst_strtablen; p++) {
+ if (*p == '\0') {
+ stp->smbst_strtab[n++] =
+ (uint16_t)(s - stp->smbst_str);
+ s = p + 1;
+ }
+ }
+ }
+
+ if (flags & SMB_O_ZIDS)
+ smb_strip(shp);
+
+ return (shp);
+}
+
+void
+smbios_close(smbios_hdl_t *shp)
+{
+ const smbios_entry_t *ep = &shp->sh_ent;
+ uint_t i;
+
+ for (i = 0; i < shp->sh_nstructs; i++) {
+ smb_free(shp->sh_structs[i].smbst_strtab,
+ sizeof (uint16_t) * shp->sh_structs[i].smbst_strtablen);
+ }
+
+ smb_free(shp->sh_structs, sizeof (smb_struct_t) * ep->smbe_stnum);
+ smb_free(shp->sh_hash, sizeof (smb_struct_t *) * shp->sh_hashlen);
+
+ if (shp->sh_flags & SMB_FL_BUFALLOC)
+ smb_free((void *)shp->sh_buf, shp->sh_buflen);
+
+ smb_free(shp, sizeof (smbios_hdl_t));
+}
+
+/*
+ * Recompute the values of the entry point checksums based upon the content
+ * of the specified SMBIOS entry point. We don't need 'shp' but require it
+ * anyway in case future versioning requires variations in the algorithm.
+ */
+/*ARGSUSED*/
+void
+smbios_checksum(smbios_hdl_t *shp, smbios_entry_t *ep)
+{
+ uchar_t *p, *q = (uchar_t *)ep;
+ uint8_t esum = 0, isum = 0;
+
+ ep->smbe_ecksum = ep->smbe_icksum = 0;
+
+ for (p = (uchar_t *)ep->smbe_ianchor; p < q + sizeof (*ep); p++)
+ isum += *p;
+
+ ep->smbe_icksum = -isum;
+
+ for (p = q; p < q + ep->smbe_elen; p++)
+ esum += *p;
+
+ ep->smbe_ecksum = -esum;
+}
+
+const void *
+smbios_buf(smbios_hdl_t *shp)
+{
+ return (shp->sh_buf);
+}
+
+size_t
+smbios_buflen(smbios_hdl_t *shp)
+{
+ return (shp->sh_buflen);
+}
+
+static smbios_struct_t *
+smb_export(const smb_struct_t *stp, smbios_struct_t *sp)
+{
+ const smb_header_t *hdr = stp->smbst_hdr;
+
+ sp->smbstr_id = hdr->smbh_hdl;
+ sp->smbstr_type = hdr->smbh_type;
+ sp->smbstr_data = hdr;
+ sp->smbstr_size = (size_t)(stp->smbst_end - (uchar_t *)hdr);
+
+ return (sp);
+}
+
+int
+smbios_lookup_id(smbios_hdl_t *shp, id_t id, smbios_struct_t *sp)
+{
+ const smb_struct_t *stp = smb_lookup_id(shp, id);
+
+ if (stp == NULL)
+ return (-1); /* errno is set for us */
+
+ if (sp != NULL)
+ (void) smb_export(stp, sp);
+
+ return (0);
+}
+
+int
+smbios_iter(smbios_hdl_t *shp, smbios_struct_f *func, void *data)
+{
+ const smb_struct_t *sp = shp->sh_structs;
+ smbios_struct_t s;
+ int i, rv = 0;
+
+ for (i = 0; i < shp->sh_nstructs; i++, sp++) {
+ if (sp->smbst_hdr->smbh_type != SMB_TYPE_INACTIVE &&
+ (rv = func(shp, smb_export(sp, &s), data)) != 0)
+ break;
+ }
+
+ return (rv);
+}
+
+const smb_struct_t *
+smb_lookup_type(smbios_hdl_t *shp, uint_t type)
+{
+ uint_t i;
+
+ for (i = 0; i < shp->sh_nstructs; i++) {
+ if (shp->sh_structs[i].smbst_hdr->smbh_type == type)
+ return (&shp->sh_structs[i]);
+ }
+
+ (void) smb_set_errno(shp, ESMB_NOENT);
+ return (NULL);
+}
+
+const smb_struct_t *
+smb_lookup_id(smbios_hdl_t *shp, uint_t id)
+{
+ const smb_struct_t *stp = shp->sh_hash[id & (shp->sh_hashlen - 1)];
+
+ switch (id) {
+ case SMB_ID_NOTSUP:
+ (void) smb_set_errno(shp, ESMB_NOTSUP);
+ return (NULL);
+ case SMB_ID_NONE:
+ (void) smb_set_errno(shp, ESMB_NOENT);
+ return (NULL);
+ }
+
+ for (; stp != NULL; stp = stp->smbst_next) {
+ if (stp->smbst_hdr->smbh_hdl == id)
+ break;
+ }
+
+ if (stp == NULL)
+ (void) smb_set_errno(shp, ESMB_NOENT);
+
+ return (stp);
+}
+
+const char *
+smb_strptr(const smb_struct_t *stp, uint_t i)
+{
+ if (i == 0 || i > stp->smbst_strtablen)
+ return (_smb_emptystr);
+ else
+ return ((char *)stp->smbst_str + stp->smbst_strtab[i - 1]);
+}
+
+int
+smb_gteq(smbios_hdl_t *shp, int version)
+{
+ return (SMB_MAJOR(shp->sh_smbvers) > SMB_MAJOR(version) || (
+ SMB_MAJOR(shp->sh_smbvers) == SMB_MAJOR(version) &&
+ SMB_MINOR(shp->sh_smbvers) >= SMB_MINOR(version)));
+}