]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_mman.c
594cef6eb09a672291d3162bdb2e5d68a0878eb9
[apple/xnu.git] / bsd / kern / kern_mman.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*
24 * Copyright (c) 1988 University of Utah.
25 * Copyright (c) 1991, 1993
26 * The Regents of the University of California. All rights reserved.
27 *
28 * This code is derived from software contributed to Berkeley by
29 * the Systems Programming Group of the University of Utah Computer
30 * Science Department.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * from: Utah $Hdr: vm_mmap.c 1.6 91/10/21$
61 *
62 * @(#)vm_mmap.c 8.10 (Berkeley) 2/19/95
63 */
64
65 /*
66 * Mapped file (mmap) interface to VM
67 */
68
69 #include <sys/param.h>
70 #include <sys/systm.h>
71 #include <sys/filedesc.h>
72 #include <sys/proc_internal.h>
73 #include <sys/kauth.h>
74 #include <sys/resourcevar.h>
75 #include <sys/vnode_internal.h>
76 #include <sys/acct.h>
77 #include <sys/wait.h>
78 #include <sys/file_internal.h>
79 #include <sys/vadvise.h>
80 #include <sys/trace.h>
81 #include <sys/mman.h>
82 #include <sys/conf.h>
83 #include <sys/stat.h>
84 #include <sys/ubc.h>
85 #include <sys/sysproto.h>
86
87 #include <bsm/audit_kernel.h>
88 #include <bsm/audit_kevents.h>
89
90 #include <mach/mach_types.h>
91 #include <mach/mach_traps.h>
92 #include <mach/vm_sync.h>
93 #include <mach/vm_behavior.h>
94 #include <mach/vm_inherit.h>
95 #include <mach/vm_statistics.h>
96 #include <mach/mach_vm.h>
97 #include <mach/vm_map.h>
98 #include <mach/host_priv.h>
99
100 #include <kern/cpu_number.h>
101 #include <kern/host.h>
102
103 #include <vm/vm_map.h>
104 #include <vm/vm_kern.h>
105 #include <vm/vm_pager.h>
106
107 int
108 sbrk(__unused struct proc *p, __unused struct sbrk_args *uap, __unused register_t *retval)
109 {
110 /* Not yet implemented */
111 return (ENOTSUP);
112 }
113
114 int
115 sstk(__unused struct proc *p, __unused struct sstk_args *uap, __unused register_t *retval)
116 {
117 /* Not yet implemented */
118 return (ENOTSUP);
119 }
120
121
122 struct osmmap_args {
123 caddr_t addr;
124 int len;
125 int prot;
126 int share;
127 int fd;
128 long pos;
129 };
130
131 int
132 osmmap(
133 struct proc *curp,
134 register struct osmmap_args *uap,
135 register_t *retval)
136 {
137 struct mmap_args newargs;
138 user_addr_t addr;
139 int ret;
140
141 if ((uap->share == MAP_SHARED )|| (uap->share == MAP_PRIVATE )) {
142 newargs.addr = CAST_USER_ADDR_T(uap->addr);
143 newargs.len = CAST_USER_ADDR_T(uap->len);
144 newargs.prot = uap->prot;
145 newargs.flags = uap->share;
146 newargs.fd = uap->fd;
147 newargs.pos = (off_t)uap->pos;
148 ret = mmap(curp, &newargs, &addr);
149 if (ret == 0)
150 *retval = CAST_DOWN(register_t, addr);
151 } else
152 ret = EINVAL;
153 return ret;
154 }
155
156
157 int
158 mmap(struct proc *p, struct mmap_args *uap, user_addr_t *retval)
159 {
160 /*
161 * Map in special device (must be SHARED) or file
162 */
163 struct fileproc *fp;
164 register struct vnode *vp;
165 int flags;
166 int prot;
167 int err=0;
168 vm_map_t user_map;
169 kern_return_t result;
170 mach_vm_offset_t user_addr;
171 mach_vm_size_t user_size;
172 vm_object_offset_t pageoff;
173 vm_object_offset_t file_pos;
174 int alloc_flags;
175 boolean_t docow;
176 vm_prot_t maxprot;
177 void *handle;
178 vm_pager_t pager;
179 int mapanon=0;
180 int fpref=0;
181 int error =0;
182 int fd = uap->fd;
183
184 user_addr = (mach_vm_offset_t)uap->addr;
185 user_size = (mach_vm_size_t) uap->len;
186
187 AUDIT_ARG(addr, user_addr);
188 AUDIT_ARG(len, user_size);
189 AUDIT_ARG(fd, uap->fd);
190
191 prot = (uap->prot & VM_PROT_ALL);
192 flags = uap->flags;
193 vp = NULLVP;
194
195 /*
196 * The vm code does not have prototypes & compiler doesn't do the'
197 * the right thing when you cast 64bit value and pass it in function
198 * call. So here it is.
199 */
200 file_pos = (vm_object_offset_t)uap->pos;
201
202
203 /* make sure mapping fits into numeric range etc */
204 if ((file_pos + user_size > (vm_object_offset_t)-PAGE_SIZE_64) ||
205 ((flags & MAP_ANON) && fd != -1))
206 return (EINVAL);
207
208 /*
209 * Align the file position to a page boundary,
210 * and save its page offset component.
211 */
212 pageoff = (file_pos & PAGE_MASK);
213 file_pos -= (vm_object_offset_t)pageoff;
214
215
216 /* Adjust size for rounding (on both ends). */
217 user_size += pageoff; /* low end... */
218 user_size = mach_vm_round_page(user_size); /* hi end */
219
220
221 /*
222 * Check for illegal addresses. Watch out for address wrap... Note
223 * that VM_*_ADDRESS are not constants due to casts (argh).
224 */
225 if (flags & MAP_FIXED) {
226 /*
227 * The specified address must have the same remainder
228 * as the file offset taken modulo PAGE_SIZE, so it
229 * should be aligned after adjustment by pageoff.
230 */
231 user_addr -= pageoff;
232 if (user_addr & PAGE_MASK)
233 return (EINVAL);
234 }
235 #ifdef notyet
236 /* DO not have apis to get this info, need to wait till then*/
237 /*
238 * XXX for non-fixed mappings where no hint is provided or
239 * the hint would fall in the potential heap space,
240 * place it after the end of the largest possible heap.
241 *
242 * There should really be a pmap call to determine a reasonable
243 * location.
244 */
245 else if (addr < mach_vm_round_page(p->p_vmspace->vm_daddr + MAXDSIZ))
246 addr = mach_vm_round_page(p->p_vmspace->vm_daddr + MAXDSIZ);
247
248 #endif
249
250
251 if (flags & MAP_ANON) {
252 /*
253 * Mapping blank space is trivial.
254 */
255 handle = NULL;
256 maxprot = VM_PROT_ALL;
257 file_pos = 0;
258 mapanon = 1;
259 } else {
260 struct vnode_attr va;
261 struct vfs_context context;
262 /*
263 * Mapping file, get fp for validation. Obtain vnode and make
264 * sure it is of appropriate type.
265 */
266 err = fp_lookup(p, fd, &fp, 0);
267 if (err)
268 return(err);
269 fpref = 1;
270 if(fp->f_fglob->fg_type == DTYPE_PSXSHM) {
271 uap->addr = (user_addr_t)user_addr;
272 uap->len = (user_size_t)user_size;
273 uap->prot = prot;
274 uap->flags = flags;
275 uap->pos = file_pos;
276 error = pshm_mmap(p, uap, retval, fp, (off_t)pageoff);
277 goto bad;
278 }
279
280 if (fp->f_fglob->fg_type != DTYPE_VNODE) {
281 error = EINVAL;
282 goto bad;
283 }
284 vp = (struct vnode *)fp->f_fglob->fg_data;
285 error = vnode_getwithref(vp);
286 if(error != 0)
287 goto bad;
288
289 if (vp->v_type != VREG && vp->v_type != VCHR) {
290 (void)vnode_put(vp);
291 error = EINVAL;
292 goto bad;
293 }
294
295 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
296
297 /* conformance change - mmap needs to update access time for mapped
298 * files
299 */
300 VATTR_INIT(&va);
301 nanotime(&va.va_access_time);
302 VATTR_SET_ACTIVE(&va, va_access_time);
303 context.vc_proc = p;
304 context.vc_ucred = kauth_cred_get();
305 vnode_setattr(vp, &va, &context);
306
307 /*
308 * XXX hack to handle use of /dev/zero to map anon memory (ala
309 * SunOS).
310 */
311 if (vp->v_type == VCHR || vp->v_type == VSTR) {
312 (void)vnode_put(vp);
313 error = ENODEV;
314 goto bad;
315 } else {
316 /*
317 * Ensure that file and memory protections are
318 * compatible. Note that we only worry about
319 * writability if mapping is shared; in this case,
320 * current and max prot are dictated by the open file.
321 * XXX use the vnode instead? Problem is: what
322 * credentials do we use for determination? What if
323 * proc does a setuid?
324 */
325 maxprot = VM_PROT_EXECUTE; /* ??? */
326 if (fp->f_fglob->fg_flag & FREAD)
327 maxprot |= VM_PROT_READ;
328 else if (prot & PROT_READ) {
329 (void)vnode_put(vp);
330 error = EACCES;
331 goto bad;
332 }
333 /*
334 * If we are sharing potential changes (either via
335 * MAP_SHARED or via the implicit sharing of character
336 * device mappings), and we are trying to get write
337 * permission although we opened it without asking
338 * for it, bail out.
339 */
340
341 if ((flags & MAP_SHARED) != 0) {
342 if ((fp->f_fglob->fg_flag & FWRITE) != 0) {
343 /*
344 * check for write access
345 *
346 * Note that we already made this check when granting FWRITE
347 * against the file, so it seems redundant here.
348 */
349 error = vnode_authorize(vp, NULL, KAUTH_VNODE_CHECKIMMUTABLE, &context);
350
351 /* if not granted for any reason, but we wanted it, bad */
352 if ((prot & PROT_WRITE) && (error != 0)) {
353 vnode_put(vp);
354 goto bad;
355 }
356
357 /* if writable, remember */
358 if (error == 0)
359 maxprot |= VM_PROT_WRITE;
360
361 } else if ((prot & PROT_WRITE) != 0) {
362 (void)vnode_put(vp);
363 error = EACCES;
364 goto bad;
365 }
366 } else
367 maxprot |= VM_PROT_WRITE;
368
369 handle = (void *)vp;
370 }
371 }
372
373 if (user_size == 0) {
374 if (!mapanon)
375 (void)vnode_put(vp);
376 error = 0;
377 goto bad;
378 }
379
380 /*
381 * We bend a little - round the start and end addresses
382 * to the nearest page boundary.
383 */
384 user_size = mach_vm_round_page(user_size);
385
386 if (file_pos & PAGE_MASK_64) {
387 if (!mapanon)
388 (void)vnode_put(vp);
389 error = EINVAL;
390 goto bad;
391 }
392
393 user_map = current_map();
394
395 if ((flags & MAP_FIXED) == 0) {
396 alloc_flags = VM_FLAGS_ANYWHERE;
397 user_addr = mach_vm_round_page(user_addr);
398 } else {
399 if (user_addr != mach_vm_trunc_page(user_addr)) {
400 if (!mapanon)
401 (void)vnode_put(vp);
402 error = EINVAL;
403 goto bad;
404 }
405 /*
406 * mmap(MAP_FIXED) will replace any existing mappings in the
407 * specified range, if the new mapping is successful.
408 * If we just deallocate the specified address range here,
409 * another thread might jump in and allocate memory in that
410 * range before we get a chance to establish the new mapping,
411 * and we won't have a chance to restore the old mappings.
412 * So we use VM_FLAGS_OVERWRITE to let Mach VM know that it
413 * has to deallocate the existing mappings and establish the
414 * new ones atomically.
415 */
416 alloc_flags = VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE;
417 }
418
419
420 /*
421 * Lookup/allocate object.
422 */
423 if (handle == NULL) {
424 pager = NULL;
425 #ifdef notyet
426 /* Hmm .. */
427 #if defined(VM_PROT_READ_IS_EXEC)
428 if (prot & VM_PROT_READ)
429 prot |= VM_PROT_EXECUTE;
430
431 if (maxprot & VM_PROT_READ)
432 maxprot |= VM_PROT_EXECUTE;
433 #endif
434 #endif
435 result = mach_vm_map(user_map, &user_addr, user_size, 0,
436 alloc_flags, IPC_PORT_NULL, 0,
437 FALSE, prot, maxprot,
438 (flags & MAP_SHARED) ? VM_INHERIT_SHARE :
439 VM_INHERIT_DEFAULT);
440 if (result != KERN_SUCCESS)
441 goto out;
442 } else {
443 UBCINFOCHECK("mmap", vp);
444 pager = (vm_pager_t)ubc_getpager(vp);
445
446 if (pager == NULL) {
447 (void)vnode_put(vp);
448 error = ENOMEM;
449 goto bad;
450 }
451
452 /*
453 * Set credentials:
454 * FIXME: if we're writing the file we need a way to
455 * ensure that someone doesn't replace our R/W creds
456 * with ones that only work for read.
457 */
458
459 ubc_setcred(vp, p);
460 docow = FALSE;
461 if ((flags & (MAP_ANON|MAP_SHARED)) == 0) {
462 docow = TRUE;
463 }
464
465 #ifdef notyet
466 /* Hmm .. */
467 #if defined(VM_PROT_READ_IS_EXEC)
468 if (prot & VM_PROT_READ)
469 prot |= VM_PROT_EXECUTE;
470
471 if (maxprot & VM_PROT_READ)
472 maxprot |= VM_PROT_EXECUTE;
473 #endif
474 #endif /* notyet */
475
476 result = mach_vm_map(user_map, &user_addr, user_size,
477 0, alloc_flags, (ipc_port_t)pager, file_pos,
478 docow, prot, maxprot,
479 (flags & MAP_SHARED) ? VM_INHERIT_SHARE :
480 VM_INHERIT_DEFAULT);
481
482 if (result != KERN_SUCCESS) {
483 (void)vnode_put(vp);
484 goto out;
485 }
486
487 (void)ubc_map(vp,(prot & ( PROT_EXEC | PROT_READ | PROT_WRITE | PROT_EXEC)));
488 }
489
490 if (!mapanon)
491 (void)vnode_put(vp);
492
493 out:
494 switch (result) {
495 case KERN_SUCCESS:
496 *retval = user_addr + pageoff;
497 error = 0;
498 break;
499 case KERN_INVALID_ADDRESS:
500 case KERN_NO_SPACE:
501 error = ENOMEM;
502 break;
503 case KERN_PROTECTION_FAILURE:
504 error = EACCES;
505 break;
506 default:
507 error = EINVAL;
508 break;
509 }
510 bad:
511 if (fpref)
512 fp_drop(p, fd, fp, 0);
513 return(error);
514 }
515
516 int
517 msync(__unused struct proc *p, struct msync_args *uap, __unused register_t *retval)
518 {
519 mach_vm_offset_t addr;
520 mach_vm_size_t size;
521 int flags;
522 vm_map_t user_map;
523 int rv;
524 vm_sync_t sync_flags=0;
525
526 addr = (mach_vm_offset_t) uap->addr;
527 size = (mach_vm_size_t)uap->len;
528
529 if (addr & PAGE_MASK_64) {
530 /* UNIX SPEC: user address is not page-aligned, return EINVAL */
531 return EINVAL;
532 }
533 if (size == 0) {
534 /*
535 * We cannot support this properly without maintaining
536 * list all mmaps done. Cannot use vm_map_entry as they could be
537 * split or coalesced by indepenedant actions. So instead of
538 * inaccurate results, lets just return error as invalid size
539 * specified
540 */
541 return (EINVAL); /* XXX breaks posix apps */
542 }
543
544 flags = uap->flags;
545 /* disallow contradictory flags */
546 if ((flags & (MS_SYNC|MS_ASYNC)) == (MS_SYNC|MS_ASYNC) ||
547 (flags & (MS_ASYNC|MS_INVALIDATE)) == (MS_ASYNC|MS_INVALIDATE))
548 return (EINVAL);
549
550 if (flags & MS_KILLPAGES)
551 sync_flags |= VM_SYNC_KILLPAGES;
552 if (flags & MS_DEACTIVATE)
553 sync_flags |= VM_SYNC_DEACTIVATE;
554 if (flags & MS_INVALIDATE)
555 sync_flags |= VM_SYNC_INVALIDATE;
556
557 if ( !(flags & (MS_KILLPAGES | MS_DEACTIVATE))) {
558 if (flags & MS_ASYNC)
559 sync_flags |= VM_SYNC_ASYNCHRONOUS;
560 else
561 sync_flags |= VM_SYNC_SYNCHRONOUS;
562 }
563
564 sync_flags |= VM_SYNC_CONTIGUOUS; /* complain if holes */
565
566 user_map = current_map();
567 rv = mach_vm_msync(user_map, addr, size, sync_flags);
568
569 switch (rv) {
570 case KERN_SUCCESS:
571 break;
572 case KERN_INVALID_ADDRESS: /* hole in region being sync'ed */
573 return (ENOMEM);
574 case KERN_FAILURE:
575 return (EIO);
576 default:
577 return (EINVAL);
578 }
579 return (0);
580 }
581
582
583 int
584 mremap(void)
585 {
586 /* Not yet implemented */
587 return (ENOTSUP);
588 }
589
590 int
591 munmap(__unused struct proc *p, struct munmap_args *uap, __unused register_t *retval)
592 {
593 mach_vm_offset_t user_addr;
594 mach_vm_size_t user_size;
595 kern_return_t result;
596
597 user_addr = (mach_vm_offset_t) uap->addr;
598 user_size = (mach_vm_size_t) uap->len;
599
600 AUDIT_ARG(addr, user_addr);
601 AUDIT_ARG(len, user_size);
602
603 if (user_addr & PAGE_MASK_64) {
604 /* UNIX SPEC: user address is not page-aligned, return EINVAL */
605 return EINVAL;
606 }
607
608 if (user_addr + user_size < user_addr)
609 return(EINVAL);
610
611 if (user_size == 0) {
612 /* UNIX SPEC: size is 0, return EINVAL */
613 return EINVAL;
614 }
615
616 result = mach_vm_deallocate(current_map(), user_addr, user_size);
617 if (result != KERN_SUCCESS) {
618 return(EINVAL);
619 }
620 return(0);
621 }
622
623 int
624 mprotect(__unused struct proc *p, struct mprotect_args *uap, __unused register_t *retval)
625 {
626 register vm_prot_t prot;
627 mach_vm_offset_t user_addr;
628 mach_vm_size_t user_size;
629 kern_return_t result;
630 vm_map_t user_map;
631
632 AUDIT_ARG(addr, uap->addr);
633 AUDIT_ARG(len, uap->len);
634 AUDIT_ARG(value, uap->prot);
635
636 user_addr = (mach_vm_offset_t) uap->addr;
637 user_size = (mach_vm_size_t) uap->len;
638 prot = (vm_prot_t)(uap->prot & VM_PROT_ALL);
639
640 if (user_addr & PAGE_MASK_64) {
641 /* UNIX SPEC: user address is not page-aligned, return EINVAL */
642 return EINVAL;
643 }
644
645 #ifdef notyet
646 /* Hmm .. */
647 #if defined(VM_PROT_READ_IS_EXEC)
648 if (prot & VM_PROT_READ)
649 prot |= VM_PROT_EXECUTE;
650 #endif
651 #endif /* notyet */
652
653 user_map = current_map();
654
655 result = mach_vm_protect(user_map, user_addr, user_size,
656 FALSE, prot);
657 switch (result) {
658 case KERN_SUCCESS:
659 return (0);
660 case KERN_PROTECTION_FAILURE:
661 return (EACCES);
662 case KERN_INVALID_ADDRESS:
663 /* UNIX SPEC: for an invalid address range, return ENOMEM */
664 return ENOMEM;
665 }
666 return (EINVAL);
667 }
668
669
670 int
671 minherit(__unused struct proc *p, struct minherit_args *uap, __unused register_t *retval)
672 {
673 mach_vm_offset_t addr;
674 mach_vm_size_t size;
675 register vm_inherit_t inherit;
676 vm_map_t user_map;
677 kern_return_t result;
678
679 AUDIT_ARG(addr, uap->addr);
680 AUDIT_ARG(len, uap->len);
681 AUDIT_ARG(value, uap->inherit);
682
683 addr = (mach_vm_offset_t)uap->addr;
684 size = (mach_vm_size_t)uap->len;
685 inherit = uap->inherit;
686
687 user_map = current_map();
688 result = mach_vm_inherit(user_map, addr, size,
689 inherit);
690 switch (result) {
691 case KERN_SUCCESS:
692 return (0);
693 case KERN_PROTECTION_FAILURE:
694 return (EACCES);
695 }
696 return (EINVAL);
697 }
698
699 int
700 madvise(__unused struct proc *p, struct madvise_args *uap, __unused register_t *retval)
701 {
702 vm_map_t user_map;
703 mach_vm_offset_t start;
704 mach_vm_size_t size;
705 vm_behavior_t new_behavior;
706 kern_return_t result;
707
708 /*
709 * Since this routine is only advisory, we default to conservative
710 * behavior.
711 */
712 switch (uap->behav) {
713 case MADV_RANDOM:
714 new_behavior = VM_BEHAVIOR_RANDOM;
715 break;
716 case MADV_SEQUENTIAL:
717 new_behavior = VM_BEHAVIOR_SEQUENTIAL;
718 break;
719 case MADV_NORMAL:
720 new_behavior = VM_BEHAVIOR_DEFAULT;
721 break;
722 case MADV_WILLNEED:
723 new_behavior = VM_BEHAVIOR_WILLNEED;
724 break;
725 case MADV_DONTNEED:
726 new_behavior = VM_BEHAVIOR_DONTNEED;
727 break;
728 default:
729 return(EINVAL);
730 }
731
732 start = (mach_vm_offset_t) uap->addr;
733 size = (mach_vm_size_t) uap->len;
734
735 user_map = current_map();
736
737 result = mach_vm_behavior_set(user_map, start, size, new_behavior);
738 switch (result) {
739 case KERN_SUCCESS:
740 return (0);
741 case KERN_INVALID_ADDRESS:
742 return (ENOMEM);
743 }
744
745 return (EINVAL);
746 }
747
748 int
749 mincore(__unused struct proc *p, struct mincore_args *uap, __unused register_t *retval)
750 {
751 mach_vm_offset_t addr, first_addr, end;
752 vm_map_t map;
753 user_addr_t vec;
754 int error;
755 int vecindex, lastvecindex;
756 int mincoreinfo=0;
757 int pqueryinfo;
758 kern_return_t ret;
759 int numref;
760
761 char c;
762
763 map = current_map();
764
765 /*
766 * Make sure that the addresses presented are valid for user
767 * mode.
768 */
769 first_addr = addr = mach_vm_trunc_page(uap->addr);
770 end = addr + mach_vm_round_page(uap->len);
771
772 if (end < addr)
773 return (EINVAL);
774
775 /*
776 * Address of byte vector
777 */
778 vec = uap->vec;
779
780 map = current_map();
781
782 /*
783 * Do this on a map entry basis so that if the pages are not
784 * in the current processes address space, we can easily look
785 * up the pages elsewhere.
786 */
787 lastvecindex = -1;
788 for( ; addr < end; addr += PAGE_SIZE ) {
789 pqueryinfo = 0;
790 ret = vm_map_page_query(map, addr, &pqueryinfo, &numref);
791 if (ret != KERN_SUCCESS)
792 pqueryinfo = 0;
793 mincoreinfo = 0;
794 if (pqueryinfo & VM_PAGE_QUERY_PAGE_PRESENT)
795 mincoreinfo |= MINCORE_INCORE;
796 if (pqueryinfo & VM_PAGE_QUERY_PAGE_REF)
797 mincoreinfo |= MINCORE_REFERENCED;
798 if (pqueryinfo & VM_PAGE_QUERY_PAGE_DIRTY)
799 mincoreinfo |= MINCORE_MODIFIED;
800
801
802 /*
803 * calculate index into user supplied byte vector
804 */
805 vecindex = (addr - first_addr)>> PAGE_SHIFT;
806
807 /*
808 * If we have skipped map entries, we need to make sure that
809 * the byte vector is zeroed for those skipped entries.
810 */
811 while((lastvecindex + 1) < vecindex) {
812 c = 0;
813 error = copyout(&c, vec + lastvecindex, 1);
814 if (error) {
815 return (EFAULT);
816 }
817 ++lastvecindex;
818 }
819
820 /*
821 * Pass the page information to the user
822 */
823 c = (char)mincoreinfo;
824 error = copyout(&c, vec + vecindex, 1);
825 if (error) {
826 return (EFAULT);
827 }
828 lastvecindex = vecindex;
829 }
830
831
832 /*
833 * Zero the last entries in the byte vector.
834 */
835 vecindex = (end - first_addr) >> PAGE_SHIFT;
836 while((lastvecindex + 1) < vecindex) {
837 c = 0;
838 error = copyout(&c, vec + lastvecindex, 1);
839 if (error) {
840 return (EFAULT);
841 }
842 ++lastvecindex;
843 }
844
845 return (0);
846 }
847
848 int
849 mlock(__unused struct proc *p, struct mlock_args *uap, __unused register_t *retvalval)
850 {
851 vm_map_t user_map;
852 vm_map_offset_t addr;
853 vm_map_size_t size, pageoff;
854 kern_return_t result;
855
856 AUDIT_ARG(addr, uap->addr);
857 AUDIT_ARG(len, uap->len);
858
859 addr = (vm_map_offset_t) uap->addr;
860 size = (vm_map_size_t)uap->len;
861
862 /* disable wrap around */
863 if (addr + size < addr)
864 return (EINVAL);
865
866 if (size == 0)
867 return (0);
868
869 pageoff = (addr & PAGE_MASK);
870 addr -= pageoff;
871 size = vm_map_round_page(size+pageoff);
872
873 #ifdef notyet
874 /* Hmm.. What am I going to do with this? */
875 if (atop(size) + cnt.v_wire_count > vm_page_max_wired)
876 return (EAGAIN);
877 #ifdef pmap_wired_count
878 if (size + ptoa(pmap_wired_count(vm_map_pmap(&p->p_vmspace->vm_map))) >
879 p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur)
880 return (ENOMEM);
881 #else
882 error = suser(kauth_cred_get(), &p->p_acflag);
883 if (error)
884 return (error);
885 #endif
886 #endif /* notyet */
887
888 user_map = current_map();
889
890 /* have to call vm_map_wire directly to pass "I don't know" protections */
891 result = vm_map_wire(user_map, addr, addr+size, VM_PROT_NONE, TRUE);
892 return (result == KERN_SUCCESS ? 0 : ENOMEM);
893 }
894
895 int
896 munlock(__unused struct proc *p, struct munlock_args *uap, __unused register_t *retval)
897 {
898 mach_vm_offset_t addr;
899 mach_vm_size_t size;
900 vm_map_t user_map;
901 kern_return_t result;
902
903 AUDIT_ARG(addr, uap->addr);
904 AUDIT_ARG(addr, uap->len);
905
906 addr = (mach_vm_offset_t) uap->addr;
907 size = (mach_vm_size_t)uap->len;
908
909
910 #ifdef notyet
911 /* Hmm.. What am I going to do with this? */
912 #ifndef pmap_wired_count
913 error = suser(kauth_cred_get(), &p->p_acflag);
914 if (error)
915 return (error);
916 #endif
917 #endif /* notyet */
918
919 user_map = current_map();
920
921 /* JMM - need to remove all wirings by spec - this just removes one */
922 result = mach_vm_wire(host_priv_self(), user_map, addr, size, VM_PROT_NONE);
923 return (result == KERN_SUCCESS ? 0 : ENOMEM);
924 }
925
926
927 int
928 mlockall(__unused struct proc *p, __unused struct mlockall_args *uap, __unused register_t *retval)
929 {
930 return (ENOSYS);
931 }
932
933 int
934 munlockall(__unused struct proc *p, __unused struct munlockall_args *uap, __unused register_t *retval)
935 {
936 return(ENOSYS);
937 }
938
939
940 /* BEGIN DEFUNCT */
941 int
942 obreak(__unused struct proc *p, __unused struct obreak_args *uap, __unused register_t *retval)
943 {
944 /* Not implemented, obsolete */
945 return (ENOMEM);
946 }
947
948 int both;
949
950 int
951 ovadvise(__unused struct proc *p, __unused struct ovadvise_args *uap, __unused register_t *retval)
952 {
953
954 #ifdef lint
955 both = 0;
956 #endif
957 return( 0 );
958 }
959 /* END DEFUNCT */
960
961 /* USV: No! need to obsolete map_fd()! mmap() already supports 64 bits */
962 kern_return_t
963 map_fd(struct map_fd_args *args)
964 {
965 int fd = args->fd;
966 vm_offset_t offset = args->offset;
967 vm_offset_t *va = args->va;
968 boolean_t findspace = args->findspace;
969 vm_size_t size = args->size;
970 kern_return_t ret;
971
972 AUDIT_MACH_SYSCALL_ENTER(AUE_MAPFD);
973 AUDIT_ARG(addr, CAST_DOWN(user_addr_t, va));
974 AUDIT_ARG(fd, fd);
975
976 ret = map_fd_funneled( fd, (vm_object_offset_t)offset, va, findspace, size);
977
978 AUDIT_MACH_SYSCALL_EXIT(ret);
979 return ret;
980 }
981
982 kern_return_t
983 map_fd_funneled(
984 int fd,
985 vm_object_offset_t offset,
986 vm_offset_t *va,
987 boolean_t findspace,
988 vm_size_t size)
989 {
990 kern_return_t result;
991 struct fileproc *fp;
992 struct vnode *vp;
993 void * pager;
994 vm_offset_t map_addr=0;
995 vm_size_t map_size;
996 int err=0;
997 vm_map_t my_map;
998 struct proc *p =(struct proc *)current_proc();
999 struct vnode_attr vattr;
1000 struct vfs_context context;
1001
1002 /*
1003 * Find the inode; verify that it's a regular file.
1004 */
1005
1006 err = fp_lookup(p, fd, &fp, 0);
1007 if (err)
1008 return(err);
1009
1010 if (fp->f_fglob->fg_type != DTYPE_VNODE){
1011 err = KERN_INVALID_ARGUMENT;
1012 goto bad;
1013 }
1014
1015 if (!(fp->f_fglob->fg_flag & FREAD)) {
1016 err = KERN_PROTECTION_FAILURE;
1017 goto bad;
1018 }
1019
1020 vp = (struct vnode *)fp->f_fglob->fg_data;
1021 err = vnode_getwithref(vp);
1022 if(err != 0)
1023 goto bad;
1024
1025 if (vp->v_type != VREG) {
1026 (void)vnode_put(vp);
1027 err = KERN_INVALID_ARGUMENT;
1028 goto bad;
1029 }
1030
1031 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
1032
1033 /* conformance change - mmap needs to update access time for mapped
1034 * files
1035 */
1036 VATTR_INIT(&vattr);
1037 nanotime(&vattr.va_access_time);
1038 VATTR_SET_ACTIVE(&vattr, va_access_time);
1039 context.vc_proc = p;
1040 context.vc_ucred = kauth_cred_get();
1041 vnode_setattr(vp, &vattr, &context);
1042
1043 if (offset & PAGE_MASK_64) {
1044 printf("map_fd: file offset not page aligned(%d : %s)\n",p->p_pid, p->p_comm);
1045 (void)vnode_put(vp);
1046 err = KERN_INVALID_ARGUMENT;
1047 goto bad;
1048 }
1049 map_size = round_page(size);
1050
1051 /*
1052 * Allow user to map in a zero length file.
1053 */
1054 if (size == 0) {
1055 (void)vnode_put(vp);
1056 err = KERN_SUCCESS;
1057 goto bad;
1058 }
1059 /*
1060 * Map in the file.
1061 */
1062 UBCINFOCHECK("map_fd_funneled", vp);
1063 pager = (void *) ubc_getpager(vp);
1064 if (pager == NULL) {
1065 (void)vnode_put(vp);
1066 err = KERN_FAILURE;
1067 goto bad;
1068 }
1069
1070
1071 my_map = current_map();
1072
1073 result = vm_map_64(
1074 my_map,
1075 &map_addr, map_size, (vm_offset_t)0,
1076 VM_FLAGS_ANYWHERE, pager, offset, TRUE,
1077 VM_PROT_DEFAULT, VM_PROT_ALL,
1078 VM_INHERIT_DEFAULT);
1079 if (result != KERN_SUCCESS) {
1080 (void)vnode_put(vp);
1081 err = result;
1082 goto bad;
1083 }
1084
1085
1086 if (!findspace) {
1087 vm_offset_t dst_addr;
1088 vm_map_copy_t tmp;
1089
1090 if (copyin(CAST_USER_ADDR_T(va), &dst_addr, sizeof (dst_addr)) ||
1091 trunc_page_32(dst_addr) != dst_addr) {
1092 (void) vm_map_remove(
1093 my_map,
1094 map_addr, map_addr + map_size,
1095 VM_MAP_NO_FLAGS);
1096 (void)vnode_put(vp);
1097 err = KERN_INVALID_ADDRESS;
1098 goto bad;
1099 }
1100
1101 result = vm_map_copyin(my_map, (vm_map_address_t)map_addr,
1102 (vm_map_size_t)map_size, TRUE, &tmp);
1103 if (result != KERN_SUCCESS) {
1104
1105 (void) vm_map_remove(my_map, vm_map_trunc_page(map_addr),
1106 vm_map_round_page(map_addr + map_size),
1107 VM_MAP_NO_FLAGS);
1108 (void)vnode_put(vp);
1109 err = result;
1110 goto bad;
1111 }
1112
1113 result = vm_map_copy_overwrite(my_map,
1114 (vm_map_address_t)dst_addr, tmp, FALSE);
1115 if (result != KERN_SUCCESS) {
1116 vm_map_copy_discard(tmp);
1117 (void)vnode_put(vp);
1118 err = result;
1119 goto bad;
1120 }
1121 } else {
1122 if (copyout(&map_addr, CAST_USER_ADDR_T(va), sizeof (map_addr))) {
1123 (void) vm_map_remove(my_map, vm_map_trunc_page(map_addr),
1124 vm_map_round_page(map_addr + map_size),
1125 VM_MAP_NO_FLAGS);
1126 (void)vnode_put(vp);
1127 err = KERN_INVALID_ADDRESS;
1128 goto bad;
1129 }
1130 }
1131
1132 ubc_setcred(vp, current_proc());
1133 (void)ubc_map(vp, (PROT_READ | PROT_WRITE | PROT_EXEC));
1134 (void)vnode_put(vp);
1135 err = 0;
1136 bad:
1137 fp_drop(p, fd, fp, 0);
1138 return (err);
1139 }
1140