1437Smws /* 2437Smws * CDDL HEADER START 3437Smws * 4437Smws * The contents of this file are subject to the terms of the 5437Smws * Common Development and Distribution License, Version 1.0 only 6437Smws * (the "License"). You may not use this file except in compliance 7437Smws * with the License. 8437Smws * 9437Smws * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10437Smws * or http://www.opensolaris.org/os/licensing. 11437Smws * See the License for the specific language governing permissions 12437Smws * and limitations under the License. 13437Smws * 14437Smws * When distributing Covered Code, include this CDDL HEADER in each 15437Smws * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16437Smws * If applicable, add the following below this CDDL HEADER, with the 17437Smws * fields enclosed by brackets "[]" replaced with your own identifying 18437Smws * information: Portions Copyright [yyyy] [name of copyright owner] 19437Smws * 20437Smws * CDDL HEADER END 21437Smws */ 22437Smws 23437Smws /* 24*1222Smws * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 25437Smws * Use is subject to license terms. 26437Smws */ 27437Smws 28437Smws #pragma ident "%Z%%M% %I% %E% SMI" 29437Smws 30437Smws #include <sys/types.h> 31437Smws #include <sys/smbios_impl.h> 32437Smws #include <sys/sysmacros.h> 33437Smws #include <sys/stat.h> 34437Smws #include <sys/mman.h> 35437Smws 36*1222Smws #include <alloca.h> 37437Smws #include <limits.h> 38437Smws #include <unistd.h> 39437Smws #include <strings.h> 40437Smws #include <stdlib.h> 41437Smws #include <errno.h> 42437Smws #include <fcntl.h> 43437Smws 44437Smws #pragma init(smb_init) 45437Smws static void 46437Smws smb_init(void) 47437Smws { 48437Smws _smb_debug = getenv("SMB_DEBUG") != NULL; 49437Smws } 50437Smws 51437Smws static smbios_hdl_t * 52437Smws smb_fileopen(int fd, int version, int flags, int *errp) 53437Smws { 54*1222Smws smbios_entry_t *ep = alloca(SMB_ENTRY_MAXLEN); 55437Smws smbios_hdl_t *shp = NULL; 56*1222Smws ssize_t n, elen; 57437Smws void *stbuf; 58437Smws 59*1222Smws if ((n = pread64(fd, ep, sizeof (*ep), 0)) != sizeof (*ep)) 60437Smws return (smb_open_error(shp, errp, n < 0 ? errno : ESMB_NOHDR)); 61437Smws 62*1222Smws if (strncmp(ep->smbe_eanchor, SMB_ENTRY_EANCHOR, SMB_ENTRY_EANCHORLEN)) 63437Smws return (smb_open_error(shp, errp, ESMB_HEADER)); 64437Smws 65*1222Smws elen = MIN(ep->smbe_elen, SMB_ENTRY_MAXLEN); 66*1222Smws 67*1222Smws if ((n = pread64(fd, ep, elen, 0)) != elen) 68*1222Smws return (smb_open_error(shp, errp, n < 0 ? errno : ESMB_NOHDR)); 69*1222Smws 70*1222Smws if ((stbuf = smb_alloc(ep->smbe_stlen)) == NULL) 71437Smws return (smb_open_error(shp, errp, ESMB_NOMEM)); 72437Smws 73*1222Smws if ((n = pread64(fd, stbuf, ep->smbe_stlen, 74*1222Smws (off64_t)ep->smbe_staddr)) != ep->smbe_stlen) { 75*1222Smws smb_free(stbuf, ep->smbe_stlen); 76437Smws return (smb_open_error(shp, errp, n < 0 ? errno : ESMB_NOSTAB)); 77437Smws } 78437Smws 79*1222Smws shp = smbios_bufopen(ep, stbuf, ep->smbe_stlen, version, flags, errp); 80437Smws 81437Smws if (shp != NULL) 82437Smws shp->sh_flags |= SMB_FL_BUFALLOC; 83437Smws else 84*1222Smws smb_free(stbuf, ep->smbe_stlen); 85437Smws 86437Smws return (shp); 87437Smws } 88437Smws 89437Smws static smbios_hdl_t * 90437Smws smb_biosopen(int fd, int version, int flags, int *errp) 91437Smws { 92*1222Smws smbios_entry_t *ep = alloca(SMB_ENTRY_MAXLEN); 93437Smws smbios_hdl_t *shp = NULL; 94437Smws size_t pgsize, pgmask, pgoff; 95437Smws void *stbuf, *bios, *p, *q; 96437Smws 97437Smws bios = mmap(NULL, SMB_RANGE_LIMIT - SMB_RANGE_START + 1, 98437Smws PROT_READ, MAP_SHARED, fd, (uint32_t)SMB_RANGE_START); 99437Smws 100437Smws if (bios == MAP_FAILED) 101437Smws return (smb_open_error(shp, errp, ESMB_MAPDEV)); 102437Smws 103437Smws q = (void *)((uintptr_t)bios + SMB_RANGE_LIMIT - SMB_RANGE_START + 1); 104437Smws 105437Smws for (p = bios; p < q; p = (void *)((uintptr_t)p + 16)) { 106437Smws if (strncmp(p, SMB_ENTRY_EANCHOR, SMB_ENTRY_EANCHORLEN) == 0) 107437Smws break; 108437Smws } 109437Smws 110437Smws if (p >= q) { 111437Smws (void) munmap(bios, SMB_RANGE_LIMIT - SMB_RANGE_START + 1); 112437Smws return (smb_open_error(NULL, errp, ESMB_NOTFOUND)); 113437Smws } 114437Smws 115*1222Smws bcopy(p, ep, sizeof (smbios_entry_t)); 116*1222Smws ep->smbe_elen = MIN(ep->smbe_elen, SMB_ENTRY_MAXLEN); 117*1222Smws bcopy(p, ep, ep->smbe_elen); 118437Smws (void) munmap(bios, SMB_RANGE_LIMIT - SMB_RANGE_START + 1); 119437Smws 120437Smws pgsize = getpagesize(); 121437Smws pgmask = ~(pgsize - 1); 122*1222Smws pgoff = ep->smbe_staddr & ~pgmask; 123437Smws 124*1222Smws bios = mmap(NULL, ep->smbe_stlen + pgoff, 125*1222Smws PROT_READ, MAP_SHARED, fd, ep->smbe_staddr & pgmask); 126437Smws 127437Smws if (bios == MAP_FAILED) 128437Smws return (smb_open_error(shp, errp, ESMB_MAPDEV)); 129437Smws 130*1222Smws if ((stbuf = smb_alloc(ep->smbe_stlen)) == NULL) { 131*1222Smws (void) munmap(bios, ep->smbe_stlen + pgoff); 132437Smws return (smb_open_error(shp, errp, ESMB_NOMEM)); 133437Smws } 134437Smws 135*1222Smws bcopy((char *)bios + pgoff, stbuf, ep->smbe_stlen); 136*1222Smws (void) munmap(bios, ep->smbe_stlen + pgoff); 137*1222Smws shp = smbios_bufopen(ep, stbuf, ep->smbe_stlen, version, flags, errp); 138437Smws 139437Smws if (shp != NULL) 140437Smws shp->sh_flags |= SMB_FL_BUFALLOC; 141437Smws else 142*1222Smws smb_free(stbuf, ep->smbe_stlen); 143437Smws 144437Smws return (shp); 145437Smws } 146437Smws 147437Smws smbios_hdl_t * 148437Smws smbios_fdopen(int fd, int version, int flags, int *errp) 149437Smws { 150437Smws struct stat64 st1, st2; 151437Smws 152437Smws if (stat64(SMB_BIOS_DEVICE, &st1) == 0 && fstat64(fd, &st2) == 0 && 153437Smws S_ISCHR(st2.st_mode) && st1.st_rdev == st2.st_rdev) 154437Smws return (smb_biosopen(fd, version, flags, errp)); 155437Smws else 156437Smws return (smb_fileopen(fd, version, flags, errp)); 157437Smws } 158437Smws 159437Smws smbios_hdl_t * 160437Smws smbios_open(const char *file, int version, int flags, int *errp) 161437Smws { 162437Smws smbios_hdl_t *shp; 163437Smws int fd; 164437Smws 165437Smws if ((fd = open64(file ? file : SMB_SMBIOS_DEVICE, O_RDONLY)) == -1) { 166437Smws if ((errno == ENOENT || errno == ENXIO) && 167437Smws (file == NULL || strcmp(file, SMB_SMBIOS_DEVICE) == 0)) 168437Smws errno = ESMB_NOTFOUND; 169437Smws return (smb_open_error(NULL, errp, errno)); 170437Smws } 171437Smws 172437Smws shp = smbios_fdopen(fd, version, flags, errp); 173437Smws (void) close(fd); 174437Smws return (shp); 175437Smws } 176437Smws 177437Smws static int 178437Smws smbios_xwrite(smbios_hdl_t *shp, int fd, const void *buf, size_t buflen) 179437Smws { 180437Smws ssize_t resid = buflen; 181437Smws ssize_t len; 182437Smws 183437Smws while (resid != 0) { 184437Smws if ((len = write(fd, buf, resid)) <= 0) 185437Smws return (smb_set_errno(shp, errno)); 186437Smws resid -= len; 187437Smws buf = (uchar_t *)buf + len; 188437Smws } 189437Smws 190437Smws return (0); 191437Smws } 192437Smws 193437Smws int 194437Smws smbios_write(smbios_hdl_t *shp, int fd) 195437Smws { 196437Smws smbios_entry_t ep; 197437Smws off64_t off = lseek64(fd, 0, SEEK_CUR) + P2ROUNDUP(sizeof (ep), 16); 198437Smws 199437Smws if (off > UINT32_MAX) 200437Smws return (smb_set_errno(shp, EOVERFLOW)); 201437Smws 202437Smws bcopy(&shp->sh_ent, &ep, sizeof (ep)); 203437Smws ep.smbe_staddr = (uint32_t)off; 204437Smws smbios_checksum(shp, &ep); 205437Smws 206437Smws if (smbios_xwrite(shp, fd, &ep, sizeof (ep)) == -1 || 207437Smws lseek64(fd, off, SEEK_SET) != off || 208437Smws smbios_xwrite(shp, fd, shp->sh_buf, shp->sh_buflen) == -1) 209437Smws return (-1); 210437Smws 211437Smws return (0); 212437Smws } 213