FreeBSD/Linux Kernel Cross Reference
sys/i386/i386/mem.c
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$
42 */
43
44 /*
45 * Memory special file
46 */
47
48 #include "opt_devfs.h"
49 #include "opt_perfmon.h"
50
51 #include <sys/param.h>
52 #include <sys/conf.h>
53 #include <sys/buf.h>
54 #ifdef DEVFS
55 #include <sys/devfsext.h>
56 #endif /* DEVFS */
57 #include <sys/kernel.h>
58 #include <sys/systm.h>
59 #include <sys/uio.h>
60 #include <sys/malloc.h>
61 #include <sys/memrange.h>
62 #include <sys/proc.h>
63 #include <sys/signalvar.h>
64
65 #include <machine/frame.h>
66 #include <machine/random.h>
67 #include <machine/psl.h>
68 #ifdef PERFMON
69 #include <machine/perfmon.h>
70 #endif
71 #include <i386/isa/intr_machdep.h>
72
73 #include <vm/vm.h>
74 #include <vm/vm_prot.h>
75 #include <vm/pmap.h>
76 #include <vm/vm_extern.h>
77
78
79
80 static d_open_t mmopen;
81 static d_close_t mmclose;
82 static d_read_t mmrw;
83 static d_ioctl_t mmioctl;
84 static d_mmap_t memmmap;
85 static d_poll_t mmpoll;
86
87 #define CDEV_MAJOR 2
88 static struct cdevsw mem_cdevsw =
89 { mmopen, mmclose, mmrw, mmrw, /*2*/
90 mmioctl, nullstop, nullreset, nodevtotty,/* memory */
91 mmpoll, memmmap, NULL, "mem", NULL, -1 };
92
93 static struct random_softc random_softc[16];
94 static caddr_t zbuf;
95
96 MALLOC_DEFINE(M_MEMDESC, "memdesc", "memory range descriptors");
97 static int mem_ioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
98 static int random_ioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
99
100 struct mem_range_softc mem_range_softc;
101
102 #ifdef DEVFS
103 static void *mem_devfs_token;
104 static void *kmem_devfs_token;
105 static void *null_devfs_token;
106 static void *random_devfs_token;
107 static void *urandom_devfs_token;
108 static void *zero_devfs_token;
109 static void *io_devfs_token;
110 #ifdef PERFMON
111 static void *perfmon_devfs_token;
112 #endif
113
114 static void memdevfs_init __P((void));
115
116 static void
117 memdevfs_init()
118 {
119 mem_devfs_token =
120 devfs_add_devswf(&mem_cdevsw, 0, DV_CHR,
121 UID_ROOT, GID_KMEM, 0640, "mem");
122 kmem_devfs_token =
123 devfs_add_devswf(&mem_cdevsw, 1, DV_CHR,
124 UID_ROOT, GID_KMEM, 0640, "kmem");
125 null_devfs_token =
126 devfs_add_devswf(&mem_cdevsw, 2, DV_CHR,
127 UID_ROOT, GID_WHEEL, 0666, "null");
128 random_devfs_token =
129 devfs_add_devswf(&mem_cdevsw, 3, DV_CHR,
130 UID_ROOT, GID_WHEEL, 0644, "random");
131 urandom_devfs_token =
132 devfs_add_devswf(&mem_cdevsw, 4, DV_CHR,
133 UID_ROOT, GID_WHEEL, 0644, "urandom");
134 zero_devfs_token =
135 devfs_add_devswf(&mem_cdevsw, 12, DV_CHR,
136 UID_ROOT, GID_WHEEL, 0666, "zero");
137 io_devfs_token =
138 devfs_add_devswf(&mem_cdevsw, 14, DV_CHR,
139 UID_ROOT, GID_WHEEL, 0600, "io");
140 #ifdef PERFMON
141 perfmon_devfs_token =
142 devfs_add_devswf(&mem_cdevsw, 32, DV_CHR,
143 UID_ROOT, GID_KMEM, 0640, "perfmon");
144 #endif /* PERFMON */
145 }
146 #endif /* DEVFS */
147
148 static int
149 mmclose(dev, flags, fmt, p)
150 dev_t dev;
151 int flags;
152 int fmt;
153 struct proc *p;
154 {
155 switch (minor(dev)) {
156 #ifdef PERFMON
157 case 32:
158 return perfmon_close(dev, flags, fmt, p);
159 #endif
160 case 14:
161 curproc->p_md.md_regs->tf_eflags &= ~PSL_IOPL;
162 break;
163 default:
164 break;
165 }
166 return(0);
167 }
168
169 static int
170 mmopen(dev, flags, fmt, p)
171 dev_t dev;
172 int flags;
173 int fmt;
174 struct proc *p;
175 {
176 int error;
177
178 switch (minor(dev)) {
179 case 32:
180 #ifdef PERFMON
181 return perfmon_open(dev, flags, fmt, p);
182 #else
183 return ENODEV;
184 #endif
185 case 14:
186 error = suser(p->p_ucred, &p->p_acflag);
187 if (error != 0)
188 return (error);
189 if (securelevel > 0)
190 return (EPERM);
191 curproc->p_md.md_regs->tf_eflags |= PSL_IOPL;
192 break;
193 default:
194 break;
195 }
196 return(0);
197 }
198
199 static int
200 mmrw(dev, uio, flags)
201 dev_t dev;
202 struct uio *uio;
203 int flags;
204 {
205 register int o;
206 register u_int c, v;
207 u_int poolsize;
208 register struct iovec *iov;
209 int error = 0;
210 caddr_t buf = NULL;
211
212 while (uio->uio_resid > 0 && error == 0) {
213 iov = uio->uio_iov;
214 if (iov->iov_len == 0) {
215 uio->uio_iov++;
216 uio->uio_iovcnt--;
217 if (uio->uio_iovcnt < 0)
218 panic("mmrw");
219 continue;
220 }
221 switch (minor(dev)) {
222
223 /* minor device 0 is physical memory */
224 case 0:
225 v = uio->uio_offset;
226 pmap_enter(kernel_pmap, (vm_offset_t)ptvmmap, v,
227 uio->uio_rw == UIO_READ ? VM_PROT_READ : VM_PROT_WRITE,
228 TRUE);
229 o = (int)uio->uio_offset & PAGE_MASK;
230 c = (u_int)(PAGE_SIZE - ((int)iov->iov_base & PAGE_MASK));
231 c = min(c, (u_int)(PAGE_SIZE - o));
232 c = min(c, (u_int)iov->iov_len);
233 error = uiomove((caddr_t)&ptvmmap[o], (int)c, uio);
234 pmap_remove(kernel_pmap, (vm_offset_t)ptvmmap,
235 (vm_offset_t)&ptvmmap[PAGE_SIZE]);
236 continue;
237
238 /* minor device 1 is kernel memory */
239 case 1: {
240 vm_offset_t addr, eaddr;
241 c = iov->iov_len;
242
243 /*
244 * Make sure that all of the pages are currently resident so
245 * that we don't create any zero-fill pages.
246 */
247 addr = trunc_page(uio->uio_offset);
248 eaddr = round_page(uio->uio_offset + c);
249
250 if (addr < (vm_offset_t)VADDR(PTDPTDI, 0))
251 return EFAULT;
252 if (eaddr >= (vm_offset_t)VADDR(APTDPTDI, 0))
253 return EFAULT;
254 for (; addr < eaddr; addr += PAGE_SIZE)
255 if (pmap_extract(kernel_pmap, addr) == 0)
256 return EFAULT;
257
258 if (!kernacc((caddr_t)(int)uio->uio_offset, c,
259 uio->uio_rw == UIO_READ ? B_READ : B_WRITE))
260 return(EFAULT);
261 error = uiomove((caddr_t)(int)uio->uio_offset, (int)c, uio);
262 continue;
263 }
264
265 /* minor device 2 is EOF/RATHOLE */
266 case 2:
267 if (uio->uio_rw == UIO_READ)
268 return (0);
269 c = iov->iov_len;
270 break;
271
272 /* minor device 3 (/dev/random) is source of filth on read, rathole on write */
273 case 3:
274 if (uio->uio_rw == UIO_WRITE) {
275 c = iov->iov_len;
276 break;
277 }
278 if (buf == NULL)
279 buf = (caddr_t)
280 malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
281 c = min(iov->iov_len, PAGE_SIZE);
282 poolsize = read_random(buf, c);
283 if (poolsize == 0) {
284 if (buf)
285 free(buf, M_TEMP);
286 return (0);
287 }
288 c = min(c, poolsize);
289 error = uiomove(buf, (int)c, uio);
290 continue;
291
292 /* minor device 4 (/dev/urandom) is source of muck on read, rathole on write */
293 case 4:
294 if (uio->uio_rw == UIO_WRITE) {
295 c = iov->iov_len;
296 break;
297 }
298 if (CURSIG(curproc) != 0) {
299 /*
300 * Use tsleep() to get the error code right.
301 * It should return immediately.
302 */
303 error = tsleep(&random_softc[0],
304 PZERO | PCATCH, "urand", 1);
305 if (error != 0 && error != EWOULDBLOCK)
306 continue;
307 }
308 if (buf == NULL)
309 buf = (caddr_t)
310 malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
311 c = min(iov->iov_len, PAGE_SIZE);
312 poolsize = read_random_unlimited(buf, c);
313 c = min(c, poolsize);
314 error = uiomove(buf, (int)c, uio);
315 continue;
316
317 /* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */
318 case 12:
319 if (uio->uio_rw == UIO_WRITE) {
320 c = iov->iov_len;
321 break;
322 }
323 if (zbuf == NULL) {
324 zbuf = (caddr_t)
325 malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
326 bzero(zbuf, PAGE_SIZE);
327 }
328 c = min(iov->iov_len, PAGE_SIZE);
329 error = uiomove(zbuf, (int)c, uio);
330 continue;
331
332 #ifdef notyet
333 /* 386 I/O address space (/dev/ioport[bwl]) is a read/write access to seperate
334 i/o device address bus, different than memory bus. Semantics here are
335 very different than ordinary read/write, as if iov_len is a multiple
336 an implied string move from a single port will be done. Note that lseek
337 must be used to set the port number reliably. */
338 case 14:
339 if (iov->iov_len == 1) {
340 u_char tmp;
341 tmp = inb(uio->uio_offset);
342 error = uiomove (&tmp, iov->iov_len, uio);
343 } else {
344 if (!useracc((caddr_t)iov->iov_base,
345 iov->iov_len, uio->uio_rw))
346 return (EFAULT);
347 insb(uio->uio_offset, iov->iov_base,
348 iov->iov_len);
349 }
350 break;
351 case 15:
352 if (iov->iov_len == sizeof (short)) {
353 u_short tmp;
354 tmp = inw(uio->uio_offset);
355 error = uiomove (&tmp, iov->iov_len, uio);
356 } else {
357 if (!useracc((caddr_t)iov->iov_base,
358 iov->iov_len, uio->uio_rw))
359 return (EFAULT);
360 insw(uio->uio_offset, iov->iov_base,
361 iov->iov_len/ sizeof (short));
362 }
363 break;
364 case 16:
365 if (iov->iov_len == sizeof (long)) {
366 u_long tmp;
367 tmp = inl(uio->uio_offset);
368 error = uiomove (&tmp, iov->iov_len, uio);
369 } else {
370 if (!useracc((caddr_t)iov->iov_base,
371 iov->iov_len, uio->uio_rw))
372 return (EFAULT);
373 insl(uio->uio_offset, iov->iov_base,
374 iov->iov_len/ sizeof (long));
375 }
376 break;
377 #endif
378
379 default:
380 return (ENXIO);
381 }
382 if (error)
383 break;
384 iov->iov_base += c;
385 iov->iov_len -= c;
386 uio->uio_offset += c;
387 uio->uio_resid -= c;
388 }
389 if (buf)
390 free(buf, M_TEMP);
391 return (error);
392 }
393
394
395
396
397 /*******************************************************\
398 * allow user processes to MMAP some memory sections *
399 * instead of going through read/write *
400 \*******************************************************/
401 static int
402 memmmap(dev_t dev, vm_offset_t offset, int nprot)
403 {
404 switch (minor(dev))
405 {
406
407 /* minor device 0 is physical memory */
408 case 0:
409 return i386_btop(offset);
410
411 /* minor device 1 is kernel memory */
412 case 1:
413 return i386_btop(vtophys(offset));
414
415 default:
416 return -1;
417 }
418 }
419
420 static int
421 mmioctl(dev, cmd, data, flags, p)
422 dev_t dev;
423 u_long cmd;
424 caddr_t data;
425 int flags;
426 struct proc *p;
427 {
428 switch (minor(dev)) {
429 case 0:
430 return mem_ioctl(dev, cmd, data, flags, p);
431 case 3:
432 case 4:
433 return random_ioctl(dev, cmd, data, flags, p);
434 #ifdef PERFMON
435 case 32:
436 return perfmon_ioctl(dev, cmd, data, flags, p);
437 #endif
438 }
439 return (ENODEV);
440 }
441
442 /*
443 * Operations for changing memory attributes.
444 *
445 * This is basically just an ioctl shim for mem_range_attr_get
446 * and mem_range_attr_set.
447 */
448 static int
449 mem_ioctl(dev, cmd, data, flags, p)
450 dev_t dev;
451 u_long cmd;
452 caddr_t data;
453 int flags;
454 struct proc *p;
455 {
456 int nd, error = 0;
457 struct mem_range_op *mo = (struct mem_range_op *)data;
458 struct mem_range_desc *md;
459
460 /* is this for us? */
461 if ((cmd != MEMRANGE_GET) &&
462 (cmd != MEMRANGE_SET))
463 return(ENODEV);
464
465 /* any chance we can handle this? */
466 if (mem_range_softc.mr_op == NULL)
467 return(EOPNOTSUPP);
468
469 /* do we have any descriptors? */
470 if (mem_range_softc.mr_ndesc == 0)
471 return(ENXIO);
472
473 switch(cmd) {
474 case MEMRANGE_GET:
475 nd = imin(mo->mo_arg[0], mem_range_softc.mr_ndesc);
476 if (nd > 0) {
477 md = (struct mem_range_desc *)
478 malloc(nd * sizeof(struct mem_range_desc),
479 M_MEMDESC, M_WAITOK);
480 error = mem_range_attr_get(md, &nd);
481 if (!error)
482 error = copyout(md, mo->mo_desc,
483 nd * sizeof(struct mem_range_desc));
484 free(md, M_MEMDESC);
485 } else {
486 nd = mem_range_softc.mr_ndesc;
487 }
488 mo->mo_arg[0] = nd;
489 break;
490
491 case MEMRANGE_SET:
492 md = (struct mem_range_desc *)malloc(sizeof(struct mem_range_desc),
493 M_MEMDESC, M_WAITOK);
494 error = copyin(mo->mo_desc, md, sizeof(struct mem_range_desc));
495 /* clamp description string */
496 md->mr_owner[sizeof(md->mr_owner) - 1] = 0;
497 if (error == 0)
498 error = mem_range_attr_set(md, &mo->mo_arg[0]);
499 free(md, M_MEMDESC);
500 break;
501
502 default:
503 error = EOPNOTSUPP;
504 }
505 return(error);
506 }
507
508 /*
509 * Implementation-neutral, kernel-callable functions for manipulating
510 * memory range attributes.
511 */
512 int
513 mem_range_attr_get(mrd, arg)
514 struct mem_range_desc *mrd;
515 int *arg;
516 {
517 /* can we handle this? */
518 if (mem_range_softc.mr_op == NULL)
519 return(EOPNOTSUPP);
520
521 if (*arg == 0) {
522 *arg = mem_range_softc.mr_ndesc;
523 } else {
524 bcopy(mem_range_softc.mr_desc, mrd, (*arg) * sizeof(struct mem_range_desc));
525 }
526 return(0);
527 }
528
529 int
530 mem_range_attr_set(mrd, arg)
531 struct mem_range_desc *mrd;
532 int *arg;
533 {
534 /* can we handle this? */
535 if (mem_range_softc.mr_op == NULL)
536 return(EOPNOTSUPP);
537
538 return(mem_range_softc.mr_op->set(&mem_range_softc, mrd, arg));
539 }
540
541 #ifdef SMP
542 void
543 mem_range_AP_init(void)
544 {
545 if (mem_range_softc.mr_op && mem_range_softc.mr_op->initAP)
546 return(mem_range_softc.mr_op->initAP(&mem_range_softc));
547 }
548 #endif
549
550 static int
551 random_ioctl(dev, cmd, data, flags, p)
552 dev_t dev;
553 u_long cmd;
554 caddr_t data;
555 int flags;
556 struct proc *p;
557 {
558 static intrmask_t interrupt_allowed;
559 intrmask_t interrupt_mask;
560 int error, intr;
561 struct random_softc *sc;
562
563 /*
564 * We're the random or urandom device. The only ioctls are for
565 * selecting and inspecting which interrupts are used in the muck
566 * gathering business.
567 */
568 if (cmd != MEM_SETIRQ && cmd != MEM_CLEARIRQ && cmd != MEM_RETURNIRQ)
569 return (ENOTTY);
570
571 /*
572 * Even inspecting the state is privileged, since it gives a hint
573 * about how easily the randomness might be guessed.
574 */
575 error = suser(p->p_ucred, &p->p_acflag);
576 if (error != 0)
577 return (error);
578
579 /*
580 * XXX the data is 16-bit due to a historical botch, so we use
581 * magic 16's instead of ICU_LEN and can't support 24 interrupts
582 * under SMP.
583 */
584 intr = *(int16_t *)data;
585 if (cmd != MEM_RETURNIRQ && (intr < 0 || intr >= 16))
586 return (EINVAL);
587
588 interrupt_mask = 1 << intr;
589 sc = &random_softc[intr];
590 switch (cmd) {
591 case MEM_SETIRQ:
592 if (interrupt_allowed & interrupt_mask)
593 break;
594 interrupt_allowed |= interrupt_mask;
595 sc->sc_intr = intr;
596 disable_intr();
597 sc->sc_handler = intr_handler[intr];
598 intr_handler[intr] = add_interrupt_randomness;
599 sc->sc_arg = intr_unit[intr];
600 intr_unit[intr] = sc;
601 enable_intr();
602 break;
603 case MEM_CLEARIRQ:
604 if (!(interrupt_allowed & interrupt_mask))
605 break;
606 interrupt_allowed &= ~interrupt_mask;
607 disable_intr();
608 intr_handler[intr] = sc->sc_handler;
609 intr_unit[intr] = sc->sc_arg;
610 enable_intr();
611 break;
612 case MEM_RETURNIRQ:
613 *(u_int16_t *)data = interrupt_allowed;
614 break;
615 default:
616 return (ENOTTY);
617 }
618 return (0);
619 }
620
621 int
622 mmpoll(dev, events, p)
623 dev_t dev;
624 int events;
625 struct proc *p;
626 {
627 switch (minor(dev)) {
628 case 3: /* /dev/random */
629 return random_poll(dev, events, p);
630 case 4: /* /dev/urandom */
631 default:
632 return seltrue(dev, events, p);
633 }
634 }
635
636 /*
637 * Routine that identifies /dev/mem and /dev/kmem.
638 *
639 * A minimal stub routine can always return 0.
640 */
641 int
642 iskmemdev(dev)
643 dev_t dev;
644 {
645
646 return ((major(dev) == mem_cdevsw.d_maj)
647 && (minor(dev) == 0 || minor(dev) == 1));
648 }
649
650 int
651 iszerodev(dev)
652 dev_t dev;
653 {
654 return ((major(dev) == mem_cdevsw.d_maj)
655 && minor(dev) == 12);
656 }
657
658
659
660 static int mem_devsw_installed;
661
662 static void
663 mem_drvinit(void *unused)
664 {
665 dev_t dev;
666
667 /* Initialise memory range handling */
668 if (mem_range_softc.mr_op != NULL)
669 mem_range_softc.mr_op->init(&mem_range_softc);
670
671 if( ! mem_devsw_installed ) {
672 dev = makedev(CDEV_MAJOR, 0);
673 cdevsw_add(&dev,&mem_cdevsw, NULL);
674 mem_devsw_installed = 1;
675 #ifdef DEVFS
676 memdevfs_init();
677 #endif
678 }
679 }
680
681 SYSINIT(memdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,mem_drvinit,NULL)
682
Cache object: df74b6826aab2ac4ce9b904904292d7a
|