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 41d021fc11SPeter Wemm * $Id: mem.c,v 1.43 1997/05/07 20:02:37 peter Exp $ 425b81b6b3SRodney W. Grimes */ 435b81b6b3SRodney W. Grimes 445b81b6b3SRodney W. Grimes /* 455b81b6b3SRodney W. Grimes * Memory special file 465b81b6b3SRodney W. Grimes */ 475b81b6b3SRodney W. Grimes 48d69e8502SGarrett Wollman #include "opt_perfmon.h" 49d69e8502SGarrett Wollman 5026f9a767SRodney W. Grimes #include <sys/param.h> 5126f9a767SRodney W. Grimes #include <sys/conf.h> 5226f9a767SRodney W. Grimes #include <sys/buf.h> 5387f6c662SJulian Elischer #ifdef DEVFS 5487f6c662SJulian Elischer #include <sys/devfsext.h> 5587f6c662SJulian Elischer #endif /* DEVFS */ 5687f6c662SJulian Elischer #include <sys/kernel.h> 5726f9a767SRodney W. Grimes #include <sys/systm.h> 5826f9a767SRodney W. Grimes #include <sys/uio.h> 5926f9a767SRodney W. Grimes #include <sys/malloc.h> 6026f9a767SRodney W. Grimes #include <sys/proc.h> 615b81b6b3SRodney W. Grimes 6226f9a767SRodney W. Grimes #include <machine/cpu.h> 6300f7f6beSBruce Evans #include <machine/random.h> 6426f9a767SRodney W. Grimes #include <machine/psl.h> 65d69e8502SGarrett Wollman #ifdef PERFMON 66d69e8502SGarrett Wollman #include <machine/perfmon.h> 67d69e8502SGarrett Wollman #endif 685b81b6b3SRodney W. Grimes 69c87801feSDavid Greenman #include <vm/vm.h> 7026f9a767SRodney W. Grimes #include <vm/vm_param.h> 71996c772fSJohn Dyson #include <sys/lock.h> 7226f9a767SRodney W. Grimes #include <vm/vm_prot.h> 7326f9a767SRodney W. Grimes #include <vm/pmap.h> 74efeaf95aSDavid Greenman #include <vm/vm_extern.h> 755b81b6b3SRodney W. Grimes 7687f6c662SJulian Elischer 7787f6c662SJulian Elischer 7887f6c662SJulian Elischer static d_open_t mmopen; 7987f6c662SJulian Elischer static d_close_t mmclose; 80c73feca0SBruce Evans static d_read_t mmrw; 8187f6c662SJulian Elischer static d_ioctl_t mmioctl; 8287f6c662SJulian Elischer static d_mmap_t memmmap; 83983febf3SPeter Wemm static d_select_t mmselect; 8487f6c662SJulian Elischer 8553ac6efbSJulian Elischer #define CDEV_MAJOR 2 86d2f265faSPoul-Henning Kamp static struct cdevsw mem_cdevsw = 8787f6c662SJulian Elischer { mmopen, mmclose, mmrw, mmrw, /*2*/ 8887f6c662SJulian Elischer mmioctl, nullstop, nullreset, nodevtotty,/* memory */ 89983febf3SPeter Wemm mmselect, memmmap, NULL, "mem", NULL, -1 }; 9053ac6efbSJulian Elischer 9120073b6dSNate Williams static caddr_t zbuf; 9220073b6dSNate Williams 938af5d536SJulian Elischer #ifdef DEVFS 9487f6c662SJulian Elischer static void *mem_devfs_token; 9587f6c662SJulian Elischer static void *kmem_devfs_token; 9687f6c662SJulian Elischer static void *null_devfs_token; 9787f6c662SJulian Elischer static void *random_devfs_token; 9887f6c662SJulian Elischer static void *urandom_devfs_token; 9987f6c662SJulian Elischer static void *zero_devfs_token; 10087f6c662SJulian Elischer static void *io_devfs_token; 101d69e8502SGarrett Wollman #ifdef PERFMON 102d69e8502SGarrett Wollman static void *perfmon_devfs_token; 103d69e8502SGarrett Wollman #endif 10433f538b9SBruce Evans 105f3fcde03SBruce Evans static void memdevfs_init __P((void)); 106f3fcde03SBruce Evans 10733f538b9SBruce Evans static void 10887f6c662SJulian Elischer memdevfs_init() 1098af5d536SJulian Elischer { 110f28213adSMarc G. Fournier mem_devfs_token = 111f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 0, DV_CHR, 112f28213adSMarc G. Fournier UID_ROOT, GID_KMEM, 0640, "mem"); 113f28213adSMarc G. Fournier kmem_devfs_token = 114f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 1, DV_CHR, 115f28213adSMarc G. Fournier UID_ROOT, GID_KMEM, 0640, "kmem"); 116f28213adSMarc G. Fournier null_devfs_token = 117f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 2, DV_CHR, 118f28213adSMarc G. Fournier UID_ROOT, GID_WHEEL, 0666, "null"); 119f28213adSMarc G. Fournier random_devfs_token = 120f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 3, DV_CHR, 121f28213adSMarc G. Fournier UID_ROOT, GID_WHEEL, 0644, "random"); 122f28213adSMarc G. Fournier urandom_devfs_token = 123f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 4, DV_CHR, 124f28213adSMarc G. Fournier UID_ROOT, GID_WHEEL, 0644, "urandom"); 125f28213adSMarc G. Fournier zero_devfs_token = 126f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 12, DV_CHR, 127f28213adSMarc G. Fournier UID_ROOT, GID_WHEEL, 0666, "zero"); 128f28213adSMarc G. Fournier io_devfs_token = 129f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 14, DV_CHR, 1305e0f6c43SBruce Evans UID_ROOT, GID_WHEEL, 0600, "io"); 131d69e8502SGarrett Wollman #ifdef PERFMON 132f28213adSMarc G. Fournier perfmon_devfs_token = 133f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 32, DV_CHR, 134f28213adSMarc G. Fournier UID_ROOT, GID_KMEM, 0640, "perfmon"); 135d69e8502SGarrett Wollman #endif /* PERFMON */ 1368af5d536SJulian Elischer } 1378af5d536SJulian Elischer #endif /* DEVFS */ 1388af5d536SJulian Elischer 13926f9a767SRodney W. Grimes extern char *ptvmmap; /* poor name! */ 14033f538b9SBruce Evans 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 } 2911bb2d314SMark Murray if (buf == NULL) 2921bb2d314SMark Murray buf = (caddr_t) 293f8845af0SPoul-Henning Kamp malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 294f8845af0SPoul-Henning Kamp c = min(iov->iov_len, PAGE_SIZE); 2951bb2d314SMark Murray poolsize = read_random_unlimited(buf, c); 2961bb2d314SMark Murray c = min(c, poolsize); 2971bb2d314SMark Murray error = uiomove(buf, (int)c, uio); 2981bb2d314SMark Murray continue; 2991bb2d314SMark Murray 3005b81b6b3SRodney W. Grimes /* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */ 3015b81b6b3SRodney W. Grimes case 12: 3025b81b6b3SRodney W. Grimes if (uio->uio_rw == UIO_WRITE) { 3035b81b6b3SRodney W. Grimes c = iov->iov_len; 3045b81b6b3SRodney W. Grimes break; 3055b81b6b3SRodney W. Grimes } 306f381a0c0SJohn Dyson if (zbuf == NULL) { 307f381a0c0SJohn Dyson zbuf = (caddr_t) 308f8845af0SPoul-Henning Kamp malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 309f381a0c0SJohn Dyson bzero(zbuf, PAGE_SIZE); 3105b81b6b3SRodney W. Grimes } 311f8845af0SPoul-Henning Kamp c = min(iov->iov_len, PAGE_SIZE); 312f381a0c0SJohn Dyson error = uiomove(zbuf, (int)c, uio); 3135b81b6b3SRodney W. Grimes continue; 3145b81b6b3SRodney W. Grimes 3155b81b6b3SRodney W. Grimes #ifdef notyet 3165b81b6b3SRodney W. Grimes /* 386 I/O address space (/dev/ioport[bwl]) is a read/write access to seperate 3175b81b6b3SRodney W. Grimes i/o device address bus, different than memory bus. Semantics here are 3185b81b6b3SRodney W. Grimes very different than ordinary read/write, as if iov_len is a multiple 3195b81b6b3SRodney W. Grimes an implied string move from a single port will be done. Note that lseek 3205b81b6b3SRodney W. Grimes must be used to set the port number reliably. */ 3215b81b6b3SRodney W. Grimes case 14: 3225b81b6b3SRodney W. Grimes if (iov->iov_len == 1) { 3235b81b6b3SRodney W. Grimes u_char tmp; 3245b81b6b3SRodney W. Grimes tmp = inb(uio->uio_offset); 3255b81b6b3SRodney W. Grimes error = uiomove (&tmp, iov->iov_len, uio); 3265b81b6b3SRodney W. Grimes } else { 3275b81b6b3SRodney W. Grimes if (!useracc((caddr_t)iov->iov_base, 3285b81b6b3SRodney W. Grimes iov->iov_len, uio->uio_rw)) 3295b81b6b3SRodney W. Grimes return (EFAULT); 3305b81b6b3SRodney W. Grimes insb(uio->uio_offset, iov->iov_base, 3315b81b6b3SRodney W. Grimes iov->iov_len); 3325b81b6b3SRodney W. Grimes } 3335b81b6b3SRodney W. Grimes break; 3345b81b6b3SRodney W. Grimes case 15: 3355b81b6b3SRodney W. Grimes if (iov->iov_len == sizeof (short)) { 3365b81b6b3SRodney W. Grimes u_short tmp; 3375b81b6b3SRodney W. Grimes tmp = inw(uio->uio_offset); 3385b81b6b3SRodney W. Grimes error = uiomove (&tmp, iov->iov_len, uio); 3395b81b6b3SRodney W. Grimes } else { 3405b81b6b3SRodney W. Grimes if (!useracc((caddr_t)iov->iov_base, 3415b81b6b3SRodney W. Grimes iov->iov_len, uio->uio_rw)) 3425b81b6b3SRodney W. Grimes return (EFAULT); 3435b81b6b3SRodney W. Grimes insw(uio->uio_offset, iov->iov_base, 3445b81b6b3SRodney W. Grimes iov->iov_len/ sizeof (short)); 3455b81b6b3SRodney W. Grimes } 3465b81b6b3SRodney W. Grimes break; 3475b81b6b3SRodney W. Grimes case 16: 3485b81b6b3SRodney W. Grimes if (iov->iov_len == sizeof (long)) { 3495b81b6b3SRodney W. Grimes u_long tmp; 3505b81b6b3SRodney W. Grimes tmp = inl(uio->uio_offset); 3515b81b6b3SRodney W. Grimes error = uiomove (&tmp, iov->iov_len, uio); 3525b81b6b3SRodney W. Grimes } else { 3535b81b6b3SRodney W. Grimes if (!useracc((caddr_t)iov->iov_base, 3545b81b6b3SRodney W. Grimes iov->iov_len, uio->uio_rw)) 3555b81b6b3SRodney W. Grimes return (EFAULT); 3565b81b6b3SRodney W. Grimes insl(uio->uio_offset, iov->iov_base, 3575b81b6b3SRodney W. Grimes iov->iov_len/ sizeof (long)); 3585b81b6b3SRodney W. Grimes } 3595b81b6b3SRodney W. Grimes break; 3605b81b6b3SRodney W. Grimes #endif 3615b81b6b3SRodney W. Grimes 3625b81b6b3SRodney W. Grimes default: 3635b81b6b3SRodney W. Grimes return (ENXIO); 3645b81b6b3SRodney W. Grimes } 3655b81b6b3SRodney W. Grimes if (error) 3665b81b6b3SRodney W. Grimes break; 3675b81b6b3SRodney W. Grimes iov->iov_base += c; 3685b81b6b3SRodney W. Grimes iov->iov_len -= c; 3695b81b6b3SRodney W. Grimes uio->uio_offset += c; 3705b81b6b3SRodney W. Grimes uio->uio_resid -= c; 3715b81b6b3SRodney W. Grimes } 3721bb2d314SMark Murray if (buf) 3731bb2d314SMark Murray free(buf, M_TEMP); 3745b81b6b3SRodney W. Grimes return (error); 3755b81b6b3SRodney W. Grimes } 376b513c262SDavid Greenman 377b513c262SDavid Greenman 378b513c262SDavid Greenman 379b513c262SDavid Greenman 380b513c262SDavid Greenman /*******************************************************\ 381b513c262SDavid Greenman * allow user processes to MMAP some memory sections * 382b513c262SDavid Greenman * instead of going through read/write * 383b513c262SDavid Greenman \*******************************************************/ 38487f6c662SJulian Elischer static int 38587f6c662SJulian Elischer memmmap(dev_t dev, int offset, int nprot) 386b513c262SDavid Greenman { 387b513c262SDavid Greenman switch (minor(dev)) 388b513c262SDavid Greenman { 389b513c262SDavid Greenman 390b513c262SDavid Greenman /* minor device 0 is physical memory */ 391b513c262SDavid Greenman case 0: 392b513c262SDavid Greenman return i386_btop(offset); 393b513c262SDavid Greenman 394b513c262SDavid Greenman /* minor device 1 is kernel memory */ 395b513c262SDavid Greenman case 1: 396b513c262SDavid Greenman return i386_btop(vtophys(offset)); 397b513c262SDavid Greenman 398b513c262SDavid Greenman default: 399b513c262SDavid Greenman return -1; 400b513c262SDavid Greenman } 401b513c262SDavid Greenman } 402b513c262SDavid Greenman 4031bb2d314SMark Murray /* 4041bb2d314SMark Murray * Allow userland to select which interrupts will be used in the muck 4051bb2d314SMark Murray * gathering business. 4061bb2d314SMark Murray */ 40787f6c662SJulian Elischer static int 40800f7f6beSBruce Evans mmioctl(dev, cmd, cmdarg, flags, p) 40900f7f6beSBruce Evans dev_t dev; 41000f7f6beSBruce Evans int cmd; 41100f7f6beSBruce Evans caddr_t cmdarg; 41200f7f6beSBruce Evans int flags; 41300f7f6beSBruce Evans struct proc *p; 4141bb2d314SMark Murray { 415e85ceed0SMark Murray static u_int16_t interrupt_allowed = 0; 416e85ceed0SMark Murray u_int16_t interrupt_mask; 417a0135d7eSMark Murray int error; 418a0135d7eSMark Murray 419d69e8502SGarrett Wollman switch(minor(dev)) { 420d69e8502SGarrett Wollman case 3: 421d69e8502SGarrett Wollman case 4: 422d69e8502SGarrett Wollman break; 423d69e8502SGarrett Wollman 424d69e8502SGarrett Wollman #ifdef PERFMON 425d69e8502SGarrett Wollman case 32: 426d69e8502SGarrett Wollman return perfmon_ioctl(dev, cmd, cmdarg, flags, p); 427d69e8502SGarrett Wollman #endif 428d69e8502SGarrett Wollman default: 429d69e8502SGarrett Wollman return ENODEV; 430d69e8502SGarrett Wollman } 4311bb2d314SMark Murray 4321bb2d314SMark Murray if (*(u_int16_t *)cmdarg >= 16) 4331bb2d314SMark Murray return (EINVAL); 4341bb2d314SMark Murray 435a0135d7eSMark Murray /* Only root can do this */ 436a0135d7eSMark Murray error = suser(p->p_ucred, &p->p_acflag); 437e85ceed0SMark Murray if (error) { 438a0135d7eSMark Murray return (error); 439a0135d7eSMark Murray } 440e85ceed0SMark Murray interrupt_mask = 1 << *(u_int16_t *)cmdarg; 441a0135d7eSMark Murray 4421bb2d314SMark Murray switch (cmd) { 4431bb2d314SMark Murray 4441bb2d314SMark Murray case MEM_SETIRQ: 445e85ceed0SMark Murray if (!(interrupt_allowed & interrupt_mask)) { 446e85ceed0SMark Murray disable_intr(); 447e85ceed0SMark Murray interrupt_allowed |= interrupt_mask; 448e85ceed0SMark Murray sec_intr_handler[*(u_int16_t *)cmdarg] = 449e85ceed0SMark Murray intr_handler[*(u_int16_t *)cmdarg]; 450e85ceed0SMark Murray intr_handler[*(u_int16_t *)cmdarg] = 451e85ceed0SMark Murray add_interrupt_randomness; 452e85ceed0SMark Murray sec_intr_unit[*(u_int16_t *)cmdarg] = 453e85ceed0SMark Murray intr_unit[*(u_int16_t *)cmdarg]; 454e85ceed0SMark Murray intr_unit[*(u_int16_t *)cmdarg] = 455e85ceed0SMark Murray *(u_int16_t *)cmdarg; 456e85ceed0SMark Murray enable_intr(); 457e85ceed0SMark Murray } 458e85ceed0SMark Murray else return (EPERM); 4591bb2d314SMark Murray break; 4601bb2d314SMark Murray 4611bb2d314SMark Murray case MEM_CLEARIRQ: 462e85ceed0SMark Murray if (interrupt_allowed & interrupt_mask) { 463e85ceed0SMark Murray disable_intr(); 464e85ceed0SMark Murray interrupt_allowed &= ~(interrupt_mask); 465e85ceed0SMark Murray intr_handler[*(u_int16_t *)cmdarg] = 466e85ceed0SMark Murray sec_intr_handler[*(u_int16_t *)cmdarg]; 467e85ceed0SMark Murray intr_unit[*(u_int16_t *)cmdarg] = 468e85ceed0SMark Murray sec_intr_unit[*(u_int16_t *)cmdarg]; 469e85ceed0SMark Murray enable_intr(); 470e85ceed0SMark Murray } 471e85ceed0SMark Murray else return (EPERM); 4721bb2d314SMark Murray break; 4731bb2d314SMark Murray 4741bb2d314SMark Murray case MEM_RETURNIRQ: 4751bb2d314SMark Murray *(u_int16_t *)cmdarg = interrupt_allowed; 4761bb2d314SMark Murray break; 4771bb2d314SMark Murray 4781bb2d314SMark Murray default: 4791bb2d314SMark Murray return (ENOTTY); 4801bb2d314SMark Murray } 4811bb2d314SMark Murray return (0); 48200f7f6beSBruce Evans } 48353ac6efbSJulian Elischer 484983febf3SPeter Wemm int 485983febf3SPeter Wemm mmselect(dev, rw, p) 486983febf3SPeter Wemm dev_t dev; 487983febf3SPeter Wemm int rw; 488983febf3SPeter Wemm struct proc *p; 489983febf3SPeter Wemm { 490983febf3SPeter Wemm switch (minor(dev)) { 491983febf3SPeter Wemm case 3: /* /dev/random */ 492983febf3SPeter Wemm return random_select(dev, rw, p); 493983febf3SPeter Wemm case 4: /* /dev/urandom */ 494983febf3SPeter Wemm default: 495983febf3SPeter Wemm return seltrue(dev, rw, p); 496983febf3SPeter Wemm } 497983febf3SPeter Wemm } 498983febf3SPeter Wemm 499ee0ef569SJulian Elischer /* 500ee0ef569SJulian Elischer * Routine that identifies /dev/mem and /dev/kmem. 501ee0ef569SJulian Elischer * 502ee0ef569SJulian Elischer * A minimal stub routine can always return 0. 503ee0ef569SJulian Elischer */ 504ee0ef569SJulian Elischer int 505ee0ef569SJulian Elischer iskmemdev(dev) 506ee0ef569SJulian Elischer dev_t dev; 507ee0ef569SJulian Elischer { 508ee0ef569SJulian Elischer 509ee0ef569SJulian Elischer return ((major(dev) == mem_cdevsw.d_maj) 510ee0ef569SJulian Elischer && (minor(dev) == 0 || minor(dev) == 1)); 511ee0ef569SJulian Elischer } 512ee0ef569SJulian Elischer 513ee0ef569SJulian Elischer int 514ee0ef569SJulian Elischer iszerodev(dev) 515ee0ef569SJulian Elischer dev_t dev; 516ee0ef569SJulian Elischer { 517ee0ef569SJulian Elischer return ((major(dev) == mem_cdevsw.d_maj) 518ee0ef569SJulian Elischer && minor(dev) == 12); 519ee0ef569SJulian Elischer } 520ee0ef569SJulian Elischer 52153ac6efbSJulian Elischer 52253ac6efbSJulian Elischer 52353ac6efbSJulian Elischer static mem_devsw_installed = 0; 52453ac6efbSJulian Elischer 52587f6c662SJulian Elischer static void 52687f6c662SJulian Elischer mem_drvinit(void *unused) 52753ac6efbSJulian Elischer { 52853ac6efbSJulian Elischer dev_t dev; 52953ac6efbSJulian Elischer 53053ac6efbSJulian Elischer if( ! mem_devsw_installed ) { 53153ac6efbSJulian Elischer dev = makedev(CDEV_MAJOR, 0); 53253ac6efbSJulian Elischer cdevsw_add(&dev,&mem_cdevsw, NULL); 53353ac6efbSJulian Elischer mem_devsw_installed = 1; 53453ac6efbSJulian Elischer #ifdef DEVFS 53587f6c662SJulian Elischer memdevfs_init(); 53653ac6efbSJulian Elischer #endif 53753ac6efbSJulian Elischer } 5387198bf47SJulian Elischer } 53953ac6efbSJulian Elischer 54053ac6efbSJulian Elischer SYSINIT(memdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,mem_drvinit,NULL) 54153ac6efbSJulian Elischer 542