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