xref: /freebsd/sys/amd64/amd64/mem.c (revision 48991a368427cadb9cdac39581d1676c29619c52)
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.20 1995/11/29 10:47:18 julian Exp $
42  */
43 
44 /*
45  * Memory special file
46  */
47 
48 #include <sys/param.h>
49 #include <sys/conf.h>
50 #include <sys/buf.h>
51 #include <sys/systm.h>
52 #include <sys/uio.h>
53 #include <sys/malloc.h>
54 #include <sys/proc.h>
55 
56 #include <machine/cpu.h>
57 #include <machine/random.h>
58 #include <machine/psl.h>
59 
60 #include <vm/vm.h>
61 #include <vm/vm_param.h>
62 #include <vm/lock.h>
63 #include <vm/vm_prot.h>
64 #include <vm/pmap.h>
65 
66 #ifdef JREMOD
67 #include <sys/kernel.h>
68 #define CDEV_MAJOR 2
69 #endif /*JREMOD*/
70 
71 #ifdef DEVFS
72 #include <sys/devfsext.h>
73 
74 static void
75 memdevfs_init(dev_t dev)
76 {
77   void * x;
78   int maj = major(dev);
79 /*            path	name		major   minor	type   uid gid perm*/
80    x=devfs_add_devsw("/misc",	"mem",	maj,    0,	DV_CHR, 0,  2, 0640);
81    x=devfs_add_devsw("/misc",	"kmem",	maj,    1,	DV_CHR, 0,  2, 0640);
82    x=devfs_add_devsw("/misc",	"null",	maj,    2,	DV_CHR, 0,  0, 0666);
83    x=devfs_add_devsw("/misc",	"random", maj,  3,	DV_CHR, 0,  0, 0666);
84    x=devfs_add_devsw("/misc",	"urandom", maj, 4,	DV_CHR, 0,  0, 0666);
85    x=devfs_add_devsw("/misc",	"zero",	maj,    12,	DV_CHR, 0,  0, 0666);
86    x=devfs_add_devsw("/misc",	"io",	maj,    14,	DV_CHR, 0,  2, 0640);
87 }
88 #endif /* DEVFS */
89 
90 extern        char *ptvmmap;            /* poor name! */
91 
92 int
93 mmclose(dev, flags, fmt, p)
94 	dev_t dev;
95 	int flags;
96 	int fmt;
97 	struct proc *p;
98 {
99 	struct trapframe *fp;
100 
101 	switch (minor(dev)) {
102 	case 14:
103 		fp = (struct trapframe *)curproc->p_md.md_regs;
104 		fp->tf_eflags &= ~PSL_IOPL;
105 		break;
106 	default:
107 		break;
108 	}
109 	return(0);
110 }
111 
112 int
113 mmopen(dev, flags, fmt, p)
114 	dev_t dev;
115 	int flags;
116 	int fmt;
117 	struct proc *p;
118 {
119 	struct trapframe *fp;
120 
121 	switch (minor(dev)) {
122 	case 14:
123 		fp = (struct trapframe *)curproc->p_md.md_regs;
124 		fp->tf_eflags |= PSL_IOPL;
125 		break;
126 	default:
127 		break;
128 	}
129 	return(0);
130 }
131 
132 int
133 mmrw(dev, uio, flags)
134 	dev_t dev;
135 	struct uio *uio;
136 	int flags;
137 {
138 	register int o;
139 	register u_int c, v;
140 	u_int poolsize;
141 	register struct iovec *iov;
142 	int error = 0;
143 	caddr_t buf = NULL;
144 
145 	while (uio->uio_resid > 0 && error == 0) {
146 		iov = uio->uio_iov;
147 		if (iov->iov_len == 0) {
148 			uio->uio_iov++;
149 			uio->uio_iovcnt--;
150 			if (uio->uio_iovcnt < 0)
151 				panic("mmrw");
152 			continue;
153 		}
154 		switch (minor(dev)) {
155 
156 /* minor device 0 is physical memory */
157 		case 0:
158 			v = uio->uio_offset;
159 			pmap_enter(kernel_pmap, (vm_offset_t)ptvmmap, v,
160 				uio->uio_rw == UIO_READ ? VM_PROT_READ : VM_PROT_WRITE,
161 				TRUE);
162 			o = (int)uio->uio_offset & PGOFSET;
163 			c = (u_int)(NBPG - ((int)iov->iov_base & PGOFSET));
164 			c = min(c, (u_int)(NBPG - o));
165 			c = min(c, (u_int)iov->iov_len);
166 			error = uiomove((caddr_t)&ptvmmap[o], (int)c, uio);
167 			pmap_remove(kernel_pmap, (vm_offset_t)ptvmmap,
168 				    (vm_offset_t)&ptvmmap[NBPG]);
169 			continue;
170 
171 /* minor device 1 is kernel memory */
172 		case 1: {
173 			vm_offset_t addr, eaddr;
174 			c = iov->iov_len;
175 
176 			/*
177 			 * Make sure that all of the pages are currently resident so
178 			 * that we don't create any zero-fill pages.
179 			 */
180 			addr = trunc_page(uio->uio_offset);
181 			eaddr = round_page(uio->uio_offset + c);
182 			for (; addr < eaddr; addr += PAGE_SIZE)
183 				if (pmap_extract(kernel_pmap, addr) == 0)
184 					return EFAULT;
185 
186 			if (!kernacc((caddr_t)(int)uio->uio_offset, c,
187 			    uio->uio_rw == UIO_READ ? B_READ : B_WRITE))
188 				return(EFAULT);
189 			error = uiomove((caddr_t)(int)uio->uio_offset, (int)c, uio);
190 			continue;
191 		}
192 
193 /* minor device 2 is EOF/RATHOLE */
194 		case 2:
195 			if (uio->uio_rw == UIO_READ)
196 				return (0);
197 			c = iov->iov_len;
198 			break;
199 
200 /* minor device 3 (/dev/random) is source of filth on read, rathole on write */
201 		case 3:
202 			if (uio->uio_rw == UIO_WRITE) {
203 				c = iov->iov_len;
204 				break;
205 			}
206 			if (buf == NULL)
207 				buf = (caddr_t)
208 				    malloc(CLBYTES, M_TEMP, M_WAITOK);
209 			c = min(iov->iov_len, CLBYTES);
210 			poolsize = read_random(buf, c);
211 			if (poolsize == 0) {
212 				if (buf)
213 					free(buf, M_TEMP);
214 				return (0);
215 			}
216 			c = min(c, poolsize);
217 			error = uiomove(buf, (int)c, uio);
218 			continue;
219 
220 /* minor device 4 (/dev/urandom) is source of muck on read, rathole on write */
221 		case 4:
222 			if (uio->uio_rw == UIO_WRITE) {
223 				c = iov->iov_len;
224 				break;
225 			}
226 			if (buf == NULL)
227 				buf = (caddr_t)
228 				    malloc(CLBYTES, M_TEMP, M_WAITOK);
229 			c = min(iov->iov_len, CLBYTES);
230 			poolsize = read_random_unlimited(buf, c);
231 			c = min(c, poolsize);
232 			error = uiomove(buf, (int)c, uio);
233 			continue;
234 
235 /* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */
236 		case 12:
237 			if (uio->uio_rw == UIO_WRITE) {
238 				c = iov->iov_len;
239 				break;
240 			}
241 			if (buf == NULL) {
242 				buf = (caddr_t)
243 				    malloc(CLBYTES, M_TEMP, M_WAITOK);
244 				bzero(buf, CLBYTES);
245 			}
246 			c = min(iov->iov_len, CLBYTES);
247 			error = uiomove(buf, (int)c, uio);
248 			continue;
249 
250 #ifdef notyet
251 /* 386 I/O address space (/dev/ioport[bwl]) is a read/write access to seperate
252    i/o device address bus, different than memory bus. Semantics here are
253    very different than ordinary read/write, as if iov_len is a multiple
254    an implied string move from a single port will be done. Note that lseek
255    must be used to set the port number reliably. */
256 		case 14:
257 			if (iov->iov_len == 1) {
258 				u_char tmp;
259 				tmp = inb(uio->uio_offset);
260 				error = uiomove (&tmp, iov->iov_len, uio);
261 			} else {
262 				if (!useracc((caddr_t)iov->iov_base,
263 					iov->iov_len, uio->uio_rw))
264 					return (EFAULT);
265 				insb(uio->uio_offset, iov->iov_base,
266 					iov->iov_len);
267 			}
268 			break;
269 		case 15:
270 			if (iov->iov_len == sizeof (short)) {
271 				u_short tmp;
272 				tmp = inw(uio->uio_offset);
273 				error = uiomove (&tmp, iov->iov_len, uio);
274 			} else {
275 				if (!useracc((caddr_t)iov->iov_base,
276 					iov->iov_len, uio->uio_rw))
277 					return (EFAULT);
278 				insw(uio->uio_offset, iov->iov_base,
279 					iov->iov_len/ sizeof (short));
280 			}
281 			break;
282 		case 16:
283 			if (iov->iov_len == sizeof (long)) {
284 				u_long tmp;
285 				tmp = inl(uio->uio_offset);
286 				error = uiomove (&tmp, iov->iov_len, uio);
287 			} else {
288 				if (!useracc((caddr_t)iov->iov_base,
289 					iov->iov_len, uio->uio_rw))
290 					return (EFAULT);
291 				insl(uio->uio_offset, iov->iov_base,
292 					iov->iov_len/ sizeof (long));
293 			}
294 			break;
295 #endif
296 
297 		default:
298 			return (ENXIO);
299 		}
300 		if (error)
301 			break;
302 		iov->iov_base += c;
303 		iov->iov_len -= c;
304 		uio->uio_offset += c;
305 		uio->uio_resid -= c;
306 	}
307 	if (buf)
308 		free(buf, M_TEMP);
309 	return (error);
310 }
311 
312 
313 
314 
315 /*******************************************************\
316 * allow user processes to MMAP some memory sections	*
317 * instead of going through read/write			*
318 \*******************************************************/
319 int memmmap(dev_t dev, int offset, int nprot)
320 {
321 	switch (minor(dev))
322 	{
323 
324 /* minor device 0 is physical memory */
325 	case 0:
326         	return i386_btop(offset);
327 
328 /* minor device 1 is kernel memory */
329 	case 1:
330         	return i386_btop(vtophys(offset));
331 
332 	default:
333 		return -1;
334 	}
335 }
336 
337 /*
338  * Allow userland to select which interrupts will be used in the muck
339  * gathering business.
340  */
341 int
342 mmioctl(dev, cmd, cmdarg, flags, p)
343 	dev_t dev;
344 	int cmd;
345 	caddr_t cmdarg;
346 	int flags;
347 	struct proc *p;
348 {
349 	int error;
350 
351 	if (minor(dev) != 3 && minor(dev) != 4)
352 		return (ENODEV);
353 
354 	if (*(u_int16_t *)cmdarg >= 16)
355 		return (EINVAL);
356 
357 	/* Only root can do this */
358 	error = suser(p->p_ucred, &p->p_acflag);
359 	if (error != 0) {
360 		return (error);
361 	}
362 
363 	switch (cmd){
364 
365 		case MEM_SETIRQ:
366 			interrupt_allowed |= 1 << *(u_int16_t *)cmdarg;
367 			break;
368 
369 		case MEM_CLEARIRQ:
370 			interrupt_allowed &= ~(1 << *(u_int16_t *)cmdarg);
371 			break;
372 
373 		case MEM_RETURNIRQ:
374 			*(u_int16_t *)cmdarg = interrupt_allowed;
375 			break;
376 
377 		default:
378 			return (ENOTTY);
379 	}
380 	return (0);
381 }
382 
383 
384 
385 #ifdef JREMOD
386 struct cdevsw mem_cdevsw =
387 	{ mmopen,	mmclose,	mmrw,		mmrw,		/*2*/
388 	  mmioctl,	nullstop,	nullreset,	nodevtotty,/* memory */
389 	  seltrue,	memmmap,	NULL };
390 
391 static mem_devsw_installed = 0;
392 
393 static void 	mem_drvinit(void *unused)
394 {
395 	dev_t dev;
396 
397 	if( ! mem_devsw_installed ) {
398 		dev = makedev(CDEV_MAJOR,0);
399 		cdevsw_add(&dev,&mem_cdevsw,NULL);
400 		mem_devsw_installed = 1;
401 #ifdef DEVFS
402 		memdevfs_init(dev);
403 #endif
404 	}
405 }
406 
407 SYSINIT(memdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,mem_drvinit,NULL)
408 
409 #endif /* JREMOD */
410 
411