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 41c3aac50fSPeter Wemm * $FreeBSD$ 425b81b6b3SRodney W. Grimes */ 435b81b6b3SRodney W. Grimes 445b81b6b3SRodney W. Grimes /* 455b81b6b3SRodney W. Grimes * Memory special file 465b81b6b3SRodney W. Grimes */ 475b81b6b3SRodney W. Grimes 4826f9a767SRodney W. Grimes #include <sys/param.h> 4926f9a767SRodney W. Grimes #include <sys/conf.h> 50265cdeddSBruce Evans #include <sys/fcntl.h> 514ffd949eSMike Smith #include <sys/ioccom.h> 52d4af7a50SDavid E. O'Brien #include <sys/kernel.h> 5326f9a767SRodney W. Grimes #include <sys/malloc.h> 544ffd949eSMike Smith #include <sys/memrange.h> 5526f9a767SRodney W. Grimes #include <sys/proc.h> 56b0e56cdeSDavid E. O'Brien #include <sys/random.h> 57bb25f0ddSBruce Evans #include <sys/signalvar.h> 58d4af7a50SDavid E. O'Brien #include <sys/systm.h> 59d4af7a50SDavid E. O'Brien #include <sys/uio.h> 605b81b6b3SRodney W. Grimes 61d1d9d260SBruce Evans #include <machine/frame.h> 6226f9a767SRodney W. Grimes #include <machine/psl.h> 634ffd949eSMike Smith #include <machine/specialreg.h> 6468352337SDoug Rabson #include <i386/isa/intr_machdep.h> 655b81b6b3SRodney W. Grimes 66c87801feSDavid Greenman #include <vm/vm.h> 6726f9a767SRodney W. Grimes #include <vm/pmap.h> 68efeaf95aSDavid Greenman #include <vm/vm_extern.h> 695b81b6b3SRodney W. Grimes 7087f6c662SJulian Elischer 7187f6c662SJulian Elischer static d_open_t mmopen; 7287f6c662SJulian Elischer static d_close_t mmclose; 73c73feca0SBruce Evans static d_read_t mmrw; 7487f6c662SJulian Elischer static d_ioctl_t mmioctl; 7587f6c662SJulian Elischer static d_mmap_t memmmap; 7635b8b2ddSPeter Wemm static d_poll_t mmpoll; 7787f6c662SJulian Elischer 7853ac6efbSJulian Elischer #define CDEV_MAJOR 2 794e2f199eSPoul-Henning Kamp static struct cdevsw mem_cdevsw = { 804e2f199eSPoul-Henning Kamp /* open */ mmopen, 814e2f199eSPoul-Henning Kamp /* close */ mmclose, 824e2f199eSPoul-Henning Kamp /* read */ mmrw, 834e2f199eSPoul-Henning Kamp /* write */ mmrw, 844e2f199eSPoul-Henning Kamp /* ioctl */ mmioctl, 854e2f199eSPoul-Henning Kamp /* poll */ mmpoll, 864e2f199eSPoul-Henning Kamp /* mmap */ memmmap, 874e2f199eSPoul-Henning Kamp /* strategy */ nostrategy, 884e2f199eSPoul-Henning Kamp /* name */ "mem", 894e2f199eSPoul-Henning Kamp /* maj */ CDEV_MAJOR, 904e2f199eSPoul-Henning Kamp /* dump */ nodump, 914e2f199eSPoul-Henning Kamp /* psize */ nopsize, 9249c68457SBrian Feldman /* flags */ D_MEM, 934e2f199eSPoul-Henning Kamp /* bmaj */ -1 944e2f199eSPoul-Henning Kamp }; 9553ac6efbSJulian Elischer 96316bbd5cSBruce Evans static struct random_softc random_softc[16]; 9720073b6dSNate Williams static caddr_t zbuf; 9820073b6dSNate Williams 994ffd949eSMike Smith MALLOC_DEFINE(M_MEMDESC, "memdesc", "memory range descriptors"); 1004ffd949eSMike Smith static int mem_ioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); 1014ffd949eSMike Smith static int random_ioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); 1024ffd949eSMike Smith 1034ffd949eSMike Smith struct mem_range_softc mem_range_softc; 1044ffd949eSMike Smith 1058af5d536SJulian Elischer 10687f6c662SJulian Elischer static int 10760039670SBruce Evans mmclose(dev, flags, fmt, p) 10878d172caSRodney W. Grimes dev_t dev; 10978d172caSRodney W. Grimes int flags; 11060039670SBruce Evans int fmt; 11160039670SBruce Evans struct proc *p; 11278d172caSRodney W. Grimes { 11378d172caSRodney W. Grimes switch (minor(dev)) { 11478d172caSRodney W. Grimes case 14: 115265cdeddSBruce Evans p->p_md.md_regs->tf_eflags &= ~PSL_IOPL; 11678d172caSRodney W. Grimes break; 11778d172caSRodney W. Grimes default: 11878d172caSRodney W. Grimes break; 11978d172caSRodney W. Grimes } 12078d172caSRodney W. Grimes return (0); 12178d172caSRodney W. Grimes } 12233f538b9SBruce Evans 12387f6c662SJulian Elischer static int 12460039670SBruce Evans mmopen(dev, flags, fmt, p) 12578d172caSRodney W. Grimes dev_t dev; 12678d172caSRodney W. Grimes int flags; 12760039670SBruce Evans int fmt; 12860039670SBruce Evans struct proc *p; 12978d172caSRodney W. Grimes { 130da3df630SBruce Evans int error; 13178d172caSRodney W. Grimes 13278d172caSRodney W. Grimes switch (minor(dev)) { 13318284c94SPoul-Henning Kamp case 0: 13418284c94SPoul-Henning Kamp case 1: 135265cdeddSBruce Evans if ((flags & FWRITE) && securelevel > 0) 13618284c94SPoul-Henning Kamp return (EPERM); 13718284c94SPoul-Henning Kamp break; 13878d172caSRodney W. Grimes case 14: 139f711d546SPoul-Henning Kamp error = suser(p); 140da3df630SBruce Evans if (error != 0) 141da3df630SBruce Evans return (error); 142da3df630SBruce Evans if (securelevel > 0) 143da3df630SBruce Evans return (EPERM); 144265cdeddSBruce Evans p->p_md.md_regs->tf_eflags |= PSL_IOPL; 14578d172caSRodney W. Grimes break; 14678d172caSRodney W. Grimes default: 14778d172caSRodney W. Grimes break; 14878d172caSRodney W. Grimes } 14978d172caSRodney W. Grimes return (0); 15078d172caSRodney W. Grimes } 15133f538b9SBruce Evans 15287f6c662SJulian Elischer static int 1535b81b6b3SRodney W. Grimes mmrw(dev, uio, flags) 1545b81b6b3SRodney W. Grimes dev_t dev; 1555b81b6b3SRodney W. Grimes struct uio *uio; 1565b81b6b3SRodney W. Grimes int flags; 1575b81b6b3SRodney W. Grimes { 1585b81b6b3SRodney W. Grimes register int o; 1595b81b6b3SRodney W. Grimes register u_int c, v; 1601bb2d314SMark Murray u_int poolsize; 1615b81b6b3SRodney W. Grimes register struct iovec *iov; 1625b81b6b3SRodney W. Grimes int error = 0; 1631bb2d314SMark Murray caddr_t buf = NULL; 1645b81b6b3SRodney W. Grimes 1655b81b6b3SRodney W. Grimes while (uio->uio_resid > 0 && error == 0) { 1665b81b6b3SRodney W. Grimes iov = uio->uio_iov; 1675b81b6b3SRodney W. Grimes if (iov->iov_len == 0) { 1685b81b6b3SRodney W. Grimes uio->uio_iov++; 1695b81b6b3SRodney W. Grimes uio->uio_iovcnt--; 1705b81b6b3SRodney W. Grimes if (uio->uio_iovcnt < 0) 1715b81b6b3SRodney W. Grimes panic("mmrw"); 1725b81b6b3SRodney W. Grimes continue; 1735b81b6b3SRodney W. Grimes } 1745b81b6b3SRodney W. Grimes switch (minor(dev)) { 1755b81b6b3SRodney W. Grimes 1765b81b6b3SRodney W. Grimes /* minor device 0 is physical memory */ 1775b81b6b3SRodney W. Grimes case 0: 1785b81b6b3SRodney W. Grimes v = uio->uio_offset; 1790385347cSPeter Wemm pmap_kenter((vm_offset_t)ptvmmap, v); 180f8845af0SPoul-Henning Kamp o = (int)uio->uio_offset & PAGE_MASK; 181f8845af0SPoul-Henning Kamp c = (u_int)(PAGE_SIZE - ((int)iov->iov_base & PAGE_MASK)); 182f8845af0SPoul-Henning Kamp c = min(c, (u_int)(PAGE_SIZE - o)); 18326f9a767SRodney W. Grimes c = min(c, (u_int)iov->iov_len); 18426f9a767SRodney W. Grimes error = uiomove((caddr_t)&ptvmmap[o], (int)c, uio); 1850385347cSPeter Wemm pmap_kremove((vm_offset_t)ptvmmap); 1865b81b6b3SRodney W. Grimes continue; 1875b81b6b3SRodney W. Grimes 1885b81b6b3SRodney W. Grimes /* minor device 1 is kernel memory */ 18997e11262SDavid Greenman case 1: { 19097e11262SDavid Greenman vm_offset_t addr, eaddr; 1915b81b6b3SRodney W. Grimes c = iov->iov_len; 19297e11262SDavid Greenman 19397e11262SDavid Greenman /* 19497e11262SDavid Greenman * Make sure that all of the pages are currently resident so 19597e11262SDavid Greenman * that we don't create any zero-fill pages. 19697e11262SDavid Greenman */ 19797e11262SDavid Greenman addr = trunc_page(uio->uio_offset); 1980704324aSDavid Greenman eaddr = round_page(uio->uio_offset + c); 199d021fc11SPeter Wemm 200d021fc11SPeter Wemm if (addr < (vm_offset_t)VADDR(PTDPTDI, 0)) 201d021fc11SPeter Wemm return EFAULT; 202d021fc11SPeter Wemm if (eaddr >= (vm_offset_t)VADDR(APTDPTDI, 0)) 203d021fc11SPeter Wemm return EFAULT; 20497e11262SDavid Greenman for (; addr < eaddr; addr += PAGE_SIZE) 20597e11262SDavid Greenman if (pmap_extract(kernel_pmap, addr) == 0) 20697e11262SDavid Greenman return EFAULT; 20797e11262SDavid Greenman 20826f9a767SRodney W. Grimes if (!kernacc((caddr_t)(int)uio->uio_offset, c, 20902c58685SPoul-Henning Kamp uio->uio_rw == UIO_READ ? 21002c58685SPoul-Henning Kamp VM_PROT_READ : VM_PROT_WRITE)) 2115b81b6b3SRodney W. Grimes return (EFAULT); 21226f9a767SRodney W. Grimes error = uiomove((caddr_t)(int)uio->uio_offset, (int)c, uio); 2135b81b6b3SRodney W. Grimes continue; 21497e11262SDavid Greenman } 2155b81b6b3SRodney W. Grimes 2165b81b6b3SRodney W. Grimes /* minor device 2 is EOF/RATHOLE */ 2175b81b6b3SRodney W. Grimes case 2: 2185b81b6b3SRodney W. Grimes if (uio->uio_rw == UIO_READ) 2195b81b6b3SRodney W. Grimes return (0); 2205b81b6b3SRodney W. Grimes c = iov->iov_len; 2215b81b6b3SRodney W. Grimes break; 2225b81b6b3SRodney W. Grimes 2231bb2d314SMark Murray /* minor device 3 (/dev/random) is source of filth on read, rathole on write */ 2241bb2d314SMark Murray case 3: 2251bb2d314SMark Murray if (uio->uio_rw == UIO_WRITE) { 2261bb2d314SMark Murray c = iov->iov_len; 2271bb2d314SMark Murray break; 2281bb2d314SMark Murray } 2291bb2d314SMark Murray if (buf == NULL) 2301bb2d314SMark Murray buf = (caddr_t) 231f8845af0SPoul-Henning Kamp malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 232f8845af0SPoul-Henning Kamp c = min(iov->iov_len, PAGE_SIZE); 2331bb2d314SMark Murray poolsize = read_random(buf, c); 2341bb2d314SMark Murray if (poolsize == 0) { 2351bb2d314SMark Murray if (buf) 2361bb2d314SMark Murray free(buf, M_TEMP); 2371bb2d314SMark Murray return (0); 2381bb2d314SMark Murray } 2391bb2d314SMark Murray c = min(c, poolsize); 2401bb2d314SMark Murray error = uiomove(buf, (int)c, uio); 2411bb2d314SMark Murray continue; 2421bb2d314SMark Murray 2431bb2d314SMark Murray /* minor device 4 (/dev/urandom) is source of muck on read, rathole on write */ 2441bb2d314SMark Murray case 4: 2451bb2d314SMark Murray if (uio->uio_rw == UIO_WRITE) { 2461bb2d314SMark Murray c = iov->iov_len; 2471bb2d314SMark Murray break; 2481bb2d314SMark Murray } 249bb25f0ddSBruce Evans if (CURSIG(curproc) != 0) { 250bb25f0ddSBruce Evans /* 251bb25f0ddSBruce Evans * Use tsleep() to get the error code right. 252bb25f0ddSBruce Evans * It should return immediately. 253bb25f0ddSBruce Evans */ 254bb25f0ddSBruce Evans error = tsleep(&random_softc[0], 255bb25f0ddSBruce Evans PZERO | PCATCH, "urand", 1); 256bb25f0ddSBruce Evans if (error != 0 && error != EWOULDBLOCK) 257bb25f0ddSBruce Evans continue; 258bb25f0ddSBruce Evans } 2591bb2d314SMark Murray if (buf == NULL) 2601bb2d314SMark Murray buf = (caddr_t) 261f8845af0SPoul-Henning Kamp malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 262f8845af0SPoul-Henning Kamp c = min(iov->iov_len, PAGE_SIZE); 2631bb2d314SMark Murray poolsize = read_random_unlimited(buf, c); 2641bb2d314SMark Murray c = min(c, poolsize); 2651bb2d314SMark Murray error = uiomove(buf, (int)c, uio); 2661bb2d314SMark Murray continue; 2671bb2d314SMark Murray 2685b81b6b3SRodney W. Grimes /* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */ 2695b81b6b3SRodney W. Grimes case 12: 2705b81b6b3SRodney W. Grimes if (uio->uio_rw == UIO_WRITE) { 2715b81b6b3SRodney W. Grimes c = iov->iov_len; 2725b81b6b3SRodney W. Grimes break; 2735b81b6b3SRodney W. Grimes } 274f381a0c0SJohn Dyson if (zbuf == NULL) { 275f381a0c0SJohn Dyson zbuf = (caddr_t) 276f8845af0SPoul-Henning Kamp malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 277f381a0c0SJohn Dyson bzero(zbuf, PAGE_SIZE); 2785b81b6b3SRodney W. Grimes } 279f8845af0SPoul-Henning Kamp c = min(iov->iov_len, PAGE_SIZE); 280f381a0c0SJohn Dyson error = uiomove(zbuf, (int)c, uio); 2815b81b6b3SRodney W. Grimes continue; 2825b81b6b3SRodney W. Grimes 2835b81b6b3SRodney W. Grimes default: 2845b81b6b3SRodney W. Grimes return (ENXIO); 2855b81b6b3SRodney W. Grimes } 2865b81b6b3SRodney W. Grimes if (error) 2875b81b6b3SRodney W. Grimes break; 2885b81b6b3SRodney W. Grimes iov->iov_base += c; 2895b81b6b3SRodney W. Grimes iov->iov_len -= c; 2905b81b6b3SRodney W. Grimes uio->uio_offset += c; 2915b81b6b3SRodney W. Grimes uio->uio_resid -= c; 2925b81b6b3SRodney W. Grimes } 2931bb2d314SMark Murray if (buf) 2941bb2d314SMark Murray free(buf, M_TEMP); 2955b81b6b3SRodney W. Grimes return (error); 2965b81b6b3SRodney W. Grimes } 297b513c262SDavid Greenman 298b513c262SDavid Greenman 299b513c262SDavid Greenman 300b513c262SDavid Greenman 301b513c262SDavid Greenman /*******************************************************\ 302b513c262SDavid Greenman * allow user processes to MMAP some memory sections * 303b513c262SDavid Greenman * instead of going through read/write * 304b513c262SDavid Greenman \*******************************************************/ 30587f6c662SJulian Elischer static int 3067095ee91SDoug Rabson memmmap(dev_t dev, vm_offset_t offset, int nprot) 307b513c262SDavid Greenman { 308b513c262SDavid Greenman switch (minor(dev)) 309b513c262SDavid Greenman { 310b513c262SDavid Greenman 311b513c262SDavid Greenman /* minor device 0 is physical memory */ 312b513c262SDavid Greenman case 0: 313b513c262SDavid Greenman return i386_btop(offset); 314b513c262SDavid Greenman 315b513c262SDavid Greenman /* minor device 1 is kernel memory */ 316b513c262SDavid Greenman case 1: 317b513c262SDavid Greenman return i386_btop(vtophys(offset)); 318b513c262SDavid Greenman 319b513c262SDavid Greenman default: 320b513c262SDavid Greenman return -1; 321b513c262SDavid Greenman } 322b513c262SDavid Greenman } 323b513c262SDavid Greenman 32487f6c662SJulian Elischer static int 325316bbd5cSBruce Evans mmioctl(dev, cmd, data, flags, p) 32600f7f6beSBruce Evans dev_t dev; 327ecbb00a2SDoug Rabson u_long cmd; 328316bbd5cSBruce Evans caddr_t data; 32900f7f6beSBruce Evans int flags; 33000f7f6beSBruce Evans struct proc *p; 3311bb2d314SMark Murray { 332a0135d7eSMark Murray 333d69e8502SGarrett Wollman switch (minor(dev)) { 3344ffd949eSMike Smith case 0: 3354ffd949eSMike Smith return mem_ioctl(dev, cmd, data, flags, p); 336d69e8502SGarrett Wollman case 3: 337d69e8502SGarrett Wollman case 4: 3384ffd949eSMike Smith return random_ioctl(dev, cmd, data, flags, p); 3394ffd949eSMike Smith } 340316bbd5cSBruce Evans return (ENODEV); 341d69e8502SGarrett Wollman } 3421bb2d314SMark Murray 343316bbd5cSBruce Evans /* 3444ffd949eSMike Smith * Operations for changing memory attributes. 3454ffd949eSMike Smith * 3464ffd949eSMike Smith * This is basically just an ioctl shim for mem_range_attr_get 3474ffd949eSMike Smith * and mem_range_attr_set. 3484ffd949eSMike Smith */ 3494ffd949eSMike Smith static int 3504ffd949eSMike Smith mem_ioctl(dev, cmd, data, flags, p) 3514ffd949eSMike Smith dev_t dev; 3524ffd949eSMike Smith u_long cmd; 3534ffd949eSMike Smith caddr_t data; 3544ffd949eSMike Smith int flags; 3554ffd949eSMike Smith struct proc *p; 3564ffd949eSMike Smith { 3574ffd949eSMike Smith int nd, error = 0; 3584ffd949eSMike Smith struct mem_range_op *mo = (struct mem_range_op *)data; 3594ffd949eSMike Smith struct mem_range_desc *md; 3604ffd949eSMike Smith 3614ffd949eSMike Smith /* is this for us? */ 3624ffd949eSMike Smith if ((cmd != MEMRANGE_GET) && 3634ffd949eSMike Smith (cmd != MEMRANGE_SET)) 3644871de2fSBrian Feldman return (ENOTTY); 3654ffd949eSMike Smith 3664ffd949eSMike Smith /* any chance we can handle this? */ 3674ffd949eSMike Smith if (mem_range_softc.mr_op == NULL) 3684ffd949eSMike Smith return (EOPNOTSUPP); 3694ffd949eSMike Smith 3704ffd949eSMike Smith /* do we have any descriptors? */ 3714ffd949eSMike Smith if (mem_range_softc.mr_ndesc == 0) 3724ffd949eSMike Smith return (ENXIO); 3734ffd949eSMike Smith 3744ffd949eSMike Smith switch (cmd) { 3754ffd949eSMike Smith case MEMRANGE_GET: 3764ffd949eSMike Smith nd = imin(mo->mo_arg[0], mem_range_softc.mr_ndesc); 3774ffd949eSMike Smith if (nd > 0) { 3784ffd949eSMike Smith md = (struct mem_range_desc *) 3794ffd949eSMike Smith malloc(nd * sizeof(struct mem_range_desc), 3804ffd949eSMike Smith M_MEMDESC, M_WAITOK); 381ac3595b0SMike Smith error = mem_range_attr_get(md, &nd); 382ac3595b0SMike Smith if (!error) 3834ffd949eSMike Smith error = copyout(md, mo->mo_desc, 3844ffd949eSMike Smith nd * sizeof(struct mem_range_desc)); 3854ffd949eSMike Smith free(md, M_MEMDESC); 3864ffd949eSMike Smith } else { 3874ffd949eSMike Smith nd = mem_range_softc.mr_ndesc; 3884ffd949eSMike Smith } 3894ffd949eSMike Smith mo->mo_arg[0] = nd; 3904ffd949eSMike Smith break; 3914ffd949eSMike Smith 3924ffd949eSMike Smith case MEMRANGE_SET: 3934ffd949eSMike Smith md = (struct mem_range_desc *)malloc(sizeof(struct mem_range_desc), 3944ffd949eSMike Smith M_MEMDESC, M_WAITOK); 3954ffd949eSMike Smith error = copyin(mo->mo_desc, md, sizeof(struct mem_range_desc)); 3964ffd949eSMike Smith /* clamp description string */ 3974ffd949eSMike Smith md->mr_owner[sizeof(md->mr_owner) - 1] = 0; 3984ffd949eSMike Smith if (error == 0) 3994ffd949eSMike Smith error = mem_range_attr_set(md, &mo->mo_arg[0]); 4004ffd949eSMike Smith free(md, M_MEMDESC); 4014ffd949eSMike Smith break; 4024ffd949eSMike Smith } 4034ffd949eSMike Smith return (error); 4044ffd949eSMike Smith } 4054ffd949eSMike Smith 4064ffd949eSMike Smith /* 4074ffd949eSMike Smith * Implementation-neutral, kernel-callable functions for manipulating 4084ffd949eSMike Smith * memory range attributes. 4094ffd949eSMike Smith */ 410ac3595b0SMike Smith int 4114af396a5SMike Smith mem_range_attr_get(mrd, arg) 4124af396a5SMike Smith struct mem_range_desc *mrd; 4134af396a5SMike Smith int *arg; 4144ffd949eSMike Smith { 4154af396a5SMike Smith /* can we handle this? */ 4164af396a5SMike Smith if (mem_range_softc.mr_op == NULL) 4174af396a5SMike Smith return (EOPNOTSUPP); 4184af396a5SMike Smith 4194ffd949eSMike Smith if (*arg == 0) { 4204ffd949eSMike Smith *arg = mem_range_softc.mr_ndesc; 4214ffd949eSMike Smith } else { 4224ffd949eSMike Smith bcopy(mem_range_softc.mr_desc, mrd, (*arg) * sizeof(struct mem_range_desc)); 4234ffd949eSMike Smith } 424ac3595b0SMike Smith return (0); 4254ffd949eSMike Smith } 4264ffd949eSMike Smith 4274ffd949eSMike Smith int 4284af396a5SMike Smith mem_range_attr_set(mrd, arg) 4294af396a5SMike Smith struct mem_range_desc *mrd; 4304af396a5SMike Smith int *arg; 4314ffd949eSMike Smith { 4324af396a5SMike Smith /* can we handle this? */ 4334af396a5SMike Smith if (mem_range_softc.mr_op == NULL) 4344af396a5SMike Smith return (EOPNOTSUPP); 4354af396a5SMike Smith 4364ffd949eSMike Smith return (mem_range_softc.mr_op->set(&mem_range_softc, mrd, arg)); 4374ffd949eSMike Smith } 4384ffd949eSMike Smith 4399c06a386SPeter Wemm #ifdef SMP 4404a034f21SMike Smith void 4414a034f21SMike Smith mem_range_AP_init(void) 4424a034f21SMike Smith { 443cbdfdcb2SPeter Wemm if (mem_range_softc.mr_op && mem_range_softc.mr_op->initAP) 4444a034f21SMike Smith return (mem_range_softc.mr_op->initAP(&mem_range_softc)); 4454a034f21SMike Smith } 4469c06a386SPeter Wemm #endif 4474a034f21SMike Smith 4484ffd949eSMike Smith static int 4494ffd949eSMike Smith random_ioctl(dev, cmd, data, flags, p) 4504ffd949eSMike Smith dev_t dev; 4514ffd949eSMike Smith u_long cmd; 4524ffd949eSMike Smith caddr_t data; 4534ffd949eSMike Smith int flags; 4544ffd949eSMike Smith struct proc *p; 4554ffd949eSMike Smith { 4564ffd949eSMike Smith static intrmask_t interrupt_allowed; 4574ffd949eSMike Smith intrmask_t interrupt_mask; 4584ffd949eSMike Smith int error, intr; 4594ffd949eSMike Smith struct random_softc *sc; 4604ffd949eSMike Smith 4614ffd949eSMike Smith /* 462316bbd5cSBruce Evans * We're the random or urandom device. The only ioctls are for 463316bbd5cSBruce Evans * selecting and inspecting which interrupts are used in the muck 464316bbd5cSBruce Evans * gathering business. 465316bbd5cSBruce Evans */ 466316bbd5cSBruce Evans if (cmd != MEM_SETIRQ && cmd != MEM_CLEARIRQ && cmd != MEM_RETURNIRQ) 467316bbd5cSBruce Evans return (ENOTTY); 468316bbd5cSBruce Evans 469316bbd5cSBruce Evans /* 470316bbd5cSBruce Evans * Even inspecting the state is privileged, since it gives a hint 471316bbd5cSBruce Evans * about how easily the randomness might be guessed. 472316bbd5cSBruce Evans */ 473f711d546SPoul-Henning Kamp error = suser(p); 474316bbd5cSBruce Evans if (error != 0) 475316bbd5cSBruce Evans return (error); 476316bbd5cSBruce Evans 477316bbd5cSBruce Evans /* 478316bbd5cSBruce Evans * XXX the data is 16-bit due to a historical botch, so we use 479316bbd5cSBruce Evans * magic 16's instead of ICU_LEN and can't support 24 interrupts 480316bbd5cSBruce Evans * under SMP. 481316bbd5cSBruce Evans */ 482316bbd5cSBruce Evans intr = *(int16_t *)data; 483316bbd5cSBruce Evans if (cmd != MEM_RETURNIRQ && (intr < 0 || intr >= 16)) 4841bb2d314SMark Murray return (EINVAL); 4851bb2d314SMark Murray 486316bbd5cSBruce Evans interrupt_mask = 1 << intr; 487316bbd5cSBruce Evans sc = &random_softc[intr]; 4881bb2d314SMark Murray switch (cmd) { 4891bb2d314SMark Murray case MEM_SETIRQ: 490316bbd5cSBruce Evans if (interrupt_allowed & interrupt_mask) 491316bbd5cSBruce Evans break; 492e85ceed0SMark Murray interrupt_allowed |= interrupt_mask; 493316bbd5cSBruce Evans sc->sc_intr = intr; 494e85ceed0SMark Murray disable_intr(); 495316bbd5cSBruce Evans sc->sc_handler = intr_handler[intr]; 496316bbd5cSBruce Evans intr_handler[intr] = add_interrupt_randomness; 497316bbd5cSBruce Evans sc->sc_arg = intr_unit[intr]; 498316bbd5cSBruce Evans intr_unit[intr] = sc; 499e85ceed0SMark Murray enable_intr(); 5001bb2d314SMark Murray break; 501316bbd5cSBruce Evans case MEM_CLEARIRQ: 502316bbd5cSBruce Evans if (!(interrupt_allowed & interrupt_mask)) 503316bbd5cSBruce Evans break; 504316bbd5cSBruce Evans interrupt_allowed &= ~interrupt_mask; 505316bbd5cSBruce Evans disable_intr(); 506316bbd5cSBruce Evans intr_handler[intr] = sc->sc_handler; 507316bbd5cSBruce Evans intr_unit[intr] = sc->sc_arg; 508316bbd5cSBruce Evans enable_intr(); 509316bbd5cSBruce Evans break; 5101bb2d314SMark Murray case MEM_RETURNIRQ: 511316bbd5cSBruce Evans *(u_int16_t *)data = interrupt_allowed; 5121bb2d314SMark Murray break; 5131bb2d314SMark Murray } 5141bb2d314SMark Murray return (0); 51500f7f6beSBruce Evans } 51653ac6efbSJulian Elischer 517983febf3SPeter Wemm int 51835b8b2ddSPeter Wemm mmpoll(dev, events, p) 519983febf3SPeter Wemm dev_t dev; 52035b8b2ddSPeter Wemm int events; 521983febf3SPeter Wemm struct proc *p; 522983febf3SPeter Wemm { 523983febf3SPeter Wemm switch (minor(dev)) { 524983febf3SPeter Wemm case 3: /* /dev/random */ 52535b8b2ddSPeter Wemm return random_poll(dev, events, p); 526983febf3SPeter Wemm case 4: /* /dev/urandom */ 527983febf3SPeter Wemm default: 52835b8b2ddSPeter Wemm return seltrue(dev, events, p); 529983febf3SPeter Wemm } 530983febf3SPeter Wemm } 531983febf3SPeter Wemm 532ee0ef569SJulian Elischer int 533ee0ef569SJulian Elischer iszerodev(dev) 534ee0ef569SJulian Elischer dev_t dev; 535ee0ef569SJulian Elischer { 536ee0ef569SJulian Elischer return ((major(dev) == mem_cdevsw.d_maj) 537ee0ef569SJulian Elischer && minor(dev) == 12); 538ee0ef569SJulian Elischer } 539ee0ef569SJulian Elischer 54087f6c662SJulian Elischer static void 54187f6c662SJulian Elischer mem_drvinit(void *unused) 54253ac6efbSJulian Elischer { 54353ac6efbSJulian Elischer 5444ffd949eSMike Smith /* Initialise memory range handling */ 5454ffd949eSMike Smith if (mem_range_softc.mr_op != NULL) 5464ffd949eSMike Smith mem_range_softc.mr_op->init(&mem_range_softc); 5474ffd949eSMike Smith 5489dcbe240SPoul-Henning Kamp make_dev(&mem_cdevsw, 0, UID_ROOT, GID_KMEM, 0640, "mem"); 5499dcbe240SPoul-Henning Kamp make_dev(&mem_cdevsw, 1, UID_ROOT, GID_KMEM, 0640, "kmem"); 5509dcbe240SPoul-Henning Kamp make_dev(&mem_cdevsw, 2, UID_ROOT, GID_WHEEL, 0666, "null"); 5519dcbe240SPoul-Henning Kamp make_dev(&mem_cdevsw, 3, UID_ROOT, GID_WHEEL, 0644, "random"); 5529dcbe240SPoul-Henning Kamp make_dev(&mem_cdevsw, 4, UID_ROOT, GID_WHEEL, 0644, "urandom"); 5539dcbe240SPoul-Henning Kamp make_dev(&mem_cdevsw, 12, UID_ROOT, GID_WHEEL, 0666, "zero"); 5549dcbe240SPoul-Henning Kamp make_dev(&mem_cdevsw, 14, UID_ROOT, GID_WHEEL, 0600, "io"); 5557198bf47SJulian Elischer } 55653ac6efbSJulian Elischer 55753ac6efbSJulian Elischer SYSINIT(memdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,mem_drvinit,NULL) 55853ac6efbSJulian Elischer 559