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