xref: /freebsd/sys/amd64/amd64/mem.c (revision 8e6b01171e30297084bb0b4457c4183c2746aacc)
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.13 1995/09/15 23:49:23 davidg 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/psl.h>
58 
59 #include <vm/vm.h>
60 #include <vm/vm_param.h>
61 #include <vm/lock.h>
62 #include <vm/vm_prot.h>
63 #include <vm/pmap.h>
64 
65 #ifdef	DEVFS
66 #include <sys/devfsext.h>
67 #include "sys/kernel.h"
68 int mmopen();
69 
70 void memdev_init(void *data) /* data not used */
71 {
72   void * x;
73 /*            path	name	devsw   minor	type   uid gid perm*/
74    x=dev_add("/misc",	"mem",	mmopen, 0,	DV_CHR, 0,  2, 0640);
75    x=dev_add("/misc",	"kmem",	mmopen, 1,	DV_CHR, 0,  2, 0640);
76    x=dev_add("/misc",	"null",	mmopen, 2,	DV_CHR, 0,  0, 0666);
77    x=dev_add("/misc",	"zero",	mmopen, 12,	DV_CHR, 0,  0, 0666);
78    x=dev_add("/misc",	"io",	mmopen, 14,	DV_CHR, 0,  2, 0640);
79 }
80 SYSINIT(memdev,SI_SUB_DEVFS, SI_ORDER_ANY, memdev_init, NULL)
81 #endif /*DEVFS*/
82 
83 
84 
85 extern        char *ptvmmap;            /* poor name! */
86 /*ARGSUSED*/
87 int
88 mmclose(dev, flags, fmt, p)
89 	dev_t dev;
90 	int flags;
91 	int fmt;
92 	struct proc *p;
93 {
94 	struct trapframe *fp;
95 
96 	switch (minor(dev)) {
97 	case 14:
98 		fp = (struct trapframe *)curproc->p_md.md_regs;
99 		fp->tf_eflags &= ~PSL_IOPL;
100 		break;
101 	default:
102 		break;
103 	}
104 	return(0);
105 }
106 /*ARGSUSED*/
107 int
108 mmopen(dev, flags, fmt, p)
109 	dev_t dev;
110 	int flags;
111 	int fmt;
112 	struct proc *p;
113 {
114 	struct trapframe *fp;
115 
116 	switch (minor(dev)) {
117 	case 14:
118 		fp = (struct trapframe *)curproc->p_md.md_regs;
119 		fp->tf_eflags |= PSL_IOPL;
120 		break;
121 	default:
122 		break;
123 	}
124 	return(0);
125 }
126 /*ARGSUSED*/
127 int
128 mmrw(dev, uio, flags)
129 	dev_t dev;
130 	struct uio *uio;
131 	int flags;
132 {
133 	register int o;
134 	register u_int c, v;
135 	register struct iovec *iov;
136 	int error = 0;
137 	caddr_t zbuf = NULL;
138 
139 	while (uio->uio_resid > 0 && error == 0) {
140 		iov = uio->uio_iov;
141 		if (iov->iov_len == 0) {
142 			uio->uio_iov++;
143 			uio->uio_iovcnt--;
144 			if (uio->uio_iovcnt < 0)
145 				panic("mmrw");
146 			continue;
147 		}
148 		switch (minor(dev)) {
149 
150 /* minor device 0 is physical memory */
151 		case 0:
152 			v = uio->uio_offset;
153 			pmap_enter(kernel_pmap, (vm_offset_t)ptvmmap, v,
154 				uio->uio_rw == UIO_READ ? VM_PROT_READ : VM_PROT_WRITE,
155 				TRUE);
156 			o = (int)uio->uio_offset & PGOFSET;
157 			c = (u_int)(NBPG - ((int)iov->iov_base & PGOFSET));
158 			c = min(c, (u_int)(NBPG - o));
159 			c = min(c, (u_int)iov->iov_len);
160 			error = uiomove((caddr_t)&ptvmmap[o], (int)c, uio);
161 			pmap_remove(kernel_pmap, (vm_offset_t)ptvmmap,
162 				    (vm_offset_t)&ptvmmap[NBPG]);
163 			continue;
164 
165 /* minor device 1 is kernel memory */
166 		case 1: {
167 			vm_offset_t addr, eaddr;
168 			c = iov->iov_len;
169 
170 			/*
171 			 * Make sure that all of the pages are currently resident so
172 			 * that we don't create any zero-fill pages.
173 			 */
174 			addr = trunc_page(uio->uio_offset);
175 			eaddr = round_page(uio->uio_offset + c);
176 			for (; addr < eaddr; addr += PAGE_SIZE)
177 				if (pmap_extract(kernel_pmap, addr) == 0)
178 					return EFAULT;
179 
180 			if (!kernacc((caddr_t)(int)uio->uio_offset, c,
181 			    uio->uio_rw == UIO_READ ? B_READ : B_WRITE))
182 				return(EFAULT);
183 			error = uiomove((caddr_t)(int)uio->uio_offset, (int)c, uio);
184 			continue;
185 		}
186 
187 /* minor device 2 is EOF/RATHOLE */
188 		case 2:
189 			if (uio->uio_rw == UIO_READ)
190 				return (0);
191 			c = iov->iov_len;
192 			break;
193 
194 /* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */
195 		case 12:
196 			if (uio->uio_rw == UIO_WRITE) {
197 				c = iov->iov_len;
198 				break;
199 			}
200 			if (zbuf == NULL) {
201 				zbuf = (caddr_t)
202 				    malloc(CLBYTES, M_TEMP, M_WAITOK);
203 				bzero(zbuf, CLBYTES);
204 			}
205 			c = min(iov->iov_len, CLBYTES);
206 			error = uiomove(zbuf, (int)c, uio);
207 			continue;
208 
209 #ifdef notyet
210 /* 386 I/O address space (/dev/ioport[bwl]) is a read/write access to seperate
211    i/o device address bus, different than memory bus. Semantics here are
212    very different than ordinary read/write, as if iov_len is a multiple
213    an implied string move from a single port will be done. Note that lseek
214    must be used to set the port number reliably. */
215 		case 14:
216 			if (iov->iov_len == 1) {
217 				u_char tmp;
218 				tmp = inb(uio->uio_offset);
219 				error = uiomove (&tmp, iov->iov_len, uio);
220 			} else {
221 				if (!useracc((caddr_t)iov->iov_base,
222 					iov->iov_len, uio->uio_rw))
223 					return (EFAULT);
224 				insb(uio->uio_offset, iov->iov_base,
225 					iov->iov_len);
226 			}
227 			break;
228 		case 15:
229 			if (iov->iov_len == sizeof (short)) {
230 				u_short tmp;
231 				tmp = inw(uio->uio_offset);
232 				error = uiomove (&tmp, iov->iov_len, uio);
233 			} else {
234 				if (!useracc((caddr_t)iov->iov_base,
235 					iov->iov_len, uio->uio_rw))
236 					return (EFAULT);
237 				insw(uio->uio_offset, iov->iov_base,
238 					iov->iov_len/ sizeof (short));
239 			}
240 			break;
241 		case 16:
242 			if (iov->iov_len == sizeof (long)) {
243 				u_long tmp;
244 				tmp = inl(uio->uio_offset);
245 				error = uiomove (&tmp, iov->iov_len, uio);
246 			} else {
247 				if (!useracc((caddr_t)iov->iov_base,
248 					iov->iov_len, uio->uio_rw))
249 					return (EFAULT);
250 				insl(uio->uio_offset, iov->iov_base,
251 					iov->iov_len/ sizeof (long));
252 			}
253 			break;
254 #endif
255 
256 		default:
257 			return (ENXIO);
258 		}
259 		if (error)
260 			break;
261 		iov->iov_base += c;
262 		iov->iov_len -= c;
263 		uio->uio_offset += c;
264 		uio->uio_resid -= c;
265 	}
266 	if (zbuf)
267 		free(zbuf, M_TEMP);
268 	return (error);
269 }
270 
271 
272 
273 
274 /*******************************************************\
275 * allow user processes to MMAP some memory sections	*
276 * instead of going through read/write			*
277 \*******************************************************/
278 int memmmap(dev_t dev, int offset, int nprot)
279 {
280 	switch (minor(dev))
281 	{
282 
283 /* minor device 0 is physical memory */
284 	case 0:
285         	return i386_btop(offset);
286 
287 /* minor device 1 is kernel memory */
288 	case 1:
289         	return i386_btop(vtophys(offset));
290 
291 	default:
292 		return -1;
293 	}
294 }
295 
296