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