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; 6796e7037fSToomas Soome uint64_t startaddr, startoff = 0; 6884ab085aSmws size_t bioslen; 69*1951a933SToomas Soome uint_t smbe_stlen; 70*1951a933SToomas Soome smbios_entry_point_t ep_type = SMBIOS_ENTRY_POINT_21; 71*1951a933SToomas Soome uint8_t smbe_major, smbe_minor; 7284ab085aSmws int err; 7384ab085aSmws 7484ab085aSmws if (file != NULL || (flags & ~SMB_O_MASK)) 7584ab085aSmws return (smb_open_error(shp, errp, ESMB_INVAL)); 7684ab085aSmws 7796e7037fSToomas Soome if ((startaddr = ddi_prop_get_int64(DDI_DEV_T_ANY, ddi_root_node(), 7896e7037fSToomas Soome DDI_PROP_DONTPASS, "smbios-address", 0)) == 0) { 7996e7037fSToomas Soome startaddr = SMB_RANGE_START; 8084ab085aSmws bioslen = SMB_RANGE_LIMIT - SMB_RANGE_START + 1; 8196e7037fSToomas Soome } else { 8296e7037fSToomas Soome /* We have smbios address from boot loader, map one page. */ 8396e7037fSToomas Soome bioslen = MMU_PAGESIZE; 8496e7037fSToomas Soome startoff = startaddr & MMU_PAGEOFFSET; 8596e7037fSToomas Soome startaddr &= MMU_PAGEMASK; 8696e7037fSToomas Soome #if defined(__i386) 8796e7037fSToomas Soome /* If the address is not good, use memory scan instead. */ 8896e7037fSToomas Soome if (startaddr > UINT32_MAX) { 8996e7037fSToomas Soome startaddr = SMB_RANGE_START; 9096e7037fSToomas Soome bioslen = SMB_RANGE_LIMIT - SMB_RANGE_START + 1; 9196e7037fSToomas Soome startoff = 0; 9296e7037fSToomas Soome } 9396e7037fSToomas Soome #endif 9496e7037fSToomas Soome } 9596e7037fSToomas Soome 9696e7037fSToomas Soome bios = psm_map_phys(startaddr, bioslen, PSM_PROT_READ); 9784ab085aSmws 9884ab085aSmws if (bios == NULL) 9984ab085aSmws return (smb_open_error(shp, errp, ESMB_MAPDEV)); 10084ab085aSmws 10196e7037fSToomas Soome /* 10296e7037fSToomas Soome * In case we did map one page, make sure we will not cross 10396e7037fSToomas Soome * the end of the page. 10496e7037fSToomas Soome */ 10596e7037fSToomas Soome p = bios + startoff; 10696e7037fSToomas Soome q = bios + bioslen - startoff; 10796e7037fSToomas Soome while (p < q) { 108*1951a933SToomas Soome #if !defined(__i386) 109*1951a933SToomas Soome err = strncmp(p, SMB3_ENTRY_EANCHOR, SMB3_ENTRY_EANCHORLEN); 110*1951a933SToomas Soome if (err == 0) { 111*1951a933SToomas Soome ep_type = SMBIOS_ENTRY_POINT_30; 112*1951a933SToomas Soome break; 113*1951a933SToomas Soome } 114*1951a933SToomas Soome #endif 11584ab085aSmws if (strncmp(p, SMB_ENTRY_EANCHOR, SMB_ENTRY_EANCHORLEN) == 0) 11684ab085aSmws break; 11796e7037fSToomas Soome p += SMB_SCAN_STEP; 11884ab085aSmws } 11984ab085aSmws 12084ab085aSmws if (p >= q) { 12184ab085aSmws psm_unmap_phys(bios, bioslen); 12284ab085aSmws return (smb_open_error(shp, errp, ESMB_NOTFOUND)); 12384ab085aSmws } 12484ab085aSmws 125e4586ebfSmws ep = smb_alloc(SMB_ENTRY_MAXLEN); 126e4586ebfSmws bcopy(p, ep, sizeof (smbios_entry_t)); 127*1951a933SToomas Soome if (ep_type == SMBIOS_ENTRY_POINT_21) { 128*1951a933SToomas Soome ep->ep21.smbe_elen = MIN(ep->ep21.smbe_elen, SMB_ENTRY_MAXLEN); 129*1951a933SToomas Soome bcopy(p, ep, ep->ep21.smbe_elen); 130*1951a933SToomas Soome } else if (ep_type == SMBIOS_ENTRY_POINT_30) { 131*1951a933SToomas Soome ep->ep30.smbe_elen = MIN(ep->ep30.smbe_elen, SMB_ENTRY_MAXLEN); 132*1951a933SToomas Soome bcopy(p, ep, ep->ep30.smbe_elen); 133*1951a933SToomas Soome } 134e4586ebfSmws 13584ab085aSmws psm_unmap_phys(bios, bioslen); 136*1951a933SToomas Soome switch (ep_type) { 137*1951a933SToomas Soome case SMBIOS_ENTRY_POINT_21: 138*1951a933SToomas Soome smbe_major = ep->ep21.smbe_major; 139*1951a933SToomas Soome smbe_minor = ep->ep21.smbe_minor; 140*1951a933SToomas Soome smbe_stlen = ep->ep21.smbe_stlen; 141*1951a933SToomas Soome bios = psm_map_phys(ep->ep21.smbe_staddr, smbe_stlen, 142*1951a933SToomas Soome PSM_PROT_READ); 143*1951a933SToomas Soome break; 144*1951a933SToomas Soome case SMBIOS_ENTRY_POINT_30: 145*1951a933SToomas Soome smbe_major = ep->ep30.smbe_major; 146*1951a933SToomas Soome smbe_minor = ep->ep30.smbe_minor; 147*1951a933SToomas Soome smbe_stlen = ep->ep30.smbe_stlen; 148*1951a933SToomas Soome bios = psm_map_phys_new(ep->ep30.smbe_staddr, smbe_stlen, 149*1951a933SToomas Soome PSM_PROT_READ); 150*1951a933SToomas Soome break; 151*1951a933SToomas Soome default: 152*1951a933SToomas Soome smb_free(ep, SMB_ENTRY_MAXLEN); 153*1951a933SToomas Soome return (smb_open_error(shp, errp, ESMB_VERSION)); 154*1951a933SToomas Soome } 15584ab085aSmws 156e4586ebfSmws if (bios == NULL) { 157e4586ebfSmws smb_free(ep, SMB_ENTRY_MAXLEN); 15884ab085aSmws return (smb_open_error(shp, errp, ESMB_MAPDEV)); 159e4586ebfSmws } 16084ab085aSmws 161*1951a933SToomas Soome stbuf = smb_alloc(smbe_stlen); 162*1951a933SToomas Soome bcopy(bios, stbuf, smbe_stlen); 163*1951a933SToomas Soome psm_unmap_phys(bios, smbe_stlen); 164*1951a933SToomas Soome shp = smbios_bufopen(ep, stbuf, smbe_stlen, version, flags, &err); 16584ab085aSmws 16684ab085aSmws if (shp == NULL) { 167*1951a933SToomas Soome smb_free(stbuf, smbe_stlen); 168e4586ebfSmws smb_free(ep, SMB_ENTRY_MAXLEN); 16984ab085aSmws return (smb_open_error(shp, errp, err)); 17084ab085aSmws } 17184ab085aSmws 17284ab085aSmws if (ksmbios == NULL) { 17384ab085aSmws cmn_err(CE_CONT, "?SMBIOS v%u.%u loaded (%u bytes)", 174*1951a933SToomas Soome smbe_major, smbe_minor, smbe_stlen); 175516627f3SJonathan Matthew if (shp->sh_flags & SMB_FL_TRUNC) 176516627f3SJonathan Matthew cmn_err(CE_CONT, "?SMBIOS table is truncated"); 17784ab085aSmws } 17884ab085aSmws 17984ab085aSmws shp->sh_flags |= SMB_FL_BUFALLOC; 180e4586ebfSmws smb_free(ep, SMB_ENTRY_MAXLEN); 181e4586ebfSmws 18284ab085aSmws return (shp); 18384ab085aSmws } 18484ab085aSmws 18584ab085aSmws /*ARGSUSED*/ 18684ab085aSmws smbios_hdl_t * 18784ab085aSmws smbios_fdopen(int fd, int version, int flags, int *errp) 18884ab085aSmws { 18984ab085aSmws return (smb_open_error(NULL, errp, ENOTSUP)); 19084ab085aSmws } 19184ab085aSmws 19284ab085aSmws /*ARGSUSED*/ 19384ab085aSmws int 19484ab085aSmws smbios_write(smbios_hdl_t *shp, int fd) 19584ab085aSmws { 19684ab085aSmws return (smb_set_errno(shp, ENOTSUP)); 19784ab085aSmws } 198