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