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