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