1 /* $NetBSD: mach_vm.c,v 1.53 2006/11/16 01:32:44 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2002-2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Emmanuel Dreyfus
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include "opt_ktrace.h"
40
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: mach_vm.c,v 1.53 2006/11/16 01:32:44 christos Exp $");
43
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/mount.h>
48 #include <sys/proc.h>
49 #include <sys/sa.h>
50 #include <sys/mman.h>
51 #include <sys/malloc.h>
52 #include <sys/vnode.h>
53 #include <sys/file.h>
54 #include <sys/filedesc.h>
55 #include <sys/ktrace.h>
56 #include <sys/exec.h>
57 #include <sys/syscallargs.h>
58
59 #include <uvm/uvm_prot.h>
60 #include <uvm/uvm_map.h>
61 #include <uvm/uvm_extern.h>
62
63 #include <compat/mach/mach_types.h>
64 #include <compat/mach/mach_message.h>
65 #include <compat/mach/mach_clock.h>
66 #include <compat/mach/mach_vm.h>
67 #include <compat/mach/mach_errno.h>
68 #include <compat/mach/mach_port.h>
69 #include <compat/mach/mach_services.h>
70 #include <compat/mach/mach_syscallargs.h>
71
72 int
73 mach_vm_map(args)
74 struct mach_trap_args *args;
75 {
76 mach_vm_map_request_t *req = args->smsg;
77 mach_vm_map_reply_t *rep = args->rmsg;
78 size_t *msglen = args->rsize;
79 struct lwp *tl = args->tl;
80 struct proc *tp = tl->l_proc;
81 struct sys_mmap_args cup;
82 vaddr_t addr;
83 int error, flags;
84 void *ret;
85
86 #ifdef DEBUG_MACH_VM
87 printf("mach_vm_map(addr = %p, size = 0x%08lx, obj = 0x%x, "
88 "mask = 0x%08lx, flags = 0x%x, offset = 0x%08llx, "
89 "copy = %d, cur_prot = 0x%x, max_prot = 0x%x, inh = 0x%x);\n",
90 (void *)req->req_address, (long)req->req_size, req->req_object.name,
91 (long)req->req_mask, req->req_flags, (off_t)req->req_offset,
92 req->req_copy, req->req_cur_protection, req->req_max_protection,
93 req->req_inherance);
94 #endif
95
96 /* XXX Darwin fails on mapping a page at address 0 */
97 if (req->req_address == 0)
98 return mach_msg_error(args, ENOMEM);
99
100 req->req_size = round_page(req->req_size);
101
102 /* Where Mach uses 0x00ff, we use 0x0100 */
103 if ((req->req_mask & (req->req_mask + 1)) || (req->req_mask == 0))
104 req->req_mask = 0;
105 else
106 req->req_mask += 1;
107
108 if (req->req_flags & MACH_VM_FLAGS_ANYWHERE) {
109 SCARG(&cup, flags) = MAP_ANON;
110 flags = 0;
111 } else {
112 SCARG(&cup, flags) = MAP_ANON | MAP_FIXED;
113 flags = MAP_FIXED;
114 }
115
116 /*
117 * Use uvm_map_findspace to find a place which conforms to the
118 * requested alignement.
119 */
120 vm_map_lock(&tp->p_vmspace->vm_map);
121 ret = uvm_map_findspace(&tp->p_vmspace->vm_map,
122 trunc_page(req->req_address), req->req_size, &addr,
123 NULL, 0, req->req_mask, flags);
124 vm_map_unlock(&tp->p_vmspace->vm_map);
125
126 if (ret == NULL)
127 return mach_msg_error(args, ENOMEM);
128
129 switch(req->req_inherance) {
130 case MACH_VM_INHERIT_SHARE:
131 SCARG(&cup, flags) |= MAP_INHERIT;
132 break;
133 case MACH_VM_INHERIT_COPY:
134 SCARG(&cup, flags) |= MAP_COPY;
135 break;
136 case MACH_VM_INHERIT_NONE:
137 break;
138 case MACH_VM_INHERIT_DONATE_COPY:
139 default:
140 uprintf("mach_vm_map: unsupported inherance flag %d\n",
141 req->req_inherance);
142 break;
143 }
144
145 SCARG(&cup, addr) = (void *)addr;
146 SCARG(&cup, len) = req->req_size;
147 SCARG(&cup, prot) = req->req_cur_protection;
148 SCARG(&cup, fd) = -1; /* XXX For now, no object mapping */
149 SCARG(&cup, pos) = req->req_offset;
150
151 if ((error = sys_mmap(tl, &cup, &rep->rep_retval)) != 0)
152 return mach_msg_error(args, error);
153
154 *msglen = sizeof(*rep);
155 mach_set_header(rep, req, *msglen);
156 mach_set_trailer(rep, *msglen);
157
158 return 0;
159 }
160
161 int
162 mach_vm_allocate(args)
163 struct mach_trap_args *args;
164 {
165 mach_vm_allocate_request_t *req = args->smsg;
166 mach_vm_allocate_reply_t *rep = args->rmsg;
167 size_t *msglen = args->rsize;
168 struct lwp *tl = args->tl;
169 struct proc *tp = tl->l_proc;
170 struct sys_mmap_args cup;
171 vaddr_t addr;
172 size_t size;
173 int error;
174
175 addr = req->req_address;
176 size = req->req_size;
177
178 #ifdef DEBUG_MACH_VM
179 printf("mach_vm_allocate(addr = %p, size = 0x%08x);\n",
180 (void *)addr, size);
181 #endif
182
183 /*
184 * Avoid mappings at address zero: it should
185 * be a "red zone" with nothing mapped on it.
186 */
187 if (addr == 0) {
188 if (req->req_flags & MACH_VM_FLAGS_ANYWHERE)
189 addr = 0x1000;
190 else
191 return mach_msg_error(args, EINVAL);
192 #ifdef DEBUG_MACH_VM
193 printf("mach_vm_allocate: trying addr = %p\n", (void *)addr);
194 #endif
195 }
196
197 size = round_page(size);
198 if (req->req_flags & MACH_VM_FLAGS_ANYWHERE)
199 addr = vm_map_min(&tp->p_vmspace->vm_map);
200 else
201 addr = trunc_page(addr);
202
203 if (((addr + size) > vm_map_max(&tp->p_vmspace->vm_map)) ||
204 ((addr + size) <= addr))
205 addr = vm_map_min(&tp->p_vmspace->vm_map);
206
207 if (size == 0)
208 goto out;
209
210 SCARG(&cup, addr) = (caddr_t)addr;
211 SCARG(&cup, len) = size;
212 SCARG(&cup, prot) = PROT_READ | PROT_WRITE;
213 SCARG(&cup, flags) = MAP_ANON;
214 if ((req->req_flags & MACH_VM_FLAGS_ANYWHERE) == 0)
215 SCARG(&cup, flags) |= MAP_FIXED;
216 SCARG(&cup, fd) = -1;
217 SCARG(&cup, pos) = 0;
218
219 if ((error = sys_mmap(tl, &cup, &rep->rep_address)) != 0)
220 return mach_msg_error(args, error);
221 #ifdef DEBUG_MACH_VM
222 printf("vm_allocate: success at %p\n", (void *)rep->rep_address);
223 #endif
224
225 out:
226 *msglen = sizeof(*rep);
227 mach_set_header(rep, req, *msglen);
228
229 rep->rep_retval = 0;
230
231 mach_set_trailer(rep, *msglen);
232
233 return 0;
234 }
235
236 int
237 mach_vm_deallocate(args)
238 struct mach_trap_args *args;
239 {
240 mach_vm_deallocate_request_t *req = args->smsg;
241 mach_vm_deallocate_reply_t *rep = args->rmsg;
242 size_t *msglen = args->rsize;
243 struct lwp *tl = args->tl;
244 struct sys_munmap_args cup;
245 int error;
246
247 #ifdef DEBUG_MACH_VM
248 printf("mach_vm_deallocate(addr = %p, size = 0x%08lx);\n",
249 (void *)req->req_address, (long)req->req_size);
250 #endif
251
252 SCARG(&cup, addr) = (caddr_t)req->req_address;
253 SCARG(&cup, len) = req->req_size;
254
255 if ((error = sys_munmap(tl, &cup, &rep->rep_retval)) != 0)
256 return mach_msg_error(args, error);
257
258 *msglen = sizeof(*rep);
259 mach_set_header(rep, req, *msglen);
260 mach_set_trailer(rep, *msglen);
261
262 return 0;
263 }
264
265 /*
266 * XXX This server message Id clashes with bootstrap_look_up.
267 * Is there a way to resolve this easily?
268 */
269 #if 0
270 int
271 mach_vm_wire(args)
272 struct mach_trap_args *args;
273 {
274 mach_vm_wire_request_t *req = args->smsg;
275 mach_vm_wire_reply_t *rep = args->rmsg;
276 size_t *msglen = args->rsize;
277 struct lwp *tl = args->tl;
278 register_t retval;
279 int error;
280
281 #ifdef DEBUG_MACH_VM
282 printf("mach_vm_wire(addr = %p, size = 0x%08x, prot = 0x%x);\n",
283 (void *)req->req_address, req->req_size, req->req_access);
284 #endif
285
286 bzero(&rep, sizeof(*rep));
287
288 if ((req->req_access & ~VM_PROT_ALL) != 0)
289 return mach_msg_error(args, EINVAL);
290
291 /*
292 * Mach maintains a count of how many times a page is wired
293 * and unwire it once the count is zero. We cannot do that yet.
294 */
295 if (req->req_access == 0) {
296 struct sys_munlock_args cup;
297
298 SCARG(&cup, addr) = (void *)req->req_address;
299 SCARG(&cup, len) = req->req_size;
300 error = sys_munlock(tl, &cup, &retval);
301 } else {
302 struct sys_mlock_args cup;
303
304 SCARG(&cup, addr) = (void *)req->req_address;
305 SCARG(&cup, len) = req->req_size;
306 error = sys_mlock(tl, &cup, &retval);
307 }
308 if (error != 0)
309 return mach_msg_error(args, error);
310
311 if ((error = uvm_map_protect(&tl->l_proc->p_vmspace->vm_map,
312 req->req_address, req->req_address + req->req_size,
313 req->req_access, 0)) != 0)
314 return mach_msg_error(args, error);
315
316 *msglen = sizeof(*rep);
317 mach_set_header(rep, req, *msglen);
318 mach_set_trailer(rep, *msglen);
319
320 return 0;
321 }
322 #endif
323
324 int
325 mach_vm_protect(args)
326 struct mach_trap_args *args;
327 {
328 mach_vm_protect_request_t *req = args->smsg;
329 mach_vm_protect_reply_t *rep = args->rmsg;
330 size_t *msglen = args->rsize;
331 struct lwp *tl = args->tl;
332 struct sys_mprotect_args cup;
333 register_t retval;
334 int error;
335
336 SCARG(&cup, addr) = (void *)req->req_addr;
337 SCARG(&cup, len) = req->req_size;
338 SCARG(&cup, prot) = req->req_prot;
339
340 if ((error = sys_mprotect(tl, &cup, &retval)) != 0)
341 return mach_msg_error(args, error);
342
343 *msglen = sizeof(*rep);
344 mach_set_header(rep, req, *msglen);
345 mach_set_trailer(rep, *msglen);
346
347 return 0;
348 }
349
350 int
351 mach_sys_map_fd(struct lwp *l, void *v, register_t *retval)
352 {
353 struct mach_sys_map_fd_args /* {
354 syscallarg(int) fd;
355 syscallarg(mach_vm_offset_t) offset;
356 syscallarg(mach_vm_offset_t *) va;
357 syscallarg(mach_boolean_t) findspace;
358 syscallarg(mach_vm_size_t) size;
359 } */ *uap = v;
360 struct file *fp;
361 struct filedesc *fdp;
362 struct vnode *vp;
363 struct exec_vmcmd evc;
364 struct vm_map_entry *ret;
365 struct proc *p = l->l_proc;
366 register_t dontcare;
367 struct sys_munmap_args cup;
368 void *va;
369 int error;
370
371 if ((error = copyin(SCARG(uap, va), (void *)&va, sizeof(va))) != 0)
372 return error;
373
374 if (SCARG(uap, findspace) == 0) {
375 /* Make some free space XXX probably not The Right Way */
376 SCARG(&cup, addr) = va;
377 SCARG(&cup, len) = SCARG(uap, size);
378 (void)sys_munmap(l, &cup, &dontcare);
379 }
380
381 fdp = p->p_fd;
382 fp = fd_getfile(fdp, SCARG(uap, fd));
383 if (fp == NULL)
384 return EBADF;
385
386 FILE_USE(fp);
387 vp = (struct vnode *)fp->f_data;
388 vref(vp);
389
390 #ifdef DEBUG_MACH_VM
391 printf("vm_map_fd: addr = %p len = 0x%08lx\n",
392 va, (long)SCARG(uap, size));
393 #endif
394 bzero(&evc, sizeof(evc));
395 evc.ev_addr = (u_long)va;
396 evc.ev_len = SCARG(uap, size);
397 evc.ev_prot = VM_PROT_ALL;
398 evc.ev_flags = SCARG(uap, findspace) ? 0 : VMCMD_FIXED;
399 evc.ev_proc = vmcmd_map_readvn;
400 evc.ev_offset = SCARG(uap, offset);
401 evc.ev_vp = vp;
402
403 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
404 if ((error = (*evc.ev_proc)(l, &evc)) != 0) {
405 VOP_UNLOCK(vp, 0);
406
407 #ifdef DEBUG_MACH_VM
408 printf("mach_sys_map_fd: mapping at %p failed\n", va);
409 #endif
410
411 if (SCARG(uap, findspace) == 0)
412 goto bad2;
413
414 vm_map_lock(&p->p_vmspace->vm_map);
415 if ((ret = uvm_map_findspace(&p->p_vmspace->vm_map,
416 vm_map_min(&p->p_vmspace->vm_map), evc.ev_len,
417 (vaddr_t *)&evc.ev_addr, NULL, 0, PAGE_SIZE, 0)) == NULL) {
418 vm_map_unlock(&p->p_vmspace->vm_map);
419 goto bad2;
420 }
421 vm_map_unlock(&p->p_vmspace->vm_map);
422
423 va = (void *)evc.ev_addr;
424
425 bzero(&evc, sizeof(evc));
426 evc.ev_addr = (u_long)va;
427 evc.ev_len = SCARG(uap, size);
428 evc.ev_prot = VM_PROT_ALL;
429 evc.ev_flags = 0;
430 evc.ev_proc = vmcmd_map_readvn;
431 evc.ev_offset = SCARG(uap, offset);
432 evc.ev_vp = vp;
433
434 #ifdef DEBUG_MACH_VM
435 printf("mach_sys_map_fd: trying at %p\n", va);
436 #endif
437 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
438 if ((error = (*evc.ev_proc)(l, &evc)) != 0)
439 goto bad1;
440 }
441
442 vput(vp);
443 FILE_UNUSE(fp, l);
444 #ifdef DEBUG_MACH_VM
445 printf("mach_sys_map_fd: mapping at %p\n", (void *)evc.ev_addr);
446 #endif
447
448 va = (mach_vm_offset_t *)evc.ev_addr;
449
450 if ((error = copyout((void *)&va, SCARG(uap, va), sizeof(va))) != 0)
451 return error;
452
453 return 0;
454
455 bad1:
456 VOP_UNLOCK(vp, 0);
457 bad2:
458 vrele(vp);
459 FILE_UNUSE(fp, l);
460 #ifdef DEBUG_MACH_VM
461 printf("mach_sys_map_fd: mapping at %p failed, error = %d\n",
462 (void *)evc.ev_addr, error);
463 #endif
464 return error;
465 }
466
467 int
468 mach_vm_inherit(args)
469 struct mach_trap_args *args;
470 {
471 mach_vm_inherit_request_t *req = args->smsg;
472 mach_vm_inherit_reply_t *rep = args->rmsg;
473 size_t *msglen = args->rsize;
474 struct lwp *tl = args->tl;
475 struct sys_minherit_args cup;
476 register_t retval;
477 int error;
478
479 SCARG(&cup, addr) = (void *)req->req_addr;
480 SCARG(&cup, len) = req->req_size;
481 /* Flags map well between Mach and NetBSD */
482 SCARG(&cup, inherit) = req->req_inh;
483
484 if ((error = sys_minherit(tl, &cup, &retval)) != 0)
485 return mach_msg_error(args, error);
486
487 *msglen = sizeof(*rep);
488 mach_set_header(rep, req, *msglen);
489 mach_set_trailer(rep, *msglen);
490
491 return 0;
492 }
493
494 int
495 mach_make_memory_entry_64(args)
496 struct mach_trap_args *args;
497 {
498 mach_make_memory_entry_64_request_t *req = args->smsg;
499 mach_make_memory_entry_64_reply_t *rep = args->rmsg;
500 size_t *msglen = args->rsize;
501 struct lwp *l = args->l;
502 struct lwp *tl = args->tl;
503 struct mach_port *mp;
504 struct mach_right *mr;
505 struct mach_memory_entry *mme;
506
507 printf("mach_make_memory_entry_64, offset 0x%lx, size 0x%lx\n",
508 (u_long)req->req_offset, (u_long)req->req_size);
509
510 mp = mach_port_get();
511 mp->mp_flags |= (MACH_MP_INKERNEL | MACH_MP_DATA_ALLOCATED);
512 mp->mp_datatype = MACH_MP_MEMORY_ENTRY;
513
514 mme = malloc(sizeof(*mme), M_EMULDATA, M_WAITOK);
515 mme->mme_proc = tl->l_proc;
516 mme->mme_offset = req->req_offset;
517 mme->mme_size = req->req_size;
518 mp->mp_data = mme;
519
520 mr = mach_right_get(mp, l, MACH_PORT_TYPE_SEND, 0);
521
522 *msglen = sizeof(*rep);
523 mach_set_header(rep, req, *msglen);
524 mach_add_port_desc(rep, mr->mr_name);
525
526 rep->rep_size = req->req_size;
527
528 mach_set_trailer(rep, *msglen);
529
530 return 0;
531 }
532
533 int
534 mach_vm_region(args)
535 struct mach_trap_args *args;
536 {
537 mach_vm_region_request_t *req = args->smsg;
538 mach_vm_region_reply_t *rep = args->rmsg;
539 size_t *msglen = args->rsize;
540 struct lwp *tl = args->tl;
541 struct mach_vm_region_basic_info *rbi;
542 struct vm_map *map;
543 struct vm_map_entry *vme;
544 int error;
545
546 /* Sanity check req_count */
547 if (req->req_count > 9)
548 return mach_msg_error(args, EINVAL);
549
550 /*
551 * MACH_VM_REGION_BASIC_INFO is the only
552 * supported flavor in Darwin.
553 */
554 if (req->req_flavor != MACH_VM_REGION_BASIC_INFO)
555 return mach_msg_error(args, EINVAL);
556 if (req->req_count != (sizeof(*rbi) / sizeof(int))) /* This is 8 */
557 return mach_msg_error(args, EINVAL);
558 *msglen = sizeof(*rep) + ((req->req_count - 9) * sizeof(int));
559
560 map = &tl->l_proc->p_vmspace->vm_map;
561
562 vm_map_lock(map);
563 error = uvm_map_lookup_entry(map, req->req_addr, &vme);
564 vm_map_unlock(map);
565
566 if (error == 0)
567 return mach_msg_error(args, ENOMEM);
568
569 mach_set_header(rep, req, *msglen);
570 mach_add_port_desc(rep, 0); /* XXX Why this null name */
571
572 rep->rep_addr = vme->start;
573 rep->rep_size = vme->end - vme->start;
574 rep->rep_count = req->req_count;
575
576 rbi = (struct mach_vm_region_basic_info *)&rep->rep_info[0];
577 rbi->protection = vme->protection;
578 rbi->inheritance = 1; /* vme->inheritance */
579 rbi->shared = 0; /* XXX how can we know? */
580 rbi->offset = vme->offset;
581 rbi->behavior = MACH_VM_BEHAVIOR_DEFAULT; /* XXX What is it? */
582 rbi->user_wired_count = vme->wired_count;
583
584 /* XXX Why this? */
585 *(short *)((u_long)&rbi->user_wired_count + sizeof(short)) = 1;
586
587 mach_set_trailer(rep, *msglen);
588
589 return 0;
590 }
591
592 int
593 mach_vm_region_64(args)
594 struct mach_trap_args *args;
595 {
596 mach_vm_region_64_request_t *req = args->smsg;
597 mach_vm_region_64_reply_t *rep = args->rmsg;
598 size_t *msglen = args->rsize;
599 struct lwp *tl = args->tl;
600 struct mach_vm_region_basic_info_64 *rbi;
601 struct vm_map *map;
602 struct vm_map_entry *vme;
603 int error;
604
605 /* Sanity check req_count */
606 if (req->req_count > 10)
607 return mach_msg_error(args, EINVAL);
608
609 /*
610 * MACH_VM_REGION_BASIC_INFO is the only
611 * supported flavor in Darwin.
612 */
613 if (req->req_flavor != MACH_VM_REGION_BASIC_INFO)
614 return mach_msg_error(args, EINVAL);
615 if (req->req_count != (sizeof(*rbi) / sizeof(int))) /* This is 8 */
616 return mach_msg_error(args, EINVAL);
617 *msglen = sizeof(*rep) + ((req->req_count - 9) * sizeof(int));
618
619 map = &tl->l_proc->p_vmspace->vm_map;
620
621 vm_map_lock(map);
622 error = uvm_map_lookup_entry(map, req->req_addr, &vme);
623 vm_map_unlock(map);
624
625 if (error == 0)
626 return mach_msg_error(args, ENOMEM);
627
628 mach_set_header(rep, req, *msglen);
629 mach_add_port_desc(rep, 0); /* XXX null port ? */
630
631 rep->rep_size = PAGE_SIZE; /* XXX Why? */
632 rep->rep_count = req->req_count;
633
634 rbi = (struct mach_vm_region_basic_info_64 *)&rep->rep_info[0];
635 rbi->protection = vme->protection;
636 rbi->inheritance = 1; /* vme->inheritance */
637 rbi->shared = 0; /* XXX how can we know? */
638 rbi->offset = vme->offset;
639 rbi->behavior = MACH_VM_BEHAVIOR_DEFAULT; /* XXX What is it? */
640 rbi->user_wired_count = vme->wired_count;
641
642 /* XXX Why this? */
643 *(short *)((u_long)&rbi->user_wired_count + sizeof(short)) = 1;
644
645 mach_set_trailer(rep, *msglen);
646
647 return 0;
648 }
649
650 int
651 mach_vm_msync(args)
652 struct mach_trap_args *args;
653 {
654 mach_vm_msync_request_t *req = args->smsg;
655 mach_vm_msync_reply_t *rep = args->rmsg;
656 size_t *msglen = args->rsize;
657 struct lwp *tl = args->tl;
658 struct sys___msync13_args cup;
659 int error;
660 register_t dontcare;
661
662 SCARG(&cup, addr) = (void *)req->req_addr;
663 SCARG(&cup, len) = req->req_size;
664 SCARG(&cup, flags) = 0;
665 if (req->req_flags & MACH_VM_SYNC_ASYNCHRONOUS)
666 SCARG(&cup, flags) |= MS_ASYNC;
667 if (req->req_flags & MACH_VM_SYNC_SYNCHRONOUS)
668 SCARG(&cup, flags) |= MS_SYNC;
669 if (req->req_flags & MACH_VM_SYNC_INVALIDATE)
670 SCARG(&cup, flags) |= MS_INVALIDATE;
671
672 error = sys___msync13(tl, &cup, &dontcare);
673
674 *msglen = sizeof(*rep);
675 mach_set_header(rep, req, *msglen);
676
677 rep->rep_retval = native_to_mach_errno[error];
678
679 mach_set_trailer(rep, *msglen);
680
681 return 0;
682 }
683
684 /* XXX Do it for remote task */
685 int
686 mach_vm_copy(args)
687 struct mach_trap_args *args;
688 {
689 mach_vm_copy_request_t *req = args->smsg;
690 mach_vm_copy_reply_t *rep = args->rmsg;
691 size_t *msglen = args->rsize;
692 char *tmpbuf;
693 int error;
694 caddr_t src, dst;
695 size_t size;
696
697 #ifdef DEBUG_MACH_VM
698 printf("mach_vm_copy: src = 0x%08lx, size = 0x%08lx, addr = 0x%08lx\n",
699 (long)req->req_src, (long)req->req_size, (long)req->req_addr);
700 #endif
701 if ((req->req_src & (PAGE_SIZE - 1)) ||
702 (req->req_addr & (PAGE_SIZE - 1)) ||
703 (req->req_size & (PAGE_SIZE - 1)))
704 return mach_msg_error(args, EINVAL);
705
706 src = (caddr_t)req->req_src;
707 dst = (caddr_t)req->req_addr;
708 size = (size_t)req->req_size;
709
710 tmpbuf = malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
711
712 /* Is there an easy way of dealing with that efficiently? */
713 do {
714 if ((error = copyin(src, tmpbuf, PAGE_SIZE)) != 0)
715 goto out;
716
717 if ((error = copyout(tmpbuf, dst, PAGE_SIZE)) != 0)
718 goto out;
719
720 src += PAGE_SIZE;
721 dst += PAGE_SIZE;
722 size -= PAGE_SIZE;
723 } while (size > 0);
724
725 *msglen = sizeof(*rep);
726 mach_set_header(rep, req, *msglen);
727
728 rep->rep_retval = 0;
729
730 mach_set_trailer(rep, *msglen);
731
732 free(tmpbuf, M_TEMP);
733 return 0;
734
735 out:
736 free(tmpbuf, M_TEMP);
737 return mach_msg_error(args, error);
738 }
739
740 int
741 mach_vm_read(args)
742 struct mach_trap_args *args;
743 {
744 mach_vm_read_request_t *req = args->smsg;
745 mach_vm_read_reply_t *rep = args->rmsg;
746 size_t *msglen = args->rsize;
747 struct lwp *l = args->l;
748 struct lwp *tl = args->tl;
749 char *tbuf;
750 void *addr;
751 vaddr_t va;
752 size_t size;
753 int error;
754
755 size = req->req_size;
756 va = vm_map_min(&l->l_proc->p_vmspace->vm_map);
757 if ((error = uvm_map(&l->l_proc->p_vmspace->vm_map, &va,
758 round_page(size), NULL, UVM_UNKNOWN_OFFSET, 0,
759 UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_ALL,
760 UVM_INH_COPY, UVM_ADV_NORMAL, UVM_FLAG_COPYONW))) != 0) {
761 printf("uvm_map error = %d\n", error);
762 return mach_msg_error(args, EFAULT);
763 }
764
765 /*
766 * Copy the data from the target process to the current process
767 * This is reasonable for small chunk of data, but we should
768 * remap COW for areas bigger than a page.
769 */
770 tbuf = malloc(size, M_EMULDATA, M_WAITOK);
771
772 addr = (void *)req->req_addr;
773 if ((error = copyin_proc(tl->l_proc, addr, tbuf, size)) != 0) {
774 printf("copyin_proc error = %d, addr = %p, size = %x\n", error, addr, size);
775 free(tbuf, M_WAITOK);
776 return mach_msg_error(args, EFAULT);
777 }
778
779 if ((error = copyout(tbuf, (void *)va, size)) != 0) {
780 printf("copyout error = %d\n", error);
781 free(tbuf, M_WAITOK);
782 return mach_msg_error(args, EFAULT);
783 }
784
785 #ifdef KTRACE
786 if (KTRPOINT(l->l_proc, KTR_MOOL) && error == 0)
787 ktrmool(l, tbuf, size, (void *)va);
788 #endif
789
790 free(tbuf, M_WAITOK);
791
792 *msglen = sizeof(*rep);
793 mach_set_header(rep, req, *msglen);
794 mach_add_ool_desc(rep, (void *)va, size);
795
796 rep->rep_count = size;
797
798 mach_set_trailer(rep, *msglen);
799
800 return 0;
801 }
802
803 int
804 mach_vm_write(args)
805 struct mach_trap_args *args;
806 {
807 mach_vm_write_request_t *req = args->smsg;
808 mach_vm_write_reply_t *rep = args->rmsg;
809 size_t *msglen = args->rsize;
810 #ifdef KTRACE
811 struct lwp *l = args->l;
812 #endif
813 struct lwp *tl = args->tl;
814 size_t size;
815 void *addr;
816 char *tbuf;
817 int error;
818
819 #ifdef DEBUG_MACH
820 if (req->req_body.msgh_descriptor_count != 1)
821 printf("mach_vm_write: OOL descriptor count is not 1\n");
822 #endif
823
824 /*
825 * Copy the data from the current process to the target process
826 * This is reasonable for small chunk of data, but we should
827 * remap COW for areas bigger than a page.
828 */
829 size = req->req_data.size;
830 tbuf = malloc(size, M_EMULDATA, M_WAITOK);
831
832 if ((error = copyin(req->req_data.address, tbuf, size)) != 0) {
833 printf("copyin error = %d\n", error);
834 free(tbuf, M_WAITOK);
835 return mach_msg_error(args, EFAULT);
836 }
837
838 addr = (void *)req->req_addr;
839 if ((error = copyout_proc(tl->l_proc, tbuf, addr, size)) != 0) {
840 printf("copyout_proc error = %d\n", error);
841 free(tbuf, M_WAITOK);
842 return mach_msg_error(args, EFAULT);
843 }
844
845 #ifdef KTRACE
846 if (KTRPOINT(l->l_proc, KTR_MOOL) && error == 0)
847 ktrmool(l, tbuf, size, (void *)addr);
848 #endif
849
850 free(tbuf, M_WAITOK);
851
852 *msglen = sizeof(*rep);
853 mach_set_header(rep, req, *msglen);
854
855 rep->rep_retval = 0;
856
857 mach_set_trailer(rep, *msglen);
858
859 return 0;
860 }
861
862 int
863 mach_vm_machine_attribute(args)
864 struct mach_trap_args *args;
865 {
866 mach_vm_machine_attribute_request_t *req = args->smsg;
867 mach_vm_machine_attribute_reply_t *rep = args->rmsg;
868 size_t *msglen = args->rsize;
869 struct lwp *tl = args->tl;
870 int error = 0;
871 int attribute, value;
872
873 attribute = req->req_attribute;
874 value = req->req_value;
875
876 switch (attribute) {
877 case MACH_MATTR_CACHE:
878 switch(value) {
879 case MACH_MATTR_VAL_CACHE_FLUSH:
880 case MACH_MATTR_VAL_DCACHE_FLUSH:
881 case MACH_MATTR_VAL_ICACHE_FLUSH:
882 case MACH_MATTR_VAL_CACHE_SYNC:
883 error = mach_vm_machine_attribute_machdep(tl,
884 req->req_addr, req->req_size, &value);
885 break;
886 default:
887 #ifdef DEBUG_MACH
888 printf("unimplemented value %d\n", req->req_value);
889 #endif
890 error = EINVAL;
891 break;
892 }
893 break;
894
895 case MACH_MATTR_MIGRATE:
896 case MACH_MATTR_REPLICATE:
897 default:
898 #ifdef DEBUG_MACH
899 printf("unimplemented attribute %d\n", req->req_attribute);
900 #endif
901 error = EINVAL;
902 break;
903 }
904
905 *msglen = sizeof(*rep);
906 mach_set_header(rep, req, *msglen);
907
908 rep->rep_retval = native_to_mach_errno[error];
909 if (error != 0)
910 rep->rep_value = value;
911
912 mach_set_trailer(rep, *msglen);
913
914 return 0;
915 }
Cache object: 27a0e60c6bf4f6e5ab7c6c9d62a7f917
|