Print this page
5042 stop using deprecated atomic functions
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/smbios.c
+++ new/usr/src/uts/common/io/smbios.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27
28 28 /*
29 29 * smbios(7D) driver
30 30 *
31 31 * This pseudo-driver makes available a snapshot of the system's SMBIOS image
32 32 * that can be accessed using libsmbios. Clients may access a snapshot using
33 33 * either read(2) or mmap(2). The driver returns the SMBIOS entry point data
34 34 * followed by the SMBIOS structure table. The entry point has its 'staddr'
35 35 * field set to indicate the byte offset of the structure table. The driver
36 36 * uses the common SMBIOS API defined in <sys/smbios.h> to access the image.
37 37 *
38 38 * At present, the kernel takes a single snapshot of SMBIOS at boot time and
39 39 * stores a handle for this snapshot in 'ksmbios'. To keep track of driver
40 40 * opens, we simply compare-and-swap this handle into an 'smb_clones' array.
41 41 * Future x86 systems may need to support dynamic SMBIOS updates: when that
42 42 * happens the SMBIOS API can be extended to support reference counting and
43 43 * handles for different snapshots can be stored in smb_clones[].
44 44 */
45 45
46 46 #include <sys/smbios.h>
47 47 #include <sys/sysmacros.h>
48 48 #include <sys/cmn_err.h>
49 49 #include <sys/vmsystm.h>
50 50 #include <vm/seg_vn.h>
51 51 #include <sys/ddi.h>
52 52 #include <sys/sunddi.h>
53 53 #include <sys/modctl.h>
54 54 #include <sys/conf.h>
55 55 #include <sys/stat.h>
56 56
57 57 typedef struct smb_clone {
58 58 smbios_hdl_t *c_hdl;
59 59 size_t c_eplen;
60 60 size_t c_stlen;
61 61 } smb_clone_t;
62 62
63 63 static dev_info_t *smb_devi;
64 64 static smb_clone_t *smb_clones;
65 65 static int smb_nclones;
66 66
67 67 /*ARGSUSED*/
68 68 static int
69 69 smb_open(dev_t *dp, int flag, int otyp, cred_t *cred)
70 70 {
↓ open down ↓ |
70 lines elided |
↑ open up ↑ |
71 71 minor_t c;
72 72
73 73 if (ksmbios == NULL)
74 74 return (ENXIO);
75 75
76 76 /*
77 77 * Locate and reserve a clone structure. We skip clone 0 as that is
78 78 * the real minor number, and we assign a new minor to each clone.
79 79 */
80 80 for (c = 1; c < smb_nclones; c++) {
81 - if (casptr(&smb_clones[c].c_hdl, NULL, ksmbios) == NULL)
81 + if (atomic_cas_ptr(&smb_clones[c].c_hdl, NULL, ksmbios) == NULL)
82 82 break;
83 83 }
84 84
85 85 if (c >= smb_nclones)
86 86 return (EAGAIN);
87 87
88 88 smb_clones[c].c_eplen = P2ROUNDUP(sizeof (smbios_entry_t), 16);
89 89 smb_clones[c].c_stlen = smbios_buflen(smb_clones[c].c_hdl);
90 90
91 91 *dp = makedevice(getemajor(*dp), c);
92 92
93 93 (void) ddi_prop_update_int(*dp, smb_devi, "size",
94 94 smb_clones[c].c_eplen + smb_clones[c].c_stlen);
95 95
96 96 return (0);
97 97 }
98 98
99 99 /*ARGSUSED*/
100 100 static int
101 101 smb_close(dev_t dev, int flag, int otyp, cred_t *cred)
102 102 {
103 103 (void) ddi_prop_remove(dev, smb_devi, "size");
104 104 smb_clones[getminor(dev)].c_hdl = NULL;
105 105 return (0);
106 106 }
107 107
108 108 /*
109 109 * Common code to copy out the SMBIOS snapshot used for both read and mmap.
110 110 * The caller must validate uio_offset for us since semantics differ there.
111 111 * The copy is done in two stages, either of which can be skipped based on the
112 112 * offset and length: first we copy the entry point, with 'staddr' recalculated
113 113 * to indicate the offset of the data buffer, and second we copy the table.
114 114 */
115 115 static int
116 116 smb_uiomove(smb_clone_t *cp, uio_t *uio)
117 117 {
118 118 off_t off = uio->uio_offset;
119 119 size_t len = uio->uio_resid;
120 120 int err = 0;
121 121
122 122 if (off + len > cp->c_eplen + cp->c_stlen)
123 123 len = cp->c_eplen + cp->c_stlen - off;
124 124
125 125 if (off < cp->c_eplen) {
126 126 smbios_entry_t *ep = kmem_zalloc(cp->c_eplen, KM_SLEEP);
127 127 size_t eprlen = MIN(len, cp->c_eplen - off);
128 128
129 129 smbios_info_smbios(cp->c_hdl, ep);
130 130 ep->smbe_staddr = (uint32_t)cp->c_eplen;
131 131 smbios_checksum(cp->c_hdl, ep);
132 132
133 133 err = uiomove((char *)ep + off, eprlen, UIO_READ, uio);
134 134 kmem_free(ep, cp->c_eplen);
135 135
136 136 off += eprlen;
137 137 len -= eprlen;
138 138 }
139 139
140 140 if (err == 0 && off >= cp->c_eplen) {
141 141 char *buf = (char *)smbios_buf(cp->c_hdl);
142 142 size_t bufoff = off - cp->c_eplen;
143 143
144 144 err = uiomove(buf + bufoff,
145 145 MIN(len, cp->c_stlen - bufoff), UIO_READ, uio);
146 146 }
147 147
148 148 return (err);
149 149 }
150 150
151 151 /*ARGSUSED*/
152 152 static int
153 153 smb_read(dev_t dev, uio_t *uio, cred_t *cred)
154 154 {
155 155 smb_clone_t *cp = &smb_clones[getminor(dev)];
156 156
157 157 if (uio->uio_offset < 0 ||
158 158 uio->uio_offset >= cp->c_eplen + cp->c_stlen)
159 159 return (0);
160 160
161 161 return (smb_uiomove(cp, uio));
162 162 }
163 163
164 164 /*ARGSUSED*/
165 165 static int
166 166 smb_segmap(dev_t dev, off_t off, struct as *as, caddr_t *addrp, off_t len,
167 167 uint_t prot, uint_t maxprot, uint_t flags, cred_t *cred)
168 168 {
169 169 smb_clone_t *cp = &smb_clones[getminor(dev)];
170 170
171 171 size_t alen = P2ROUNDUP(len, PAGESIZE);
172 172 caddr_t addr = NULL;
173 173
174 174 iovec_t iov;
175 175 uio_t uio;
176 176 int err;
177 177
178 178 if (len <= 0 || (flags & MAP_FIXED))
179 179 return (EINVAL);
180 180
181 181 if ((prot & PROT_WRITE) && (flags & MAP_SHARED))
182 182 return (EACCES);
183 183
184 184 if (off < 0 || off + len < off || off + len > cp->c_eplen + cp->c_stlen)
185 185 return (ENXIO);
186 186
187 187 as_rangelock(as);
188 188 map_addr(&addr, alen, 0, 1, 0);
189 189
190 190 if (addr != NULL)
191 191 err = as_map(as, addr, alen, segvn_create, zfod_argsp);
192 192 else
193 193 err = ENOMEM;
194 194
195 195 as_rangeunlock(as);
196 196 *addrp = addr;
197 197
198 198 if (err != 0)
199 199 return (err);
200 200
201 201 iov.iov_base = addr;
202 202 iov.iov_len = len;
203 203
204 204 bzero(&uio, sizeof (uio_t));
205 205 uio.uio_iov = &iov;
206 206 uio.uio_iovcnt = 1;
207 207 uio.uio_offset = off;
208 208 uio.uio_segflg = UIO_USERSPACE;
209 209 uio.uio_extflg = UIO_COPY_DEFAULT;
210 210 uio.uio_resid = len;
211 211
212 212 if ((err = smb_uiomove(cp, &uio)) != 0)
213 213 (void) as_unmap(as, addr, alen);
214 214
215 215 return (err);
216 216 }
217 217
218 218 /*ARGSUSED*/
219 219 static int
220 220 smb_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
221 221 {
222 222 switch (infocmd) {
223 223 case DDI_INFO_DEVT2DEVINFO:
224 224 *result = smb_devi;
225 225 return (DDI_SUCCESS);
226 226 case DDI_INFO_DEVT2INSTANCE:
227 227 *result = 0;
228 228 return (DDI_SUCCESS);
229 229 }
230 230 return (DDI_FAILURE);
231 231 }
232 232
233 233 static int
234 234 smb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
235 235 {
236 236 if (cmd != DDI_ATTACH)
237 237 return (DDI_FAILURE);
238 238
239 239 if (ddi_create_minor_node(devi, "smbios",
240 240 S_IFCHR, 0, DDI_PSEUDO, 0) == DDI_FAILURE) {
241 241 ddi_remove_minor_node(devi, NULL);
242 242 return (DDI_FAILURE);
243 243 }
244 244
245 245 smb_devi = devi;
246 246 return (DDI_SUCCESS);
247 247 }
248 248
249 249 static int
250 250 smb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
251 251 {
252 252 if (cmd != DDI_DETACH)
253 253 return (DDI_FAILURE);
254 254
255 255 ddi_remove_minor_node(devi, NULL);
256 256 return (DDI_SUCCESS);
257 257 }
258 258
259 259 static struct cb_ops smb_cb_ops = {
260 260 smb_open, /* open */
261 261 smb_close, /* close */
262 262 nodev, /* strategy */
263 263 nodev, /* print */
264 264 nodev, /* dump */
265 265 smb_read, /* read */
266 266 nodev, /* write */
267 267 nodev, /* ioctl */
268 268 nodev, /* devmap */
269 269 nodev, /* mmap */
270 270 smb_segmap, /* segmap */
271 271 nochpoll, /* poll */
272 272 ddi_prop_op, /* prop_op */
273 273 NULL, /* streamtab */
274 274 D_NEW | D_MP /* flags */
275 275 };
276 276
277 277 static struct dev_ops smb_ops = {
278 278 DEVO_REV, /* rev */
279 279 0, /* refcnt */
280 280 smb_info, /* info */
281 281 nulldev, /* identify */
282 282 nulldev, /* probe */
283 283 smb_attach, /* attach */
284 284 smb_detach, /* detach */
285 285 nodev, /* reset */
286 286 &smb_cb_ops, /* cb ops */
287 287 NULL, /* bus ops */
288 288 NULL, /* power */
289 289 ddi_quiesce_not_needed, /* quiesce */
290 290 };
291 291
292 292 static struct modldrv modldrv = {
293 293 &mod_driverops, "System Management BIOS driver", &smb_ops,
294 294 };
295 295
296 296 static struct modlinkage modlinkage = {
297 297 MODREV_1, { (void *)&modldrv }
298 298 };
299 299
300 300 int
301 301 _init(void)
302 302 {
303 303 int err;
304 304
305 305 if (smb_nclones <= 0)
306 306 smb_nclones = maxusers;
307 307
308 308 smb_clones = kmem_zalloc(sizeof (smb_clone_t) * smb_nclones, KM_SLEEP);
309 309
310 310 if ((err = mod_install(&modlinkage)) != 0)
311 311 kmem_free(smb_clones, sizeof (smb_clone_t) * smb_nclones);
312 312
313 313 return (err);
314 314 }
315 315
316 316 int
317 317 _fini(void)
318 318 {
319 319 int err;
320 320
321 321 if ((err = mod_remove(&modlinkage)) == 0)
322 322 kmem_free(smb_clones, sizeof (smb_clone_t) * smb_nclones);
323 323
324 324 return (err);
325 325 }
326 326
327 327 int
328 328 _info(struct modinfo *mip)
329 329 {
330 330 return (mod_info(&modlinkage, mip));
331 331 }
↓ open down ↓ |
240 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX