FreeBSD/Linux Kernel Cross Reference
sys/i386/i386/mem.c
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 */
42
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD: releng/5.2/sys/i386/i386/mem.c 115683 2003-06-02 06:43:15Z obrien $");
45
46 /*
47 * Memory special file
48 */
49
50 #include <sys/param.h>
51 #include <sys/conf.h>
52 #include <sys/fcntl.h>
53 #include <sys/ioccom.h>
54 #include <sys/kernel.h>
55 #include <sys/lock.h>
56 #include <sys/malloc.h>
57 #include <sys/memrange.h>
58 #include <sys/mutex.h>
59 #include <sys/proc.h>
60 #include <sys/signalvar.h>
61 #include <sys/systm.h>
62 #include <sys/uio.h>
63
64 #include <machine/db_machdep.h>
65 #include <machine/frame.h>
66 #include <machine/psl.h>
67 #include <machine/specialreg.h>
68
69 #include <vm/vm.h>
70 #include <vm/pmap.h>
71 #include <vm/vm_extern.h>
72
73 static dev_t memdev, kmemdev, iodev;
74
75 static d_open_t mmopen;
76 static d_close_t mmclose;
77 static d_read_t mmrw;
78 static d_ioctl_t mmioctl;
79 static d_mmap_t memmmap;
80
81 #define CDEV_MAJOR 2
82 static struct cdevsw mem_cdevsw = {
83 .d_open = mmopen,
84 .d_close = mmclose,
85 .d_read = mmrw,
86 .d_write = mmrw,
87 .d_ioctl = mmioctl,
88 .d_mmap = memmmap,
89 .d_name = "mem",
90 .d_maj = CDEV_MAJOR,
91 .d_flags = D_MEM,
92 };
93
94 MALLOC_DEFINE(M_MEMDESC, "memdesc", "memory range descriptors");
95
96 struct mem_range_softc mem_range_softc;
97
98 static int
99 mmclose(dev_t dev, int flags, int fmt, struct thread *td)
100 {
101 switch (minor(dev)) {
102 case 14:
103 td->td_frame->tf_eflags &= ~PSL_IOPL;
104 }
105 return (0);
106 }
107
108 static int
109 mmopen(dev_t dev, int flags, int fmt, struct thread *td)
110 {
111 int error;
112
113 switch (minor(dev)) {
114 case 0:
115 case 1:
116 if (flags & FWRITE) {
117 error = securelevel_gt(td->td_ucred, 0);
118 if (error != 0)
119 return (error);
120 }
121 break;
122 case 14:
123 error = suser(td);
124 if (error != 0)
125 return (error);
126 error = securelevel_gt(td->td_ucred, 0);
127 if (error != 0)
128 return (error);
129 td->td_frame->tf_eflags |= PSL_IOPL;
130 break;
131 }
132 return (0);
133 }
134
135 /*ARGSUSED*/
136 static int
137 mmrw(dev_t dev, struct uio *uio, int flags)
138 {
139 int o;
140 u_int c = 0, v;
141 struct iovec *iov;
142 int error = 0;
143 vm_offset_t addr, eaddr;
144
145 GIANT_REQUIRED;
146
147 while (uio->uio_resid > 0 && error == 0) {
148 iov = uio->uio_iov;
149 if (iov->iov_len == 0) {
150 uio->uio_iov++;
151 uio->uio_iovcnt--;
152 if (uio->uio_iovcnt < 0)
153 panic("mmrw");
154 continue;
155 }
156 switch (minor(dev)) {
157
158 /* minor device 0 is physical memory */
159 case 0:
160 v = uio->uio_offset;
161 v &= ~PAGE_MASK;
162 pmap_kenter((vm_offset_t)ptvmmap, v);
163 o = (int)uio->uio_offset & PAGE_MASK;
164 c = (u_int)(PAGE_SIZE - ((int)iov->iov_base & PAGE_MASK));
165 c = min(c, (u_int)(PAGE_SIZE - o));
166 c = min(c, (u_int)iov->iov_len);
167 error = uiomove((caddr_t)&ptvmmap[o], (int)c, uio);
168 pmap_qremove((vm_offset_t)ptvmmap, 1);
169 continue;
170
171 /* minor device 1 is kernel memory */
172 case 1:
173 c = iov->iov_len;
174
175 /*
176 * Make sure that all of the pages are currently resident so
177 * that we don't create any zero-fill pages.
178 */
179 addr = trunc_page(uio->uio_offset);
180 eaddr = round_page(uio->uio_offset + c);
181
182 if (addr < (vm_offset_t)VADDR(PTDPTDI, 0))
183 return (EFAULT);
184 for (; addr < eaddr; addr += PAGE_SIZE)
185 if (pmap_extract(kernel_pmap, addr) == 0)
186 return (EFAULT);
187
188 if (!kernacc((caddr_t)(int)uio->uio_offset, c,
189 uio->uio_rw == UIO_READ ?
190 VM_PROT_READ : VM_PROT_WRITE))
191 return (EFAULT);
192 error = uiomove((caddr_t)(int)uio->uio_offset, (int)c, uio);
193 continue;
194
195 default:
196 return (ENODEV);
197 }
198
199 if (error)
200 break;
201 iov->iov_base = (char *)iov->iov_base + c;
202 iov->iov_len -= c;
203 uio->uio_offset += c;
204 uio->uio_resid -= c;
205 }
206 return (error);
207 }
208
209 /*******************************************************\
210 * allow user processes to MMAP some memory sections *
211 * instead of going through read/write *
212 \*******************************************************/
213 static int
214 memmmap(dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int prot)
215 {
216 switch (minor(dev))
217 {
218
219 /* minor device 0 is physical memory */
220 case 0:
221 *paddr = offset;
222 break;
223
224 /* minor device 1 is kernel memory */
225 case 1:
226 *paddr = vtophys(offset);
227 break;
228
229 default:
230 return (-1);
231 }
232 return (0);
233 }
234
235 /*
236 * Operations for changing memory attributes.
237 *
238 * This is basically just an ioctl shim for mem_range_attr_get
239 * and mem_range_attr_set.
240 */
241 static int
242 mmioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct thread *td)
243 {
244 int nd, error = 0;
245 struct mem_range_op *mo = (struct mem_range_op *)data;
246 struct mem_range_desc *md;
247
248 /* is this for us? */
249 if ((cmd != MEMRANGE_GET) &&
250 (cmd != MEMRANGE_SET))
251 return (ENOTTY);
252
253 /* any chance we can handle this? */
254 if (mem_range_softc.mr_op == NULL)
255 return (EOPNOTSUPP);
256
257 /* do we have any descriptors? */
258 if (mem_range_softc.mr_ndesc == 0)
259 return (ENXIO);
260
261 switch (cmd) {
262 case MEMRANGE_GET:
263 nd = imin(mo->mo_arg[0], mem_range_softc.mr_ndesc);
264 if (nd > 0) {
265 md = (struct mem_range_desc *)
266 malloc(nd * sizeof(struct mem_range_desc),
267 M_MEMDESC, M_WAITOK);
268 error = mem_range_attr_get(md, &nd);
269 if (!error)
270 error = copyout(md, mo->mo_desc,
271 nd * sizeof(struct mem_range_desc));
272 free(md, M_MEMDESC);
273 }
274 else
275 nd = mem_range_softc.mr_ndesc;
276 mo->mo_arg[0] = nd;
277 break;
278
279 case MEMRANGE_SET:
280 md = (struct mem_range_desc *)malloc(sizeof(struct mem_range_desc),
281 M_MEMDESC, M_WAITOK);
282 error = copyin(mo->mo_desc, md, sizeof(struct mem_range_desc));
283 /* clamp description string */
284 md->mr_owner[sizeof(md->mr_owner) - 1] = 0;
285 if (error == 0)
286 error = mem_range_attr_set(md, &mo->mo_arg[0]);
287 free(md, M_MEMDESC);
288 break;
289 }
290 return (error);
291 }
292
293 /*
294 * Implementation-neutral, kernel-callable functions for manipulating
295 * memory range attributes.
296 */
297 int
298 mem_range_attr_get(struct mem_range_desc *mrd, int *arg)
299 {
300 /* can we handle this? */
301 if (mem_range_softc.mr_op == NULL)
302 return (EOPNOTSUPP);
303
304 if (*arg == 0)
305 *arg = mem_range_softc.mr_ndesc;
306 else
307 bcopy(mem_range_softc.mr_desc, mrd,
308 (*arg) * sizeof(struct mem_range_desc));
309 return (0);
310 }
311
312 int
313 mem_range_attr_set(struct mem_range_desc *mrd, int *arg)
314 {
315 /* can we handle this? */
316 if (mem_range_softc.mr_op == NULL)
317 return (EOPNOTSUPP);
318
319 return (mem_range_softc.mr_op->set(&mem_range_softc, mrd, arg));
320 }
321
322 #ifdef SMP
323 void
324 mem_range_AP_init(void)
325 {
326 if (mem_range_softc.mr_op && mem_range_softc.mr_op->initAP)
327 (mem_range_softc.mr_op->initAP(&mem_range_softc));
328 }
329 #endif
330
331 static int
332 mem_modevent(module_t mod, int type, void *data)
333 {
334 switch(type) {
335 case MOD_LOAD:
336 if (bootverbose)
337 printf("mem: <memory & I/O>\n");
338 /* Initialise memory range handling */
339 if (mem_range_softc.mr_op != NULL)
340 mem_range_softc.mr_op->init(&mem_range_softc);
341
342 memdev = make_dev(&mem_cdevsw, 0, UID_ROOT, GID_KMEM,
343 0640, "mem");
344 kmemdev = make_dev(&mem_cdevsw, 1, UID_ROOT, GID_KMEM,
345 0640, "kmem");
346 iodev = make_dev(&mem_cdevsw, 14, UID_ROOT, GID_WHEEL,
347 0600, "io");
348 return (0);
349
350 case MOD_UNLOAD:
351 destroy_dev(memdev);
352 destroy_dev(kmemdev);
353 destroy_dev(iodev);
354 return (0);
355
356 case MOD_SHUTDOWN:
357 return (0);
358
359 default:
360 return (EOPNOTSUPP);
361 }
362 }
363
364 DEV_MODULE(mem, mem_modevent, NULL);
Cache object: 56486e2123174e3fe758ff931d7d3550
|