Deleted Added
full compact
mem.c (111462) mem.c (111815)
1/*-
2 * Copyright (c) 1988 University of Utah.
3 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * the Systems Programming Group of the University of Utah Computer
8 * Science Department, and code derived from software contributed to
9 * Berkeley by William Jolitz.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * from: Utah $Hdr: mem.c 1.13 89/10/08$
40 * from: @(#)mem.c 7.2 (Berkeley) 5/9/91
1/*-
2 * Copyright (c) 1988 University of Utah.
3 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * the Systems Programming Group of the University of Utah Computer
8 * Science Department, and code derived from software contributed to
9 * Berkeley by William Jolitz.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * from: Utah $Hdr: mem.c 1.13 89/10/08$
40 * from: @(#)mem.c 7.2 (Berkeley) 5/9/91
41 * $FreeBSD: head/sys/i386/i386/mem.c 111462 2003-02-25 03:21:22Z mux $
41 * $FreeBSD: head/sys/i386/i386/mem.c 111815 2003-03-03 12:15:54Z phk $
42 */
43
44/*
45 * Memory special file
46 */
47
48#include <sys/param.h>
49#include <sys/conf.h>
50#include <sys/fcntl.h>
51#include <sys/ioccom.h>
52#include <sys/kernel.h>
53#include <sys/lock.h>
54#include <sys/malloc.h>
55#include <sys/memrange.h>
56#include <sys/mutex.h>
57#include <sys/proc.h>
58#include <sys/signalvar.h>
59#include <sys/systm.h>
60#include <sys/uio.h>
61
62#include <machine/db_machdep.h>
63#include <machine/frame.h>
64#include <machine/psl.h>
65#include <machine/specialreg.h>
66
67#include <vm/vm.h>
68#include <vm/pmap.h>
69#include <vm/vm_extern.h>
70
71static dev_t memdev, kmemdev, iodev;
72
73static d_open_t mmopen;
74static d_close_t mmclose;
75static d_read_t mmrw;
76static d_ioctl_t mmioctl;
77static d_mmap_t memmmap;
78
79#define CDEV_MAJOR 2
80static struct cdevsw mem_cdevsw = {
42 */
43
44/*
45 * Memory special file
46 */
47
48#include <sys/param.h>
49#include <sys/conf.h>
50#include <sys/fcntl.h>
51#include <sys/ioccom.h>
52#include <sys/kernel.h>
53#include <sys/lock.h>
54#include <sys/malloc.h>
55#include <sys/memrange.h>
56#include <sys/mutex.h>
57#include <sys/proc.h>
58#include <sys/signalvar.h>
59#include <sys/systm.h>
60#include <sys/uio.h>
61
62#include <machine/db_machdep.h>
63#include <machine/frame.h>
64#include <machine/psl.h>
65#include <machine/specialreg.h>
66
67#include <vm/vm.h>
68#include <vm/pmap.h>
69#include <vm/vm_extern.h>
70
71static dev_t memdev, kmemdev, iodev;
72
73static d_open_t mmopen;
74static d_close_t mmclose;
75static d_read_t mmrw;
76static d_ioctl_t mmioctl;
77static d_mmap_t memmmap;
78
79#define CDEV_MAJOR 2
80static struct cdevsw mem_cdevsw = {
81 /* open */ mmopen,
82 /* close */ mmclose,
83 /* read */ mmrw,
84 /* write */ mmrw,
85 /* ioctl */ mmioctl,
86 /* poll */ (d_poll_t *)seltrue,
87 /* mmap */ memmmap,
88 /* strategy */ nostrategy,
89 /* name */ "mem",
90 /* maj */ CDEV_MAJOR,
91 /* dump */ nodump,
92 /* psize */ nopsize,
93 /* flags */ D_MEM,
81 .d_open = mmopen,
82 .d_close = mmclose,
83 .d_read = mmrw,
84 .d_write = mmrw,
85 .d_ioctl = mmioctl,
86 .d_mmap = memmmap,
87 .d_name = "mem",
88 .d_maj = CDEV_MAJOR,
89 .d_flags = D_MEM,
94};
95
96MALLOC_DEFINE(M_MEMDESC, "memdesc", "memory range descriptors");
97
98struct mem_range_softc mem_range_softc;
99
100static int
101mmclose(dev_t dev, int flags, int fmt, struct thread *td)
102{
103 switch (minor(dev)) {
104 case 14:
105 td->td_frame->tf_eflags &= ~PSL_IOPL;
106 }
107 return (0);
108}
109
110static int
111mmopen(dev_t dev, int flags, int fmt, struct thread *td)
112{
113 int error;
114
115 switch (minor(dev)) {
116 case 0:
117 case 1:
118 if (flags & FWRITE) {
119 error = securelevel_gt(td->td_ucred, 0);
120 if (error != 0)
121 return (error);
122 }
123 break;
124 case 14:
125 error = suser(td);
126 if (error != 0)
127 return (error);
128 error = securelevel_gt(td->td_ucred, 0);
129 if (error != 0)
130 return (error);
131 td->td_frame->tf_eflags |= PSL_IOPL;
132 break;
133 }
134 return (0);
135}
136
137/*ARGSUSED*/
138static int
139mmrw(dev_t dev, struct uio *uio, int flags)
140{
141 int o;
142 u_int c = 0, v;
143 struct iovec *iov;
144 int error = 0;
145 vm_offset_t addr, eaddr;
146
147 GIANT_REQUIRED;
148
149 while (uio->uio_resid > 0 && error == 0) {
150 iov = uio->uio_iov;
151 if (iov->iov_len == 0) {
152 uio->uio_iov++;
153 uio->uio_iovcnt--;
154 if (uio->uio_iovcnt < 0)
155 panic("mmrw");
156 continue;
157 }
158 switch (minor(dev)) {
159
160/* minor device 0 is physical memory */
161 case 0:
162 v = uio->uio_offset;
163 v &= ~PAGE_MASK;
164 pmap_kenter((vm_offset_t)ptvmmap, v);
165 o = (int)uio->uio_offset & PAGE_MASK;
166 c = (u_int)(PAGE_SIZE - ((int)iov->iov_base & PAGE_MASK));
167 c = min(c, (u_int)(PAGE_SIZE - o));
168 c = min(c, (u_int)iov->iov_len);
169 error = uiomove((caddr_t)&ptvmmap[o], (int)c, uio);
170 pmap_qremove((vm_offset_t)ptvmmap, 1);
171 continue;
172
173/* minor device 1 is kernel memory */
174 case 1:
175 c = iov->iov_len;
176
177 /*
178 * Make sure that all of the pages are currently resident so
179 * that we don't create any zero-fill pages.
180 */
181 addr = trunc_page(uio->uio_offset);
182 eaddr = round_page(uio->uio_offset + c);
183
184 if (addr < (vm_offset_t)VADDR(PTDPTDI, 0))
185 return (EFAULT);
186 if (eaddr >= (vm_offset_t)VADDR(APTDPTDI, 0))
187 return (EFAULT);
188 for (; addr < eaddr; addr += PAGE_SIZE)
189 if (pmap_extract(kernel_pmap, addr) == 0)
190 return (EFAULT);
191
192 if (!kernacc((caddr_t)(int)uio->uio_offset, c,
193 uio->uio_rw == UIO_READ ?
194 VM_PROT_READ : VM_PROT_WRITE))
195 return (EFAULT);
196 error = uiomove((caddr_t)(int)uio->uio_offset, (int)c, uio);
197 continue;
198
199 default:
200 return (ENODEV);
201 }
202
203 if (error)
204 break;
205 iov->iov_base = (char *)iov->iov_base + c;
206 iov->iov_len -= c;
207 uio->uio_offset += c;
208 uio->uio_resid -= c;
209 }
210 return (error);
211}
212
213/*******************************************************\
214* allow user processes to MMAP some memory sections *
215* instead of going through read/write *
216\*******************************************************/
217static int
218memmmap(dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int prot)
219{
220 switch (minor(dev))
221 {
222
223 /* minor device 0 is physical memory */
224 case 0:
225 *paddr = offset;
226 break;
227
228 /* minor device 1 is kernel memory */
229 case 1:
230 *paddr = vtophys(offset);
231 break;
232
233 default:
234 return (-1);
235 }
236 return (0);
237}
238
239/*
240 * Operations for changing memory attributes.
241 *
242 * This is basically just an ioctl shim for mem_range_attr_get
243 * and mem_range_attr_set.
244 */
245static int
246mmioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct thread *td)
247{
248 int nd, error = 0;
249 struct mem_range_op *mo = (struct mem_range_op *)data;
250 struct mem_range_desc *md;
251
252 /* is this for us? */
253 if ((cmd != MEMRANGE_GET) &&
254 (cmd != MEMRANGE_SET))
255 return (ENOTTY);
256
257 /* any chance we can handle this? */
258 if (mem_range_softc.mr_op == NULL)
259 return (EOPNOTSUPP);
260
261 /* do we have any descriptors? */
262 if (mem_range_softc.mr_ndesc == 0)
263 return (ENXIO);
264
265 switch (cmd) {
266 case MEMRANGE_GET:
267 nd = imin(mo->mo_arg[0], mem_range_softc.mr_ndesc);
268 if (nd > 0) {
269 md = (struct mem_range_desc *)
270 malloc(nd * sizeof(struct mem_range_desc),
271 M_MEMDESC, M_WAITOK);
272 error = mem_range_attr_get(md, &nd);
273 if (!error)
274 error = copyout(md, mo->mo_desc,
275 nd * sizeof(struct mem_range_desc));
276 free(md, M_MEMDESC);
277 }
278 else
279 nd = mem_range_softc.mr_ndesc;
280 mo->mo_arg[0] = nd;
281 break;
282
283 case MEMRANGE_SET:
284 md = (struct mem_range_desc *)malloc(sizeof(struct mem_range_desc),
285 M_MEMDESC, M_WAITOK);
286 error = copyin(mo->mo_desc, md, sizeof(struct mem_range_desc));
287 /* clamp description string */
288 md->mr_owner[sizeof(md->mr_owner) - 1] = 0;
289 if (error == 0)
290 error = mem_range_attr_set(md, &mo->mo_arg[0]);
291 free(md, M_MEMDESC);
292 break;
293 }
294 return (error);
295}
296
297/*
298 * Implementation-neutral, kernel-callable functions for manipulating
299 * memory range attributes.
300 */
301int
302mem_range_attr_get(struct mem_range_desc *mrd, int *arg)
303{
304 /* can we handle this? */
305 if (mem_range_softc.mr_op == NULL)
306 return (EOPNOTSUPP);
307
308 if (*arg == 0)
309 *arg = mem_range_softc.mr_ndesc;
310 else
311 bcopy(mem_range_softc.mr_desc, mrd,
312 (*arg) * sizeof(struct mem_range_desc));
313 return (0);
314}
315
316int
317mem_range_attr_set(struct mem_range_desc *mrd, int *arg)
318{
319 /* can we handle this? */
320 if (mem_range_softc.mr_op == NULL)
321 return (EOPNOTSUPP);
322
323 return (mem_range_softc.mr_op->set(&mem_range_softc, mrd, arg));
324}
325
326#ifdef SMP
327void
328mem_range_AP_init(void)
329{
330 if (mem_range_softc.mr_op && mem_range_softc.mr_op->initAP)
331 (mem_range_softc.mr_op->initAP(&mem_range_softc));
332}
333#endif
334
335static int
336mem_modevent(module_t mod, int type, void *data)
337{
338 switch(type) {
339 case MOD_LOAD:
340 if (bootverbose)
341 printf("mem: <memory & I/O>\n");
342 /* Initialise memory range handling */
343 if (mem_range_softc.mr_op != NULL)
344 mem_range_softc.mr_op->init(&mem_range_softc);
345
346 memdev = make_dev(&mem_cdevsw, 0, UID_ROOT, GID_KMEM,
347 0640, "mem");
348 kmemdev = make_dev(&mem_cdevsw, 1, UID_ROOT, GID_KMEM,
349 0640, "kmem");
350 iodev = make_dev(&mem_cdevsw, 14, UID_ROOT, GID_WHEEL,
351 0600, "io");
352 return (0);
353
354 case MOD_UNLOAD:
355 destroy_dev(memdev);
356 destroy_dev(kmemdev);
357 destroy_dev(iodev);
358 return (0);
359
360 case MOD_SHUTDOWN:
361 return (0);
362
363 default:
364 return (EOPNOTSUPP);
365 }
366}
367
368DEV_MODULE(mem, mem_modevent, NULL);
90};
91
92MALLOC_DEFINE(M_MEMDESC, "memdesc", "memory range descriptors");
93
94struct mem_range_softc mem_range_softc;
95
96static int
97mmclose(dev_t dev, int flags, int fmt, struct thread *td)
98{
99 switch (minor(dev)) {
100 case 14:
101 td->td_frame->tf_eflags &= ~PSL_IOPL;
102 }
103 return (0);
104}
105
106static int
107mmopen(dev_t dev, int flags, int fmt, struct thread *td)
108{
109 int error;
110
111 switch (minor(dev)) {
112 case 0:
113 case 1:
114 if (flags & FWRITE) {
115 error = securelevel_gt(td->td_ucred, 0);
116 if (error != 0)
117 return (error);
118 }
119 break;
120 case 14:
121 error = suser(td);
122 if (error != 0)
123 return (error);
124 error = securelevel_gt(td->td_ucred, 0);
125 if (error != 0)
126 return (error);
127 td->td_frame->tf_eflags |= PSL_IOPL;
128 break;
129 }
130 return (0);
131}
132
133/*ARGSUSED*/
134static int
135mmrw(dev_t dev, struct uio *uio, int flags)
136{
137 int o;
138 u_int c = 0, v;
139 struct iovec *iov;
140 int error = 0;
141 vm_offset_t addr, eaddr;
142
143 GIANT_REQUIRED;
144
145 while (uio->uio_resid > 0 && error == 0) {
146 iov = uio->uio_iov;
147 if (iov->iov_len == 0) {
148 uio->uio_iov++;
149 uio->uio_iovcnt--;
150 if (uio->uio_iovcnt < 0)
151 panic("mmrw");
152 continue;
153 }
154 switch (minor(dev)) {
155
156/* minor device 0 is physical memory */
157 case 0:
158 v = uio->uio_offset;
159 v &= ~PAGE_MASK;
160 pmap_kenter((vm_offset_t)ptvmmap, v);
161 o = (int)uio->uio_offset & PAGE_MASK;
162 c = (u_int)(PAGE_SIZE - ((int)iov->iov_base & PAGE_MASK));
163 c = min(c, (u_int)(PAGE_SIZE - o));
164 c = min(c, (u_int)iov->iov_len);
165 error = uiomove((caddr_t)&ptvmmap[o], (int)c, uio);
166 pmap_qremove((vm_offset_t)ptvmmap, 1);
167 continue;
168
169/* minor device 1 is kernel memory */
170 case 1:
171 c = iov->iov_len;
172
173 /*
174 * Make sure that all of the pages are currently resident so
175 * that we don't create any zero-fill pages.
176 */
177 addr = trunc_page(uio->uio_offset);
178 eaddr = round_page(uio->uio_offset + c);
179
180 if (addr < (vm_offset_t)VADDR(PTDPTDI, 0))
181 return (EFAULT);
182 if (eaddr >= (vm_offset_t)VADDR(APTDPTDI, 0))
183 return (EFAULT);
184 for (; addr < eaddr; addr += PAGE_SIZE)
185 if (pmap_extract(kernel_pmap, addr) == 0)
186 return (EFAULT);
187
188 if (!kernacc((caddr_t)(int)uio->uio_offset, c,
189 uio->uio_rw == UIO_READ ?
190 VM_PROT_READ : VM_PROT_WRITE))
191 return (EFAULT);
192 error = uiomove((caddr_t)(int)uio->uio_offset, (int)c, uio);
193 continue;
194
195 default:
196 return (ENODEV);
197 }
198
199 if (error)
200 break;
201 iov->iov_base = (char *)iov->iov_base + c;
202 iov->iov_len -= c;
203 uio->uio_offset += c;
204 uio->uio_resid -= c;
205 }
206 return (error);
207}
208
209/*******************************************************\
210* allow user processes to MMAP some memory sections *
211* instead of going through read/write *
212\*******************************************************/
213static int
214memmmap(dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int prot)
215{
216 switch (minor(dev))
217 {
218
219 /* minor device 0 is physical memory */
220 case 0:
221 *paddr = offset;
222 break;
223
224 /* minor device 1 is kernel memory */
225 case 1:
226 *paddr = vtophys(offset);
227 break;
228
229 default:
230 return (-1);
231 }
232 return (0);
233}
234
235/*
236 * Operations for changing memory attributes.
237 *
238 * This is basically just an ioctl shim for mem_range_attr_get
239 * and mem_range_attr_set.
240 */
241static int
242mmioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct thread *td)
243{
244 int nd, error = 0;
245 struct mem_range_op *mo = (struct mem_range_op *)data;
246 struct mem_range_desc *md;
247
248 /* is this for us? */
249 if ((cmd != MEMRANGE_GET) &&
250 (cmd != MEMRANGE_SET))
251 return (ENOTTY);
252
253 /* any chance we can handle this? */
254 if (mem_range_softc.mr_op == NULL)
255 return (EOPNOTSUPP);
256
257 /* do we have any descriptors? */
258 if (mem_range_softc.mr_ndesc == 0)
259 return (ENXIO);
260
261 switch (cmd) {
262 case MEMRANGE_GET:
263 nd = imin(mo->mo_arg[0], mem_range_softc.mr_ndesc);
264 if (nd > 0) {
265 md = (struct mem_range_desc *)
266 malloc(nd * sizeof(struct mem_range_desc),
267 M_MEMDESC, M_WAITOK);
268 error = mem_range_attr_get(md, &nd);
269 if (!error)
270 error = copyout(md, mo->mo_desc,
271 nd * sizeof(struct mem_range_desc));
272 free(md, M_MEMDESC);
273 }
274 else
275 nd = mem_range_softc.mr_ndesc;
276 mo->mo_arg[0] = nd;
277 break;
278
279 case MEMRANGE_SET:
280 md = (struct mem_range_desc *)malloc(sizeof(struct mem_range_desc),
281 M_MEMDESC, M_WAITOK);
282 error = copyin(mo->mo_desc, md, sizeof(struct mem_range_desc));
283 /* clamp description string */
284 md->mr_owner[sizeof(md->mr_owner) - 1] = 0;
285 if (error == 0)
286 error = mem_range_attr_set(md, &mo->mo_arg[0]);
287 free(md, M_MEMDESC);
288 break;
289 }
290 return (error);
291}
292
293/*
294 * Implementation-neutral, kernel-callable functions for manipulating
295 * memory range attributes.
296 */
297int
298mem_range_attr_get(struct mem_range_desc *mrd, int *arg)
299{
300 /* can we handle this? */
301 if (mem_range_softc.mr_op == NULL)
302 return (EOPNOTSUPP);
303
304 if (*arg == 0)
305 *arg = mem_range_softc.mr_ndesc;
306 else
307 bcopy(mem_range_softc.mr_desc, mrd,
308 (*arg) * sizeof(struct mem_range_desc));
309 return (0);
310}
311
312int
313mem_range_attr_set(struct mem_range_desc *mrd, int *arg)
314{
315 /* can we handle this? */
316 if (mem_range_softc.mr_op == NULL)
317 return (EOPNOTSUPP);
318
319 return (mem_range_softc.mr_op->set(&mem_range_softc, mrd, arg));
320}
321
322#ifdef SMP
323void
324mem_range_AP_init(void)
325{
326 if (mem_range_softc.mr_op && mem_range_softc.mr_op->initAP)
327 (mem_range_softc.mr_op->initAP(&mem_range_softc));
328}
329#endif
330
331static int
332mem_modevent(module_t mod, int type, void *data)
333{
334 switch(type) {
335 case MOD_LOAD:
336 if (bootverbose)
337 printf("mem: <memory & I/O>\n");
338 /* Initialise memory range handling */
339 if (mem_range_softc.mr_op != NULL)
340 mem_range_softc.mr_op->init(&mem_range_softc);
341
342 memdev = make_dev(&mem_cdevsw, 0, UID_ROOT, GID_KMEM,
343 0640, "mem");
344 kmemdev = make_dev(&mem_cdevsw, 1, UID_ROOT, GID_KMEM,
345 0640, "kmem");
346 iodev = make_dev(&mem_cdevsw, 14, UID_ROOT, GID_WHEEL,
347 0600, "io");
348 return (0);
349
350 case MOD_UNLOAD:
351 destroy_dev(memdev);
352 destroy_dev(kmemdev);
353 destroy_dev(iodev);
354 return (0);
355
356 case MOD_SHUTDOWN:
357 return (0);
358
359 default:
360 return (EOPNOTSUPP);
361 }
362}
363
364DEV_MODULE(mem, mem_modevent, NULL);