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 414ffd949eSMike Smith * $Id: mem.c,v 1.54 1999/02/02 14:14:05 bde 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> 604ffd949eSMike Smith #include <sys/ioccom.h> 6126f9a767SRodney W. Grimes #include <sys/malloc.h> 624ffd949eSMike Smith #include <sys/memrange.h> 6326f9a767SRodney W. Grimes #include <sys/proc.h> 64bb25f0ddSBruce Evans #include <sys/signalvar.h> 655b81b6b3SRodney W. Grimes 66d1d9d260SBruce Evans #include <machine/frame.h> 674ffd949eSMike Smith #include <machine/md_var.h> 6800f7f6beSBruce Evans #include <machine/random.h> 6926f9a767SRodney W. Grimes #include <machine/psl.h> 704ffd949eSMike Smith #include <machine/specialreg.h> 71d69e8502SGarrett Wollman #ifdef PERFMON 72d69e8502SGarrett Wollman #include <machine/perfmon.h> 73d69e8502SGarrett Wollman #endif 7468352337SDoug Rabson #include <i386/isa/intr_machdep.h> 755b81b6b3SRodney W. Grimes 76c87801feSDavid Greenman #include <vm/vm.h> 7726f9a767SRodney W. Grimes #include <vm/vm_prot.h> 7826f9a767SRodney W. Grimes #include <vm/pmap.h> 79efeaf95aSDavid Greenman #include <vm/vm_extern.h> 805b81b6b3SRodney W. Grimes 8187f6c662SJulian Elischer 8287f6c662SJulian Elischer static d_open_t mmopen; 8387f6c662SJulian Elischer static d_close_t mmclose; 84c73feca0SBruce Evans static d_read_t mmrw; 8587f6c662SJulian Elischer static d_ioctl_t mmioctl; 8687f6c662SJulian Elischer static d_mmap_t memmmap; 8735b8b2ddSPeter Wemm static d_poll_t mmpoll; 8887f6c662SJulian Elischer 8953ac6efbSJulian Elischer #define CDEV_MAJOR 2 90d2f265faSPoul-Henning Kamp static struct cdevsw mem_cdevsw = 9187f6c662SJulian Elischer { mmopen, mmclose, mmrw, mmrw, /*2*/ 9287f6c662SJulian Elischer mmioctl, nullstop, nullreset, nodevtotty,/* memory */ 9335b8b2ddSPeter Wemm mmpoll, memmmap, NULL, "mem", NULL, -1 }; 9453ac6efbSJulian Elischer 95316bbd5cSBruce Evans static struct random_softc random_softc[16]; 9620073b6dSNate Williams static caddr_t zbuf; 9720073b6dSNate Williams 984ffd949eSMike Smith MALLOC_DEFINE(M_MEMDESC, "memdesc", "memory range descriptors"); 994ffd949eSMike Smith static int mem_ioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); 1004ffd949eSMike Smith static int random_ioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); 1014ffd949eSMike Smith 1024ffd949eSMike Smith struct mem_range_softc mem_range_softc; 1034ffd949eSMike Smith 1048af5d536SJulian Elischer #ifdef DEVFS 10587f6c662SJulian Elischer static void *mem_devfs_token; 10687f6c662SJulian Elischer static void *kmem_devfs_token; 10787f6c662SJulian Elischer static void *null_devfs_token; 10887f6c662SJulian Elischer static void *random_devfs_token; 10987f6c662SJulian Elischer static void *urandom_devfs_token; 11087f6c662SJulian Elischer static void *zero_devfs_token; 11187f6c662SJulian Elischer static void *io_devfs_token; 112d69e8502SGarrett Wollman #ifdef PERFMON 113d69e8502SGarrett Wollman static void *perfmon_devfs_token; 114d69e8502SGarrett Wollman #endif 11533f538b9SBruce Evans 116f3fcde03SBruce Evans static void memdevfs_init __P((void)); 117f3fcde03SBruce Evans 11833f538b9SBruce Evans static void 11987f6c662SJulian Elischer memdevfs_init() 1208af5d536SJulian Elischer { 121f28213adSMarc G. Fournier mem_devfs_token = 122f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 0, DV_CHR, 123f28213adSMarc G. Fournier UID_ROOT, GID_KMEM, 0640, "mem"); 124f28213adSMarc G. Fournier kmem_devfs_token = 125f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 1, DV_CHR, 126f28213adSMarc G. Fournier UID_ROOT, GID_KMEM, 0640, "kmem"); 127f28213adSMarc G. Fournier null_devfs_token = 128f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 2, DV_CHR, 129f28213adSMarc G. Fournier UID_ROOT, GID_WHEEL, 0666, "null"); 130f28213adSMarc G. Fournier random_devfs_token = 131f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 3, DV_CHR, 132f28213adSMarc G. Fournier UID_ROOT, GID_WHEEL, 0644, "random"); 133f28213adSMarc G. Fournier urandom_devfs_token = 134f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 4, DV_CHR, 135f28213adSMarc G. Fournier UID_ROOT, GID_WHEEL, 0644, "urandom"); 136f28213adSMarc G. Fournier zero_devfs_token = 137f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 12, DV_CHR, 138f28213adSMarc G. Fournier UID_ROOT, GID_WHEEL, 0666, "zero"); 139f28213adSMarc G. Fournier io_devfs_token = 140f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 14, DV_CHR, 1415e0f6c43SBruce Evans UID_ROOT, GID_WHEEL, 0600, "io"); 142d69e8502SGarrett Wollman #ifdef PERFMON 143f28213adSMarc G. Fournier perfmon_devfs_token = 144f28213adSMarc G. Fournier devfs_add_devswf(&mem_cdevsw, 32, DV_CHR, 145f28213adSMarc G. Fournier UID_ROOT, GID_KMEM, 0640, "perfmon"); 146d69e8502SGarrett Wollman #endif /* PERFMON */ 1478af5d536SJulian Elischer } 1488af5d536SJulian Elischer #endif /* DEVFS */ 1498af5d536SJulian Elischer 15087f6c662SJulian Elischer static int 15160039670SBruce Evans mmclose(dev, flags, fmt, p) 15278d172caSRodney W. Grimes dev_t dev; 15378d172caSRodney W. Grimes int flags; 15460039670SBruce Evans int fmt; 15560039670SBruce Evans struct proc *p; 15678d172caSRodney W. Grimes { 15778d172caSRodney W. Grimes switch (minor(dev)) { 158d69e8502SGarrett Wollman #ifdef PERFMON 159d69e8502SGarrett Wollman case 32: 160d69e8502SGarrett Wollman return perfmon_close(dev, flags, fmt, p); 161d69e8502SGarrett Wollman #endif 16278d172caSRodney W. Grimes case 14: 16336428e61SPeter Wemm curproc->p_md.md_regs->tf_eflags &= ~PSL_IOPL; 16478d172caSRodney W. Grimes break; 16578d172caSRodney W. Grimes default: 16678d172caSRodney W. Grimes break; 16778d172caSRodney W. Grimes } 16878d172caSRodney W. Grimes return(0); 16978d172caSRodney W. Grimes } 17033f538b9SBruce Evans 17187f6c662SJulian Elischer static int 17260039670SBruce Evans mmopen(dev, flags, fmt, p) 17378d172caSRodney W. Grimes dev_t dev; 17478d172caSRodney W. Grimes int flags; 17560039670SBruce Evans int fmt; 17660039670SBruce Evans struct proc *p; 17778d172caSRodney W. Grimes { 178da3df630SBruce Evans int error; 17978d172caSRodney W. Grimes 18078d172caSRodney W. Grimes switch (minor(dev)) { 181d69e8502SGarrett Wollman case 32: 182d69e8502SGarrett Wollman #ifdef PERFMON 183d69e8502SGarrett Wollman return perfmon_open(dev, flags, fmt, p); 184d69e8502SGarrett Wollman #else 185d69e8502SGarrett Wollman return ENODEV; 186d69e8502SGarrett Wollman #endif 18778d172caSRodney W. Grimes case 14: 188da3df630SBruce Evans error = suser(p->p_ucred, &p->p_acflag); 189da3df630SBruce Evans if (error != 0) 190da3df630SBruce Evans return (error); 191da3df630SBruce Evans if (securelevel > 0) 192da3df630SBruce Evans return (EPERM); 19336428e61SPeter Wemm curproc->p_md.md_regs->tf_eflags |= PSL_IOPL; 19478d172caSRodney W. Grimes break; 19578d172caSRodney W. Grimes default: 19678d172caSRodney W. Grimes break; 19778d172caSRodney W. Grimes } 19878d172caSRodney W. Grimes return(0); 19978d172caSRodney W. Grimes } 20033f538b9SBruce Evans 20187f6c662SJulian Elischer static int 2025b81b6b3SRodney W. Grimes mmrw(dev, uio, flags) 2035b81b6b3SRodney W. Grimes dev_t dev; 2045b81b6b3SRodney W. Grimes struct uio *uio; 2055b81b6b3SRodney W. Grimes int flags; 2065b81b6b3SRodney W. Grimes { 2075b81b6b3SRodney W. Grimes register int o; 2085b81b6b3SRodney W. Grimes register u_int c, v; 2091bb2d314SMark Murray u_int poolsize; 2105b81b6b3SRodney W. Grimes register struct iovec *iov; 2115b81b6b3SRodney W. Grimes int error = 0; 2121bb2d314SMark Murray caddr_t buf = NULL; 2135b81b6b3SRodney W. Grimes 2145b81b6b3SRodney W. Grimes while (uio->uio_resid > 0 && error == 0) { 2155b81b6b3SRodney W. Grimes iov = uio->uio_iov; 2165b81b6b3SRodney W. Grimes if (iov->iov_len == 0) { 2175b81b6b3SRodney W. Grimes uio->uio_iov++; 2185b81b6b3SRodney W. Grimes uio->uio_iovcnt--; 2195b81b6b3SRodney W. Grimes if (uio->uio_iovcnt < 0) 2205b81b6b3SRodney W. Grimes panic("mmrw"); 2215b81b6b3SRodney W. Grimes continue; 2225b81b6b3SRodney W. Grimes } 2235b81b6b3SRodney W. Grimes switch (minor(dev)) { 2245b81b6b3SRodney W. Grimes 2255b81b6b3SRodney W. Grimes /* minor device 0 is physical memory */ 2265b81b6b3SRodney W. Grimes case 0: 2275b81b6b3SRodney W. Grimes v = uio->uio_offset; 22826f9a767SRodney W. Grimes pmap_enter(kernel_pmap, (vm_offset_t)ptvmmap, v, 2295b81b6b3SRodney W. Grimes uio->uio_rw == UIO_READ ? VM_PROT_READ : VM_PROT_WRITE, 2305b81b6b3SRodney W. Grimes TRUE); 231f8845af0SPoul-Henning Kamp o = (int)uio->uio_offset & PAGE_MASK; 232f8845af0SPoul-Henning Kamp c = (u_int)(PAGE_SIZE - ((int)iov->iov_base & PAGE_MASK)); 233f8845af0SPoul-Henning Kamp c = min(c, (u_int)(PAGE_SIZE - o)); 23426f9a767SRodney W. Grimes c = min(c, (u_int)iov->iov_len); 23526f9a767SRodney W. Grimes error = uiomove((caddr_t)&ptvmmap[o], (int)c, uio); 23626f9a767SRodney W. Grimes pmap_remove(kernel_pmap, (vm_offset_t)ptvmmap, 237f8845af0SPoul-Henning Kamp (vm_offset_t)&ptvmmap[PAGE_SIZE]); 2385b81b6b3SRodney W. Grimes continue; 2395b81b6b3SRodney W. Grimes 2405b81b6b3SRodney W. Grimes /* minor device 1 is kernel memory */ 24197e11262SDavid Greenman case 1: { 24297e11262SDavid Greenman vm_offset_t addr, eaddr; 2435b81b6b3SRodney W. Grimes c = iov->iov_len; 24497e11262SDavid Greenman 24597e11262SDavid Greenman /* 24697e11262SDavid Greenman * Make sure that all of the pages are currently resident so 24797e11262SDavid Greenman * that we don't create any zero-fill pages. 24897e11262SDavid Greenman */ 24997e11262SDavid Greenman addr = trunc_page(uio->uio_offset); 2500704324aSDavid Greenman eaddr = round_page(uio->uio_offset + c); 251d021fc11SPeter Wemm 252d021fc11SPeter Wemm if (addr < (vm_offset_t)VADDR(PTDPTDI, 0)) 253d021fc11SPeter Wemm return EFAULT; 254d021fc11SPeter Wemm if (eaddr >= (vm_offset_t)VADDR(APTDPTDI, 0)) 255d021fc11SPeter Wemm return EFAULT; 25697e11262SDavid Greenman for (; addr < eaddr; addr += PAGE_SIZE) 25797e11262SDavid Greenman if (pmap_extract(kernel_pmap, addr) == 0) 25897e11262SDavid Greenman return EFAULT; 25997e11262SDavid Greenman 26026f9a767SRodney W. Grimes if (!kernacc((caddr_t)(int)uio->uio_offset, c, 2615b81b6b3SRodney W. Grimes uio->uio_rw == UIO_READ ? B_READ : B_WRITE)) 2625b81b6b3SRodney W. Grimes return(EFAULT); 26326f9a767SRodney W. Grimes error = uiomove((caddr_t)(int)uio->uio_offset, (int)c, uio); 2645b81b6b3SRodney W. Grimes continue; 26597e11262SDavid Greenman } 2665b81b6b3SRodney W. Grimes 2675b81b6b3SRodney W. Grimes /* minor device 2 is EOF/RATHOLE */ 2685b81b6b3SRodney W. Grimes case 2: 2695b81b6b3SRodney W. Grimes if (uio->uio_rw == UIO_READ) 2705b81b6b3SRodney W. Grimes return (0); 2715b81b6b3SRodney W. Grimes c = iov->iov_len; 2725b81b6b3SRodney W. Grimes break; 2735b81b6b3SRodney W. Grimes 2741bb2d314SMark Murray /* minor device 3 (/dev/random) is source of filth on read, rathole on write */ 2751bb2d314SMark Murray case 3: 2761bb2d314SMark Murray if (uio->uio_rw == UIO_WRITE) { 2771bb2d314SMark Murray c = iov->iov_len; 2781bb2d314SMark Murray break; 2791bb2d314SMark Murray } 2801bb2d314SMark Murray if (buf == NULL) 2811bb2d314SMark Murray buf = (caddr_t) 282f8845af0SPoul-Henning Kamp malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 283f8845af0SPoul-Henning Kamp c = min(iov->iov_len, PAGE_SIZE); 2841bb2d314SMark Murray poolsize = read_random(buf, c); 2851bb2d314SMark Murray if (poolsize == 0) { 2861bb2d314SMark Murray if (buf) 2871bb2d314SMark Murray free(buf, M_TEMP); 2881bb2d314SMark Murray return (0); 2891bb2d314SMark Murray } 2901bb2d314SMark Murray c = min(c, poolsize); 2911bb2d314SMark Murray error = uiomove(buf, (int)c, uio); 2921bb2d314SMark Murray continue; 2931bb2d314SMark Murray 2941bb2d314SMark Murray /* minor device 4 (/dev/urandom) is source of muck on read, rathole on write */ 2951bb2d314SMark Murray case 4: 2961bb2d314SMark Murray if (uio->uio_rw == UIO_WRITE) { 2971bb2d314SMark Murray c = iov->iov_len; 2981bb2d314SMark Murray break; 2991bb2d314SMark Murray } 300bb25f0ddSBruce Evans if (CURSIG(curproc) != 0) { 301bb25f0ddSBruce Evans /* 302bb25f0ddSBruce Evans * Use tsleep() to get the error code right. 303bb25f0ddSBruce Evans * It should return immediately. 304bb25f0ddSBruce Evans */ 305bb25f0ddSBruce Evans error = tsleep(&random_softc[0], 306bb25f0ddSBruce Evans PZERO | PCATCH, "urand", 1); 307bb25f0ddSBruce Evans if (error != 0 && error != EWOULDBLOCK) 308bb25f0ddSBruce Evans continue; 309bb25f0ddSBruce Evans } 3101bb2d314SMark Murray if (buf == NULL) 3111bb2d314SMark Murray buf = (caddr_t) 312f8845af0SPoul-Henning Kamp malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 313f8845af0SPoul-Henning Kamp c = min(iov->iov_len, PAGE_SIZE); 3141bb2d314SMark Murray poolsize = read_random_unlimited(buf, c); 3151bb2d314SMark Murray c = min(c, poolsize); 3161bb2d314SMark Murray error = uiomove(buf, (int)c, uio); 3171bb2d314SMark Murray continue; 3181bb2d314SMark Murray 3195b81b6b3SRodney W. Grimes /* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */ 3205b81b6b3SRodney W. Grimes case 12: 3215b81b6b3SRodney W. Grimes if (uio->uio_rw == UIO_WRITE) { 3225b81b6b3SRodney W. Grimes c = iov->iov_len; 3235b81b6b3SRodney W. Grimes break; 3245b81b6b3SRodney W. Grimes } 325f381a0c0SJohn Dyson if (zbuf == NULL) { 326f381a0c0SJohn Dyson zbuf = (caddr_t) 327f8845af0SPoul-Henning Kamp malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 328f381a0c0SJohn Dyson bzero(zbuf, PAGE_SIZE); 3295b81b6b3SRodney W. Grimes } 330f8845af0SPoul-Henning Kamp c = min(iov->iov_len, PAGE_SIZE); 331f381a0c0SJohn Dyson error = uiomove(zbuf, (int)c, uio); 3325b81b6b3SRodney W. Grimes continue; 3335b81b6b3SRodney W. Grimes 3345b81b6b3SRodney W. Grimes #ifdef notyet 3355b81b6b3SRodney W. Grimes /* 386 I/O address space (/dev/ioport[bwl]) is a read/write access to seperate 3365b81b6b3SRodney W. Grimes i/o device address bus, different than memory bus. Semantics here are 3375b81b6b3SRodney W. Grimes very different than ordinary read/write, as if iov_len is a multiple 3385b81b6b3SRodney W. Grimes an implied string move from a single port will be done. Note that lseek 3395b81b6b3SRodney W. Grimes must be used to set the port number reliably. */ 3405b81b6b3SRodney W. Grimes case 14: 3415b81b6b3SRodney W. Grimes if (iov->iov_len == 1) { 3425b81b6b3SRodney W. Grimes u_char tmp; 3435b81b6b3SRodney W. Grimes tmp = inb(uio->uio_offset); 3445b81b6b3SRodney W. Grimes error = uiomove (&tmp, iov->iov_len, uio); 3455b81b6b3SRodney W. Grimes } else { 3465b81b6b3SRodney W. Grimes if (!useracc((caddr_t)iov->iov_base, 3475b81b6b3SRodney W. Grimes iov->iov_len, uio->uio_rw)) 3485b81b6b3SRodney W. Grimes return (EFAULT); 3495b81b6b3SRodney W. Grimes insb(uio->uio_offset, iov->iov_base, 3505b81b6b3SRodney W. Grimes iov->iov_len); 3515b81b6b3SRodney W. Grimes } 3525b81b6b3SRodney W. Grimes break; 3535b81b6b3SRodney W. Grimes case 15: 3545b81b6b3SRodney W. Grimes if (iov->iov_len == sizeof (short)) { 3555b81b6b3SRodney W. Grimes u_short tmp; 3565b81b6b3SRodney W. Grimes tmp = inw(uio->uio_offset); 3575b81b6b3SRodney W. Grimes error = uiomove (&tmp, iov->iov_len, uio); 3585b81b6b3SRodney W. Grimes } else { 3595b81b6b3SRodney W. Grimes if (!useracc((caddr_t)iov->iov_base, 3605b81b6b3SRodney W. Grimes iov->iov_len, uio->uio_rw)) 3615b81b6b3SRodney W. Grimes return (EFAULT); 3625b81b6b3SRodney W. Grimes insw(uio->uio_offset, iov->iov_base, 3635b81b6b3SRodney W. Grimes iov->iov_len/ sizeof (short)); 3645b81b6b3SRodney W. Grimes } 3655b81b6b3SRodney W. Grimes break; 3665b81b6b3SRodney W. Grimes case 16: 3675b81b6b3SRodney W. Grimes if (iov->iov_len == sizeof (long)) { 3685b81b6b3SRodney W. Grimes u_long tmp; 3695b81b6b3SRodney W. Grimes tmp = inl(uio->uio_offset); 3705b81b6b3SRodney W. Grimes error = uiomove (&tmp, iov->iov_len, uio); 3715b81b6b3SRodney W. Grimes } else { 3725b81b6b3SRodney W. Grimes if (!useracc((caddr_t)iov->iov_base, 3735b81b6b3SRodney W. Grimes iov->iov_len, uio->uio_rw)) 3745b81b6b3SRodney W. Grimes return (EFAULT); 3755b81b6b3SRodney W. Grimes insl(uio->uio_offset, iov->iov_base, 3765b81b6b3SRodney W. Grimes iov->iov_len/ sizeof (long)); 3775b81b6b3SRodney W. Grimes } 3785b81b6b3SRodney W. Grimes break; 3795b81b6b3SRodney W. Grimes #endif 3805b81b6b3SRodney W. Grimes 3815b81b6b3SRodney W. Grimes default: 3825b81b6b3SRodney W. Grimes return (ENXIO); 3835b81b6b3SRodney W. Grimes } 3845b81b6b3SRodney W. Grimes if (error) 3855b81b6b3SRodney W. Grimes break; 3865b81b6b3SRodney W. Grimes iov->iov_base += c; 3875b81b6b3SRodney W. Grimes iov->iov_len -= c; 3885b81b6b3SRodney W. Grimes uio->uio_offset += c; 3895b81b6b3SRodney W. Grimes uio->uio_resid -= c; 3905b81b6b3SRodney W. Grimes } 3911bb2d314SMark Murray if (buf) 3921bb2d314SMark Murray free(buf, M_TEMP); 3935b81b6b3SRodney W. Grimes return (error); 3945b81b6b3SRodney W. Grimes } 395b513c262SDavid Greenman 396b513c262SDavid Greenman 397b513c262SDavid Greenman 398b513c262SDavid Greenman 399b513c262SDavid Greenman /*******************************************************\ 400b513c262SDavid Greenman * allow user processes to MMAP some memory sections * 401b513c262SDavid Greenman * instead of going through read/write * 402b513c262SDavid Greenman \*******************************************************/ 40387f6c662SJulian Elischer static int 4047095ee91SDoug Rabson memmmap(dev_t dev, vm_offset_t offset, int nprot) 405b513c262SDavid Greenman { 406b513c262SDavid Greenman switch (minor(dev)) 407b513c262SDavid Greenman { 408b513c262SDavid Greenman 409b513c262SDavid Greenman /* minor device 0 is physical memory */ 410b513c262SDavid Greenman case 0: 411b513c262SDavid Greenman return i386_btop(offset); 412b513c262SDavid Greenman 413b513c262SDavid Greenman /* minor device 1 is kernel memory */ 414b513c262SDavid Greenman case 1: 415b513c262SDavid Greenman return i386_btop(vtophys(offset)); 416b513c262SDavid Greenman 417b513c262SDavid Greenman default: 418b513c262SDavid Greenman return -1; 419b513c262SDavid Greenman } 420b513c262SDavid Greenman } 421b513c262SDavid Greenman 42287f6c662SJulian Elischer static int 423316bbd5cSBruce Evans mmioctl(dev, cmd, data, flags, p) 42400f7f6beSBruce Evans dev_t dev; 425ecbb00a2SDoug Rabson u_long cmd; 426316bbd5cSBruce Evans caddr_t data; 42700f7f6beSBruce Evans int flags; 42800f7f6beSBruce Evans struct proc *p; 4291bb2d314SMark Murray { 430a0135d7eSMark Murray 431d69e8502SGarrett Wollman switch (minor(dev)) { 4324ffd949eSMike Smith case 0: 4334ffd949eSMike Smith return mem_ioctl(dev, cmd, data, flags, p); 434d69e8502SGarrett Wollman case 3: 435d69e8502SGarrett Wollman case 4: 4364ffd949eSMike Smith return random_ioctl(dev, cmd, data, flags, p); 437d69e8502SGarrett Wollman #ifdef PERFMON 438d69e8502SGarrett Wollman case 32: 439316bbd5cSBruce Evans return perfmon_ioctl(dev, cmd, data, flags, p); 440d69e8502SGarrett Wollman #endif 4414ffd949eSMike Smith } 442316bbd5cSBruce Evans return (ENODEV); 443d69e8502SGarrett Wollman } 4441bb2d314SMark Murray 445316bbd5cSBruce Evans /* 4464ffd949eSMike Smith * Operations for changing memory attributes. 4474ffd949eSMike Smith * 4484ffd949eSMike Smith * This is basically just an ioctl shim for mem_range_attr_get 4494ffd949eSMike Smith * and mem_range_attr_set. 4504ffd949eSMike Smith */ 4514ffd949eSMike Smith static int 4524ffd949eSMike Smith mem_ioctl(dev, cmd, data, flags, p) 4534ffd949eSMike Smith dev_t dev; 4544ffd949eSMike Smith u_long cmd; 4554ffd949eSMike Smith caddr_t data; 4564ffd949eSMike Smith int flags; 4574ffd949eSMike Smith struct proc *p; 4584ffd949eSMike Smith { 4594ffd949eSMike Smith int nd, error = 0; 4604ffd949eSMike Smith struct mem_range_op *mo = (struct mem_range_op *)data; 4614ffd949eSMike Smith struct mem_range_desc *md; 4624ffd949eSMike Smith 4634ffd949eSMike Smith /* is this for us? */ 4644ffd949eSMike Smith if ((cmd != MEMRANGE_GET) && 4654ffd949eSMike Smith (cmd != MEMRANGE_SET)) 4664ffd949eSMike Smith return(ENODEV); 4674ffd949eSMike Smith 4684ffd949eSMike Smith /* any chance we can handle this? */ 4694ffd949eSMike Smith if (mem_range_softc.mr_op == NULL) 4704ffd949eSMike Smith return(EOPNOTSUPP); 4714ffd949eSMike Smith 4724ffd949eSMike Smith /* do we have any descriptors? */ 4734ffd949eSMike Smith if (mem_range_softc.mr_ndesc == 0) 4744ffd949eSMike Smith return(ENXIO); 4754ffd949eSMike Smith 4764ffd949eSMike Smith switch(cmd) { 4774ffd949eSMike Smith case MEMRANGE_GET: 4784ffd949eSMike Smith nd = imin(mo->mo_arg[0], mem_range_softc.mr_ndesc); 4794ffd949eSMike Smith if (nd > 0) { 4804ffd949eSMike Smith md = (struct mem_range_desc *) 4814ffd949eSMike Smith malloc(nd * sizeof(struct mem_range_desc), 4824ffd949eSMike Smith M_MEMDESC, M_WAITOK); 4834ffd949eSMike Smith mem_range_attr_get(md, &nd); 4844ffd949eSMike Smith error = copyout(md, mo->mo_desc, 4854ffd949eSMike Smith nd * sizeof(struct mem_range_desc)); 4864ffd949eSMike Smith free(md, M_MEMDESC); 4874ffd949eSMike Smith } else { 4884ffd949eSMike Smith nd = mem_range_softc.mr_ndesc; 4894ffd949eSMike Smith } 4904ffd949eSMike Smith mo->mo_arg[0] = nd; 4914ffd949eSMike Smith break; 4924ffd949eSMike Smith 4934ffd949eSMike Smith case MEMRANGE_SET: 4944ffd949eSMike Smith md = (struct mem_range_desc *)malloc(sizeof(struct mem_range_desc), 4954ffd949eSMike Smith M_MEMDESC, M_WAITOK); 4964ffd949eSMike Smith error = copyin(mo->mo_desc, md, sizeof(struct mem_range_desc)); 4974ffd949eSMike Smith /* clamp description string */ 4984ffd949eSMike Smith md->mr_owner[sizeof(md->mr_owner) - 1] = 0; 4994ffd949eSMike Smith if (error == 0) 5004ffd949eSMike Smith error = mem_range_attr_set(md, &mo->mo_arg[0]); 5014ffd949eSMike Smith free(md, M_MEMDESC); 5024ffd949eSMike Smith break; 5034ffd949eSMike Smith 5044ffd949eSMike Smith default: 5054ffd949eSMike Smith error = EOPNOTSUPP; 5064ffd949eSMike Smith } 5074ffd949eSMike Smith return(error); 5084ffd949eSMike Smith } 5094ffd949eSMike Smith 5104ffd949eSMike Smith /* 5114ffd949eSMike Smith * Implementation-neutral, kernel-callable functions for manipulating 5124ffd949eSMike Smith * memory range attributes. 5134ffd949eSMike Smith */ 5144ffd949eSMike Smith void 5154ffd949eSMike Smith mem_range_attr_get(struct mem_range_desc *mrd, int *arg) 5164ffd949eSMike Smith { 5174ffd949eSMike Smith if (*arg == 0) { 5184ffd949eSMike Smith *arg = mem_range_softc.mr_ndesc; 5194ffd949eSMike Smith } else { 5204ffd949eSMike Smith bcopy(mem_range_softc.mr_desc, mrd, (*arg) * sizeof(struct mem_range_desc)); 5214ffd949eSMike Smith } 5224ffd949eSMike Smith } 5234ffd949eSMike Smith 5244ffd949eSMike Smith int 5254ffd949eSMike Smith mem_range_attr_set(struct mem_range_desc *mrd, int *arg) 5264ffd949eSMike Smith { 5274ffd949eSMike Smith return(mem_range_softc.mr_op->set(&mem_range_softc, mrd, arg)); 5284ffd949eSMike Smith } 5294ffd949eSMike Smith 5304ffd949eSMike Smith static int 5314ffd949eSMike Smith random_ioctl(dev, cmd, data, flags, p) 5324ffd949eSMike Smith dev_t dev; 5334ffd949eSMike Smith u_long cmd; 5344ffd949eSMike Smith caddr_t data; 5354ffd949eSMike Smith int flags; 5364ffd949eSMike Smith struct proc *p; 5374ffd949eSMike Smith { 5384ffd949eSMike Smith static intrmask_t interrupt_allowed; 5394ffd949eSMike Smith intrmask_t interrupt_mask; 5404ffd949eSMike Smith int error, intr; 5414ffd949eSMike Smith struct random_softc *sc; 5424ffd949eSMike Smith 5434ffd949eSMike Smith /* 544316bbd5cSBruce Evans * We're the random or urandom device. The only ioctls are for 545316bbd5cSBruce Evans * selecting and inspecting which interrupts are used in the muck 546316bbd5cSBruce Evans * gathering business. 547316bbd5cSBruce Evans */ 548316bbd5cSBruce Evans if (cmd != MEM_SETIRQ && cmd != MEM_CLEARIRQ && cmd != MEM_RETURNIRQ) 549316bbd5cSBruce Evans return (ENOTTY); 550316bbd5cSBruce Evans 551316bbd5cSBruce Evans /* 552316bbd5cSBruce Evans * Even inspecting the state is privileged, since it gives a hint 553316bbd5cSBruce Evans * about how easily the randomness might be guessed. 554316bbd5cSBruce Evans */ 555316bbd5cSBruce Evans error = suser(p->p_ucred, &p->p_acflag); 556316bbd5cSBruce Evans if (error != 0) 557316bbd5cSBruce Evans return (error); 558316bbd5cSBruce Evans 559316bbd5cSBruce Evans /* 560316bbd5cSBruce Evans * XXX the data is 16-bit due to a historical botch, so we use 561316bbd5cSBruce Evans * magic 16's instead of ICU_LEN and can't support 24 interrupts 562316bbd5cSBruce Evans * under SMP. 563316bbd5cSBruce Evans */ 564316bbd5cSBruce Evans intr = *(int16_t *)data; 565316bbd5cSBruce Evans if (cmd != MEM_RETURNIRQ && (intr < 0 || intr >= 16)) 5661bb2d314SMark Murray return (EINVAL); 5671bb2d314SMark Murray 568316bbd5cSBruce Evans interrupt_mask = 1 << intr; 569316bbd5cSBruce Evans sc = &random_softc[intr]; 5701bb2d314SMark Murray switch (cmd) { 5711bb2d314SMark Murray case MEM_SETIRQ: 572316bbd5cSBruce Evans if (interrupt_allowed & interrupt_mask) 573316bbd5cSBruce Evans break; 574e85ceed0SMark Murray interrupt_allowed |= interrupt_mask; 575316bbd5cSBruce Evans sc->sc_intr = intr; 576e85ceed0SMark Murray disable_intr(); 577316bbd5cSBruce Evans sc->sc_handler = intr_handler[intr]; 578316bbd5cSBruce Evans intr_handler[intr] = add_interrupt_randomness; 579316bbd5cSBruce Evans sc->sc_arg = intr_unit[intr]; 580316bbd5cSBruce Evans intr_unit[intr] = sc; 581e85ceed0SMark Murray enable_intr(); 5821bb2d314SMark Murray break; 583316bbd5cSBruce Evans case MEM_CLEARIRQ: 584316bbd5cSBruce Evans if (!(interrupt_allowed & interrupt_mask)) 585316bbd5cSBruce Evans break; 586316bbd5cSBruce Evans interrupt_allowed &= ~interrupt_mask; 587316bbd5cSBruce Evans disable_intr(); 588316bbd5cSBruce Evans intr_handler[intr] = sc->sc_handler; 589316bbd5cSBruce Evans intr_unit[intr] = sc->sc_arg; 590316bbd5cSBruce Evans enable_intr(); 591316bbd5cSBruce Evans break; 5921bb2d314SMark Murray case MEM_RETURNIRQ: 593316bbd5cSBruce Evans *(u_int16_t *)data = interrupt_allowed; 5941bb2d314SMark Murray break; 5951bb2d314SMark Murray default: 5961bb2d314SMark Murray return (ENOTTY); 5971bb2d314SMark Murray } 5981bb2d314SMark Murray return (0); 59900f7f6beSBruce Evans } 60053ac6efbSJulian Elischer 601983febf3SPeter Wemm int 60235b8b2ddSPeter Wemm mmpoll(dev, events, p) 603983febf3SPeter Wemm dev_t dev; 60435b8b2ddSPeter Wemm int events; 605983febf3SPeter Wemm struct proc *p; 606983febf3SPeter Wemm { 607983febf3SPeter Wemm switch (minor(dev)) { 608983febf3SPeter Wemm case 3: /* /dev/random */ 60935b8b2ddSPeter Wemm return random_poll(dev, events, p); 610983febf3SPeter Wemm case 4: /* /dev/urandom */ 611983febf3SPeter Wemm default: 61235b8b2ddSPeter Wemm return seltrue(dev, events, p); 613983febf3SPeter Wemm } 614983febf3SPeter Wemm } 615983febf3SPeter Wemm 616ee0ef569SJulian Elischer /* 617ee0ef569SJulian Elischer * Routine that identifies /dev/mem and /dev/kmem. 618ee0ef569SJulian Elischer * 619ee0ef569SJulian Elischer * A minimal stub routine can always return 0. 620ee0ef569SJulian Elischer */ 621ee0ef569SJulian Elischer int 622ee0ef569SJulian Elischer iskmemdev(dev) 623ee0ef569SJulian Elischer dev_t dev; 624ee0ef569SJulian Elischer { 625ee0ef569SJulian Elischer 626ee0ef569SJulian Elischer return ((major(dev) == mem_cdevsw.d_maj) 627ee0ef569SJulian Elischer && (minor(dev) == 0 || minor(dev) == 1)); 628ee0ef569SJulian Elischer } 629ee0ef569SJulian Elischer 630ee0ef569SJulian Elischer int 631ee0ef569SJulian Elischer iszerodev(dev) 632ee0ef569SJulian Elischer dev_t dev; 633ee0ef569SJulian Elischer { 634ee0ef569SJulian Elischer return ((major(dev) == mem_cdevsw.d_maj) 635ee0ef569SJulian Elischer && minor(dev) == 12); 636ee0ef569SJulian Elischer } 637ee0ef569SJulian Elischer 63853ac6efbSJulian Elischer 63953ac6efbSJulian Elischer 640d1d9d260SBruce Evans static int mem_devsw_installed; 64153ac6efbSJulian Elischer 64287f6c662SJulian Elischer static void 64387f6c662SJulian Elischer mem_drvinit(void *unused) 64453ac6efbSJulian Elischer { 64553ac6efbSJulian Elischer dev_t dev; 64653ac6efbSJulian Elischer 6474ffd949eSMike Smith /* Initialise memory range handling */ 6484ffd949eSMike Smith if (mem_range_softc.mr_op != NULL) 6494ffd949eSMike Smith mem_range_softc.mr_op->init(&mem_range_softc); 6504ffd949eSMike Smith 6514ffd949eSMike Smith /* device registration */ 65253ac6efbSJulian Elischer if( ! mem_devsw_installed ) { 6534ffd949eSMike Smith 65453ac6efbSJulian Elischer dev = makedev(CDEV_MAJOR, 0); 65553ac6efbSJulian Elischer cdevsw_add(&dev,&mem_cdevsw, NULL); 65653ac6efbSJulian Elischer mem_devsw_installed = 1; 65753ac6efbSJulian Elischer #ifdef DEVFS 65887f6c662SJulian Elischer memdevfs_init(); 65953ac6efbSJulian Elischer #endif 66053ac6efbSJulian Elischer } 6617198bf47SJulian Elischer } 66253ac6efbSJulian Elischer 66353ac6efbSJulian Elischer SYSINIT(memdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,mem_drvinit,NULL) 66453ac6efbSJulian Elischer 665