xref: /freebsd/sys/amd64/amd64/mem.c (revision bb25f0dd238cdc884f6d9da83cb6002ce1a46ab1)
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