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*174bc649SRobert 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 * 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 * 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*174bc649SRobert Mustacchi caddr_t smb2, smb3; 69b10a562eSToomas Soome uint64_t startaddr, startoff = 0; 7084ab085aSmws size_t bioslen; 71c325726fSToomas Soome uint_t smbe_stlen; 72*174bc649SRobert Mustacchi smbios_entry_point_t ep_type; 73c325726fSToomas 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 79b10a562eSToomas Soome if ((startaddr = ddi_prop_get_int64(DDI_DEV_T_ANY, ddi_root_node(), 80b10a562eSToomas Soome DDI_PROP_DONTPASS, "smbios-address", 0)) == 0) { 81b10a562eSToomas Soome startaddr = SMB_RANGE_START; 8284ab085aSmws bioslen = SMB_RANGE_LIMIT - SMB_RANGE_START + 1; 83b10a562eSToomas Soome } else { 84b10a562eSToomas Soome /* We have smbios address from boot loader, map one page. */ 85b10a562eSToomas Soome bioslen = MMU_PAGESIZE; 86b10a562eSToomas Soome startoff = startaddr & MMU_PAGEOFFSET; 87b10a562eSToomas Soome startaddr &= MMU_PAGEMASK; 88b10a562eSToomas Soome } 89b10a562eSToomas Soome 90b10a562eSToomas 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 95b10a562eSToomas Soome /* 96b10a562eSToomas Soome * In case we did map one page, make sure we will not cross 97b10a562eSToomas Soome * the end of the page. 98b10a562eSToomas Soome */ 99b10a562eSToomas Soome p = bios + startoff; 100b10a562eSToomas Soome q = bios + bioslen - startoff; 101*174bc649SRobert Mustacchi smb2 = smb3 = NULL; 102b10a562eSToomas Soome while (p < q) { 103*174bc649SRobert Mustacchi if (smb2 != NULL && smb3 != NULL) 104c325726fSToomas Soome break; 105*174bc649SRobert Mustacchi 106*174bc649SRobert Mustacchi if (smb3 == NULL && strncmp(p, SMB3_ENTRY_EANCHOR, 107*174bc649SRobert Mustacchi SMB3_ENTRY_EANCHORLEN) == 0) { 108*174bc649SRobert Mustacchi smb3 = p; 109*174bc649SRobert Mustacchi } else if (smb2 == NULL && strncmp(p, SMB_ENTRY_EANCHOR, 110*174bc649SRobert Mustacchi SMB_ENTRY_EANCHORLEN) == 0) { 111*174bc649SRobert Mustacchi smb2 = p; 112c325726fSToomas Soome } 113be84ea34SToomas Soome 114b10a562eSToomas Soome p += SMB_SCAN_STEP; 11584ab085aSmws } 11684ab085aSmws 117*174bc649SRobert Mustacchi if (smb2 == NULL && smb3 == NULL) { 11884ab085aSmws psm_unmap_phys(bios, bioslen); 11984ab085aSmws return (smb_open_error(shp, errp, ESMB_NOTFOUND)); 12084ab085aSmws } 12184ab085aSmws 122*174bc649SRobert Mustacchi /* 123*174bc649SRobert Mustacchi * While they're not supposed to (as per the SMBIOS 3.2 spec), some 124*174bc649SRobert Mustacchi * vendors end up having a newer version in one of the two entry points 125*174bc649SRobert Mustacchi * than the other. If we found multiple tables then we will prefer the 126*174bc649SRobert Mustacchi * one with the newer version. If they're equivalent, we prefer the 127*174bc649SRobert Mustacchi * 32-bit version. If only one is present, then we use that. 128*174bc649SRobert Mustacchi */ 129e4586ebfSmws ep = smb_alloc(SMB_ENTRY_MAXLEN); 130*174bc649SRobert Mustacchi if (smb2 != NULL && smb3 != NULL) { 131*174bc649SRobert Mustacchi uint8_t smb2maj, smb2min, smb3maj, smb3min; 132*174bc649SRobert Mustacchi 133*174bc649SRobert Mustacchi bcopy(smb2, ep, sizeof (smbios_entry_t)); 134*174bc649SRobert Mustacchi smb2maj = ep->ep21.smbe_major; 135*174bc649SRobert Mustacchi smb2min = ep->ep21.smbe_minor; 136*174bc649SRobert Mustacchi bcopy(smb3, ep, sizeof (smbios_entry_t)); 137*174bc649SRobert Mustacchi smb3maj = ep->ep30.smbe_major; 138*174bc649SRobert Mustacchi smb3min = ep->ep30.smbe_minor; 139*174bc649SRobert Mustacchi 140*174bc649SRobert Mustacchi if (smb3maj > smb2maj || 141*174bc649SRobert Mustacchi (smb3maj == smb2maj && smb3min > smb2min)) { 142*174bc649SRobert Mustacchi ep_type = SMBIOS_ENTRY_POINT_30; 143*174bc649SRobert Mustacchi p = smb3; 144*174bc649SRobert Mustacchi } else { 145*174bc649SRobert Mustacchi ep_type = SMBIOS_ENTRY_POINT_21; 146*174bc649SRobert Mustacchi p = smb2; 147*174bc649SRobert Mustacchi } 148*174bc649SRobert Mustacchi } else if (smb3 != NULL) { 149*174bc649SRobert Mustacchi ep_type = SMBIOS_ENTRY_POINT_30; 150*174bc649SRobert Mustacchi p = smb3; 151*174bc649SRobert Mustacchi } else if (smb2 != NULL) { 152*174bc649SRobert Mustacchi ep_type = SMBIOS_ENTRY_POINT_21; 153*174bc649SRobert Mustacchi p = smb2; 154*174bc649SRobert Mustacchi } 155e4586ebfSmws bcopy(p, ep, sizeof (smbios_entry_t)); 156c325726fSToomas Soome if (ep_type == SMBIOS_ENTRY_POINT_21) { 157c325726fSToomas Soome ep->ep21.smbe_elen = MIN(ep->ep21.smbe_elen, SMB_ENTRY_MAXLEN); 158c325726fSToomas Soome bcopy(p, ep, ep->ep21.smbe_elen); 159c325726fSToomas Soome } else if (ep_type == SMBIOS_ENTRY_POINT_30) { 160c325726fSToomas Soome ep->ep30.smbe_elen = MIN(ep->ep30.smbe_elen, SMB_ENTRY_MAXLEN); 161c325726fSToomas Soome bcopy(p, ep, ep->ep30.smbe_elen); 162c325726fSToomas Soome } 163e4586ebfSmws 16484ab085aSmws psm_unmap_phys(bios, bioslen); 165c325726fSToomas Soome switch (ep_type) { 166c325726fSToomas Soome case SMBIOS_ENTRY_POINT_21: 167c325726fSToomas Soome smbe_major = ep->ep21.smbe_major; 168c325726fSToomas Soome smbe_minor = ep->ep21.smbe_minor; 169c325726fSToomas Soome smbe_stlen = ep->ep21.smbe_stlen; 170c325726fSToomas Soome bios = psm_map_phys(ep->ep21.smbe_staddr, smbe_stlen, 171c325726fSToomas Soome PSM_PROT_READ); 172c325726fSToomas Soome break; 173c325726fSToomas Soome case SMBIOS_ENTRY_POINT_30: 174c325726fSToomas Soome smbe_major = ep->ep30.smbe_major; 175c325726fSToomas Soome smbe_minor = ep->ep30.smbe_minor; 176c325726fSToomas Soome smbe_stlen = ep->ep30.smbe_stlen; 177c325726fSToomas Soome bios = psm_map_phys_new(ep->ep30.smbe_staddr, smbe_stlen, 178c325726fSToomas Soome PSM_PROT_READ); 179c325726fSToomas Soome break; 180c325726fSToomas Soome default: 181c325726fSToomas Soome smb_free(ep, SMB_ENTRY_MAXLEN); 182c325726fSToomas Soome return (smb_open_error(shp, errp, ESMB_VERSION)); 183c325726fSToomas Soome } 18484ab085aSmws 185e4586ebfSmws if (bios == NULL) { 186e4586ebfSmws smb_free(ep, SMB_ENTRY_MAXLEN); 18784ab085aSmws return (smb_open_error(shp, errp, ESMB_MAPDEV)); 188e4586ebfSmws } 18984ab085aSmws 190c325726fSToomas Soome stbuf = smb_alloc(smbe_stlen); 191c325726fSToomas Soome bcopy(bios, stbuf, smbe_stlen); 192c325726fSToomas Soome psm_unmap_phys(bios, smbe_stlen); 193c325726fSToomas Soome shp = smbios_bufopen(ep, stbuf, smbe_stlen, version, flags, &err); 19484ab085aSmws 19584ab085aSmws if (shp == NULL) { 196c325726fSToomas 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)", 203c325726fSToomas Soome smbe_major, smbe_minor, smbe_stlen); 204b60ae21dSJonathan Matthew if (shp->sh_flags & SMB_FL_TRUNC) 205b60ae21dSJonathan 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 * 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 22384ab085aSmws smbios_write(smbios_hdl_t *shp, int fd) 22484ab085aSmws { 22584ab085aSmws return (smb_set_errno(shp, ENOTSUP)); 22684ab085aSmws } 227