No empty .Rs/.Re
[netbsd-mini2440.git] / sys / compat / mach / mach_vm.c
blob6fc7693a57690e4bb0ea613473b53f6db923cd62
1 /* $NetBSD: mach_vm.c,v 1.60 2008/04/28 20:23:45 martin Exp $ */
3 /*-
4 * Copyright (c) 2002-2003, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Emmanuel Dreyfus
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: mach_vm.c,v 1.60 2008/04/28 20:23:45 martin Exp $");
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/mount.h>
39 #include <sys/proc.h>
40 #include <sys/mman.h>
41 #include <sys/malloc.h>
42 #include <sys/vnode.h>
43 #include <sys/file.h>
44 #include <sys/filedesc.h>
45 #include <sys/ktrace.h>
46 #include <sys/exec.h>
47 #include <sys/syscallargs.h>
49 #include <uvm/uvm_prot.h>
50 #include <uvm/uvm_map.h>
51 #include <uvm/uvm_extern.h>
53 #include <compat/mach/mach_types.h>
54 #include <compat/mach/mach_message.h>
55 #include <compat/mach/mach_clock.h>
56 #include <compat/mach/mach_vm.h>
57 #include <compat/mach/mach_errno.h>
58 #include <compat/mach/mach_port.h>
59 #include <compat/mach/mach_services.h>
60 #include <compat/mach/mach_syscallargs.h>
62 int
63 mach_vm_map(struct mach_trap_args *args)
65 mach_vm_map_request_t *req = args->smsg;
66 mach_vm_map_reply_t *rep = args->rmsg;
67 size_t *msglen = args->rsize;
68 struct lwp *tl = args->tl;
69 struct proc *tp = tl->l_proc;
70 struct sys_mmap_args cup;
71 vaddr_t addr;
72 int error, flags;
73 void *ret;
75 #ifdef DEBUG_MACH_VM
76 printf("mach_vm_map(addr = %p, size = 0x%08lx, obj = 0x%x, "
77 "mask = 0x%08lx, flags = 0x%x, offset = 0x%08llx, "
78 "copy = %d, cur_prot = 0x%x, max_prot = 0x%x, inh = 0x%x);\n",
79 (void *)req->req_address, (long)req->req_size, req->req_object.name,
80 (long)req->req_mask, req->req_flags, (off_t)req->req_offset,
81 req->req_copy, req->req_cur_protection, req->req_max_protection,
82 req->req_inherance);
83 #endif
85 /* XXX Darwin fails on mapping a page at address 0 */
86 if (req->req_address == 0)
87 return mach_msg_error(args, ENOMEM);
89 req->req_size = round_page(req->req_size);
91 /* Where Mach uses 0x00ff, we use 0x0100 */
92 if ((req->req_mask & (req->req_mask + 1)) || (req->req_mask == 0))
93 req->req_mask = 0;
94 else
95 req->req_mask += 1;
97 if (req->req_flags & MACH_VM_FLAGS_ANYWHERE) {
98 SCARG(&cup, flags) = MAP_ANON;
99 flags = 0;
100 } else {
101 SCARG(&cup, flags) = MAP_ANON | MAP_FIXED;
102 flags = MAP_FIXED;
106 * Use uvm_map_findspace to find a place which conforms to the
107 * requested alignement.
109 vm_map_lock(&tp->p_vmspace->vm_map);
110 ret = uvm_map_findspace(&tp->p_vmspace->vm_map,
111 trunc_page(req->req_address), req->req_size, &addr,
112 NULL, 0, req->req_mask, flags);
113 vm_map_unlock(&tp->p_vmspace->vm_map);
115 if (ret == NULL)
116 return mach_msg_error(args, ENOMEM);
118 switch(req->req_inherance) {
119 case MACH_VM_INHERIT_SHARE:
120 SCARG(&cup, flags) |= MAP_INHERIT;
121 break;
122 case MACH_VM_INHERIT_COPY:
123 SCARG(&cup, flags) |= MAP_COPY;
124 break;
125 case MACH_VM_INHERIT_NONE:
126 break;
127 case MACH_VM_INHERIT_DONATE_COPY:
128 default:
129 uprintf("mach_vm_map: unsupported inherance flag %d\n",
130 req->req_inherance);
131 break;
134 SCARG(&cup, addr) = (void *)addr;
135 SCARG(&cup, len) = req->req_size;
136 SCARG(&cup, prot) = req->req_cur_protection;
137 SCARG(&cup, fd) = -1; /* XXX For now, no object mapping */
138 SCARG(&cup, pos) = req->req_offset;
140 if ((error = sys_mmap(tl, &cup, &rep->rep_retval)) != 0)
141 return mach_msg_error(args, error);
143 *msglen = sizeof(*rep);
144 mach_set_header(rep, req, *msglen);
145 mach_set_trailer(rep, *msglen);
147 return 0;
151 mach_vm_allocate(struct mach_trap_args *args)
153 mach_vm_allocate_request_t *req = args->smsg;
154 mach_vm_allocate_reply_t *rep = args->rmsg;
155 size_t *msglen = args->rsize;
156 struct lwp *tl = args->tl;
157 struct proc *tp = tl->l_proc;
158 struct sys_mmap_args cup;
159 vaddr_t addr;
160 size_t size;
161 int error;
163 addr = req->req_address;
164 size = req->req_size;
166 #ifdef DEBUG_MACH_VM
167 printf("mach_vm_allocate(addr = %p, size = 0x%08x);\n",
168 (void *)addr, size);
169 #endif
172 * Avoid mappings at address zero: it should
173 * be a "red zone" with nothing mapped on it.
175 if (addr == 0) {
176 if (req->req_flags & MACH_VM_FLAGS_ANYWHERE)
177 addr = 0x1000;
178 else
179 return mach_msg_error(args, EINVAL);
180 #ifdef DEBUG_MACH_VM
181 printf("mach_vm_allocate: trying addr = %p\n", (void *)addr);
182 #endif
185 size = round_page(size);
186 if (req->req_flags & MACH_VM_FLAGS_ANYWHERE)
187 addr = vm_map_min(&tp->p_vmspace->vm_map);
188 else
189 addr = trunc_page(addr);
191 if (((addr + size) > vm_map_max(&tp->p_vmspace->vm_map)) ||
192 ((addr + size) <= addr))
193 addr = vm_map_min(&tp->p_vmspace->vm_map);
195 if (size == 0)
196 goto out;
198 SCARG(&cup, addr) = (void *)addr;
199 SCARG(&cup, len) = size;
200 SCARG(&cup, prot) = PROT_READ | PROT_WRITE;
201 SCARG(&cup, flags) = MAP_ANON;
202 if ((req->req_flags & MACH_VM_FLAGS_ANYWHERE) == 0)
203 SCARG(&cup, flags) |= MAP_FIXED;
204 SCARG(&cup, fd) = -1;
205 SCARG(&cup, pos) = 0;
207 if ((error = sys_mmap(tl, &cup, &rep->rep_address)) != 0)
208 return mach_msg_error(args, error);
209 #ifdef DEBUG_MACH_VM
210 printf("vm_allocate: success at %p\n", (void *)rep->rep_address);
211 #endif
213 out:
214 *msglen = sizeof(*rep);
215 mach_set_header(rep, req, *msglen);
217 rep->rep_retval = 0;
219 mach_set_trailer(rep, *msglen);
221 return 0;
225 mach_vm_deallocate(struct mach_trap_args *args)
227 mach_vm_deallocate_request_t *req = args->smsg;
228 mach_vm_deallocate_reply_t *rep = args->rmsg;
229 size_t *msglen = args->rsize;
230 struct lwp *tl = args->tl;
231 struct sys_munmap_args cup;
232 int error;
234 #ifdef DEBUG_MACH_VM
235 printf("mach_vm_deallocate(addr = %p, size = 0x%08lx);\n",
236 (void *)req->req_address, (long)req->req_size);
237 #endif
239 SCARG(&cup, addr) = (void *)req->req_address;
240 SCARG(&cup, len) = req->req_size;
242 if ((error = sys_munmap(tl, &cup, &rep->rep_retval)) != 0)
243 return mach_msg_error(args, error);
245 *msglen = sizeof(*rep);
246 mach_set_header(rep, req, *msglen);
247 mach_set_trailer(rep, *msglen);
249 return 0;
253 * XXX This server message Id clashes with bootstrap_look_up.
254 * Is there a way to resolve this easily?
256 #if 0
258 mach_vm_wire(struct mach_trap_args *args)
260 mach_vm_wire_request_t *req = args->smsg;
261 mach_vm_wire_reply_t *rep = args->rmsg;
262 size_t *msglen = args->rsize;
263 struct lwp *tl = args->tl;
264 register_t retval;
265 int error;
267 #ifdef DEBUG_MACH_VM
268 printf("mach_vm_wire(addr = %p, size = 0x%08x, prot = 0x%x);\n",
269 (void *)req->req_address, req->req_size, req->req_access);
270 #endif
272 memset(&rep, 0, sizeof(*rep));
274 if ((req->req_access & ~VM_PROT_ALL) != 0)
275 return mach_msg_error(args, EINVAL);
278 * Mach maintains a count of how many times a page is wired
279 * and unwire it once the count is zero. We cannot do that yet.
281 if (req->req_access == 0) {
282 struct sys_munlock_args cup;
284 SCARG(&cup, addr) = (void *)req->req_address;
285 SCARG(&cup, len) = req->req_size;
286 error = sys_munlock(tl, &cup, &retval);
287 } else {
288 struct sys_mlock_args cup;
290 SCARG(&cup, addr) = (void *)req->req_address;
291 SCARG(&cup, len) = req->req_size;
292 error = sys_mlock(tl, &cup, &retval);
294 if (error != 0)
295 return mach_msg_error(args, error);
297 if ((error = uvm_map_protect(&tl->l_proc->p_vmspace->vm_map,
298 req->req_address, req->req_address + req->req_size,
299 req->req_access, 0)) != 0)
300 return mach_msg_error(args, error);
302 *msglen = sizeof(*rep);
303 mach_set_header(rep, req, *msglen);
304 mach_set_trailer(rep, *msglen);
306 return 0;
308 #endif
311 mach_vm_protect(struct mach_trap_args *args)
313 mach_vm_protect_request_t *req = args->smsg;
314 mach_vm_protect_reply_t *rep = args->rmsg;
315 size_t *msglen = args->rsize;
316 struct lwp *tl = args->tl;
317 struct sys_mprotect_args cup;
318 register_t retval;
319 int error;
321 SCARG(&cup, addr) = (void *)req->req_addr;
322 SCARG(&cup, len) = req->req_size;
323 SCARG(&cup, prot) = req->req_prot;
325 if ((error = sys_mprotect(tl, &cup, &retval)) != 0)
326 return mach_msg_error(args, error);
328 *msglen = sizeof(*rep);
329 mach_set_header(rep, req, *msglen);
330 mach_set_trailer(rep, *msglen);
332 return 0;
336 mach_sys_map_fd(struct lwp *l, const struct mach_sys_map_fd_args *uap, register_t *retval)
338 /* {
339 syscallarg(int) fd;
340 syscallarg(mach_vm_offset_t) offset;
341 syscallarg(mach_vm_offset_t *) va;
342 syscallarg(mach_boolean_t) findspace;
343 syscallarg(mach_vm_size_t) size;
344 } */
345 file_t *fp;
346 struct vnode *vp;
347 struct exec_vmcmd evc;
348 struct vm_map_entry *ret;
349 struct proc *p = l->l_proc;
350 register_t dontcare;
351 struct sys_munmap_args cup;
352 void *va;
353 int error;
355 if ((error = copyin(SCARG(uap, va), (void *)&va, sizeof(va))) != 0)
356 return error;
358 if (SCARG(uap, findspace) == 0) {
359 /* Make some free space XXX probably not The Right Way */
360 SCARG(&cup, addr) = va;
361 SCARG(&cup, len) = SCARG(uap, size);
362 (void)sys_munmap(l, &cup, &dontcare);
365 fp = fd_getfile(SCARG(uap, fd));
366 if (fp == NULL)
367 return EBADF;
369 vp = fp->f_data;
370 vref(vp);
372 #ifdef DEBUG_MACH_VM
373 printf("vm_map_fd: addr = %p len = 0x%08lx\n",
374 va, (long)SCARG(uap, size));
375 #endif
376 memset(&evc, 0, sizeof(evc));
377 evc.ev_addr = (u_long)va;
378 evc.ev_len = SCARG(uap, size);
379 evc.ev_prot = VM_PROT_ALL;
380 evc.ev_flags = SCARG(uap, findspace) ? 0 : VMCMD_FIXED;
381 evc.ev_proc = vmcmd_map_readvn;
382 evc.ev_offset = SCARG(uap, offset);
383 evc.ev_vp = vp;
385 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
386 if ((error = (*evc.ev_proc)(l, &evc)) != 0) {
387 VOP_UNLOCK(vp, 0);
389 #ifdef DEBUG_MACH_VM
390 printf("mach_sys_map_fd: mapping at %p failed\n", va);
391 #endif
393 if (SCARG(uap, findspace) == 0)
394 goto bad2;
396 vm_map_lock(&p->p_vmspace->vm_map);
397 if ((ret = uvm_map_findspace(&p->p_vmspace->vm_map,
398 vm_map_min(&p->p_vmspace->vm_map), evc.ev_len,
399 (vaddr_t *)&evc.ev_addr, NULL, 0, PAGE_SIZE, 0)) == NULL) {
400 vm_map_unlock(&p->p_vmspace->vm_map);
401 goto bad2;
403 vm_map_unlock(&p->p_vmspace->vm_map);
405 va = (void *)evc.ev_addr;
407 memset(&evc, 0, sizeof(evc));
408 evc.ev_addr = (u_long)va;
409 evc.ev_len = SCARG(uap, size);
410 evc.ev_prot = VM_PROT_ALL;
411 evc.ev_flags = 0;
412 evc.ev_proc = vmcmd_map_readvn;
413 evc.ev_offset = SCARG(uap, offset);
414 evc.ev_vp = vp;
416 #ifdef DEBUG_MACH_VM
417 printf("mach_sys_map_fd: trying at %p\n", va);
418 #endif
419 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
420 if ((error = (*evc.ev_proc)(l, &evc)) != 0)
421 goto bad1;
424 vput(vp);
425 fd_putfile(SCARG(uap, fd));
426 #ifdef DEBUG_MACH_VM
427 printf("mach_sys_map_fd: mapping at %p\n", (void *)evc.ev_addr);
428 #endif
430 va = (mach_vm_offset_t *)evc.ev_addr;
432 if ((error = copyout((void *)&va, SCARG(uap, va), sizeof(va))) != 0)
433 return error;
435 return 0;
437 bad1:
438 VOP_UNLOCK(vp, 0);
439 bad2:
440 vrele(vp);
441 fd_putfile(SCARG(uap, fd));
442 #ifdef DEBUG_MACH_VM
443 printf("mach_sys_map_fd: mapping at %p failed, error = %d\n",
444 (void *)evc.ev_addr, error);
445 #endif
446 return error;
450 mach_vm_inherit(struct mach_trap_args *args)
452 mach_vm_inherit_request_t *req = args->smsg;
453 mach_vm_inherit_reply_t *rep = args->rmsg;
454 size_t *msglen = args->rsize;
455 struct lwp *tl = args->tl;
456 struct sys_minherit_args cup;
457 register_t retval;
458 int error;
460 SCARG(&cup, addr) = (void *)req->req_addr;
461 SCARG(&cup, len) = req->req_size;
462 /* Flags map well between Mach and NetBSD */
463 SCARG(&cup, inherit) = req->req_inh;
465 if ((error = sys_minherit(tl, &cup, &retval)) != 0)
466 return mach_msg_error(args, error);
468 *msglen = sizeof(*rep);
469 mach_set_header(rep, req, *msglen);
470 mach_set_trailer(rep, *msglen);
472 return 0;
476 mach_make_memory_entry_64(struct mach_trap_args *args)
478 mach_make_memory_entry_64_request_t *req = args->smsg;
479 mach_make_memory_entry_64_reply_t *rep = args->rmsg;
480 size_t *msglen = args->rsize;
481 struct lwp *l = args->l;
482 struct lwp *tl = args->tl;
483 struct mach_port *mp;
484 struct mach_right *mr;
485 struct mach_memory_entry *mme;
487 printf("mach_make_memory_entry_64, offset 0x%lx, size 0x%lx\n",
488 (u_long)req->req_offset, (u_long)req->req_size);
490 mp = mach_port_get();
491 mp->mp_flags |= (MACH_MP_INKERNEL | MACH_MP_DATA_ALLOCATED);
492 mp->mp_datatype = MACH_MP_MEMORY_ENTRY;
494 mme = malloc(sizeof(*mme), M_EMULDATA, M_WAITOK);
495 mme->mme_proc = tl->l_proc;
496 mme->mme_offset = req->req_offset;
497 mme->mme_size = req->req_size;
498 mp->mp_data = mme;
500 mr = mach_right_get(mp, l, MACH_PORT_TYPE_SEND, 0);
502 *msglen = sizeof(*rep);
503 mach_set_header(rep, req, *msglen);
504 mach_add_port_desc(rep, mr->mr_name);
506 rep->rep_size = req->req_size;
508 mach_set_trailer(rep, *msglen);
510 return 0;
514 mach_vm_region(struct mach_trap_args *args)
516 mach_vm_region_request_t *req = args->smsg;
517 mach_vm_region_reply_t *rep = args->rmsg;
518 size_t *msglen = args->rsize;
519 struct lwp *tl = args->tl;
520 struct mach_vm_region_basic_info *rbi;
521 struct vm_map *map;
522 struct vm_map_entry *vme;
523 int error;
525 /* Sanity check req_count */
526 if (req->req_count > 9)
527 return mach_msg_error(args, EINVAL);
530 * MACH_VM_REGION_BASIC_INFO is the only
531 * supported flavor in Darwin.
533 if (req->req_flavor != MACH_VM_REGION_BASIC_INFO)
534 return mach_msg_error(args, EINVAL);
535 if (req->req_count != (sizeof(*rbi) / sizeof(int))) /* This is 8 */
536 return mach_msg_error(args, EINVAL);
537 *msglen = sizeof(*rep) + ((req->req_count - 9) * sizeof(int));
539 map = &tl->l_proc->p_vmspace->vm_map;
541 vm_map_lock(map);
542 error = uvm_map_lookup_entry(map, req->req_addr, &vme);
543 vm_map_unlock(map);
545 if (error == 0)
546 return mach_msg_error(args, ENOMEM);
548 mach_set_header(rep, req, *msglen);
549 mach_add_port_desc(rep, 0); /* XXX Why this null name */
551 rep->rep_addr = vme->start;
552 rep->rep_size = vme->end - vme->start;
553 rep->rep_count = req->req_count;
555 rbi = (struct mach_vm_region_basic_info *)&rep->rep_info[0];
556 rbi->protection = vme->protection;
557 rbi->inheritance = 1; /* vme->inheritance */
558 rbi->shared = 0; /* XXX how can we know? */
559 rbi->offset = vme->offset;
560 rbi->behavior = MACH_VM_BEHAVIOR_DEFAULT; /* XXX What is it? */
561 rbi->user_wired_count = vme->wired_count;
563 /* XXX Why this? */
564 *(short *)((u_long)&rbi->user_wired_count + sizeof(short)) = 1;
566 mach_set_trailer(rep, *msglen);
568 return 0;
572 mach_vm_region_64(struct mach_trap_args *args)
574 mach_vm_region_64_request_t *req = args->smsg;
575 mach_vm_region_64_reply_t *rep = args->rmsg;
576 size_t *msglen = args->rsize;
577 struct lwp *tl = args->tl;
578 struct mach_vm_region_basic_info_64 *rbi;
579 struct vm_map *map;
580 struct vm_map_entry *vme;
581 int error;
583 /* Sanity check req_count */
584 if (req->req_count > 10)
585 return mach_msg_error(args, EINVAL);
588 * MACH_VM_REGION_BASIC_INFO is the only
589 * supported flavor in Darwin.
591 if (req->req_flavor != MACH_VM_REGION_BASIC_INFO)
592 return mach_msg_error(args, EINVAL);
593 if (req->req_count != (sizeof(*rbi) / sizeof(int))) /* This is 8 */
594 return mach_msg_error(args, EINVAL);
595 *msglen = sizeof(*rep) + ((req->req_count - 9) * sizeof(int));
597 map = &tl->l_proc->p_vmspace->vm_map;
599 vm_map_lock(map);
600 error = uvm_map_lookup_entry(map, req->req_addr, &vme);
601 vm_map_unlock(map);
603 if (error == 0)
604 return mach_msg_error(args, ENOMEM);
606 mach_set_header(rep, req, *msglen);
607 mach_add_port_desc(rep, 0); /* XXX null port ? */
609 rep->rep_size = PAGE_SIZE; /* XXX Why? */
610 rep->rep_count = req->req_count;
612 rbi = (struct mach_vm_region_basic_info_64 *)&rep->rep_info[0];
613 rbi->protection = vme->protection;
614 rbi->inheritance = 1; /* vme->inheritance */
615 rbi->shared = 0; /* XXX how can we know? */
616 rbi->offset = vme->offset;
617 rbi->behavior = MACH_VM_BEHAVIOR_DEFAULT; /* XXX What is it? */
618 rbi->user_wired_count = vme->wired_count;
620 /* XXX Why this? */
621 *(short *)((u_long)&rbi->user_wired_count + sizeof(short)) = 1;
623 mach_set_trailer(rep, *msglen);
625 return 0;
629 mach_vm_msync(struct mach_trap_args *args)
631 mach_vm_msync_request_t *req = args->smsg;
632 mach_vm_msync_reply_t *rep = args->rmsg;
633 size_t *msglen = args->rsize;
634 struct lwp *tl = args->tl;
635 struct sys___msync13_args cup;
636 int error;
637 register_t dontcare;
639 SCARG(&cup, addr) = (void *)req->req_addr;
640 SCARG(&cup, len) = req->req_size;
641 SCARG(&cup, flags) = 0;
642 if (req->req_flags & MACH_VM_SYNC_ASYNCHRONOUS)
643 SCARG(&cup, flags) |= MS_ASYNC;
644 if (req->req_flags & MACH_VM_SYNC_SYNCHRONOUS)
645 SCARG(&cup, flags) |= MS_SYNC;
646 if (req->req_flags & MACH_VM_SYNC_INVALIDATE)
647 SCARG(&cup, flags) |= MS_INVALIDATE;
649 error = sys___msync13(tl, &cup, &dontcare);
651 *msglen = sizeof(*rep);
652 mach_set_header(rep, req, *msglen);
654 rep->rep_retval = native_to_mach_errno[error];
656 mach_set_trailer(rep, *msglen);
658 return 0;
661 /* XXX Do it for remote task */
663 mach_vm_copy(struct mach_trap_args *args)
665 mach_vm_copy_request_t *req = args->smsg;
666 mach_vm_copy_reply_t *rep = args->rmsg;
667 size_t *msglen = args->rsize;
668 char *tmpbuf;
669 int error;
670 char *src, *dst;
671 size_t size;
673 #ifdef DEBUG_MACH_VM
674 printf("mach_vm_copy: src = 0x%08lx, size = 0x%08lx, addr = 0x%08lx\n",
675 (long)req->req_src, (long)req->req_size, (long)req->req_addr);
676 #endif
677 if ((req->req_src & (PAGE_SIZE - 1)) ||
678 (req->req_addr & (PAGE_SIZE - 1)) ||
679 (req->req_size & (PAGE_SIZE - 1)))
680 return mach_msg_error(args, EINVAL);
682 src = (void *)req->req_src;
683 dst = (void *)req->req_addr;
684 size = (size_t)req->req_size;
686 tmpbuf = malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
688 /* Is there an easy way of dealing with that efficiently? */
689 do {
690 if ((error = copyin(src, tmpbuf, PAGE_SIZE)) != 0)
691 goto out;
693 if ((error = copyout(tmpbuf, dst, PAGE_SIZE)) != 0)
694 goto out;
696 src += PAGE_SIZE;
697 dst += PAGE_SIZE;
698 size -= PAGE_SIZE;
699 } while (size > 0);
701 *msglen = sizeof(*rep);
702 mach_set_header(rep, req, *msglen);
704 rep->rep_retval = 0;
706 mach_set_trailer(rep, *msglen);
708 free(tmpbuf, M_TEMP);
709 return 0;
711 out:
712 free(tmpbuf, M_TEMP);
713 return mach_msg_error(args, error);
717 mach_vm_read(struct mach_trap_args *args)
719 mach_vm_read_request_t *req = args->smsg;
720 mach_vm_read_reply_t *rep = args->rmsg;
721 size_t *msglen = args->rsize;
722 struct lwp *l = args->l;
723 struct lwp *tl = args->tl;
724 char *tbuf;
725 void *addr;
726 vaddr_t va;
727 size_t size;
728 int error;
730 size = req->req_size;
731 va = vm_map_min(&l->l_proc->p_vmspace->vm_map);
732 if ((error = uvm_map(&l->l_proc->p_vmspace->vm_map, &va,
733 round_page(size), NULL, UVM_UNKNOWN_OFFSET, 0,
734 UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_ALL,
735 UVM_INH_COPY, UVM_ADV_NORMAL, UVM_FLAG_COPYONW))) != 0) {
736 printf("uvm_map error = %d\n", error);
737 return mach_msg_error(args, EFAULT);
741 * Copy the data from the target process to the current process
742 * This is reasonable for small chunk of data, but we should
743 * remap COW for areas bigger than a page.
745 tbuf = malloc(size, M_EMULDATA, M_WAITOK);
747 addr = (void *)req->req_addr;
748 if ((error = copyin_proc(tl->l_proc, addr, tbuf, size)) != 0) {
749 printf("copyin_proc error = %d, addr = %p, size = %x\n", error, addr, size);
750 free(tbuf, M_WAITOK);
751 return mach_msg_error(args, EFAULT);
754 if ((error = copyout(tbuf, (void *)va, size)) != 0) {
755 printf("copyout error = %d\n", error);
756 free(tbuf, M_WAITOK);
757 return mach_msg_error(args, EFAULT);
760 if (error == 0)
761 ktrmool(tbuf, size, (void *)va);
763 free(tbuf, M_WAITOK);
765 *msglen = sizeof(*rep);
766 mach_set_header(rep, req, *msglen);
767 mach_add_ool_desc(rep, (void *)va, size);
769 rep->rep_count = size;
771 mach_set_trailer(rep, *msglen);
773 return 0;
777 mach_vm_write(struct mach_trap_args *args)
779 mach_vm_write_request_t *req = args->smsg;
780 mach_vm_write_reply_t *rep = args->rmsg;
781 size_t *msglen = args->rsize;
782 struct lwp *tl = args->tl;
783 size_t size;
784 void *addr;
785 char *tbuf;
786 int error;
788 #ifdef DEBUG_MACH
789 if (req->req_body.msgh_descriptor_count != 1)
790 printf("mach_vm_write: OOL descriptor count is not 1\n");
791 #endif
794 * Copy the data from the current process to the target process
795 * This is reasonable for small chunk of data, but we should
796 * remap COW for areas bigger than a page.
798 size = req->req_data.size;
799 tbuf = malloc(size, M_EMULDATA, M_WAITOK);
801 if ((error = copyin(req->req_data.address, tbuf, size)) != 0) {
802 printf("copyin error = %d\n", error);
803 free(tbuf, M_WAITOK);
804 return mach_msg_error(args, EFAULT);
807 addr = (void *)req->req_addr;
808 if ((error = copyout_proc(tl->l_proc, tbuf, addr, size)) != 0) {
809 printf("copyout_proc error = %d\n", error);
810 free(tbuf, M_WAITOK);
811 return mach_msg_error(args, EFAULT);
814 if (error == 0)
815 ktrmool(tbuf, size, (void *)addr);
817 free(tbuf, M_WAITOK);
819 *msglen = sizeof(*rep);
820 mach_set_header(rep, req, *msglen);
822 rep->rep_retval = 0;
824 mach_set_trailer(rep, *msglen);
826 return 0;
830 mach_vm_machine_attribute(struct mach_trap_args *args)
832 mach_vm_machine_attribute_request_t *req = args->smsg;
833 mach_vm_machine_attribute_reply_t *rep = args->rmsg;
834 size_t *msglen = args->rsize;
835 struct lwp *tl = args->tl;
836 int error = 0;
837 int attribute, value;
839 attribute = req->req_attribute;
840 value = req->req_value;
842 switch (attribute) {
843 case MACH_MATTR_CACHE:
844 switch(value) {
845 case MACH_MATTR_VAL_CACHE_FLUSH:
846 case MACH_MATTR_VAL_DCACHE_FLUSH:
847 case MACH_MATTR_VAL_ICACHE_FLUSH:
848 case MACH_MATTR_VAL_CACHE_SYNC:
849 error = mach_vm_machine_attribute_machdep(tl,
850 req->req_addr, req->req_size, &value);
851 break;
852 default:
853 #ifdef DEBUG_MACH
854 printf("unimplemented value %d\n", req->req_value);
855 #endif
856 error = EINVAL;
857 break;
859 break;
861 case MACH_MATTR_MIGRATE:
862 case MACH_MATTR_REPLICATE:
863 default:
864 #ifdef DEBUG_MACH
865 printf("unimplemented attribute %d\n", req->req_attribute);
866 #endif
867 error = EINVAL;
868 break;
871 *msglen = sizeof(*rep);
872 mach_set_header(rep, req, *msglen);
874 rep->rep_retval = native_to_mach_errno[error];
875 if (error != 0)
876 rep->rep_value = value;
878 mach_set_trailer(rep, *msglen);
880 return 0;