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