1 /* $NetBSD: mach_vm.c,v 1.60 2008/04/28 20:23:45 martin Exp $ */
2
3 /*-
4 * Copyright (c) 2002-2003, 2008 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 *
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.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: mach_vm.c,v 1.60 2008/04/28 20:23:45 martin Exp $");
34
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>
48
49 #include <uvm/uvm_prot.h>
50 #include <uvm/uvm_map.h>
51 #include <uvm/uvm_extern.h>
52
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>
61
62 int
63 mach_vm_map(struct mach_trap_args *args)
64 {
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;
74
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
84
85 /* XXX Darwin fails on mapping a page at address 0 */
86 if (req->req_address == 0)
87 return mach_msg_error(args, ENOMEM);
88
89 req->req_size = round_page(req->req_size);
90
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;
96
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;
103 }
104
105 /*
106 * Use uvm_map_findspace to find a place which conforms to the
107 * requested alignement.
108 */
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);
114
115 if (ret == NULL)
116 return mach_msg_error(args, ENOMEM);
117
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;
132 }
133
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;
139
140 if ((error = sys_mmap(tl, &cup, &rep->rep_retval)) != 0)
141 return mach_msg_error(args, error);
142
143 *msglen = sizeof(*rep);
144 mach_set_header(rep, req, *msglen);
145 mach_set_trailer(rep, *msglen);
146
147 return 0;
148 }
149
150 int
151 mach_vm_allocate(struct mach_trap_args *args)
152 {
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;
162
163 addr = req->req_address;
164 size = req->req_size;
165
166 #ifdef DEBUG_MACH_VM
167 printf("mach_vm_allocate(addr = %p, size = 0x%08x);\n",
168 (void *)addr, size);
169 #endif
170
171 /*
172 * Avoid mappings at address zero: it should
173 * be a "red zone" with nothing mapped on it.
174 */
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
183 }
184
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);
190
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);
194
195 if (size == 0)
196 goto out;
197
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;
206
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
212
213 out:
214 *msglen = sizeof(*rep);
215 mach_set_header(rep, req, *msglen);
216
217 rep->rep_retval = 0;
218
219 mach_set_trailer(rep, *msglen);
220
221 return 0;
222 }
223
224 int
225 mach_vm_deallocate(struct mach_trap_args *args)
226 {
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;
233
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
238
239 SCARG(&cup, addr) = (void *)req->req_address;
240 SCARG(&cup, len) = req->req_size;
241
242 if ((error = sys_munmap(tl, &cup, &rep->rep_retval)) != 0)
243 return mach_msg_error(args, error);
244
245 *msglen = sizeof(*rep);
246 mach_set_header(rep, req, *msglen);
247 mach_set_trailer(rep, *msglen);
248
249 return 0;
250 }
251
252 /*
253 * XXX This server message Id clashes with bootstrap_look_up.
254 * Is there a way to resolve this easily?
255 */
256 #if 0
257 int
258 mach_vm_wire(struct mach_trap_args *args)
259 {
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;
266
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
271
272 bzero(&rep, sizeof(*rep));
273
274 if ((req->req_access & ~VM_PROT_ALL) != 0)
275 return mach_msg_error(args, EINVAL);
276
277 /*
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.
280 */
281 if (req->req_access == 0) {
282 struct sys_munlock_args cup;
283
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;
289
290 SCARG(&cup, addr) = (void *)req->req_address;
291 SCARG(&cup, len) = req->req_size;
292 error = sys_mlock(tl, &cup, &retval);
293 }
294 if (error != 0)
295 return mach_msg_error(args, error);
296
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);
301
302 *msglen = sizeof(*rep);
303 mach_set_header(rep, req, *msglen);
304 mach_set_trailer(rep, *msglen);
305
306 return 0;
307 }
308 #endif
309
310 int
311 mach_vm_protect(struct mach_trap_args *args)
312 {
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;
320
321 SCARG(&cup, addr) = (void *)req->req_addr;
322 SCARG(&cup, len) = req->req_size;
323 SCARG(&cup, prot) = req->req_prot;
324
325 if ((error = sys_mprotect(tl, &cup, &retval)) != 0)
326 return mach_msg_error(args, error);
327
328 *msglen = sizeof(*rep);
329 mach_set_header(rep, req, *msglen);
330 mach_set_trailer(rep, *msglen);
331
332 return 0;
333 }
334
335 int
336 mach_sys_map_fd(struct lwp *l, const struct mach_sys_map_fd_args *uap, register_t *retval)
337 {
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;
354
355 if ((error = copyin(SCARG(uap, va), (void *)&va, sizeof(va))) != 0)
356 return error;
357
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);
363 }
364
365 fp = fd_getfile(SCARG(uap, fd));
366 if (fp == NULL)
367 return EBADF;
368
369 vp = fp->f_data;
370 vref(vp);
371
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 bzero(&evc, 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;
384
385 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
386 if ((error = (*evc.ev_proc)(l, &evc)) != 0) {
387 VOP_UNLOCK(vp, 0);
388
389 #ifdef DEBUG_MACH_VM
390 printf("mach_sys_map_fd: mapping at %p failed\n", va);
391 #endif
392
393 if (SCARG(uap, findspace) == 0)
394 goto bad2;
395
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;
402 }
403 vm_map_unlock(&p->p_vmspace->vm_map);
404
405 va = (void *)evc.ev_addr;
406
407 bzero(&evc, 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;
415
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;
422 }
423
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
429
430 va = (mach_vm_offset_t *)evc.ev_addr;
431
432 if ((error = copyout((void *)&va, SCARG(uap, va), sizeof(va))) != 0)
433 return error;
434
435 return 0;
436
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;
447 }
448
449 int
450 mach_vm_inherit(struct mach_trap_args *args)
451 {
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;
459
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;
464
465 if ((error = sys_minherit(tl, &cup, &retval)) != 0)
466 return mach_msg_error(args, error);
467
468 *msglen = sizeof(*rep);
469 mach_set_header(rep, req, *msglen);
470 mach_set_trailer(rep, *msglen);
471
472 return 0;
473 }
474
475 int
476 mach_make_memory_entry_64(struct mach_trap_args *args)
477 {
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;
486
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);
489
490 mp = mach_port_get();
491 mp->mp_flags |= (MACH_MP_INKERNEL | MACH_MP_DATA_ALLOCATED);
492 mp->mp_datatype = MACH_MP_MEMORY_ENTRY;
493
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;
499
500 mr = mach_right_get(mp, l, MACH_PORT_TYPE_SEND, 0);
501
502 *msglen = sizeof(*rep);
503 mach_set_header(rep, req, *msglen);
504 mach_add_port_desc(rep, mr->mr_name);
505
506 rep->rep_size = req->req_size;
507
508 mach_set_trailer(rep, *msglen);
509
510 return 0;
511 }
512
513 int
514 mach_vm_region(struct mach_trap_args *args)
515 {
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;
524
525 /* Sanity check req_count */
526 if (req->req_count > 9)
527 return mach_msg_error(args, EINVAL);
528
529 /*
530 * MACH_VM_REGION_BASIC_INFO is the only
531 * supported flavor in Darwin.
532 */
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));
538
539 map = &tl->l_proc->p_vmspace->vm_map;
540
541 vm_map_lock(map);
542 error = uvm_map_lookup_entry(map, req->req_addr, &vme);
543 vm_map_unlock(map);
544
545 if (error == 0)
546 return mach_msg_error(args, ENOMEM);
547
548 mach_set_header(rep, req, *msglen);
549 mach_add_port_desc(rep, 0); /* XXX Why this null name */
550
551 rep->rep_addr = vme->start;
552 rep->rep_size = vme->end - vme->start;
553 rep->rep_count = req->req_count;
554
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;
562
563 /* XXX Why this? */
564 *(short *)((u_long)&rbi->user_wired_count + sizeof(short)) = 1;
565
566 mach_set_trailer(rep, *msglen);
567
568 return 0;
569 }
570
571 int
572 mach_vm_region_64(struct mach_trap_args *args)
573 {
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;
582
583 /* Sanity check req_count */
584 if (req->req_count > 10)
585 return mach_msg_error(args, EINVAL);
586
587 /*
588 * MACH_VM_REGION_BASIC_INFO is the only
589 * supported flavor in Darwin.
590 */
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));
596
597 map = &tl->l_proc->p_vmspace->vm_map;
598
599 vm_map_lock(map);
600 error = uvm_map_lookup_entry(map, req->req_addr, &vme);
601 vm_map_unlock(map);
602
603 if (error == 0)
604 return mach_msg_error(args, ENOMEM);
605
606 mach_set_header(rep, req, *msglen);
607 mach_add_port_desc(rep, 0); /* XXX null port ? */
608
609 rep->rep_size = PAGE_SIZE; /* XXX Why? */
610 rep->rep_count = req->req_count;
611
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;
619
620 /* XXX Why this? */
621 *(short *)((u_long)&rbi->user_wired_count + sizeof(short)) = 1;
622
623 mach_set_trailer(rep, *msglen);
624
625 return 0;
626 }
627
628 int
629 mach_vm_msync(struct mach_trap_args *args)
630 {
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;
638
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;
648
649 error = sys___msync13(tl, &cup, &dontcare);
650
651 *msglen = sizeof(*rep);
652 mach_set_header(rep, req, *msglen);
653
654 rep->rep_retval = native_to_mach_errno[error];
655
656 mach_set_trailer(rep, *msglen);
657
658 return 0;
659 }
660
661 /* XXX Do it for remote task */
662 int
663 mach_vm_copy(struct mach_trap_args *args)
664 {
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;
672
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);
681
682 src = (void *)req->req_src;
683 dst = (void *)req->req_addr;
684 size = (size_t)req->req_size;
685
686 tmpbuf = malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
687
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;
692
693 if ((error = copyout(tmpbuf, dst, PAGE_SIZE)) != 0)
694 goto out;
695
696 src += PAGE_SIZE;
697 dst += PAGE_SIZE;
698 size -= PAGE_SIZE;
699 } while (size > 0);
700
701 *msglen = sizeof(*rep);
702 mach_set_header(rep, req, *msglen);
703
704 rep->rep_retval = 0;
705
706 mach_set_trailer(rep, *msglen);
707
708 free(tmpbuf, M_TEMP);
709 return 0;
710
711 out:
712 free(tmpbuf, M_TEMP);
713 return mach_msg_error(args, error);
714 }
715
716 int
717 mach_vm_read(struct mach_trap_args *args)
718 {
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;
729
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);
738 }
739
740 /*
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.
744 */
745 tbuf = malloc(size, M_EMULDATA, M_WAITOK);
746
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);
752 }
753
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);
758 }
759
760 if (error == 0)
761 ktrmool(tbuf, size, (void *)va);
762
763 free(tbuf, M_WAITOK);
764
765 *msglen = sizeof(*rep);
766 mach_set_header(rep, req, *msglen);
767 mach_add_ool_desc(rep, (void *)va, size);
768
769 rep->rep_count = size;
770
771 mach_set_trailer(rep, *msglen);
772
773 return 0;
774 }
775
776 int
777 mach_vm_write(struct mach_trap_args *args)
778 {
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;
787
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
792
793 /*
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.
797 */
798 size = req->req_data.size;
799 tbuf = malloc(size, M_EMULDATA, M_WAITOK);
800
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);
805 }
806
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);
812 }
813
814 if (error == 0)
815 ktrmool(tbuf, size, (void *)addr);
816
817 free(tbuf, M_WAITOK);
818
819 *msglen = sizeof(*rep);
820 mach_set_header(rep, req, *msglen);
821
822 rep->rep_retval = 0;
823
824 mach_set_trailer(rep, *msglen);
825
826 return 0;
827 }
828
829 int
830 mach_vm_machine_attribute(struct mach_trap_args *args)
831 {
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;
838
839 attribute = req->req_attribute;
840 value = req->req_value;
841
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;
858 }
859 break;
860
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;
869 }
870
871 *msglen = sizeof(*rep);
872 mach_set_header(rep, req, *msglen);
873
874 rep->rep_retval = native_to_mach_errno[error];
875 if (error != 0)
876 rep->rep_value = value;
877
878 mach_set_trailer(rep, *msglen);
879
880 return 0;
881 }
Cache object: 97f31278f914923512eb25f214e9ef01
|