]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_mman.c
xnu-124.1.tar.gz
[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 (EINVAL);
737 if (VM_MIN_ADDRESS > 0 && uap->addr < VM_MIN_ADDRESS)
738 return (EINVAL);
739
740 if (((vm_offset_t) uap->addr + uap->len) < (vm_offset_t) uap->addr)
741 return (EINVAL);
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 case MADV_SEQUENTIAL:
756 new_behavior = VM_BEHAVIOR_SEQUENTIAL;
757 case MADV_NORMAL:
758 default:
759 new_behavior = VM_BEHAVIOR_DEFAULT;
760 }
761
762 result = vm_behavior_set(user_map, start, end, uap->behav);
763 switch (result) {
764 case KERN_SUCCESS:
765 return (0);
766 case KERN_INVALID_ADDRESS:
767 return (EINVAL);
768 }
769
770 return (EINVAL);
771 }
772
773 struct mincore_args {
774 const void *addr;
775 size_t len;
776 char *vec;
777 };
778 /* ARGSUSED */
779 int
780 mincore(p, uap, retval)
781 struct proc *p;
782 struct mincore_args *uap;
783 register_t *retval;
784 {
785 vm_offset_t addr, first_addr;
786 vm_offset_t end;
787 vm_map_t map;
788 char *vec;
789 int error;
790 int vecindex, lastvecindex;
791 int mincoreinfo=0;
792 int pqueryinfo;
793 kern_return_t ret;
794 int numref;
795
796 map = current_map();
797
798 /*
799 * Make sure that the addresses presented are valid for user
800 * mode.
801 */
802 first_addr = addr = trunc_page((vm_offset_t) uap->addr);
803 end = addr + (vm_size_t)round_page(uap->len);
804
805 if (VM_MAX_ADDRESS > 0 && end > VM_MAX_ADDRESS)
806 return (EINVAL);
807 if (end < addr)
808 return (EINVAL);
809
810 /*
811 * Address of byte vector
812 */
813 vec = uap->vec;
814
815 map = current_map();
816
817 /*
818 * Do this on a map entry basis so that if the pages are not
819 * in the current processes address space, we can easily look
820 * up the pages elsewhere.
821 */
822 lastvecindex = -1;
823 for(addr; addr < end; addr += PAGE_SIZE) {
824 pqueryinfo = 0;
825 ret = vm_map_page_query(map, addr, &pqueryinfo, &numref);
826 if (ret != KERN_SUCCESS)
827 pqueryinfo = 0;
828 mincoreinfo = 0;
829 if (pqueryinfo & VM_PAGE_QUERY_PAGE_PRESENT)
830 mincoreinfo |= MINCORE_INCORE;
831 if (pqueryinfo & VM_PAGE_QUERY_PAGE_REF)
832 mincoreinfo |= MINCORE_REFERENCED;
833 if (pqueryinfo & VM_PAGE_QUERY_PAGE_DIRTY)
834 mincoreinfo |= MINCORE_MODIFIED;
835
836
837 /*
838 * calculate index into user supplied byte vector
839 */
840 vecindex = (addr - first_addr)>> PAGE_SHIFT;
841
842 /*
843 * If we have skipped map entries, we need to make sure that
844 * the byte vector is zeroed for those skipped entries.
845 */
846 while((lastvecindex + 1) < vecindex) {
847 error = subyte( vec + lastvecindex, 0);
848 if (error) {
849 return (EFAULT);
850 }
851 ++lastvecindex;
852 }
853
854 /*
855 * Pass the page information to the user
856 */
857 error = subyte( vec + vecindex, mincoreinfo);
858 if (error) {
859 return (EFAULT);
860 }
861 lastvecindex = vecindex;
862 }
863
864
865 /*
866 * Zero the last entries in the byte vector.
867 */
868 vecindex = (end - first_addr) >> PAGE_SHIFT;
869 while((lastvecindex + 1) < vecindex) {
870 error = subyte( vec + lastvecindex, 0);
871 if (error) {
872 return (EFAULT);
873 }
874 ++lastvecindex;
875 }
876
877 return (0);
878 }
879
880 struct mlock_args {
881 caddr_t addr;
882 size_t len;
883 };
884
885 int
886 mlock(p, uap, retval)
887 struct proc *p;
888 struct mlock_args *uap;
889 register_t *retval;
890 {
891 vm_map_t user_map;
892 vm_offset_t addr;
893 vm_size_t size, pageoff;
894 int error;
895 kern_return_t result;
896
897 addr = (vm_offset_t) uap->addr;
898 size = uap->len;
899
900 pageoff = (addr & PAGE_MASK);
901 addr -= pageoff;
902 size += pageoff;
903 size = (vm_size_t) round_page(size);
904
905 /* disable wrap around */
906 if (addr + size < addr)
907 return (EINVAL);
908 #ifdef notyet
909 /* Hmm.. What am I going to do with this? */
910 if (atop(size) + cnt.v_wire_count > vm_page_max_wired)
911 return (EAGAIN);
912 #ifdef pmap_wired_count
913 if (size + ptoa(pmap_wired_count(vm_map_pmap(&p->p_vmspace->vm_map))) >
914 p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur)
915 return (ENOMEM);
916 #else
917 error = suser(p->p_ucred, &p->p_acflag);
918 if (error)
919 return (error);
920 #endif
921 #endif /* notyet */
922
923 user_map = current_map();
924
925 /* vm_wire */
926 result = vm_wire(host_priv_self(), user_map, addr, size, VM_PROT_ALL);
927 return (result == KERN_SUCCESS ? 0 : ENOMEM);
928 }
929
930 struct munlock_args {
931 caddr_t addr;
932 size_t len;
933 };
934 int
935 munlock(p, uap, retval)
936 struct proc *p;
937 struct munlock_args *uap;
938 register_t *retval;
939 {
940 vm_offset_t addr;
941 vm_size_t size, pageoff;
942 int error;
943 vm_map_t user_map;
944 kern_return_t result;
945
946 addr = (vm_offset_t) uap->addr;
947 size = uap->len;
948
949 pageoff = (addr & PAGE_MASK);
950 addr -= pageoff;
951 size += pageoff;
952 size = (vm_size_t) round_page(size);
953
954 /* disable wrap around */
955 if (addr + size < addr)
956 return (EINVAL);
957
958 #ifdef notyet
959 /* Hmm.. What am I going to do with this? */
960 #ifndef pmap_wired_count
961 error = suser(p->p_ucred, &p->p_acflag);
962 if (error)
963 return (error);
964 #endif
965 #endif /* notyet */
966
967 user_map = current_map();
968
969 /* vm_wire */
970 result = vm_wire(host_priv_self(), user_map, addr, size, VM_PROT_NONE);
971 return (result == KERN_SUCCESS ? 0 : ENOMEM);
972 }
973
974
975 struct mlockall_args {
976 int how;
977 };
978
979 int
980 mlockall(p, uap)
981 struct proc *p;
982 struct mlockall_args *uap;
983 {
984 return (ENOSYS);
985 }
986
987 struct munlockall_args {
988 int how;
989 };
990
991 int
992 munlockall(p, uap)
993 struct proc *p;
994 struct munlockall_args *uap;
995 {
996 return(ENOSYS);
997 }
998
999
1000 /* BEGIN DEFUNCT */
1001 struct obreak_args {
1002 char *nsiz;
1003 };
1004 obreak(p, uap, retval)
1005 struct proc *p;
1006 struct obreak_args *uap;
1007 register_t *retval;
1008 {
1009 /* Not implemented, obsolete */
1010 return (ENOMEM);
1011 }
1012
1013 int both;
1014
1015 ovadvise()
1016 {
1017
1018 #ifdef lint
1019 both = 0;
1020 #endif
1021 }
1022 /* END DEFUNCT */
1023 #if 1
1024 int print_map_addr=0;
1025 #endif /* 1 */
1026
1027 /* CDY need to fix interface to allow user to map above 32 bits */
1028 kern_return_t map_fd(
1029 int fd,
1030 vm_offset_t offset,
1031 vm_offset_t *va,
1032 boolean_t findspace,
1033 vm_size_t size)
1034 {
1035 kern_return_t ret;
1036 boolean_t funnel_state;
1037
1038 funnel_state = thread_funnel_set(kernel_flock, TRUE);
1039
1040 ret = map_fd_funneled( fd, (vm_object_offset_t)offset,
1041 va, findspace, size);
1042
1043 (void) thread_funnel_set(kernel_flock, FALSE);
1044
1045 return ret;
1046 }
1047
1048 kern_return_t map_fd_funneled(
1049 int fd,
1050 vm_object_offset_t offset,
1051 vm_offset_t *va,
1052 boolean_t findspace,
1053 vm_size_t size)
1054 {
1055 kern_return_t result;
1056 struct file *fp;
1057 struct vnode *vp;
1058 void * pager;
1059 vm_offset_t map_addr=0;
1060 vm_size_t map_size;
1061 vm_map_copy_t tmp;
1062 int err=0;
1063 vm_map_t my_map;
1064 struct proc *p =(struct proc *)(get_bsdtask_info(current_task()));
1065 #if 0
1066 extern int print_map_addr;
1067 #endif /* 0 */
1068
1069 /*
1070 * Find the inode; verify that it's a regular file.
1071 */
1072
1073 err = fdgetf(p, fd, &fp);
1074 if (err)
1075 return(err);
1076
1077 if (fp->f_type != DTYPE_VNODE)
1078 return(KERN_INVALID_ARGUMENT);
1079 vp = (struct vnode *)fp->f_data;
1080
1081 if (vp->v_type != VREG)
1082 return (KERN_INVALID_ARGUMENT);
1083
1084 if (offset & PAGE_MASK_64) {
1085 printf("map_fd: file offset not page aligned(%d : %s\)n",p->p_pid, p->p_comm);
1086 return (KERN_INVALID_ARGUMENT);
1087 }
1088 map_size = round_page(size);
1089
1090 /*
1091 * Allow user to map in a zero length file.
1092 */
1093 if (size == 0)
1094 return (KERN_SUCCESS);
1095 /*
1096 * Map in the file.
1097 */
1098 UBCINFOCHECK("map_fd_funneled", vp);
1099 pager = (void *) ubc_getpager(vp);
1100 if (pager == NULL)
1101 return (KERN_FAILURE);
1102
1103
1104 my_map = current_map();
1105
1106 result = vm_map_64(
1107 my_map,
1108 &map_addr, map_size, (vm_offset_t)0, TRUE,
1109 pager, offset, TRUE,
1110 VM_PROT_DEFAULT, VM_PROT_ALL,
1111 VM_INHERIT_DEFAULT);
1112 if (result != KERN_SUCCESS)
1113 return (result);
1114
1115
1116 if (!findspace) {
1117 vm_offset_t dst_addr;
1118 vm_map_copy_t tmp;
1119
1120 if (copyin(va, &dst_addr, sizeof (dst_addr)) ||
1121 trunc_page(dst_addr) != dst_addr) {
1122 (void) vm_map_remove(
1123 my_map,
1124 map_addr, map_addr + map_size,
1125 VM_MAP_NO_FLAGS);
1126 return (KERN_INVALID_ADDRESS);
1127 }
1128
1129 result = vm_map_copyin(
1130 my_map,
1131 map_addr, map_size, TRUE,
1132 &tmp);
1133 if (result != KERN_SUCCESS) {
1134
1135 (void) vm_map_remove(
1136 my_map,
1137 map_addr, map_addr + map_size,
1138 VM_MAP_NO_FLAGS);
1139 return (result);
1140 }
1141
1142 result = vm_map_copy_overwrite(
1143 my_map,
1144 dst_addr, tmp, FALSE);
1145 if (result != KERN_SUCCESS) {
1146 vm_map_copy_discard(tmp);
1147 return (result);
1148 }
1149 } else {
1150 if (copyout(&map_addr, va, sizeof (map_addr))) {
1151 (void) vm_map_remove(
1152 my_map,
1153 map_addr, map_addr + map_size,
1154 VM_MAP_NO_FLAGS);
1155 return (KERN_INVALID_ADDRESS);
1156 }
1157 }
1158
1159 ubc_setcred(vp, current_proc());
1160 ubc_map(vp);
1161
1162 return (KERN_SUCCESS);
1163 }