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