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