xref: /freebsd/sys/amd64/amd64/mem.c (revision a8445737e740901f5f2c8d24c12ef7fc8b00134e)
1 /*-
2  * Copyright (c) 1988 University of Utah.
3  * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * the Systems Programming Group of the University of Utah Computer
8  * Science Department, and code derived from software contributed to
9  * Berkeley by William Jolitz.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the University of
22  *	California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  *	from: Utah $Hdr: mem.c 1.13 89/10/08$
40  *	from: @(#)mem.c	7.2 (Berkeley) 5/9/91
41  *	$Id: mem.c,v 1.51 1998/06/07 17:10:02 dfr Exp $
42  */
43 
44 /*
45  * Memory special file
46  */
47 
48 #include "opt_devfs.h"
49 #include "opt_perfmon.h"
50 
51 #include <sys/param.h>
52 #include <sys/conf.h>
53 #include <sys/buf.h>
54 #ifdef DEVFS
55 #include <sys/devfsext.h>
56 #endif /* DEVFS */
57 #include <sys/kernel.h>
58 #include <sys/systm.h>
59 #include <sys/uio.h>
60 #include <sys/malloc.h>
61 #include <sys/proc.h>
62 
63 #include <machine/frame.h>
64 #include <machine/random.h>
65 #include <machine/psl.h>
66 #ifdef PERFMON
67 #include <machine/perfmon.h>
68 #endif
69 #include <i386/isa/intr_machdep.h>
70 
71 #include <vm/vm.h>
72 #include <vm/vm_prot.h>
73 #include <vm/pmap.h>
74 #include <vm/vm_extern.h>
75 
76 
77 
78 static	d_open_t	mmopen;
79 static	d_close_t	mmclose;
80 static	d_read_t	mmrw;
81 static	d_ioctl_t	mmioctl;
82 static	d_mmap_t	memmmap;
83 static	d_poll_t	mmpoll;
84 
85 #define CDEV_MAJOR 2
86 static struct cdevsw mem_cdevsw =
87 	{ mmopen,	mmclose,	mmrw,		mmrw,		/*2*/
88 	  mmioctl,	nullstop,	nullreset,	nodevtotty,/* memory */
89 	  mmpoll,	memmmap,	NULL,	"mem",	NULL, -1 };
90 
91 static struct random_softc random_softc[16];
92 static caddr_t	zbuf;
93 
94 #ifdef DEVFS
95 static void *mem_devfs_token;
96 static void *kmem_devfs_token;
97 static void *null_devfs_token;
98 static void *random_devfs_token;
99 static void *urandom_devfs_token;
100 static void *zero_devfs_token;
101 static void *io_devfs_token;
102 #ifdef PERFMON
103 static void *perfmon_devfs_token;
104 #endif
105 
106 static void memdevfs_init __P((void));
107 
108 static void
109 memdevfs_init()
110 {
111     mem_devfs_token =
112 	devfs_add_devswf(&mem_cdevsw, 0, DV_CHR,
113 			 UID_ROOT, GID_KMEM, 0640, "mem");
114     kmem_devfs_token =
115 	devfs_add_devswf(&mem_cdevsw, 1, DV_CHR,
116 			 UID_ROOT, GID_KMEM, 0640, "kmem");
117     null_devfs_token =
118 	devfs_add_devswf(&mem_cdevsw, 2, DV_CHR,
119 			 UID_ROOT, GID_WHEEL, 0666, "null");
120     random_devfs_token =
121 	devfs_add_devswf(&mem_cdevsw, 3, DV_CHR,
122 			 UID_ROOT, GID_WHEEL, 0644, "random");
123     urandom_devfs_token =
124 	devfs_add_devswf(&mem_cdevsw, 4, DV_CHR,
125 			 UID_ROOT, GID_WHEEL, 0644, "urandom");
126     zero_devfs_token =
127 	devfs_add_devswf(&mem_cdevsw, 12, DV_CHR,
128 			 UID_ROOT, GID_WHEEL, 0666, "zero");
129     io_devfs_token =
130 	devfs_add_devswf(&mem_cdevsw, 14, DV_CHR,
131 			 UID_ROOT, GID_WHEEL, 0600, "io");
132 #ifdef PERFMON
133     perfmon_devfs_token =
134 	devfs_add_devswf(&mem_cdevsw, 32, DV_CHR,
135 			 UID_ROOT, GID_KMEM, 0640, "perfmon");
136 #endif /* PERFMON */
137 }
138 #endif /* DEVFS */
139 
140 static int
141 mmclose(dev, flags, fmt, p)
142 	dev_t dev;
143 	int flags;
144 	int fmt;
145 	struct proc *p;
146 {
147 	switch (minor(dev)) {
148 #ifdef PERFMON
149 	case 32:
150 		return perfmon_close(dev, flags, fmt, p);
151 #endif
152 	case 14:
153 		curproc->p_md.md_regs->tf_eflags &= ~PSL_IOPL;
154 		break;
155 	default:
156 		break;
157 	}
158 	return(0);
159 }
160 
161 static int
162 mmopen(dev, flags, fmt, p)
163 	dev_t dev;
164 	int flags;
165 	int fmt;
166 	struct proc *p;
167 {
168 	int error;
169 
170 	switch (minor(dev)) {
171 	case 32:
172 #ifdef PERFMON
173 		return perfmon_open(dev, flags, fmt, p);
174 #else
175 		return ENODEV;
176 #endif
177 	case 14:
178 		error = suser(p->p_ucred, &p->p_acflag);
179 		if (error != 0)
180 			return (error);
181 		if (securelevel > 0)
182 			return (EPERM);
183 		curproc->p_md.md_regs->tf_eflags |= PSL_IOPL;
184 		break;
185 	default:
186 		break;
187 	}
188 	return(0);
189 }
190 
191 static int
192 mmrw(dev, uio, flags)
193 	dev_t dev;
194 	struct uio *uio;
195 	int flags;
196 {
197 	register int o;
198 	register u_int c, v;
199 	u_int poolsize;
200 	register struct iovec *iov;
201 	int error = 0;
202 	caddr_t buf = NULL;
203 
204 	while (uio->uio_resid > 0 && error == 0) {
205 		iov = uio->uio_iov;
206 		if (iov->iov_len == 0) {
207 			uio->uio_iov++;
208 			uio->uio_iovcnt--;
209 			if (uio->uio_iovcnt < 0)
210 				panic("mmrw");
211 			continue;
212 		}
213 		switch (minor(dev)) {
214 
215 /* minor device 0 is physical memory */
216 		case 0:
217 			v = uio->uio_offset;
218 			pmap_enter(kernel_pmap, (vm_offset_t)ptvmmap, v,
219 				uio->uio_rw == UIO_READ ? VM_PROT_READ : VM_PROT_WRITE,
220 				TRUE);
221 			o = (int)uio->uio_offset & PAGE_MASK;
222 			c = (u_int)(PAGE_SIZE - ((int)iov->iov_base & PAGE_MASK));
223 			c = min(c, (u_int)(PAGE_SIZE - o));
224 			c = min(c, (u_int)iov->iov_len);
225 			error = uiomove((caddr_t)&ptvmmap[o], (int)c, uio);
226 			pmap_remove(kernel_pmap, (vm_offset_t)ptvmmap,
227 				    (vm_offset_t)&ptvmmap[PAGE_SIZE]);
228 			continue;
229 
230 /* minor device 1 is kernel memory */
231 		case 1: {
232 			vm_offset_t addr, eaddr;
233 			c = iov->iov_len;
234 
235 			/*
236 			 * Make sure that all of the pages are currently resident so
237 			 * that we don't create any zero-fill pages.
238 			 */
239 			addr = trunc_page(uio->uio_offset);
240 			eaddr = round_page(uio->uio_offset + c);
241 
242 			if (addr < (vm_offset_t)VADDR(PTDPTDI, 0))
243 				return EFAULT;
244 			if (eaddr >= (vm_offset_t)VADDR(APTDPTDI, 0))
245 				return EFAULT;
246 			for (; addr < eaddr; addr += PAGE_SIZE)
247 				if (pmap_extract(kernel_pmap, addr) == 0)
248 					return EFAULT;
249 
250 			if (!kernacc((caddr_t)(int)uio->uio_offset, c,
251 			    uio->uio_rw == UIO_READ ? B_READ : B_WRITE))
252 				return(EFAULT);
253 			error = uiomove((caddr_t)(int)uio->uio_offset, (int)c, uio);
254 			continue;
255 		}
256 
257 /* minor device 2 is EOF/RATHOLE */
258 		case 2:
259 			if (uio->uio_rw == UIO_READ)
260 				return (0);
261 			c = iov->iov_len;
262 			break;
263 
264 /* minor device 3 (/dev/random) is source of filth on read, rathole on write */
265 		case 3:
266 			if (uio->uio_rw == UIO_WRITE) {
267 				c = iov->iov_len;
268 				break;
269 			}
270 			if (buf == NULL)
271 				buf = (caddr_t)
272 				    malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
273 			c = min(iov->iov_len, PAGE_SIZE);
274 			poolsize = read_random(buf, c);
275 			if (poolsize == 0) {
276 				if (buf)
277 					free(buf, M_TEMP);
278 				return (0);
279 			}
280 			c = min(c, poolsize);
281 			error = uiomove(buf, (int)c, uio);
282 			continue;
283 
284 /* minor device 4 (/dev/urandom) is source of muck on read, rathole on write */
285 		case 4:
286 			if (uio->uio_rw == UIO_WRITE) {
287 				c = iov->iov_len;
288 				break;
289 			}
290 			if (buf == NULL)
291 				buf = (caddr_t)
292 				    malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
293 			c = min(iov->iov_len, PAGE_SIZE);
294 			poolsize = read_random_unlimited(buf, c);
295 			c = min(c, poolsize);
296 			error = uiomove(buf, (int)c, uio);
297 			continue;
298 
299 /* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */
300 		case 12:
301 			if (uio->uio_rw == UIO_WRITE) {
302 				c = iov->iov_len;
303 				break;
304 			}
305 			if (zbuf == NULL) {
306 				zbuf = (caddr_t)
307 				    malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
308 				bzero(zbuf, PAGE_SIZE);
309 			}
310 			c = min(iov->iov_len, PAGE_SIZE);
311 			error = uiomove(zbuf, (int)c, uio);
312 			continue;
313 
314 #ifdef notyet
315 /* 386 I/O address space (/dev/ioport[bwl]) is a read/write access to seperate
316    i/o device address bus, different than memory bus. Semantics here are
317    very different than ordinary read/write, as if iov_len is a multiple
318    an implied string move from a single port will be done. Note that lseek
319    must be used to set the port number reliably. */
320 		case 14:
321 			if (iov->iov_len == 1) {
322 				u_char tmp;
323 				tmp = inb(uio->uio_offset);
324 				error = uiomove (&tmp, iov->iov_len, uio);
325 			} else {
326 				if (!useracc((caddr_t)iov->iov_base,
327 					iov->iov_len, uio->uio_rw))
328 					return (EFAULT);
329 				insb(uio->uio_offset, iov->iov_base,
330 					iov->iov_len);
331 			}
332 			break;
333 		case 15:
334 			if (iov->iov_len == sizeof (short)) {
335 				u_short tmp;
336 				tmp = inw(uio->uio_offset);
337 				error = uiomove (&tmp, iov->iov_len, uio);
338 			} else {
339 				if (!useracc((caddr_t)iov->iov_base,
340 					iov->iov_len, uio->uio_rw))
341 					return (EFAULT);
342 				insw(uio->uio_offset, iov->iov_base,
343 					iov->iov_len/ sizeof (short));
344 			}
345 			break;
346 		case 16:
347 			if (iov->iov_len == sizeof (long)) {
348 				u_long tmp;
349 				tmp = inl(uio->uio_offset);
350 				error = uiomove (&tmp, iov->iov_len, uio);
351 			} else {
352 				if (!useracc((caddr_t)iov->iov_base,
353 					iov->iov_len, uio->uio_rw))
354 					return (EFAULT);
355 				insl(uio->uio_offset, iov->iov_base,
356 					iov->iov_len/ sizeof (long));
357 			}
358 			break;
359 #endif
360 
361 		default:
362 			return (ENXIO);
363 		}
364 		if (error)
365 			break;
366 		iov->iov_base += c;
367 		iov->iov_len -= c;
368 		uio->uio_offset += c;
369 		uio->uio_resid -= c;
370 	}
371 	if (buf)
372 		free(buf, M_TEMP);
373 	return (error);
374 }
375 
376 
377 
378 
379 /*******************************************************\
380 * allow user processes to MMAP some memory sections	*
381 * instead of going through read/write			*
382 \*******************************************************/
383 static int
384 memmmap(dev_t dev, int offset, int nprot)
385 {
386 	switch (minor(dev))
387 	{
388 
389 /* minor device 0 is physical memory */
390 	case 0:
391         	return i386_btop(offset);
392 
393 /* minor device 1 is kernel memory */
394 	case 1:
395         	return i386_btop(vtophys(offset));
396 
397 	default:
398 		return -1;
399 	}
400 }
401 
402 static int
403 mmioctl(dev, cmd, data, flags, p)
404 	dev_t dev;
405 	u_long cmd;
406 	caddr_t data;
407 	int flags;
408 	struct proc *p;
409 {
410 	static intrmask_t interrupt_allowed;
411 	intrmask_t interrupt_mask;
412 	int error, intr;
413 	struct random_softc *sc;
414 
415 	switch (minor(dev)) {
416 	case 3:
417 	case 4:
418 		break;
419 #ifdef PERFMON
420 	case 32:
421 		return perfmon_ioctl(dev, cmd, data, flags, p);
422 #endif
423 	default:
424 		return (ENODEV);
425 	}
426 
427 	/*
428 	 * We're the random or urandom device.  The only ioctls are for
429 	 * selecting and inspecting which interrupts are used in the muck
430 	 * gathering business.
431 	 */
432 	if (cmd != MEM_SETIRQ && cmd != MEM_CLEARIRQ && cmd != MEM_RETURNIRQ)
433 		return (ENOTTY);
434 
435 	/*
436 	 * Even inspecting the state is privileged, since it gives a hint
437 	 * about how easily the randomness might be guessed.
438 	 */
439 	error = suser(p->p_ucred, &p->p_acflag);
440 	if (error != 0)
441 		return (error);
442 
443 	/*
444 	 * XXX the data is 16-bit due to a historical botch, so we use
445 	 * magic 16's instead of ICU_LEN and can't support 24 interrupts
446 	 * under SMP.
447 	 */
448 	intr = *(int16_t *)data;
449 	if (cmd != MEM_RETURNIRQ && (intr < 0 || intr >= 16))
450 		return (EINVAL);
451 
452 	interrupt_mask = 1 << intr;
453 	sc = &random_softc[intr];
454 	switch (cmd) {
455 	case MEM_SETIRQ:
456 		if (interrupt_allowed & interrupt_mask)
457 			break;
458 		interrupt_allowed |= interrupt_mask;
459 		sc->sc_intr = intr;
460 		disable_intr();
461 		sc->sc_handler = intr_handler[intr];
462 		intr_handler[intr] = add_interrupt_randomness;
463 		sc->sc_arg = intr_unit[intr];
464 		intr_unit[intr] = sc;
465 		enable_intr();
466 		break;
467 	case MEM_CLEARIRQ:
468 		if (!(interrupt_allowed & interrupt_mask))
469 			break;
470 		interrupt_allowed &= ~interrupt_mask;
471 		disable_intr();
472 		intr_handler[intr] = sc->sc_handler;
473 		intr_unit[intr] = sc->sc_arg;
474 		enable_intr();
475 		break;
476 	case MEM_RETURNIRQ:
477 		*(u_int16_t *)data = interrupt_allowed;
478 		break;
479 	default:
480 		return (ENOTTY);
481 	}
482 	return (0);
483 }
484 
485 int
486 mmpoll(dev, events, p)
487 	dev_t dev;
488 	int events;
489 	struct proc *p;
490 {
491 	switch (minor(dev)) {
492 	case 3:		/* /dev/random */
493 		return random_poll(dev, events, p);
494 	case 4:		/* /dev/urandom */
495 	default:
496 		return seltrue(dev, events, p);
497 	}
498 }
499 
500 /*
501  * Routine that identifies /dev/mem and /dev/kmem.
502  *
503  * A minimal stub routine can always return 0.
504  */
505 int
506 iskmemdev(dev)
507 	dev_t dev;
508 {
509 
510 	return ((major(dev) == mem_cdevsw.d_maj)
511 	      && (minor(dev) == 0 || minor(dev) == 1));
512 }
513 
514 int
515 iszerodev(dev)
516 	dev_t dev;
517 {
518 	return ((major(dev) == mem_cdevsw.d_maj)
519 	  && minor(dev) == 12);
520 }
521 
522 
523 
524 static int mem_devsw_installed;
525 
526 static void
527 mem_drvinit(void *unused)
528 {
529 	dev_t dev;
530 
531 	if( ! mem_devsw_installed ) {
532 		dev = makedev(CDEV_MAJOR, 0);
533 		cdevsw_add(&dev,&mem_cdevsw, NULL);
534 		mem_devsw_installed = 1;
535 #ifdef DEVFS
536 		memdevfs_init();
537 #endif
538 	}
539 }
540 
541 SYSINIT(memdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,mem_drvinit,NULL)
542 
543