]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_mman.c
xnu-344.tar.gz
[apple/xnu.git] / bsd / kern / kern_mman.c
CommitLineData
1c79356b
A
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
98struct sbrk_args {
99 int incr;
100};
101
102/* ARGSUSED */
103int
104sbrk(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
113struct sstk_args {
114 int incr;
115} *uap;
116
117/* ARGSUSED */
118int
119sstk(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 */
130int
131ogetpagesize(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
142struct osmmap_args {
143 caddr_t addr;
144 int len;
145 int prot;
146 int share;
147 int fd;
148 long pos;
149};
150
151osmmap(curp, uap, retval)
152 struct proc *curp;
153 register struct osmmap_args *uap;
154 register_t *retval;
155{
156struct 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
180struct 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};
191int
192mmap(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
470out:
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
488struct msync_args {
489 caddr_t addr;
490 int len;
491 int flags;
492};
493int
494msync(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
563mremap()
564{
565 /* Not yet implemented */
566 return (EOPNOTSUPP);
567}
568
569struct munmap_args {
570 caddr_t addr;
571 int len;
572};
573munmap(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
611void
612munmapfd(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
622struct mprotect_args {
623 caddr_t addr;
624 int len;
625 int prot;
626};
627int
628mprotect(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
672struct minherit_args {
673 void *addr;
674 size_t len;
675 int inherit;
676};
677
678int
679minherit(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
713struct madvise_args {
714 caddr_t addr;
715 int len;
716 int behav;
717};
718/* ARGSUSED */
719int
720madvise(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)
9bccf70c 736 return (ENOMEM);
1c79356b 737 if (VM_MIN_ADDRESS > 0 && uap->addr < VM_MIN_ADDRESS)
9bccf70c 738 return (ENOMEM);
1c79356b
A
739
740 if (((vm_offset_t) uap->addr + uap->len) < (vm_offset_t) uap->addr)
9bccf70c 741 return (ENOMEM);
1c79356b
A
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;
9bccf70c 755 break;
1c79356b
A
756 case MADV_SEQUENTIAL:
757 new_behavior = VM_BEHAVIOR_SEQUENTIAL;
9bccf70c 758 break;
1c79356b 759 case MADV_NORMAL:
1c79356b 760 new_behavior = VM_BEHAVIOR_DEFAULT;
9bccf70c
A
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);
1c79356b
A
770 }
771
9bccf70c 772 result = vm_behavior_set(user_map, start, end, new_behavior);
1c79356b
A
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
783struct mincore_args {
784 const void *addr;
785 size_t len;
786 char *vec;
787};
788/* ARGSUSED */
789int
790mincore(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
890struct mlock_args {
891 caddr_t addr;
892 size_t len;
893};
894
895int
896mlock(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 */
9bccf70c 936 result = vm_map_wire(user_map, addr, (vm_offset_t)(addr+size), VM_PROT_NONE, TRUE);
1c79356b
A
937 return (result == KERN_SUCCESS ? 0 : ENOMEM);
938}
939
940struct munlock_args {
941 caddr_t addr;
942 size_t len;
943};
944int
945munlock(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
985struct mlockall_args {
986 int how;
987};
988
989int
990mlockall(p, uap)
991 struct proc *p;
992 struct mlockall_args *uap;
993{
994 return (ENOSYS);
995}
996
997struct munlockall_args {
998 int how;
999};
1000
1001int
1002munlockall(p, uap)
1003 struct proc *p;
1004 struct munlockall_args *uap;
1005{
1006 return(ENOSYS);
1007}
1008
1009
1010/* BEGIN DEFUNCT */
1011struct obreak_args {
1012 char *nsiz;
1013};
1014obreak(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
1023int both;
1024
1025ovadvise()
1026{
1027
1028#ifdef lint
1029 both = 0;
1030#endif
1031}
1032/* END DEFUNCT */
1033#if 1
1034int print_map_addr=0;
1035#endif /* 1 */
1036
1037/* CDY need to fix interface to allow user to map above 32 bits */
1038kern_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
1058kern_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;
0b4e3aa0 1074 struct proc *p =(struct proc *)current_proc();
1c79356b
A
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 vp = (struct vnode *)fp->f_data;
1090
1091 if (vp->v_type != VREG)
1092 return (KERN_INVALID_ARGUMENT);
1093
1094 if (offset & PAGE_MASK_64) {
9bccf70c 1095 printf("map_fd: file offset not page aligned(%d : %s)\n",p->p_pid, p->p_comm);
1c79356b
A
1096 return (KERN_INVALID_ARGUMENT);
1097 }
1098 map_size = round_page(size);
1099
1100 /*
1101 * Allow user to map in a zero length file.
1102 */
1103 if (size == 0)
1104 return (KERN_SUCCESS);
1105 /*
1106 * Map in the file.
1107 */
1108 UBCINFOCHECK("map_fd_funneled", vp);
1109 pager = (void *) ubc_getpager(vp);
1110 if (pager == NULL)
1111 return (KERN_FAILURE);
1112
1113
1114 my_map = current_map();
1115
1116 result = vm_map_64(
1117 my_map,
1118 &map_addr, map_size, (vm_offset_t)0, TRUE,
1119 pager, offset, TRUE,
1120 VM_PROT_DEFAULT, VM_PROT_ALL,
1121 VM_INHERIT_DEFAULT);
1122 if (result != KERN_SUCCESS)
1123 return (result);
1124
1125
1126 if (!findspace) {
1127 vm_offset_t dst_addr;
1128 vm_map_copy_t tmp;
1129
1130 if (copyin(va, &dst_addr, sizeof (dst_addr)) ||
1131 trunc_page(dst_addr) != dst_addr) {
1132 (void) vm_map_remove(
1133 my_map,
1134 map_addr, map_addr + map_size,
1135 VM_MAP_NO_FLAGS);
1136 return (KERN_INVALID_ADDRESS);
1137 }
1138
1139 result = vm_map_copyin(
1140 my_map,
1141 map_addr, map_size, TRUE,
1142 &tmp);
1143 if (result != KERN_SUCCESS) {
1144
1145 (void) vm_map_remove(
1146 my_map,
1147 map_addr, map_addr + map_size,
1148 VM_MAP_NO_FLAGS);
1149 return (result);
1150 }
1151
1152 result = vm_map_copy_overwrite(
1153 my_map,
1154 dst_addr, tmp, FALSE);
1155 if (result != KERN_SUCCESS) {
1156 vm_map_copy_discard(tmp);
1157 return (result);
1158 }
1159 } else {
1160 if (copyout(&map_addr, va, sizeof (map_addr))) {
1161 (void) vm_map_remove(
1162 my_map,
1163 map_addr, map_addr + map_size,
1164 VM_MAP_NO_FLAGS);
1165 return (KERN_INVALID_ADDRESS);
1166 }
1167 }
1168
1169 ubc_setcred(vp, current_proc());
1170 ubc_map(vp);
1171
1172 return (KERN_SUCCESS);
1173}