4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
24 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
28 #include <sys/types.h>
29 #include <sys/smbios_impl.h>
30 #include <sys/sysmacros.h>
41 #include <libdevinfo.h>
43 #pragma init(smb_init)
47 _smb_debug
= getenv("SMB_DEBUG") != NULL
;
51 smb_fileopen(int fd
, int version
, int flags
, int *errp
)
53 smbios_entry_t
*ep
= alloca(SMB_ENTRY_MAXLEN
);
54 smbios_entry_point_t ep_type
;
55 smbios_hdl_t
*shp
= NULL
;
61 if ((n
= pread64(fd
, ep
, sizeof (*ep
), 0)) != sizeof (*ep
))
62 return (smb_open_error(shp
, errp
, n
< 0 ? errno
: ESMB_NOHDR
));
64 if (strncmp(ep
->ep21
.smbe_eanchor
, SMB_ENTRY_EANCHOR
,
65 SMB_ENTRY_EANCHORLEN
) == 0) {
66 ep_type
= SMBIOS_ENTRY_POINT_21
;
67 elen
= MIN(ep
->ep21
.smbe_elen
, SMB_ENTRY_MAXLEN
);
68 } else if (strncmp(ep
->ep30
.smbe_eanchor
, SMB3_ENTRY_EANCHOR
,
69 SMB3_ENTRY_EANCHORLEN
) == 0) {
70 ep_type
= SMBIOS_ENTRY_POINT_30
;
71 elen
= MIN(ep
->ep30
.smbe_elen
, SMB_ENTRY_MAXLEN
);
73 return (smb_open_error(shp
, errp
, ESMB_HEADER
));
76 if ((n
= pread64(fd
, ep
, elen
, 0)) != elen
)
77 return (smb_open_error(shp
, errp
, n
< 0 ? errno
: ESMB_NOHDR
));
79 if (ep_type
== SMBIOS_ENTRY_POINT_21
) {
80 smbe_stlen
= ep
->ep21
.smbe_stlen
;
81 smbe_staddr
= (off64_t
)ep
->ep21
.smbe_staddr
;
83 smbe_stlen
= ep
->ep30
.smbe_stlen
;
84 smbe_staddr
= (off64_t
)ep
->ep30
.smbe_staddr
;
86 stbuf
= smb_alloc(smbe_stlen
);
89 return (smb_open_error(shp
, errp
, ESMB_NOMEM
));
91 if ((n
= pread64(fd
, stbuf
, smbe_stlen
, smbe_staddr
)) != smbe_stlen
) {
92 smb_free(stbuf
, smbe_stlen
);
93 return (smb_open_error(shp
, errp
, n
< 0 ? errno
: ESMB_NOSTAB
));
96 shp
= smbios_bufopen(ep
, stbuf
, smbe_stlen
, version
, flags
, errp
);
99 shp
->sh_flags
|= SMB_FL_BUFALLOC
;
101 smb_free(stbuf
, smbe_stlen
);
106 static smbios_hdl_t
*
107 smb_biosopen(int fd
, int version
, int flags
, int *errp
)
109 smbios_entry_t
*ep
= alloca(SMB_ENTRY_MAXLEN
);
110 smbios_entry_point_t ep_type
;
111 smbios_hdl_t
*shp
= NULL
;
112 size_t elen
, pgsize
, pgmask
, pgoff
;
113 void *stbuf
, *bios
, *p
, *q
;
120 if ((root
= di_init("/", DINFOPROP
)) != DI_NODE_NIL
) {
121 if (di_prop_lookup_int64(DDI_DEV_T_ANY
, root
,
122 "smbios-address", &val64
) == 1) {
123 bios
= mmap(NULL
, SMB_RANGE_LIMIT
- SMB_RANGE_START
+ 1,
124 PROT_READ
, MAP_SHARED
, fd
, (off_t
)*val64
);
128 if (bios
== MAP_FAILED
) {
129 bios
= mmap(NULL
, SMB_RANGE_LIMIT
- SMB_RANGE_START
+ 1,
130 PROT_READ
, MAP_SHARED
, fd
, (uint32_t)SMB_RANGE_START
);
133 if (bios
== MAP_FAILED
)
134 return (smb_open_error(shp
, errp
, ESMB_MAPDEV
));
136 q
= (void *)((uintptr_t)bios
+ SMB_RANGE_LIMIT
- SMB_RANGE_START
+ 1);
138 for (p
= bios
; p
< q
; p
= (void *)((uintptr_t)p
+ SMB_SCAN_STEP
)) {
139 if (strncmp(p
, SMB_ENTRY_EANCHOR
, SMB_ENTRY_EANCHORLEN
) == 0) {
140 ep_type
= SMBIOS_ENTRY_POINT_21
;
141 elen
= MIN(ep
->ep21
.smbe_elen
, SMB_ENTRY_MAXLEN
);
144 if (strncmp(p
, SMB3_ENTRY_EANCHOR
,
145 SMB3_ENTRY_EANCHORLEN
) == 0) {
146 ep_type
= SMBIOS_ENTRY_POINT_30
;
147 elen
= MIN(ep
->ep30
.smbe_elen
, SMB_ENTRY_MAXLEN
);
153 (void) munmap(bios
, SMB_RANGE_LIMIT
- SMB_RANGE_START
+ 1);
154 return (smb_open_error(NULL
, errp
, ESMB_NOTFOUND
));
157 bcopy(p
, ep
, sizeof (smbios_entry_t
));
159 (void) munmap(bios
, SMB_RANGE_LIMIT
- SMB_RANGE_START
+ 1);
162 case SMBIOS_ENTRY_POINT_21
:
163 smbe_stlen
= ep
->ep21
.smbe_stlen
;
164 smbe_staddr
= ep
->ep21
.smbe_staddr
;
166 case SMBIOS_ENTRY_POINT_30
:
167 smbe_stlen
= ep
->ep30
.smbe_stlen
;
168 smbe_staddr
= ep
->ep30
.smbe_staddr
;
171 return (smb_open_error(NULL
, errp
, ESMB_VERSION
));
174 pgsize
= getpagesize();
175 pgmask
= ~(pgsize
- 1);
176 pgoff
= smbe_staddr
& ~pgmask
;
178 bios
= mmap(NULL
, smbe_stlen
+ pgoff
,
179 PROT_READ
, MAP_SHARED
, fd
, smbe_staddr
& pgmask
);
181 if (bios
== MAP_FAILED
)
182 return (smb_open_error(shp
, errp
, ESMB_MAPDEV
));
184 if ((stbuf
= smb_alloc(smbe_stlen
)) == NULL
) {
185 (void) munmap(bios
, smbe_stlen
+ pgoff
);
186 return (smb_open_error(shp
, errp
, ESMB_NOMEM
));
189 bcopy((char *)bios
+ pgoff
, stbuf
, smbe_stlen
);
190 (void) munmap(bios
, smbe_stlen
+ pgoff
);
191 shp
= smbios_bufopen(ep
, stbuf
, smbe_stlen
, version
, flags
, errp
);
194 shp
->sh_flags
|= SMB_FL_BUFALLOC
;
196 smb_free(stbuf
, smbe_stlen
);
202 smbios_fdopen(int fd
, int version
, int flags
, int *errp
)
204 struct stat64 st1
, st2
;
206 if (stat64(SMB_BIOS_DEVICE
, &st1
) == 0 && fstat64(fd
, &st2
) == 0 &&
207 S_ISCHR(st2
.st_mode
) && st1
.st_rdev
== st2
.st_rdev
)
208 return (smb_biosopen(fd
, version
, flags
, errp
));
210 return (smb_fileopen(fd
, version
, flags
, errp
));
214 smbios_open(const char *file
, int version
, int flags
, int *errp
)
219 if ((fd
= open64(file
? file
: SMB_SMBIOS_DEVICE
, O_RDONLY
)) == -1) {
220 if ((errno
== ENOENT
|| errno
== ENXIO
) &&
221 (file
== NULL
|| strcmp(file
, SMB_SMBIOS_DEVICE
) == 0))
222 errno
= ESMB_NOTFOUND
;
223 return (smb_open_error(NULL
, errp
, errno
));
226 shp
= smbios_fdopen(fd
, version
, flags
, errp
);
232 smbios_xwrite(smbios_hdl_t
*shp
, int fd
, const void *buf
, size_t buflen
)
234 ssize_t resid
= buflen
;
238 if ((len
= write(fd
, buf
, resid
)) <= 0)
239 return (smb_set_errno(shp
, errno
));
241 buf
= (uchar_t
*)buf
+ len
;
248 smbios_write(smbios_hdl_t
*shp
, int fd
)
251 off64_t off
= lseek64(fd
, 0, SEEK_CUR
) + P2ROUNDUP(sizeof (ep
), 16);
253 if (off
> UINT32_MAX
)
254 return (smb_set_errno(shp
, EOVERFLOW
));
256 bcopy(&shp
->sh_ent
, &ep
, sizeof (ep
));
257 if (shp
->sh_ent_type
== SMBIOS_ENTRY_POINT_21
)
258 ep
.ep21
.smbe_staddr
= (uint32_t)off
;
259 else if (shp
->sh_ent_type
== SMBIOS_ENTRY_POINT_30
)
260 ep
.ep30
.smbe_staddr
= (uint64_t)off
;
264 smbios_checksum(shp
, &ep
);
266 if (smbios_xwrite(shp
, fd
, &ep
, sizeof (ep
)) == -1 ||
267 lseek64(fd
, off
, SEEK_SET
) != off
||
268 smbios_xwrite(shp
, fd
, shp
->sh_buf
, shp
->sh_buflen
) == -1)