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