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