184ab085aSmws /*
284ab085aSmws * CDDL HEADER START
384ab085aSmws *
484ab085aSmws * The contents of this file are subject to the terms of the
584ab085aSmws * Common Development and Distribution License, Version 1.0 only
684ab085aSmws * (the "License"). You may not use this file except in compliance
784ab085aSmws * with the License.
884ab085aSmws *
984ab085aSmws * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1084ab085aSmws * or http://www.opensolaris.org/os/licensing.
1184ab085aSmws * See the License for the specific language governing permissions
1284ab085aSmws * and limitations under the License.
1384ab085aSmws *
1484ab085aSmws * When distributing Covered Code, include this CDDL HEADER in each
1584ab085aSmws * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1684ab085aSmws * If applicable, add the following below this CDDL HEADER, with the
1784ab085aSmws * fields enclosed by brackets "[]" replaced with your own identifying
1884ab085aSmws * information: Portions Copyright [yyyy] [name of copyright owner]
1984ab085aSmws *
2084ab085aSmws * CDDL HEADER END
2184ab085aSmws */
2284ab085aSmws
2384ab085aSmws /*
24e4586ebfSmws * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
2584ab085aSmws * Use is subject to license terms.
26*a60349c8SRobert Mustacchi * Copyright (c) 2018, Joyent, Inc.
2784ab085aSmws */
2884ab085aSmws
2984ab085aSmws /*
3084ab085aSmws * Platform-Specific SMBIOS Subroutines
3184ab085aSmws *
3284ab085aSmws * The routines in this file form part of <sys/smbios_impl.h> and combine with
3384ab085aSmws * the usr/src/common/smbios code to form an in-kernel SMBIOS decoding service.
3484ab085aSmws * The SMBIOS entry point is locating by scanning a range of physical memory
3584ab085aSmws * assigned to BIOS as described in Section 2 of the DMTF SMBIOS specification.
3684ab085aSmws */
3784ab085aSmws
3884ab085aSmws #include <sys/smbios_impl.h>
3984ab085aSmws #include <sys/sysmacros.h>
4084ab085aSmws #include <sys/errno.h>
4184ab085aSmws #include <sys/psm.h>
4284ab085aSmws #include <sys/smp_impldefs.h>
4384ab085aSmws
4484ab085aSmws smbios_hdl_t *ksmbios;
4584ab085aSmws int ksmbios_flags;
4684ab085aSmws
4784ab085aSmws smbios_hdl_t *
smb_open_error(smbios_hdl_t * shp,int * errp,int err)4884ab085aSmws smb_open_error(smbios_hdl_t *shp, int *errp, int err)
4984ab085aSmws {
5084ab085aSmws if (shp != NULL)
5184ab085aSmws smbios_close(shp);
5284ab085aSmws
5384ab085aSmws if (errp != NULL)
5484ab085aSmws *errp = err;
5584ab085aSmws
5684ab085aSmws if (ksmbios == NULL)
5784ab085aSmws cmn_err(CE_CONT, "?SMBIOS not loaded (%s)", smbios_errmsg(err));
5884ab085aSmws
5984ab085aSmws return (NULL);
6084ab085aSmws }
6184ab085aSmws
6284ab085aSmws smbios_hdl_t *
smbios_open(const char * file,int version,int flags,int * errp)6384ab085aSmws smbios_open(const char *file, int version, int flags, int *errp)
6484ab085aSmws {
6584ab085aSmws smbios_hdl_t *shp = NULL;
66e4586ebfSmws smbios_entry_t *ep;
6784ab085aSmws caddr_t stbuf, bios, p, q;
68*a60349c8SRobert Mustacchi caddr_t smb2, smb3;
69a009cb8cSToomas Soome uint64_t startaddr, startoff = 0;
7084ab085aSmws size_t bioslen;
71af349cd6SToomas Soome uint_t smbe_stlen;
72*a60349c8SRobert Mustacchi smbios_entry_point_t ep_type;
73af349cd6SToomas Soome uint8_t smbe_major, smbe_minor;
7484ab085aSmws int err;
7584ab085aSmws
7684ab085aSmws if (file != NULL || (flags & ~SMB_O_MASK))
7784ab085aSmws return (smb_open_error(shp, errp, ESMB_INVAL));
7884ab085aSmws
79a009cb8cSToomas Soome if ((startaddr = ddi_prop_get_int64(DDI_DEV_T_ANY, ddi_root_node(),
80a009cb8cSToomas Soome DDI_PROP_DONTPASS, "smbios-address", 0)) == 0) {
81a009cb8cSToomas Soome startaddr = SMB_RANGE_START;
8284ab085aSmws bioslen = SMB_RANGE_LIMIT - SMB_RANGE_START + 1;
83a009cb8cSToomas Soome } else {
84a009cb8cSToomas Soome /* We have smbios address from boot loader, map one page. */
85a009cb8cSToomas Soome bioslen = MMU_PAGESIZE;
86a009cb8cSToomas Soome startoff = startaddr & MMU_PAGEOFFSET;
87a009cb8cSToomas Soome startaddr &= MMU_PAGEMASK;
88a009cb8cSToomas Soome }
89a009cb8cSToomas Soome
90a009cb8cSToomas Soome bios = psm_map_phys(startaddr, bioslen, PSM_PROT_READ);
9184ab085aSmws
9284ab085aSmws if (bios == NULL)
9384ab085aSmws return (smb_open_error(shp, errp, ESMB_MAPDEV));
9484ab085aSmws
95a009cb8cSToomas Soome /*
96a009cb8cSToomas Soome * In case we did map one page, make sure we will not cross
97a009cb8cSToomas Soome * the end of the page.
98a009cb8cSToomas Soome */
99a009cb8cSToomas Soome p = bios + startoff;
100a009cb8cSToomas Soome q = bios + bioslen - startoff;
101*a60349c8SRobert Mustacchi smb2 = smb3 = NULL;
102a009cb8cSToomas Soome while (p < q) {
103*a60349c8SRobert Mustacchi if (smb2 != NULL && smb3 != NULL)
104af349cd6SToomas Soome break;
105*a60349c8SRobert Mustacchi
106*a60349c8SRobert Mustacchi if (smb3 == NULL && strncmp(p, SMB3_ENTRY_EANCHOR,
107*a60349c8SRobert Mustacchi SMB3_ENTRY_EANCHORLEN) == 0) {
108*a60349c8SRobert Mustacchi smb3 = p;
109*a60349c8SRobert Mustacchi } else if (smb2 == NULL && strncmp(p, SMB_ENTRY_EANCHOR,
110*a60349c8SRobert Mustacchi SMB_ENTRY_EANCHORLEN) == 0) {
111*a60349c8SRobert Mustacchi smb2 = p;
112af349cd6SToomas Soome }
11368365d72SToomas Soome
114a009cb8cSToomas Soome p += SMB_SCAN_STEP;
11584ab085aSmws }
11684ab085aSmws
117*a60349c8SRobert Mustacchi if (smb2 == NULL && smb3 == NULL) {
11884ab085aSmws psm_unmap_phys(bios, bioslen);
11984ab085aSmws return (smb_open_error(shp, errp, ESMB_NOTFOUND));
12084ab085aSmws }
12184ab085aSmws
122*a60349c8SRobert Mustacchi /*
123*a60349c8SRobert Mustacchi * While they're not supposed to (as per the SMBIOS 3.2 spec), some
124*a60349c8SRobert Mustacchi * vendors end up having a newer version in one of the two entry points
125*a60349c8SRobert Mustacchi * than the other. If we found multiple tables then we will prefer the
126*a60349c8SRobert Mustacchi * one with the newer version. If they're equivalent, we prefer the
127*a60349c8SRobert Mustacchi * 32-bit version. If only one is present, then we use that.
128*a60349c8SRobert Mustacchi */
129e4586ebfSmws ep = smb_alloc(SMB_ENTRY_MAXLEN);
130*a60349c8SRobert Mustacchi if (smb2 != NULL && smb3 != NULL) {
131*a60349c8SRobert Mustacchi uint8_t smb2maj, smb2min, smb3maj, smb3min;
132*a60349c8SRobert Mustacchi
133*a60349c8SRobert Mustacchi bcopy(smb2, ep, sizeof (smbios_entry_t));
134*a60349c8SRobert Mustacchi smb2maj = ep->ep21.smbe_major;
135*a60349c8SRobert Mustacchi smb2min = ep->ep21.smbe_minor;
136*a60349c8SRobert Mustacchi bcopy(smb3, ep, sizeof (smbios_entry_t));
137*a60349c8SRobert Mustacchi smb3maj = ep->ep30.smbe_major;
138*a60349c8SRobert Mustacchi smb3min = ep->ep30.smbe_minor;
139*a60349c8SRobert Mustacchi
140*a60349c8SRobert Mustacchi if (smb3maj > smb2maj ||
141*a60349c8SRobert Mustacchi (smb3maj == smb2maj && smb3min > smb2min)) {
142*a60349c8SRobert Mustacchi ep_type = SMBIOS_ENTRY_POINT_30;
143*a60349c8SRobert Mustacchi p = smb3;
144*a60349c8SRobert Mustacchi } else {
145*a60349c8SRobert Mustacchi ep_type = SMBIOS_ENTRY_POINT_21;
146*a60349c8SRobert Mustacchi p = smb2;
147*a60349c8SRobert Mustacchi }
148*a60349c8SRobert Mustacchi } else if (smb3 != NULL) {
149*a60349c8SRobert Mustacchi ep_type = SMBIOS_ENTRY_POINT_30;
150*a60349c8SRobert Mustacchi p = smb3;
151*a60349c8SRobert Mustacchi } else if (smb2 != NULL) {
152*a60349c8SRobert Mustacchi ep_type = SMBIOS_ENTRY_POINT_21;
153*a60349c8SRobert Mustacchi p = smb2;
154*a60349c8SRobert Mustacchi }
155e4586ebfSmws bcopy(p, ep, sizeof (smbios_entry_t));
156af349cd6SToomas Soome if (ep_type == SMBIOS_ENTRY_POINT_21) {
157af349cd6SToomas Soome ep->ep21.smbe_elen = MIN(ep->ep21.smbe_elen, SMB_ENTRY_MAXLEN);
158af349cd6SToomas Soome bcopy(p, ep, ep->ep21.smbe_elen);
159af349cd6SToomas Soome } else if (ep_type == SMBIOS_ENTRY_POINT_30) {
160af349cd6SToomas Soome ep->ep30.smbe_elen = MIN(ep->ep30.smbe_elen, SMB_ENTRY_MAXLEN);
161af349cd6SToomas Soome bcopy(p, ep, ep->ep30.smbe_elen);
162af349cd6SToomas Soome }
163e4586ebfSmws
16484ab085aSmws psm_unmap_phys(bios, bioslen);
165af349cd6SToomas Soome switch (ep_type) {
166af349cd6SToomas Soome case SMBIOS_ENTRY_POINT_21:
167af349cd6SToomas Soome smbe_major = ep->ep21.smbe_major;
168af349cd6SToomas Soome smbe_minor = ep->ep21.smbe_minor;
169af349cd6SToomas Soome smbe_stlen = ep->ep21.smbe_stlen;
170af349cd6SToomas Soome bios = psm_map_phys(ep->ep21.smbe_staddr, smbe_stlen,
171af349cd6SToomas Soome PSM_PROT_READ);
172af349cd6SToomas Soome break;
173af349cd6SToomas Soome case SMBIOS_ENTRY_POINT_30:
174af349cd6SToomas Soome smbe_major = ep->ep30.smbe_major;
175af349cd6SToomas Soome smbe_minor = ep->ep30.smbe_minor;
176af349cd6SToomas Soome smbe_stlen = ep->ep30.smbe_stlen;
177af349cd6SToomas Soome bios = psm_map_phys_new(ep->ep30.smbe_staddr, smbe_stlen,
178af349cd6SToomas Soome PSM_PROT_READ);
179af349cd6SToomas Soome break;
180af349cd6SToomas Soome default:
181af349cd6SToomas Soome smb_free(ep, SMB_ENTRY_MAXLEN);
182af349cd6SToomas Soome return (smb_open_error(shp, errp, ESMB_VERSION));
183af349cd6SToomas Soome }
18484ab085aSmws
185e4586ebfSmws if (bios == NULL) {
186e4586ebfSmws smb_free(ep, SMB_ENTRY_MAXLEN);
18784ab085aSmws return (smb_open_error(shp, errp, ESMB_MAPDEV));
188e4586ebfSmws }
18984ab085aSmws
190af349cd6SToomas Soome stbuf = smb_alloc(smbe_stlen);
191af349cd6SToomas Soome bcopy(bios, stbuf, smbe_stlen);
192af349cd6SToomas Soome psm_unmap_phys(bios, smbe_stlen);
193af349cd6SToomas Soome shp = smbios_bufopen(ep, stbuf, smbe_stlen, version, flags, &err);
19484ab085aSmws
19584ab085aSmws if (shp == NULL) {
196af349cd6SToomas Soome smb_free(stbuf, smbe_stlen);
197e4586ebfSmws smb_free(ep, SMB_ENTRY_MAXLEN);
19884ab085aSmws return (smb_open_error(shp, errp, err));
19984ab085aSmws }
20084ab085aSmws
20184ab085aSmws if (ksmbios == NULL) {
20284ab085aSmws cmn_err(CE_CONT, "?SMBIOS v%u.%u loaded (%u bytes)",
203af349cd6SToomas Soome smbe_major, smbe_minor, smbe_stlen);
204dabec466SJonathan Matthew if (shp->sh_flags & SMB_FL_TRUNC)
205dabec466SJonathan Matthew cmn_err(CE_CONT, "?SMBIOS table is truncated");
20684ab085aSmws }
20784ab085aSmws
20884ab085aSmws shp->sh_flags |= SMB_FL_BUFALLOC;
209e4586ebfSmws smb_free(ep, SMB_ENTRY_MAXLEN);
210e4586ebfSmws
21184ab085aSmws return (shp);
21284ab085aSmws }
21384ab085aSmws
21484ab085aSmws /*ARGSUSED*/
21584ab085aSmws smbios_hdl_t *
smbios_fdopen(int fd,int version,int flags,int * errp)21684ab085aSmws smbios_fdopen(int fd, int version, int flags, int *errp)
21784ab085aSmws {
21884ab085aSmws return (smb_open_error(NULL, errp, ENOTSUP));
21984ab085aSmws }
22084ab085aSmws
22184ab085aSmws /*ARGSUSED*/
22284ab085aSmws int
smbios_write(smbios_hdl_t * shp,int fd)22384ab085aSmws smbios_write(smbios_hdl_t *shp, int fd)
22484ab085aSmws {
22584ab085aSmws return (smb_set_errno(shp, ENOTSUP));
22684ab085aSmws }
227