15b81b6b3SRodney W. Grimes /*- 25b81b6b3SRodney W. Grimes * Copyright (c) 1988 University of Utah. 35b81b6b3SRodney W. Grimes * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 45b81b6b3SRodney W. Grimes * All rights reserved. 55b81b6b3SRodney W. Grimes * 65b81b6b3SRodney W. Grimes * This code is derived from software contributed to Berkeley by 75b81b6b3SRodney W. Grimes * the Systems Programming Group of the University of Utah Computer 85b81b6b3SRodney W. Grimes * Science Department, and code derived from software contributed to 95b81b6b3SRodney W. Grimes * Berkeley by William Jolitz. 105b81b6b3SRodney W. Grimes * 115b81b6b3SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 125b81b6b3SRodney W. Grimes * modification, are permitted provided that the following conditions 135b81b6b3SRodney W. Grimes * are met: 145b81b6b3SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 155b81b6b3SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 165b81b6b3SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 175b81b6b3SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 185b81b6b3SRodney W. Grimes * documentation and/or other materials provided with the distribution. 195b81b6b3SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 205b81b6b3SRodney W. Grimes * must display the following acknowledgement: 215b81b6b3SRodney W. Grimes * This product includes software developed by the University of 225b81b6b3SRodney W. Grimes * California, Berkeley and its contributors. 235b81b6b3SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 245b81b6b3SRodney W. Grimes * may be used to endorse or promote products derived from this software 255b81b6b3SRodney W. Grimes * without specific prior written permission. 265b81b6b3SRodney W. Grimes * 275b81b6b3SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 285b81b6b3SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 295b81b6b3SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 305b81b6b3SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 315b81b6b3SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 325b81b6b3SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 335b81b6b3SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 345b81b6b3SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 355b81b6b3SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 365b81b6b3SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 375b81b6b3SRodney W. Grimes * SUCH DAMAGE. 385b81b6b3SRodney W. Grimes * 395b81b6b3SRodney W. Grimes * from: Utah $Hdr: mem.c 1.13 89/10/08$ 4047cacd38SRodney W. Grimes * from: @(#)mem.c 7.2 (Berkeley) 5/9/91 41bb25f0ddSBruce Evans * $Id: mem.c,v 1.53 1998/11/08 12:39:01 dfr Exp $ 425b81b6b3SRodney W. Grimes */ 435b81b6b3SRodney W. Grimes 445b81b6b3SRodney W. Grimes /* 455b81b6b3SRodney W. Grimes * Memory special file 465b81b6b3SRodney W. Grimes */ 475b81b6b3SRodney W. Grimes 487b778b5eSEivind Eklund #include "opt_devfs.h" 49d69e8502SGarrett Wollman #include "opt_perfmon.h" 50d69e8502SGarrett Wollman 5126f9a767SRodney W. Grimes #include <sys/param.h> 5226f9a767SRodney W. Grimes #include <sys/conf.h> 5326f9a767SRodney W. Grimes #include <sys/buf.h> 5487f6c662SJulian Elischer #ifdef DEVFS 5587f6c662SJulian Elischer #include <sys/devfsext.h> 5687f6c662SJulian Elischer #endif /* DEVFS */ 5787f6c662SJulian Elischer #include <sys/kernel.h> 5826f9a767SRodney W. Grimes #include <sys/systm.h> 5926f9a767SRodney W. Grimes #include <sys/uio.h> 6026f9a767SRodney W. Grimes #include <sys/malloc.h> 6126f9a767SRodney W. Grimes #include <sys/proc.h> 62bb25f0ddSBruce Evans #include <sys/signalvar.h> 635b81b6b3SRodney W. Grimes 64d1d9d260SBruce Evans #include <machine/frame.h> 6500f7f6beSBruce Evans #include <machine/random.h> 6626f9a767SRodney W. Grimes #include <machine/psl.h> 67d69e8502SGarrett Wollman #ifdef PERFMON 68d69e8502SGarrett Wollman #include <machine/perfmon.h> 69d69e8502SGarrett Wollman #endif 7068352337SDoug Rabson #include <i386/isa/intr_machdep.h> 715b81b6b3SRodney W. Grimes 72c87801feSDavid Greenman #include <vm/vm.h> 7326f9a767SRodney W. Grimes #include <vm/vm_prot.h> 7426f9a767SRodney W. Grimes #include <vm/pmap.h> 75efeaf95aSDavid Greenman #include <vm/vm_extern.h> 765b81b6b3SRodney W. Grimes 7787f6c662SJulian Elischer 7887f6c662SJulian Elischer 7987f6c662SJulian Elischer static d_open_t mmopen; 8087f6c662SJulian Elischer static d_close_t mmclose; 81c73feca0SBruce Evans static d_read_t mmrw; 8287f6c662SJulian Elischer static d_ioctl_t mmioctl; 8387f6c662SJulian Elischer static d_mmap_t memmmap; 8435b8b2ddSPeter Wemm static d_poll_t mmpoll; 8587f6c662SJulian Elischer 8653ac6efbSJulian Elischer #define CDEV_MAJOR 2 87d2f265faSPoul-Henning Kamp static struct cdevsw mem_cdevsw = 8887f6c662SJulian Elischer { mmopen, mmclose, mmrw, mmrw, /*2*/ 8987f6c662SJulian Elischer mmioctl, nullstop, nullreset, nodevtotty,/* memory */ 9035b8b2ddSPeter Wemm mmpoll, memmmap, NULL, "mem", NULL, -1 }; 9153ac6efbSJulian Elischer 92316bbd5cSBruce Evans static struct random_softc random_softc[16]; 9320073b6dSNate Williams static caddr_t zbuf; 9420073b6dSNate Williams 958af5d536SJulian Elischer #ifdef DEVFS 9687f6c662SJulian Elischer static void *mem_devfs_token; 9787f6c662SJulian Elischer static void *kmem_devfs_token; 9887f6c662SJulian Elischer static void *null_devfs_token; 9987f6c662SJulian Elischer static void *random_devfs_token; 10087f6c662SJulian Elischer static void *urandom_devfs_token; 10187f6c662SJulian Elischer static void *zero_devfs_token; 10287f6c662SJulian Elischer static void *io_devfs_token; 103d69e8502SGarrett Wollman #ifdef PERFMON 104d69e8502SGarrett Wollman static void *perfmon_devfs_token; 105d69e8502SGarrett Wollman #endif 10633f538b9SBruce Evans 107f3fcde03SBruce Evans static void memdevfs_init __P((void)); 108f3fcde03SBruce Evans 10933f538b9SBruce Evans static void 11087f6c662SJulian Elischer memdevfs_init() 1118af5d536SJulian Elischer { 112f28213adSMarc G. Fournier mem_devfs_token = 113f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 0, DV_CHR, 114f28213adSMarc G. Fournier UID_ROOT, GID_KMEM, 0640, "mem"); 115f28213adSMarc G. Fournier kmem_devfs_token = 116f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 1, DV_CHR, 117f28213adSMarc G. Fournier UID_ROOT, GID_KMEM, 0640, "kmem"); 118f28213adSMarc G. Fournier null_devfs_token = 119f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 2, DV_CHR, 120f28213adSMarc G. Fournier UID_ROOT, GID_WHEEL, 0666, "null"); 121f28213adSMarc G. Fournier random_devfs_token = 122f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 3, DV_CHR, 123f28213adSMarc G. Fournier UID_ROOT, GID_WHEEL, 0644, "random"); 124f28213adSMarc G. Fournier urandom_devfs_token = 125f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 4, DV_CHR, 126f28213adSMarc G. Fournier UID_ROOT, GID_WHEEL, 0644, "urandom"); 127f28213adSMarc G. Fournier zero_devfs_token = 128f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 12, DV_CHR, 129f28213adSMarc G. Fournier UID_ROOT, GID_WHEEL, 0666, "zero"); 130f28213adSMarc G. Fournier io_devfs_token = 131f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 14, DV_CHR, 1325e0f6c43SBruce Evans UID_ROOT, GID_WHEEL, 0600, "io"); 133d69e8502SGarrett Wollman #ifdef PERFMON 134f28213adSMarc G. Fournier perfmon_devfs_token = 135f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 32, DV_CHR, 136f28213adSMarc G. Fournier UID_ROOT, GID_KMEM, 0640, "perfmon"); 137d69e8502SGarrett Wollman #endif /* PERFMON */ 1388af5d536SJulian Elischer } 1398af5d536SJulian Elischer #endif /* DEVFS */ 1408af5d536SJulian Elischer 14187f6c662SJulian Elischer static int 14260039670SBruce Evans mmclose(dev, flags, fmt, p) 14378d172caSRodney W. Grimes dev_t dev; 14478d172caSRodney W. Grimes int flags; 14560039670SBruce Evans int fmt; 14660039670SBruce Evans struct proc *p; 14778d172caSRodney W. Grimes { 14878d172caSRodney W. Grimes switch (minor(dev)) { 149d69e8502SGarrett Wollman #ifdef PERFMON 150d69e8502SGarrett Wollman case 32: 151d69e8502SGarrett Wollman return perfmon_close(dev, flags, fmt, p); 152d69e8502SGarrett Wollman #endif 15378d172caSRodney W. Grimes case 14: 15436428e61SPeter Wemm curproc->p_md.md_regs->tf_eflags &= ~PSL_IOPL; 15578d172caSRodney W. Grimes break; 15678d172caSRodney W. Grimes default: 15778d172caSRodney W. Grimes break; 15878d172caSRodney W. Grimes } 15978d172caSRodney W. Grimes return(0); 16078d172caSRodney W. Grimes } 16133f538b9SBruce Evans 16287f6c662SJulian Elischer static int 16360039670SBruce Evans mmopen(dev, flags, fmt, p) 16478d172caSRodney W. Grimes dev_t dev; 16578d172caSRodney W. Grimes int flags; 16660039670SBruce Evans int fmt; 16760039670SBruce Evans struct proc *p; 16878d172caSRodney W. Grimes { 169da3df630SBruce Evans int error; 17078d172caSRodney W. Grimes 17178d172caSRodney W. Grimes switch (minor(dev)) { 172d69e8502SGarrett Wollman case 32: 173d69e8502SGarrett Wollman #ifdef PERFMON 174d69e8502SGarrett Wollman return perfmon_open(dev, flags, fmt, p); 175d69e8502SGarrett Wollman #else 176d69e8502SGarrett Wollman return ENODEV; 177d69e8502SGarrett Wollman #endif 17878d172caSRodney W. Grimes case 14: 179da3df630SBruce Evans error = suser(p->p_ucred, &p->p_acflag); 180da3df630SBruce Evans if (error != 0) 181da3df630SBruce Evans return (error); 182da3df630SBruce Evans if (securelevel > 0) 183da3df630SBruce Evans return (EPERM); 18436428e61SPeter Wemm curproc->p_md.md_regs->tf_eflags |= PSL_IOPL; 18578d172caSRodney W. Grimes break; 18678d172caSRodney W. Grimes default: 18778d172caSRodney W. Grimes break; 18878d172caSRodney W. Grimes } 18978d172caSRodney W. Grimes return(0); 19078d172caSRodney W. Grimes } 19133f538b9SBruce Evans 19287f6c662SJulian Elischer static int 1935b81b6b3SRodney W. Grimes mmrw(dev, uio, flags) 1945b81b6b3SRodney W. Grimes dev_t dev; 1955b81b6b3SRodney W. Grimes struct uio *uio; 1965b81b6b3SRodney W. Grimes int flags; 1975b81b6b3SRodney W. Grimes { 1985b81b6b3SRodney W. Grimes register int o; 1995b81b6b3SRodney W. Grimes register u_int c, v; 2001bb2d314SMark Murray u_int poolsize; 2015b81b6b3SRodney W. Grimes register struct iovec *iov; 2025b81b6b3SRodney W. Grimes int error = 0; 2031bb2d314SMark Murray caddr_t buf = NULL; 2045b81b6b3SRodney W. Grimes 2055b81b6b3SRodney W. Grimes while (uio->uio_resid > 0 && error == 0) { 2065b81b6b3SRodney W. Grimes iov = uio->uio_iov; 2075b81b6b3SRodney W. Grimes if (iov->iov_len == 0) { 2085b81b6b3SRodney W. Grimes uio->uio_iov++; 2095b81b6b3SRodney W. Grimes uio->uio_iovcnt--; 2105b81b6b3SRodney W. Grimes if (uio->uio_iovcnt < 0) 2115b81b6b3SRodney W. Grimes panic("mmrw"); 2125b81b6b3SRodney W. Grimes continue; 2135b81b6b3SRodney W. Grimes } 2145b81b6b3SRodney W. Grimes switch (minor(dev)) { 2155b81b6b3SRodney W. Grimes 2165b81b6b3SRodney W. Grimes /* minor device 0 is physical memory */ 2175b81b6b3SRodney W. Grimes case 0: 2185b81b6b3SRodney W. Grimes v = uio->uio_offset; 21926f9a767SRodney W. Grimes pmap_enter(kernel_pmap, (vm_offset_t)ptvmmap, v, 2205b81b6b3SRodney W. Grimes uio->uio_rw == UIO_READ ? VM_PROT_READ : VM_PROT_WRITE, 2215b81b6b3SRodney W. Grimes TRUE); 222f8845af0SPoul-Henning Kamp o = (int)uio->uio_offset & PAGE_MASK; 223f8845af0SPoul-Henning Kamp c = (u_int)(PAGE_SIZE - ((int)iov->iov_base & PAGE_MASK)); 224f8845af0SPoul-Henning Kamp c = min(c, (u_int)(PAGE_SIZE - o)); 22526f9a767SRodney W. Grimes c = min(c, (u_int)iov->iov_len); 22626f9a767SRodney W. Grimes error = uiomove((caddr_t)&ptvmmap[o], (int)c, uio); 22726f9a767SRodney W. Grimes pmap_remove(kernel_pmap, (vm_offset_t)ptvmmap, 228f8845af0SPoul-Henning Kamp (vm_offset_t)&ptvmmap[PAGE_SIZE]); 2295b81b6b3SRodney W. Grimes continue; 2305b81b6b3SRodney W. Grimes 2315b81b6b3SRodney W. Grimes /* minor device 1 is kernel memory */ 23297e11262SDavid Greenman case 1: { 23397e11262SDavid Greenman vm_offset_t addr, eaddr; 2345b81b6b3SRodney W. Grimes c = iov->iov_len; 23597e11262SDavid Greenman 23697e11262SDavid Greenman /* 23797e11262SDavid Greenman * Make sure that all of the pages are currently resident so 23897e11262SDavid Greenman * that we don't create any zero-fill pages. 23997e11262SDavid Greenman */ 24097e11262SDavid Greenman addr = trunc_page(uio->uio_offset); 2410704324aSDavid Greenman eaddr = round_page(uio->uio_offset + c); 242d021fc11SPeter Wemm 243d021fc11SPeter Wemm if (addr < (vm_offset_t)VADDR(PTDPTDI, 0)) 244d021fc11SPeter Wemm return EFAULT; 245d021fc11SPeter Wemm if (eaddr >= (vm_offset_t)VADDR(APTDPTDI, 0)) 246d021fc11SPeter Wemm return EFAULT; 24797e11262SDavid Greenman for (; addr < eaddr; addr += PAGE_SIZE) 24897e11262SDavid Greenman if (pmap_extract(kernel_pmap, addr) == 0) 24997e11262SDavid Greenman return EFAULT; 25097e11262SDavid Greenman 25126f9a767SRodney W. Grimes if (!kernacc((caddr_t)(int)uio->uio_offset, c, 2525b81b6b3SRodney W. Grimes uio->uio_rw == UIO_READ ? B_READ : B_WRITE)) 2535b81b6b3SRodney W. Grimes return(EFAULT); 25426f9a767SRodney W. Grimes error = uiomove((caddr_t)(int)uio->uio_offset, (int)c, uio); 2555b81b6b3SRodney W. Grimes continue; 25697e11262SDavid Greenman } 2575b81b6b3SRodney W. Grimes 2585b81b6b3SRodney W. Grimes /* minor device 2 is EOF/RATHOLE */ 2595b81b6b3SRodney W. Grimes case 2: 2605b81b6b3SRodney W. Grimes if (uio->uio_rw == UIO_READ) 2615b81b6b3SRodney W. Grimes return (0); 2625b81b6b3SRodney W. Grimes c = iov->iov_len; 2635b81b6b3SRodney W. Grimes break; 2645b81b6b3SRodney W. Grimes 2651bb2d314SMark Murray /* minor device 3 (/dev/random) is source of filth on read, rathole on write */ 2661bb2d314SMark Murray case 3: 2671bb2d314SMark Murray if (uio->uio_rw == UIO_WRITE) { 2681bb2d314SMark Murray c = iov->iov_len; 2691bb2d314SMark Murray break; 2701bb2d314SMark Murray } 2711bb2d314SMark Murray if (buf == NULL) 2721bb2d314SMark Murray buf = (caddr_t) 273f8845af0SPoul-Henning Kamp malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 274f8845af0SPoul-Henning Kamp c = min(iov->iov_len, PAGE_SIZE); 2751bb2d314SMark Murray poolsize = read_random(buf, c); 2761bb2d314SMark Murray if (poolsize == 0) { 2771bb2d314SMark Murray if (buf) 2781bb2d314SMark Murray free(buf, M_TEMP); 2791bb2d314SMark Murray return (0); 2801bb2d314SMark Murray } 2811bb2d314SMark Murray c = min(c, poolsize); 2821bb2d314SMark Murray error = uiomove(buf, (int)c, uio); 2831bb2d314SMark Murray continue; 2841bb2d314SMark Murray 2851bb2d314SMark Murray /* minor device 4 (/dev/urandom) is source of muck on read, rathole on write */ 2861bb2d314SMark Murray case 4: 2871bb2d314SMark Murray if (uio->uio_rw == UIO_WRITE) { 2881bb2d314SMark Murray c = iov->iov_len; 2891bb2d314SMark Murray break; 2901bb2d314SMark Murray } 291bb25f0ddSBruce Evans if (CURSIG(curproc) != 0) { 292bb25f0ddSBruce Evans /* 293bb25f0ddSBruce Evans * Use tsleep() to get the error code right. 294bb25f0ddSBruce Evans * It should return immediately. 295bb25f0ddSBruce Evans */ 296bb25f0ddSBruce Evans error = tsleep(&random_softc[0], 297bb25f0ddSBruce Evans PZERO | PCATCH, "urand", 1); 298bb25f0ddSBruce Evans if (error != 0 && error != EWOULDBLOCK) 299bb25f0ddSBruce Evans continue; 300bb25f0ddSBruce Evans } 3011bb2d314SMark Murray if (buf == NULL) 3021bb2d314SMark Murray buf = (caddr_t) 303f8845af0SPoul-Henning Kamp malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 304f8845af0SPoul-Henning Kamp c = min(iov->iov_len, PAGE_SIZE); 3051bb2d314SMark Murray poolsize = read_random_unlimited(buf, c); 3061bb2d314SMark Murray c = min(c, poolsize); 3071bb2d314SMark Murray error = uiomove(buf, (int)c, uio); 3081bb2d314SMark Murray continue; 3091bb2d314SMark Murray 3105b81b6b3SRodney W. Grimes /* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */ 3115b81b6b3SRodney W. Grimes case 12: 3125b81b6b3SRodney W. Grimes if (uio->uio_rw == UIO_WRITE) { 3135b81b6b3SRodney W. Grimes c = iov->iov_len; 3145b81b6b3SRodney W. Grimes break; 3155b81b6b3SRodney W. Grimes } 316f381a0c0SJohn Dyson if (zbuf == NULL) { 317f381a0c0SJohn Dyson zbuf = (caddr_t) 318f8845af0SPoul-Henning Kamp malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 319f381a0c0SJohn Dyson bzero(zbuf, PAGE_SIZE); 3205b81b6b3SRodney W. Grimes } 321f8845af0SPoul-Henning Kamp c = min(iov->iov_len, PAGE_SIZE); 322f381a0c0SJohn Dyson error = uiomove(zbuf, (int)c, uio); 3235b81b6b3SRodney W. Grimes continue; 3245b81b6b3SRodney W. Grimes 3255b81b6b3SRodney W. Grimes #ifdef notyet 3265b81b6b3SRodney W. Grimes /* 386 I/O address space (/dev/ioport[bwl]) is a read/write access to seperate 3275b81b6b3SRodney W. Grimes i/o device address bus, different than memory bus. Semantics here are 3285b81b6b3SRodney W. Grimes very different than ordinary read/write, as if iov_len is a multiple 3295b81b6b3SRodney W. Grimes an implied string move from a single port will be done. Note that lseek 3305b81b6b3SRodney W. Grimes must be used to set the port number reliably. */ 3315b81b6b3SRodney W. Grimes case 14: 3325b81b6b3SRodney W. Grimes if (iov->iov_len == 1) { 3335b81b6b3SRodney W. Grimes u_char tmp; 3345b81b6b3SRodney W. Grimes tmp = inb(uio->uio_offset); 3355b81b6b3SRodney W. Grimes error = uiomove (&tmp, iov->iov_len, uio); 3365b81b6b3SRodney W. Grimes } else { 3375b81b6b3SRodney W. Grimes if (!useracc((caddr_t)iov->iov_base, 3385b81b6b3SRodney W. Grimes iov->iov_len, uio->uio_rw)) 3395b81b6b3SRodney W. Grimes return (EFAULT); 3405b81b6b3SRodney W. Grimes insb(uio->uio_offset, iov->iov_base, 3415b81b6b3SRodney W. Grimes iov->iov_len); 3425b81b6b3SRodney W. Grimes } 3435b81b6b3SRodney W. Grimes break; 3445b81b6b3SRodney W. Grimes case 15: 3455b81b6b3SRodney W. Grimes if (iov->iov_len == sizeof (short)) { 3465b81b6b3SRodney W. Grimes u_short tmp; 3475b81b6b3SRodney W. Grimes tmp = inw(uio->uio_offset); 3485b81b6b3SRodney W. Grimes error = uiomove (&tmp, iov->iov_len, uio); 3495b81b6b3SRodney W. Grimes } else { 3505b81b6b3SRodney W. Grimes if (!useracc((caddr_t)iov->iov_base, 3515b81b6b3SRodney W. Grimes iov->iov_len, uio->uio_rw)) 3525b81b6b3SRodney W. Grimes return (EFAULT); 3535b81b6b3SRodney W. Grimes insw(uio->uio_offset, iov->iov_base, 3545b81b6b3SRodney W. Grimes iov->iov_len/ sizeof (short)); 3555b81b6b3SRodney W. Grimes } 3565b81b6b3SRodney W. Grimes break; 3575b81b6b3SRodney W. Grimes case 16: 3585b81b6b3SRodney W. Grimes if (iov->iov_len == sizeof (long)) { 3595b81b6b3SRodney W. Grimes u_long tmp; 3605b81b6b3SRodney W. Grimes tmp = inl(uio->uio_offset); 3615b81b6b3SRodney W. Grimes error = uiomove (&tmp, iov->iov_len, uio); 3625b81b6b3SRodney W. Grimes } else { 3635b81b6b3SRodney W. Grimes if (!useracc((caddr_t)iov->iov_base, 3645b81b6b3SRodney W. Grimes iov->iov_len, uio->uio_rw)) 3655b81b6b3SRodney W. Grimes return (EFAULT); 3665b81b6b3SRodney W. Grimes insl(uio->uio_offset, iov->iov_base, 3675b81b6b3SRodney W. Grimes iov->iov_len/ sizeof (long)); 3685b81b6b3SRodney W. Grimes } 3695b81b6b3SRodney W. Grimes break; 3705b81b6b3SRodney W. Grimes #endif 3715b81b6b3SRodney W. Grimes 3725b81b6b3SRodney W. Grimes default: 3735b81b6b3SRodney W. Grimes return (ENXIO); 3745b81b6b3SRodney W. Grimes } 3755b81b6b3SRodney W. Grimes if (error) 3765b81b6b3SRodney W. Grimes break; 3775b81b6b3SRodney W. Grimes iov->iov_base += c; 3785b81b6b3SRodney W. Grimes iov->iov_len -= c; 3795b81b6b3SRodney W. Grimes uio->uio_offset += c; 3805b81b6b3SRodney W. Grimes uio->uio_resid -= c; 3815b81b6b3SRodney W. Grimes } 3821bb2d314SMark Murray if (buf) 3831bb2d314SMark Murray free(buf, M_TEMP); 3845b81b6b3SRodney W. Grimes return (error); 3855b81b6b3SRodney W. Grimes } 386b513c262SDavid Greenman 387b513c262SDavid Greenman 388b513c262SDavid Greenman 389b513c262SDavid Greenman 390b513c262SDavid Greenman /*******************************************************\ 391b513c262SDavid Greenman * allow user processes to MMAP some memory sections * 392b513c262SDavid Greenman * instead of going through read/write * 393b513c262SDavid Greenman \*******************************************************/ 39487f6c662SJulian Elischer static int 3957095ee91SDoug Rabson memmmap(dev_t dev, vm_offset_t offset, int nprot) 396b513c262SDavid Greenman { 397b513c262SDavid Greenman switch (minor(dev)) 398b513c262SDavid Greenman { 399b513c262SDavid Greenman 400b513c262SDavid Greenman /* minor device 0 is physical memory */ 401b513c262SDavid Greenman case 0: 402b513c262SDavid Greenman return i386_btop(offset); 403b513c262SDavid Greenman 404b513c262SDavid Greenman /* minor device 1 is kernel memory */ 405b513c262SDavid Greenman case 1: 406b513c262SDavid Greenman return i386_btop(vtophys(offset)); 407b513c262SDavid Greenman 408b513c262SDavid Greenman default: 409b513c262SDavid Greenman return -1; 410b513c262SDavid Greenman } 411b513c262SDavid Greenman } 412b513c262SDavid Greenman 41387f6c662SJulian Elischer static int 414316bbd5cSBruce Evans mmioctl(dev, cmd, data, flags, p) 41500f7f6beSBruce Evans dev_t dev; 416ecbb00a2SDoug Rabson u_long cmd; 417316bbd5cSBruce Evans caddr_t data; 41800f7f6beSBruce Evans int flags; 41900f7f6beSBruce Evans struct proc *p; 4201bb2d314SMark Murray { 421316bbd5cSBruce Evans static intrmask_t interrupt_allowed; 422316bbd5cSBruce Evans intrmask_t interrupt_mask; 423316bbd5cSBruce Evans int error, intr; 424316bbd5cSBruce Evans struct random_softc *sc; 425a0135d7eSMark Murray 426d69e8502SGarrett Wollman switch (minor(dev)) { 427d69e8502SGarrett Wollman case 3: 428d69e8502SGarrett Wollman case 4: 429d69e8502SGarrett Wollman break; 430d69e8502SGarrett Wollman #ifdef PERFMON 431d69e8502SGarrett Wollman case 32: 432316bbd5cSBruce Evans return perfmon_ioctl(dev, cmd, data, flags, p); 433d69e8502SGarrett Wollman #endif 434d69e8502SGarrett Wollman default: 435316bbd5cSBruce Evans return (ENODEV); 436d69e8502SGarrett Wollman } 4371bb2d314SMark Murray 438316bbd5cSBruce Evans /* 439316bbd5cSBruce Evans * We're the random or urandom device. The only ioctls are for 440316bbd5cSBruce Evans * selecting and inspecting which interrupts are used in the muck 441316bbd5cSBruce Evans * gathering business. 442316bbd5cSBruce Evans */ 443316bbd5cSBruce Evans if (cmd != MEM_SETIRQ && cmd != MEM_CLEARIRQ && cmd != MEM_RETURNIRQ) 444316bbd5cSBruce Evans return (ENOTTY); 445316bbd5cSBruce Evans 446316bbd5cSBruce Evans /* 447316bbd5cSBruce Evans * Even inspecting the state is privileged, since it gives a hint 448316bbd5cSBruce Evans * about how easily the randomness might be guessed. 449316bbd5cSBruce Evans */ 450316bbd5cSBruce Evans error = suser(p->p_ucred, &p->p_acflag); 451316bbd5cSBruce Evans if (error != 0) 452316bbd5cSBruce Evans return (error); 453316bbd5cSBruce Evans 454316bbd5cSBruce Evans /* 455316bbd5cSBruce Evans * XXX the data is 16-bit due to a historical botch, so we use 456316bbd5cSBruce Evans * magic 16's instead of ICU_LEN and can't support 24 interrupts 457316bbd5cSBruce Evans * under SMP. 458316bbd5cSBruce Evans */ 459316bbd5cSBruce Evans intr = *(int16_t *)data; 460316bbd5cSBruce Evans if (cmd != MEM_RETURNIRQ && (intr < 0 || intr >= 16)) 4611bb2d314SMark Murray return (EINVAL); 4621bb2d314SMark Murray 463316bbd5cSBruce Evans interrupt_mask = 1 << intr; 464316bbd5cSBruce Evans sc = &random_softc[intr]; 4651bb2d314SMark Murray switch (cmd) { 4661bb2d314SMark Murray case MEM_SETIRQ: 467316bbd5cSBruce Evans if (interrupt_allowed & interrupt_mask) 468316bbd5cSBruce Evans break; 469e85ceed0SMark Murray interrupt_allowed |= interrupt_mask; 470316bbd5cSBruce Evans sc->sc_intr = intr; 471e85ceed0SMark Murray disable_intr(); 472316bbd5cSBruce Evans sc->sc_handler = intr_handler[intr]; 473316bbd5cSBruce Evans intr_handler[intr] = add_interrupt_randomness; 474316bbd5cSBruce Evans sc->sc_arg = intr_unit[intr]; 475316bbd5cSBruce Evans intr_unit[intr] = sc; 476e85ceed0SMark Murray enable_intr(); 4771bb2d314SMark Murray break; 478316bbd5cSBruce Evans case MEM_CLEARIRQ: 479316bbd5cSBruce Evans if (!(interrupt_allowed & interrupt_mask)) 480316bbd5cSBruce Evans break; 481316bbd5cSBruce Evans interrupt_allowed &= ~interrupt_mask; 482316bbd5cSBruce Evans disable_intr(); 483316bbd5cSBruce Evans intr_handler[intr] = sc->sc_handler; 484316bbd5cSBruce Evans intr_unit[intr] = sc->sc_arg; 485316bbd5cSBruce Evans enable_intr(); 486316bbd5cSBruce Evans break; 4871bb2d314SMark Murray case MEM_RETURNIRQ: 488316bbd5cSBruce Evans *(u_int16_t *)data = interrupt_allowed; 4891bb2d314SMark Murray break; 4901bb2d314SMark Murray default: 4911bb2d314SMark Murray return (ENOTTY); 4921bb2d314SMark Murray } 4931bb2d314SMark Murray return (0); 49400f7f6beSBruce Evans } 49553ac6efbSJulian Elischer 496983febf3SPeter Wemm int 49735b8b2ddSPeter Wemm mmpoll(dev, events, p) 498983febf3SPeter Wemm dev_t dev; 49935b8b2ddSPeter Wemm int events; 500983febf3SPeter Wemm struct proc *p; 501983febf3SPeter Wemm { 502983febf3SPeter Wemm switch (minor(dev)) { 503983febf3SPeter Wemm case 3: /* /dev/random */ 50435b8b2ddSPeter Wemm return random_poll(dev, events, p); 505983febf3SPeter Wemm case 4: /* /dev/urandom */ 506983febf3SPeter Wemm default: 50735b8b2ddSPeter Wemm return seltrue(dev, events, p); 508983febf3SPeter Wemm } 509983febf3SPeter Wemm } 510983febf3SPeter Wemm 511ee0ef569SJulian Elischer /* 512ee0ef569SJulian Elischer * Routine that identifies /dev/mem and /dev/kmem. 513ee0ef569SJulian Elischer * 514ee0ef569SJulian Elischer * A minimal stub routine can always return 0. 515ee0ef569SJulian Elischer */ 516ee0ef569SJulian Elischer int 517ee0ef569SJulian Elischer iskmemdev(dev) 518ee0ef569SJulian Elischer dev_t dev; 519ee0ef569SJulian Elischer { 520ee0ef569SJulian Elischer 521ee0ef569SJulian Elischer return ((major(dev) == mem_cdevsw.d_maj) 522ee0ef569SJulian Elischer && (minor(dev) == 0 || minor(dev) == 1)); 523ee0ef569SJulian Elischer } 524ee0ef569SJulian Elischer 525ee0ef569SJulian Elischer int 526ee0ef569SJulian Elischer iszerodev(dev) 527ee0ef569SJulian Elischer dev_t dev; 528ee0ef569SJulian Elischer { 529ee0ef569SJulian Elischer return ((major(dev) == mem_cdevsw.d_maj) 530ee0ef569SJulian Elischer && minor(dev) == 12); 531ee0ef569SJulian Elischer } 532ee0ef569SJulian Elischer 53353ac6efbSJulian Elischer 53453ac6efbSJulian Elischer 535d1d9d260SBruce Evans static int mem_devsw_installed; 53653ac6efbSJulian Elischer 53787f6c662SJulian Elischer static void 53887f6c662SJulian Elischer mem_drvinit(void *unused) 53953ac6efbSJulian Elischer { 54053ac6efbSJulian Elischer dev_t dev; 54153ac6efbSJulian Elischer 54253ac6efbSJulian Elischer if( ! mem_devsw_installed ) { 54353ac6efbSJulian Elischer dev = makedev(CDEV_MAJOR, 0); 54453ac6efbSJulian Elischer cdevsw_add(&dev,&mem_cdevsw, NULL); 54553ac6efbSJulian Elischer mem_devsw_installed = 1; 54653ac6efbSJulian Elischer #ifdef DEVFS 54787f6c662SJulian Elischer memdevfs_init(); 54853ac6efbSJulian Elischer #endif 54953ac6efbSJulian Elischer } 5507198bf47SJulian Elischer } 55153ac6efbSJulian Elischer 55253ac6efbSJulian Elischer SYSINIT(memdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,mem_drvinit,NULL) 55353ac6efbSJulian Elischer 554