xref: /illumos-gate/usr/src/uts/i86pc/os/smb_dev.c (revision 96e7037f)
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.
2684ab085aSmws  */
2784ab085aSmws 
2884ab085aSmws /*
2984ab085aSmws  * Platform-Specific SMBIOS Subroutines
3084ab085aSmws  *
3184ab085aSmws  * The routines in this file form part of <sys/smbios_impl.h> and combine with
3284ab085aSmws  * the usr/src/common/smbios code to form an in-kernel SMBIOS decoding service.
3384ab085aSmws  * The SMBIOS entry point is locating by scanning a range of physical memory
3484ab085aSmws  * assigned to BIOS as described in Section 2 of the DMTF SMBIOS specification.
3584ab085aSmws  */
3684ab085aSmws 
3784ab085aSmws #include <sys/smbios_impl.h>
3884ab085aSmws #include <sys/sysmacros.h>
3984ab085aSmws #include <sys/errno.h>
4084ab085aSmws #include <sys/psm.h>
4184ab085aSmws #include <sys/smp_impldefs.h>
4284ab085aSmws 
4384ab085aSmws smbios_hdl_t *ksmbios;
4484ab085aSmws int ksmbios_flags;
4584ab085aSmws 
4684ab085aSmws smbios_hdl_t *
4784ab085aSmws smb_open_error(smbios_hdl_t *shp, int *errp, int err)
4884ab085aSmws {
4984ab085aSmws 	if (shp != NULL)
5084ab085aSmws 		smbios_close(shp);
5184ab085aSmws 
5284ab085aSmws 	if (errp != NULL)
5384ab085aSmws 		*errp = err;
5484ab085aSmws 
5584ab085aSmws 	if (ksmbios == NULL)
5684ab085aSmws 		cmn_err(CE_CONT, "?SMBIOS not loaded (%s)", smbios_errmsg(err));
5784ab085aSmws 
5884ab085aSmws 	return (NULL);
5984ab085aSmws }
6084ab085aSmws 
6184ab085aSmws smbios_hdl_t *
6284ab085aSmws smbios_open(const char *file, int version, int flags, int *errp)
6384ab085aSmws {
6484ab085aSmws 	smbios_hdl_t *shp = NULL;
65e4586ebfSmws 	smbios_entry_t *ep;
6684ab085aSmws 	caddr_t stbuf, bios, p, q;
67*96e7037fSToomas Soome 	uint64_t startaddr, startoff = 0;
6884ab085aSmws 	size_t bioslen;
6984ab085aSmws 	int err;
7084ab085aSmws 
7184ab085aSmws 	if (file != NULL || (flags & ~SMB_O_MASK))
7284ab085aSmws 		return (smb_open_error(shp, errp, ESMB_INVAL));
7384ab085aSmws 
74*96e7037fSToomas Soome 	if ((startaddr = ddi_prop_get_int64(DDI_DEV_T_ANY, ddi_root_node(),
75*96e7037fSToomas Soome 	    DDI_PROP_DONTPASS, "smbios-address", 0)) == 0) {
76*96e7037fSToomas Soome 		startaddr = SMB_RANGE_START;
7784ab085aSmws 		bioslen = SMB_RANGE_LIMIT - SMB_RANGE_START + 1;
78*96e7037fSToomas Soome 	} else {
79*96e7037fSToomas Soome 		/* We have smbios address from boot loader, map one page. */
80*96e7037fSToomas Soome 		bioslen = MMU_PAGESIZE;
81*96e7037fSToomas Soome 		startoff = startaddr & MMU_PAGEOFFSET;
82*96e7037fSToomas Soome 		startaddr &= MMU_PAGEMASK;
83*96e7037fSToomas Soome #if defined(__i386)
84*96e7037fSToomas Soome 		/* If the address is not good, use memory scan instead. */
85*96e7037fSToomas Soome 		if (startaddr > UINT32_MAX) {
86*96e7037fSToomas Soome 			startaddr = SMB_RANGE_START;
87*96e7037fSToomas Soome 			bioslen = SMB_RANGE_LIMIT - SMB_RANGE_START + 1;
88*96e7037fSToomas Soome 			startoff = 0;
89*96e7037fSToomas Soome 		}
90*96e7037fSToomas Soome #endif
91*96e7037fSToomas Soome 	}
92*96e7037fSToomas Soome 
93*96e7037fSToomas Soome 	bios = psm_map_phys(startaddr, bioslen, PSM_PROT_READ);
9484ab085aSmws 
9584ab085aSmws 	if (bios == NULL)
9684ab085aSmws 		return (smb_open_error(shp, errp, ESMB_MAPDEV));
9784ab085aSmws 
98*96e7037fSToomas Soome 	/*
99*96e7037fSToomas Soome 	 * In case we did map one page, make sure we will not cross
100*96e7037fSToomas Soome 	 * the end of the page.
101*96e7037fSToomas Soome 	 */
102*96e7037fSToomas Soome 	p = bios + startoff;
103*96e7037fSToomas Soome 	q = bios + bioslen - startoff;
104*96e7037fSToomas Soome 	while (p < q) {
10584ab085aSmws 		if (strncmp(p, SMB_ENTRY_EANCHOR, SMB_ENTRY_EANCHORLEN) == 0)
10684ab085aSmws 			break;
107*96e7037fSToomas Soome 		p += SMB_SCAN_STEP;
10884ab085aSmws 	}
10984ab085aSmws 
11084ab085aSmws 	if (p >= q) {
11184ab085aSmws 		psm_unmap_phys(bios, bioslen);
11284ab085aSmws 		return (smb_open_error(shp, errp, ESMB_NOTFOUND));
11384ab085aSmws 	}
11484ab085aSmws 
115e4586ebfSmws 	ep = smb_alloc(SMB_ENTRY_MAXLEN);
116e4586ebfSmws 	bcopy(p, ep, sizeof (smbios_entry_t));
117e4586ebfSmws 	ep->smbe_elen = MIN(ep->smbe_elen, SMB_ENTRY_MAXLEN);
118e4586ebfSmws 	bcopy(p, ep, ep->smbe_elen);
119e4586ebfSmws 
12084ab085aSmws 	psm_unmap_phys(bios, bioslen);
121e4586ebfSmws 	bios = psm_map_phys(ep->smbe_staddr, ep->smbe_stlen, PSM_PROT_READ);
12284ab085aSmws 
123e4586ebfSmws 	if (bios == NULL) {
124e4586ebfSmws 		smb_free(ep, SMB_ENTRY_MAXLEN);
12584ab085aSmws 		return (smb_open_error(shp, errp, ESMB_MAPDEV));
126e4586ebfSmws 	}
12784ab085aSmws 
128e4586ebfSmws 	stbuf = smb_alloc(ep->smbe_stlen);
129e4586ebfSmws 	bcopy(bios, stbuf, ep->smbe_stlen);
130e4586ebfSmws 	psm_unmap_phys(bios, ep->smbe_stlen);
131e4586ebfSmws 	shp = smbios_bufopen(ep, stbuf, ep->smbe_stlen, version, flags, &err);
13284ab085aSmws 
13384ab085aSmws 	if (shp == NULL) {
134e4586ebfSmws 		smb_free(stbuf, ep->smbe_stlen);
135e4586ebfSmws 		smb_free(ep, SMB_ENTRY_MAXLEN);
13684ab085aSmws 		return (smb_open_error(shp, errp, err));
13784ab085aSmws 	}
13884ab085aSmws 
13984ab085aSmws 	if (ksmbios == NULL) {
14084ab085aSmws 		cmn_err(CE_CONT, "?SMBIOS v%u.%u loaded (%u bytes)",
141e4586ebfSmws 		    ep->smbe_major, ep->smbe_minor, ep->smbe_stlen);
142516627f3SJonathan Matthew 		if (shp->sh_flags & SMB_FL_TRUNC)
143516627f3SJonathan Matthew 			cmn_err(CE_CONT, "?SMBIOS table is truncated");
14484ab085aSmws 	}
14584ab085aSmws 
14684ab085aSmws 	shp->sh_flags |= SMB_FL_BUFALLOC;
147e4586ebfSmws 	smb_free(ep, SMB_ENTRY_MAXLEN);
148e4586ebfSmws 
14984ab085aSmws 	return (shp);
15084ab085aSmws }
15184ab085aSmws 
15284ab085aSmws /*ARGSUSED*/
15384ab085aSmws smbios_hdl_t *
15484ab085aSmws smbios_fdopen(int fd, int version, int flags, int *errp)
15584ab085aSmws {
15684ab085aSmws 	return (smb_open_error(NULL, errp, ENOTSUP));
15784ab085aSmws }
15884ab085aSmws 
15984ab085aSmws /*ARGSUSED*/
16084ab085aSmws int
16184ab085aSmws smbios_write(smbios_hdl_t *shp, int fd)
16284ab085aSmws {
16384ab085aSmws 	return (smb_set_errno(shp, ENOTSUP));
16484ab085aSmws }
165