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
smb_init(void)46437Smws smb_init(void)
47437Smws {
48437Smws _smb_debug = getenv("SMB_DEBUG") != NULL;
49437Smws }
50437Smws
51437Smws static smbios_hdl_t *
smb_fileopen(int fd,int version,int flags,int * errp)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 *
smb_biosopen(int fd,int version,int flags,int * errp)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 *
smbios_fdopen(int fd,int version,int flags,int * errp)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 *
smbios_open(const char * file,int version,int flags,int * errp)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
smbios_xwrite(smbios_hdl_t * shp,int fd,const void * buf,size_t buflen)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
smbios_write(smbios_hdl_t * shp,int fd)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