1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1988 University of Utah. 3df8bae1dSRodney W. Grimes * Copyright (c) 1991, 1993 4df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 5df8bae1dSRodney W. Grimes * 6df8bae1dSRodney W. Grimes * This code is derived from software contributed to Berkeley by 7df8bae1dSRodney W. Grimes * the Systems Programming Group of the University of Utah Computer 8df8bae1dSRodney W. Grimes * Science Department. 9df8bae1dSRodney W. Grimes * 10df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 11df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 12df8bae1dSRodney W. Grimes * are met: 13df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 15df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 17df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 18df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 19df8bae1dSRodney W. Grimes * must display the following acknowledgement: 20df8bae1dSRodney W. Grimes * This product includes software developed by the University of 21df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 22df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 23df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 24df8bae1dSRodney W. Grimes * without specific prior written permission. 25df8bae1dSRodney W. Grimes * 26df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36df8bae1dSRodney W. Grimes * SUCH DAMAGE. 37df8bae1dSRodney W. Grimes * 38df8bae1dSRodney W. Grimes * from: Utah $Hdr: vm_mmap.c 1.6 91/10/21$ 39df8bae1dSRodney W. Grimes * 40df8bae1dSRodney W. Grimes * @(#)vm_mmap.c 8.4 (Berkeley) 1/12/94 41a316d390SJohn Dyson * $Id: vm_mmap.c,v 1.31 1995/12/07 12:48:19 davidg Exp $ 42df8bae1dSRodney W. Grimes */ 43df8bae1dSRodney W. Grimes 44df8bae1dSRodney W. Grimes /* 45df8bae1dSRodney W. Grimes * Mapped file (mmap) interface to VM 46df8bae1dSRodney W. Grimes */ 47df8bae1dSRodney W. Grimes 48df8bae1dSRodney W. Grimes #include <sys/param.h> 49df8bae1dSRodney W. Grimes #include <sys/systm.h> 50d2d3e875SBruce Evans #include <sys/sysproto.h> 51df8bae1dSRodney W. Grimes #include <sys/filedesc.h> 52df8bae1dSRodney W. Grimes #include <sys/resourcevar.h> 53df8bae1dSRodney W. Grimes #include <sys/proc.h> 54df8bae1dSRodney W. Grimes #include <sys/vnode.h> 55df8bae1dSRodney W. Grimes #include <sys/file.h> 56df8bae1dSRodney W. Grimes #include <sys/mman.h> 57df8bae1dSRodney W. Grimes #include <sys/conf.h> 58efeaf95aSDavid Greenman #include <sys/vmmeter.h> 59df8bae1dSRodney W. Grimes 60df8bae1dSRodney W. Grimes #include <miscfs/specfs/specdev.h> 61df8bae1dSRodney W. Grimes 62df8bae1dSRodney W. Grimes #include <vm/vm.h> 63efeaf95aSDavid Greenman #include <vm/vm_param.h> 64efeaf95aSDavid Greenman #include <vm/vm_prot.h> 65efeaf95aSDavid Greenman #include <vm/vm_inherit.h> 66efeaf95aSDavid Greenman #include <vm/lock.h> 67efeaf95aSDavid Greenman #include <vm/pmap.h> 68efeaf95aSDavid Greenman #include <vm/vm_map.h> 69efeaf95aSDavid Greenman #include <vm/vm_object.h> 70df8bae1dSRodney W. Grimes #include <vm/vm_pager.h> 71b5e8ce9fSBruce Evans #include <vm/vm_pageout.h> 72efeaf95aSDavid Greenman #include <vm/vm_extern.h> 73df8bae1dSRodney W. Grimes 74cac597e4SBruce Evans extern void pmap_object_init_pt __P((pmap_t pmap, vm_offset_t addr, 75cac597e4SBruce Evans vm_object_t object, vm_offset_t offset, 76cac597e4SBruce Evans vm_offset_t size)); 77f720dc2cSDavid Greenman 78d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 79df8bae1dSRodney W. Grimes struct sbrk_args { 80df8bae1dSRodney W. Grimes int incr; 81df8bae1dSRodney W. Grimes }; 82d2d3e875SBruce Evans #endif 830d94caffSDavid Greenman 84df8bae1dSRodney W. Grimes /* ARGSUSED */ 85df8bae1dSRodney W. Grimes int 86df8bae1dSRodney W. Grimes sbrk(p, uap, retval) 87df8bae1dSRodney W. Grimes struct proc *p; 88df8bae1dSRodney W. Grimes struct sbrk_args *uap; 89df8bae1dSRodney W. Grimes int *retval; 90df8bae1dSRodney W. Grimes { 91df8bae1dSRodney W. Grimes 92df8bae1dSRodney W. Grimes /* Not yet implemented */ 93df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 94df8bae1dSRodney W. Grimes } 95df8bae1dSRodney W. Grimes 96d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 97df8bae1dSRodney W. Grimes struct sstk_args { 98df8bae1dSRodney W. Grimes int incr; 99df8bae1dSRodney W. Grimes }; 100d2d3e875SBruce Evans #endif 1010d94caffSDavid Greenman 102df8bae1dSRodney W. Grimes /* ARGSUSED */ 103df8bae1dSRodney W. Grimes int 104df8bae1dSRodney W. Grimes sstk(p, uap, retval) 105df8bae1dSRodney W. Grimes struct proc *p; 106df8bae1dSRodney W. Grimes struct sstk_args *uap; 107df8bae1dSRodney W. Grimes int *retval; 108df8bae1dSRodney W. Grimes { 109df8bae1dSRodney W. Grimes 110df8bae1dSRodney W. Grimes /* Not yet implemented */ 111df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 112df8bae1dSRodney W. Grimes } 113df8bae1dSRodney W. Grimes 114df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 115d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 116df8bae1dSRodney W. Grimes struct getpagesize_args { 117df8bae1dSRodney W. Grimes int dummy; 118df8bae1dSRodney W. Grimes }; 119d2d3e875SBruce Evans #endif 1200d94caffSDavid Greenman 121df8bae1dSRodney W. Grimes /* ARGSUSED */ 122df8bae1dSRodney W. Grimes int 123df8bae1dSRodney W. Grimes ogetpagesize(p, uap, retval) 124df8bae1dSRodney W. Grimes struct proc *p; 125df8bae1dSRodney W. Grimes struct getpagesize_args *uap; 126df8bae1dSRodney W. Grimes int *retval; 127df8bae1dSRodney W. Grimes { 128df8bae1dSRodney W. Grimes 129df8bae1dSRodney W. Grimes *retval = PAGE_SIZE; 130df8bae1dSRodney W. Grimes return (0); 131df8bae1dSRodney W. Grimes } 132df8bae1dSRodney W. Grimes #endif /* COMPAT_43 || COMPAT_SUNOS */ 133df8bae1dSRodney W. Grimes 134d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 135df8bae1dSRodney W. Grimes struct mmap_args { 136df8bae1dSRodney W. Grimes caddr_t addr; 137df8bae1dSRodney W. Grimes size_t len; 138df8bae1dSRodney W. Grimes int prot; 139df8bae1dSRodney W. Grimes int flags; 140df8bae1dSRodney W. Grimes int fd; 141df8bae1dSRodney W. Grimes long pad; 142df8bae1dSRodney W. Grimes off_t pos; 143df8bae1dSRodney W. Grimes }; 144d2d3e875SBruce Evans #endif 145df8bae1dSRodney W. Grimes 146df8bae1dSRodney W. Grimes int 147df8bae1dSRodney W. Grimes mmap(p, uap, retval) 148df8bae1dSRodney W. Grimes struct proc *p; 149df8bae1dSRodney W. Grimes register struct mmap_args *uap; 150df8bae1dSRodney W. Grimes int *retval; 151df8bae1dSRodney W. Grimes { 152df8bae1dSRodney W. Grimes register struct filedesc *fdp = p->p_fd; 153df8bae1dSRodney W. Grimes register struct file *fp; 154df8bae1dSRodney W. Grimes struct vnode *vp; 155df8bae1dSRodney W. Grimes vm_offset_t addr; 156df8bae1dSRodney W. Grimes vm_size_t size; 157df8bae1dSRodney W. Grimes vm_prot_t prot, maxprot; 158df8bae1dSRodney W. Grimes caddr_t handle; 159df8bae1dSRodney W. Grimes int flags, error; 160df8bae1dSRodney W. Grimes 161df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 162df8bae1dSRodney W. Grimes flags = uap->flags; 163df8bae1dSRodney W. Grimes /* 1640d94caffSDavid Greenman * Address (if FIXED) must be page aligned. Size is implicitly rounded 1650d94caffSDavid Greenman * to a page boundary. 166df8bae1dSRodney W. Grimes */ 167df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 168df8bae1dSRodney W. Grimes if (((flags & MAP_FIXED) && (addr & PAGE_MASK)) || 169df8bae1dSRodney W. Grimes (ssize_t) uap->len < 0 || ((flags & MAP_ANON) && uap->fd != -1)) 170df8bae1dSRodney W. Grimes return (EINVAL); 171df8bae1dSRodney W. Grimes size = (vm_size_t) round_page(uap->len); 172df8bae1dSRodney W. Grimes /* 1730d94caffSDavid Greenman * Check for illegal addresses. Watch out for address wrap... Note 1740d94caffSDavid Greenman * that VM_*_ADDRESS are not constants due to casts (argh). 175df8bae1dSRodney W. Grimes */ 176df8bae1dSRodney W. Grimes if (flags & MAP_FIXED) { 177bbc0ec52SDavid Greenman if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS) 178df8bae1dSRodney W. Grimes return (EINVAL); 17926f9a767SRodney W. Grimes #ifndef i386 180df8bae1dSRodney W. Grimes if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS) 181df8bae1dSRodney W. Grimes return (EINVAL); 18226f9a767SRodney W. Grimes #endif 183bbc0ec52SDavid Greenman if (addr + size < addr) 184df8bae1dSRodney W. Grimes return (EINVAL); 185df8bae1dSRodney W. Grimes } 186df8bae1dSRodney W. Grimes /* 1870d94caffSDavid Greenman * XXX if no hint provided for a non-fixed mapping place it after the 1880d94caffSDavid Greenman * end of the largest possible heap. 189df8bae1dSRodney W. Grimes * 1900d94caffSDavid Greenman * There should really be a pmap call to determine a reasonable location. 191df8bae1dSRodney W. Grimes */ 192df8bae1dSRodney W. Grimes if (addr == 0 && (flags & MAP_FIXED) == 0) 193df8bae1dSRodney W. Grimes addr = round_page(p->p_vmspace->vm_daddr + MAXDSIZ); 194df8bae1dSRodney W. Grimes if (flags & MAP_ANON) { 195df8bae1dSRodney W. Grimes /* 196df8bae1dSRodney W. Grimes * Mapping blank space is trivial. 197df8bae1dSRodney W. Grimes */ 198df8bae1dSRodney W. Grimes handle = NULL; 199df8bae1dSRodney W. Grimes maxprot = VM_PROT_ALL; 200df8bae1dSRodney W. Grimes } else { 201df8bae1dSRodney W. Grimes /* 2020d94caffSDavid Greenman * Mapping file, get fp for validation. Obtain vnode and make 2030d94caffSDavid Greenman * sure it is of appropriate type. 204df8bae1dSRodney W. Grimes */ 205df8bae1dSRodney W. Grimes if (((unsigned) uap->fd) >= fdp->fd_nfiles || 206df8bae1dSRodney W. Grimes (fp = fdp->fd_ofiles[uap->fd]) == NULL) 207df8bae1dSRodney W. Grimes return (EBADF); 208df8bae1dSRodney W. Grimes if (fp->f_type != DTYPE_VNODE) 209df8bae1dSRodney W. Grimes return (EINVAL); 210df8bae1dSRodney W. Grimes vp = (struct vnode *) fp->f_data; 211df8bae1dSRodney W. Grimes if (vp->v_type != VREG && vp->v_type != VCHR) 212df8bae1dSRodney W. Grimes return (EINVAL); 213df8bae1dSRodney W. Grimes /* 2140d94caffSDavid Greenman * XXX hack to handle use of /dev/zero to map anon memory (ala 2150d94caffSDavid Greenman * SunOS). 216df8bae1dSRodney W. Grimes */ 217df8bae1dSRodney W. Grimes if (vp->v_type == VCHR && iszerodev(vp->v_rdev)) { 218df8bae1dSRodney W. Grimes handle = NULL; 219df8bae1dSRodney W. Grimes maxprot = VM_PROT_ALL; 220df8bae1dSRodney W. Grimes flags |= MAP_ANON; 221df8bae1dSRodney W. Grimes } else { 222df8bae1dSRodney W. Grimes /* 223df8bae1dSRodney W. Grimes * Ensure that file and memory protections are 224df8bae1dSRodney W. Grimes * compatible. Note that we only worry about 225df8bae1dSRodney W. Grimes * writability if mapping is shared; in this case, 226df8bae1dSRodney W. Grimes * current and max prot are dictated by the open file. 227df8bae1dSRodney W. Grimes * XXX use the vnode instead? Problem is: what 2280d94caffSDavid Greenman * credentials do we use for determination? What if 2290d94caffSDavid Greenman * proc does a setuid? 230df8bae1dSRodney W. Grimes */ 231df8bae1dSRodney W. Grimes maxprot = VM_PROT_EXECUTE; /* ??? */ 232df8bae1dSRodney W. Grimes if (fp->f_flag & FREAD) 233df8bae1dSRodney W. Grimes maxprot |= VM_PROT_READ; 234df8bae1dSRodney W. Grimes else if (prot & PROT_READ) 235df8bae1dSRodney W. Grimes return (EACCES); 236df8bae1dSRodney W. Grimes if (flags & MAP_SHARED) { 237df8bae1dSRodney W. Grimes if (fp->f_flag & FWRITE) 238df8bae1dSRodney W. Grimes maxprot |= VM_PROT_WRITE; 239df8bae1dSRodney W. Grimes else if (prot & PROT_WRITE) 240df8bae1dSRodney W. Grimes return (EACCES); 241df8bae1dSRodney W. Grimes } else 242df8bae1dSRodney W. Grimes maxprot |= VM_PROT_WRITE; 243df8bae1dSRodney W. Grimes handle = (caddr_t) vp; 244df8bae1dSRodney W. Grimes } 245df8bae1dSRodney W. Grimes } 246df8bae1dSRodney W. Grimes error = vm_mmap(&p->p_vmspace->vm_map, &addr, size, prot, maxprot, 247a316d390SJohn Dyson flags, handle, uap->pos); 248df8bae1dSRodney W. Grimes if (error == 0) 249df8bae1dSRodney W. Grimes *retval = (int) addr; 250df8bae1dSRodney W. Grimes return (error); 251df8bae1dSRodney W. Grimes } 252df8bae1dSRodney W. Grimes 25305f0fdd2SPoul-Henning Kamp #ifdef COMPAT_43 254d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 25505f0fdd2SPoul-Henning Kamp struct ommap_args { 25605f0fdd2SPoul-Henning Kamp caddr_t addr; 25705f0fdd2SPoul-Henning Kamp int len; 25805f0fdd2SPoul-Henning Kamp int prot; 25905f0fdd2SPoul-Henning Kamp int flags; 26005f0fdd2SPoul-Henning Kamp int fd; 26105f0fdd2SPoul-Henning Kamp long pos; 26205f0fdd2SPoul-Henning Kamp }; 263d2d3e875SBruce Evans #endif 26405f0fdd2SPoul-Henning Kamp int 26505f0fdd2SPoul-Henning Kamp ommap(p, uap, retval) 26605f0fdd2SPoul-Henning Kamp struct proc *p; 26705f0fdd2SPoul-Henning Kamp register struct ommap_args *uap; 26805f0fdd2SPoul-Henning Kamp int *retval; 26905f0fdd2SPoul-Henning Kamp { 27005f0fdd2SPoul-Henning Kamp struct mmap_args nargs; 27105f0fdd2SPoul-Henning Kamp static const char cvtbsdprot[8] = { 27205f0fdd2SPoul-Henning Kamp 0, 27305f0fdd2SPoul-Henning Kamp PROT_EXEC, 27405f0fdd2SPoul-Henning Kamp PROT_WRITE, 27505f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE, 27605f0fdd2SPoul-Henning Kamp PROT_READ, 27705f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_READ, 27805f0fdd2SPoul-Henning Kamp PROT_WRITE | PROT_READ, 27905f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE | PROT_READ, 28005f0fdd2SPoul-Henning Kamp }; 2810d94caffSDavid Greenman 28205f0fdd2SPoul-Henning Kamp #define OMAP_ANON 0x0002 28305f0fdd2SPoul-Henning Kamp #define OMAP_COPY 0x0020 28405f0fdd2SPoul-Henning Kamp #define OMAP_SHARED 0x0010 28505f0fdd2SPoul-Henning Kamp #define OMAP_FIXED 0x0100 28605f0fdd2SPoul-Henning Kamp #define OMAP_INHERIT 0x0800 28705f0fdd2SPoul-Henning Kamp 28805f0fdd2SPoul-Henning Kamp nargs.addr = uap->addr; 28905f0fdd2SPoul-Henning Kamp nargs.len = uap->len; 29005f0fdd2SPoul-Henning Kamp nargs.prot = cvtbsdprot[uap->prot & 0x7]; 29105f0fdd2SPoul-Henning Kamp nargs.flags = 0; 29205f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_ANON) 29305f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_ANON; 29405f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_COPY) 29505f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_COPY; 29605f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_SHARED) 29705f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_SHARED; 29805f0fdd2SPoul-Henning Kamp else 29905f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_PRIVATE; 30005f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_FIXED) 30105f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_FIXED; 30205f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_INHERIT) 30305f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_INHERIT; 30405f0fdd2SPoul-Henning Kamp nargs.fd = uap->fd; 30505f0fdd2SPoul-Henning Kamp nargs.pos = uap->pos; 30605f0fdd2SPoul-Henning Kamp return (mmap(p, &nargs, retval)); 30705f0fdd2SPoul-Henning Kamp } 30805f0fdd2SPoul-Henning Kamp #endif /* COMPAT_43 */ 30905f0fdd2SPoul-Henning Kamp 31005f0fdd2SPoul-Henning Kamp 311d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 312df8bae1dSRodney W. Grimes struct msync_args { 313df8bae1dSRodney W. Grimes caddr_t addr; 314df8bae1dSRodney W. Grimes int len; 315e6c6af11SDavid Greenman int flags; 316df8bae1dSRodney W. Grimes }; 317d2d3e875SBruce Evans #endif 318df8bae1dSRodney W. Grimes int 319df8bae1dSRodney W. Grimes msync(p, uap, retval) 320df8bae1dSRodney W. Grimes struct proc *p; 321df8bae1dSRodney W. Grimes struct msync_args *uap; 322df8bae1dSRodney W. Grimes int *retval; 323df8bae1dSRodney W. Grimes { 324df8bae1dSRodney W. Grimes vm_offset_t addr; 325df8bae1dSRodney W. Grimes vm_size_t size; 326e6c6af11SDavid Greenman int flags; 327df8bae1dSRodney W. Grimes vm_map_t map; 328df8bae1dSRodney W. Grimes int rv; 329df8bae1dSRodney W. Grimes 330df8bae1dSRodney W. Grimes map = &p->p_vmspace->vm_map; 331df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 332df8bae1dSRodney W. Grimes size = (vm_size_t) uap->len; 333e6c6af11SDavid Greenman flags = uap->flags; 334e6c6af11SDavid Greenman 3351e62bc63SDavid Greenman if (((int) addr & PAGE_MASK) || addr + size < addr || 3361e62bc63SDavid Greenman (flags & (MS_ASYNC|MS_INVALIDATE)) == (MS_ASYNC|MS_INVALIDATE)) 3371e62bc63SDavid Greenman return (EINVAL); 3381e62bc63SDavid Greenman 339df8bae1dSRodney W. Grimes /* 340df8bae1dSRodney W. Grimes * XXX Gak! If size is zero we are supposed to sync "all modified 3410d94caffSDavid Greenman * pages with the region containing addr". Unfortunately, we don't 3420d94caffSDavid Greenman * really keep track of individual mmaps so we approximate by flushing 3430d94caffSDavid Greenman * the range of the map entry containing addr. This can be incorrect 3440d94caffSDavid Greenman * if the region splits or is coalesced with a neighbor. 345df8bae1dSRodney W. Grimes */ 346df8bae1dSRodney W. Grimes if (size == 0) { 347df8bae1dSRodney W. Grimes vm_map_entry_t entry; 348df8bae1dSRodney W. Grimes 349df8bae1dSRodney W. Grimes vm_map_lock_read(map); 350df8bae1dSRodney W. Grimes rv = vm_map_lookup_entry(map, addr, &entry); 351df8bae1dSRodney W. Grimes vm_map_unlock_read(map); 352fbcfcdf7SDavid Greenman if (rv == FALSE) 353df8bae1dSRodney W. Grimes return (EINVAL); 354df8bae1dSRodney W. Grimes addr = entry->start; 355df8bae1dSRodney W. Grimes size = entry->end - entry->start; 356df8bae1dSRodney W. Grimes } 357e6c6af11SDavid Greenman 358df8bae1dSRodney W. Grimes /* 359df8bae1dSRodney W. Grimes * Clean the pages and interpret the return value. 360df8bae1dSRodney W. Grimes */ 3616c534ad8SDavid Greenman rv = vm_map_clean(map, addr, addr + size, (flags & MS_ASYNC) == 0, 362e6c6af11SDavid Greenman (flags & MS_INVALIDATE) != 0); 363e6c6af11SDavid Greenman 364df8bae1dSRodney W. Grimes switch (rv) { 365df8bae1dSRodney W. Grimes case KERN_SUCCESS: 366df8bae1dSRodney W. Grimes break; 367df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 368df8bae1dSRodney W. Grimes return (EINVAL); /* Sun returns ENOMEM? */ 369df8bae1dSRodney W. Grimes case KERN_FAILURE: 370df8bae1dSRodney W. Grimes return (EIO); 371df8bae1dSRodney W. Grimes default: 372df8bae1dSRodney W. Grimes return (EINVAL); 373df8bae1dSRodney W. Grimes } 374e6c6af11SDavid Greenman 375df8bae1dSRodney W. Grimes return (0); 376df8bae1dSRodney W. Grimes } 377df8bae1dSRodney W. Grimes 378d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 379df8bae1dSRodney W. Grimes struct munmap_args { 380df8bae1dSRodney W. Grimes caddr_t addr; 381df8bae1dSRodney W. Grimes int len; 382df8bae1dSRodney W. Grimes }; 383d2d3e875SBruce Evans #endif 384df8bae1dSRodney W. Grimes int 385df8bae1dSRodney W. Grimes munmap(p, uap, retval) 386df8bae1dSRodney W. Grimes register struct proc *p; 387df8bae1dSRodney W. Grimes register struct munmap_args *uap; 388df8bae1dSRodney W. Grimes int *retval; 389df8bae1dSRodney W. Grimes { 390df8bae1dSRodney W. Grimes vm_offset_t addr; 391df8bae1dSRodney W. Grimes vm_size_t size; 392df8bae1dSRodney W. Grimes vm_map_t map; 393df8bae1dSRodney W. Grimes 394df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 395df8bae1dSRodney W. Grimes if ((addr & PAGE_MASK) || uap->len < 0) 396df8bae1dSRodney W. Grimes return (EINVAL); 397df8bae1dSRodney W. Grimes size = (vm_size_t) round_page(uap->len); 398df8bae1dSRodney W. Grimes if (size == 0) 399df8bae1dSRodney W. Grimes return (0); 400df8bae1dSRodney W. Grimes /* 4010d94caffSDavid Greenman * Check for illegal addresses. Watch out for address wrap... Note 4020d94caffSDavid Greenman * that VM_*_ADDRESS are not constants due to casts (argh). 403df8bae1dSRodney W. Grimes */ 404bbc0ec52SDavid Greenman if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS) 405df8bae1dSRodney W. Grimes return (EINVAL); 40626f9a767SRodney W. Grimes #ifndef i386 407df8bae1dSRodney W. Grimes if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS) 408df8bae1dSRodney W. Grimes return (EINVAL); 40926f9a767SRodney W. Grimes #endif 410bbc0ec52SDavid Greenman if (addr + size < addr) 411df8bae1dSRodney W. Grimes return (EINVAL); 412df8bae1dSRodney W. Grimes map = &p->p_vmspace->vm_map; 413df8bae1dSRodney W. Grimes /* 414df8bae1dSRodney W. Grimes * Make sure entire range is allocated. 415df8bae1dSRodney W. Grimes */ 416df8bae1dSRodney W. Grimes if (!vm_map_check_protection(map, addr, addr + size, VM_PROT_NONE)) 417df8bae1dSRodney W. Grimes return (EINVAL); 418df8bae1dSRodney W. Grimes /* returns nothing but KERN_SUCCESS anyway */ 419df8bae1dSRodney W. Grimes (void) vm_map_remove(map, addr, addr + size); 420df8bae1dSRodney W. Grimes return (0); 421df8bae1dSRodney W. Grimes } 422df8bae1dSRodney W. Grimes 423df8bae1dSRodney W. Grimes void 42490324b07SDavid Greenman munmapfd(p, fd) 42590324b07SDavid Greenman struct proc *p; 426df8bae1dSRodney W. Grimes int fd; 427df8bae1dSRodney W. Grimes { 428df8bae1dSRodney W. Grimes /* 429c4ed5a07SDavid Greenman * XXX should unmap any regions mapped to this file 430df8bae1dSRodney W. Grimes */ 43190324b07SDavid Greenman p->p_fd->fd_ofileflags[fd] &= ~UF_MAPPED; 432df8bae1dSRodney W. Grimes } 433df8bae1dSRodney W. Grimes 434d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 435df8bae1dSRodney W. Grimes struct mprotect_args { 436df8bae1dSRodney W. Grimes caddr_t addr; 437df8bae1dSRodney W. Grimes int len; 438df8bae1dSRodney W. Grimes int prot; 439df8bae1dSRodney W. Grimes }; 440d2d3e875SBruce Evans #endif 441df8bae1dSRodney W. Grimes int 442df8bae1dSRodney W. Grimes mprotect(p, uap, retval) 443df8bae1dSRodney W. Grimes struct proc *p; 444df8bae1dSRodney W. Grimes struct mprotect_args *uap; 445df8bae1dSRodney W. Grimes int *retval; 446df8bae1dSRodney W. Grimes { 447df8bae1dSRodney W. Grimes vm_offset_t addr; 448df8bae1dSRodney W. Grimes vm_size_t size; 449df8bae1dSRodney W. Grimes register vm_prot_t prot; 450df8bae1dSRodney W. Grimes 451df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 452df8bae1dSRodney W. Grimes if ((addr & PAGE_MASK) || uap->len < 0) 453df8bae1dSRodney W. Grimes return (EINVAL); 454df8bae1dSRodney W. Grimes size = (vm_size_t) uap->len; 455df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 456df8bae1dSRodney W. Grimes 457df8bae1dSRodney W. Grimes switch (vm_map_protect(&p->p_vmspace->vm_map, addr, addr + size, prot, 458df8bae1dSRodney W. Grimes FALSE)) { 459df8bae1dSRodney W. Grimes case KERN_SUCCESS: 460df8bae1dSRodney W. Grimes return (0); 461df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 462df8bae1dSRodney W. Grimes return (EACCES); 463df8bae1dSRodney W. Grimes } 464df8bae1dSRodney W. Grimes return (EINVAL); 465df8bae1dSRodney W. Grimes } 466df8bae1dSRodney W. Grimes 467d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 468df8bae1dSRodney W. Grimes struct madvise_args { 469df8bae1dSRodney W. Grimes caddr_t addr; 470df8bae1dSRodney W. Grimes int len; 471df8bae1dSRodney W. Grimes int behav; 472df8bae1dSRodney W. Grimes }; 473d2d3e875SBruce Evans #endif 4740d94caffSDavid Greenman 475df8bae1dSRodney W. Grimes /* ARGSUSED */ 476df8bae1dSRodney W. Grimes int 477df8bae1dSRodney W. Grimes madvise(p, uap, retval) 478df8bae1dSRodney W. Grimes struct proc *p; 479df8bae1dSRodney W. Grimes struct madvise_args *uap; 480df8bae1dSRodney W. Grimes int *retval; 481df8bae1dSRodney W. Grimes { 482df8bae1dSRodney W. Grimes 483df8bae1dSRodney W. Grimes /* Not yet implemented */ 484df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 485df8bae1dSRodney W. Grimes } 486df8bae1dSRodney W. Grimes 487d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 488df8bae1dSRodney W. Grimes struct mincore_args { 489df8bae1dSRodney W. Grimes caddr_t addr; 490df8bae1dSRodney W. Grimes int len; 491df8bae1dSRodney W. Grimes char *vec; 492df8bae1dSRodney W. Grimes }; 493d2d3e875SBruce Evans #endif 4940d94caffSDavid Greenman 495df8bae1dSRodney W. Grimes /* ARGSUSED */ 496df8bae1dSRodney W. Grimes int 497df8bae1dSRodney W. Grimes mincore(p, uap, retval) 498df8bae1dSRodney W. Grimes struct proc *p; 499df8bae1dSRodney W. Grimes struct mincore_args *uap; 500df8bae1dSRodney W. Grimes int *retval; 501df8bae1dSRodney W. Grimes { 50202c04a2fSJohn Dyson vm_offset_t addr; 50302c04a2fSJohn Dyson vm_offset_t end; 50402c04a2fSJohn Dyson char *vec; 505df8bae1dSRodney W. Grimes 50602c04a2fSJohn Dyson addr = trunc_page((vm_offset_t) uap->addr); 50702c04a2fSJohn Dyson end = addr + round_page((vm_size_t) uap->len); 50802c04a2fSJohn Dyson if (VM_MAXUSER_ADDRESS > 0 && end > VM_MAXUSER_ADDRESS) 50902c04a2fSJohn Dyson return (EINVAL); 51002c04a2fSJohn Dyson if (end < addr) 51102c04a2fSJohn Dyson return (EINVAL); 51202c04a2fSJohn Dyson 51302c04a2fSJohn Dyson vec = uap->vec; 51402c04a2fSJohn Dyson while(addr < end) { 51502c04a2fSJohn Dyson int error; 51602c04a2fSJohn Dyson if (pmap_extract(&p->p_vmspace->vm_pmap, addr)) { 51702c04a2fSJohn Dyson error = subyte( vec, 1); 51802c04a2fSJohn Dyson } else { 51902c04a2fSJohn Dyson error = subyte( vec, 0); 52002c04a2fSJohn Dyson } 52102c04a2fSJohn Dyson if (error) 52202c04a2fSJohn Dyson return EFAULT; 52302c04a2fSJohn Dyson vec++; 52402c04a2fSJohn Dyson addr += PAGE_SIZE; 52502c04a2fSJohn Dyson } 52602c04a2fSJohn Dyson return (0); 527df8bae1dSRodney W. Grimes } 528df8bae1dSRodney W. Grimes 529d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 530df8bae1dSRodney W. Grimes struct mlock_args { 531df8bae1dSRodney W. Grimes caddr_t addr; 532df8bae1dSRodney W. Grimes size_t len; 533df8bae1dSRodney W. Grimes }; 534d2d3e875SBruce Evans #endif 535df8bae1dSRodney W. Grimes int 536df8bae1dSRodney W. Grimes mlock(p, uap, retval) 537df8bae1dSRodney W. Grimes struct proc *p; 538df8bae1dSRodney W. Grimes struct mlock_args *uap; 539df8bae1dSRodney W. Grimes int *retval; 540df8bae1dSRodney W. Grimes { 541df8bae1dSRodney W. Grimes vm_offset_t addr; 542df8bae1dSRodney W. Grimes vm_size_t size; 543df8bae1dSRodney W. Grimes int error; 544df8bae1dSRodney W. Grimes 545df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 546df8bae1dSRodney W. Grimes if ((addr & PAGE_MASK) || uap->addr + uap->len < uap->addr) 547df8bae1dSRodney W. Grimes return (EINVAL); 548df8bae1dSRodney W. Grimes size = round_page((vm_size_t) uap->len); 549df8bae1dSRodney W. Grimes if (atop(size) + cnt.v_wire_count > vm_page_max_wired) 550df8bae1dSRodney W. Grimes return (EAGAIN); 551df8bae1dSRodney W. Grimes #ifdef pmap_wired_count 552df8bae1dSRodney W. Grimes if (size + ptoa(pmap_wired_count(vm_map_pmap(&p->p_vmspace->vm_map))) > 553df8bae1dSRodney W. Grimes p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur) 554df8bae1dSRodney W. Grimes return (EAGAIN); 555df8bae1dSRodney W. Grimes #else 55605f0fdd2SPoul-Henning Kamp error = suser(p->p_ucred, &p->p_acflag); 55705f0fdd2SPoul-Henning Kamp if (error) 558df8bae1dSRodney W. Grimes return (error); 559df8bae1dSRodney W. Grimes #endif 560df8bae1dSRodney W. Grimes 561df8bae1dSRodney W. Grimes error = vm_map_pageable(&p->p_vmspace->vm_map, addr, addr + size, FALSE); 562df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 563df8bae1dSRodney W. Grimes } 564df8bae1dSRodney W. Grimes 565d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 566df8bae1dSRodney W. Grimes struct munlock_args { 567df8bae1dSRodney W. Grimes caddr_t addr; 568df8bae1dSRodney W. Grimes size_t len; 569df8bae1dSRodney W. Grimes }; 570d2d3e875SBruce Evans #endif 571df8bae1dSRodney W. Grimes int 572df8bae1dSRodney W. Grimes munlock(p, uap, retval) 573df8bae1dSRodney W. Grimes struct proc *p; 574df8bae1dSRodney W. Grimes struct munlock_args *uap; 575df8bae1dSRodney W. Grimes int *retval; 576df8bae1dSRodney W. Grimes { 577df8bae1dSRodney W. Grimes vm_offset_t addr; 578df8bae1dSRodney W. Grimes vm_size_t size; 579df8bae1dSRodney W. Grimes int error; 580df8bae1dSRodney W. Grimes 581df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 582df8bae1dSRodney W. Grimes if ((addr & PAGE_MASK) || uap->addr + uap->len < uap->addr) 583df8bae1dSRodney W. Grimes return (EINVAL); 584df8bae1dSRodney W. Grimes #ifndef pmap_wired_count 58505f0fdd2SPoul-Henning Kamp error = suser(p->p_ucred, &p->p_acflag); 58605f0fdd2SPoul-Henning Kamp if (error) 587df8bae1dSRodney W. Grimes return (error); 588df8bae1dSRodney W. Grimes #endif 589df8bae1dSRodney W. Grimes size = round_page((vm_size_t) uap->len); 590df8bae1dSRodney W. Grimes 591df8bae1dSRodney W. Grimes error = vm_map_pageable(&p->p_vmspace->vm_map, addr, addr + size, TRUE); 592df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 593df8bae1dSRodney W. Grimes } 594df8bae1dSRodney W. Grimes 595df8bae1dSRodney W. Grimes /* 596df8bae1dSRodney W. Grimes * Internal version of mmap. 597df8bae1dSRodney W. Grimes * Currently used by mmap, exec, and sys5 shared memory. 598df8bae1dSRodney W. Grimes * Handle is either a vnode pointer or NULL for MAP_ANON. 599df8bae1dSRodney W. Grimes */ 600df8bae1dSRodney W. Grimes int 601df8bae1dSRodney W. Grimes vm_mmap(map, addr, size, prot, maxprot, flags, handle, foff) 602df8bae1dSRodney W. Grimes register vm_map_t map; 603df8bae1dSRodney W. Grimes register vm_offset_t *addr; 604df8bae1dSRodney W. Grimes register vm_size_t size; 605df8bae1dSRodney W. Grimes vm_prot_t prot, maxprot; 606df8bae1dSRodney W. Grimes register int flags; 607df8bae1dSRodney W. Grimes caddr_t handle; /* XXX should be vp */ 608a316d390SJohn Dyson vm_ooffset_t foff; 609df8bae1dSRodney W. Grimes { 610df8bae1dSRodney W. Grimes boolean_t fitit; 611df8bae1dSRodney W. Grimes vm_object_t object; 612df8bae1dSRodney W. Grimes struct vnode *vp = NULL; 61324a1cce3SDavid Greenman objtype_t type; 614df8bae1dSRodney W. Grimes int rv = KERN_SUCCESS; 61506cb7259SDavid Greenman vm_size_t objsize; 61606cb7259SDavid Greenman struct proc *p = curproc; 617df8bae1dSRodney W. Grimes 618df8bae1dSRodney W. Grimes if (size == 0) 619df8bae1dSRodney W. Grimes return (0); 620df8bae1dSRodney W. Grimes 62106cb7259SDavid Greenman objsize = size = round_page(size); 622df8bae1dSRodney W. Grimes 623df8bae1dSRodney W. Grimes /* 624bc9ad247SDavid Greenman * We currently can only deal with page aligned file offsets. 625bc9ad247SDavid Greenman * The check is here rather than in the syscall because the 626bc9ad247SDavid Greenman * kernel calls this function internally for other mmaping 627bc9ad247SDavid Greenman * operations (such as in exec) and non-aligned offsets will 628bc9ad247SDavid Greenman * cause pmap inconsistencies...so we want to be sure to 629bc9ad247SDavid Greenman * disallow this in all cases. 630bc9ad247SDavid Greenman */ 631bc9ad247SDavid Greenman if (foff & PAGE_MASK) 632bc9ad247SDavid Greenman return (EINVAL); 633bc9ad247SDavid Greenman 63406cb7259SDavid Greenman if ((flags & MAP_FIXED) == 0) { 63506cb7259SDavid Greenman fitit = TRUE; 63606cb7259SDavid Greenman *addr = round_page(*addr); 63706cb7259SDavid Greenman } else { 63806cb7259SDavid Greenman if (*addr != trunc_page(*addr)) 63906cb7259SDavid Greenman return (EINVAL); 64006cb7259SDavid Greenman fitit = FALSE; 64106cb7259SDavid Greenman (void) vm_map_remove(map, *addr, *addr + size); 64206cb7259SDavid Greenman } 64306cb7259SDavid Greenman 644bc9ad247SDavid Greenman /* 64524a1cce3SDavid Greenman * Lookup/allocate object. 646df8bae1dSRodney W. Grimes */ 6475f55e841SDavid Greenman if (flags & MAP_ANON) { 64824a1cce3SDavid Greenman type = OBJT_SWAP; 6495f55e841SDavid Greenman /* 6505f55e841SDavid Greenman * Unnamed anonymous regions always start at 0. 6515f55e841SDavid Greenman */ 6525f55e841SDavid Greenman if (handle == 0) 6535f55e841SDavid Greenman foff = 0; 6545f55e841SDavid Greenman } else { 655df8bae1dSRodney W. Grimes vp = (struct vnode *) handle; 656df8bae1dSRodney W. Grimes if (vp->v_type == VCHR) { 65724a1cce3SDavid Greenman type = OBJT_DEVICE; 658df8bae1dSRodney W. Grimes handle = (caddr_t) vp->v_rdev; 65906cb7259SDavid Greenman } else { 66006cb7259SDavid Greenman struct vattr vat; 66106cb7259SDavid Greenman int error; 66206cb7259SDavid Greenman 66306cb7259SDavid Greenman error = VOP_GETATTR(vp, &vat, p->p_ucred, p); 66406cb7259SDavid Greenman if (error) 66506cb7259SDavid Greenman return (error); 66606cb7259SDavid Greenman objsize = vat.va_size; 66724a1cce3SDavid Greenman type = OBJT_VNODE; 668df8bae1dSRodney W. Grimes } 66906cb7259SDavid Greenman } 67024a1cce3SDavid Greenman object = vm_pager_allocate(type, handle, objsize, prot, foff); 67124a1cce3SDavid Greenman if (object == NULL) 67224a1cce3SDavid Greenman return (type == OBJT_DEVICE ? EINVAL : ENOMEM); 673df8bae1dSRodney W. Grimes 6747fb0c17eSDavid Greenman rv = vm_map_find(map, object, foff, addr, size, fitit); 675df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 6767fb0c17eSDavid Greenman /* 67724a1cce3SDavid Greenman * Lose the object reference. Will destroy the 67824a1cce3SDavid Greenman * object if it's an unnamed anonymous mapping 67924a1cce3SDavid Greenman * or named anonymous without other references. 6807fb0c17eSDavid Greenman */ 681df8bae1dSRodney W. Grimes vm_object_deallocate(object); 682df8bae1dSRodney W. Grimes goto out; 683df8bae1dSRodney W. Grimes } 684e17bed12SJohn Dyson 685df8bae1dSRodney W. Grimes /* 68650ce2102SDavid Greenman * mmap a COW regular file 687df8bae1dSRodney W. Grimes */ 688e17bed12SJohn Dyson if ((flags & (MAP_ANON|MAP_SHARED)) == 0 && (type != OBJT_DEVICE)) { 68950ce2102SDavid Greenman vm_map_entry_t entry; 69050ce2102SDavid Greenman if (!vm_map_lookup_entry(map, *addr, &entry)) { 691edf8a815SDavid Greenman panic("vm_mmap: missing map entry!!!"); 69250ce2102SDavid Greenman } 69350ce2102SDavid Greenman entry->copy_on_write = TRUE; 694e17bed12SJohn Dyson /* 695e17bed12SJohn Dyson * This will create the processes private object on 696e17bed12SJohn Dyson * an as needed basis. 697e17bed12SJohn Dyson */ 698e17bed12SJohn Dyson entry->needs_copy = TRUE; 69950ce2102SDavid Greenman 70050ce2102SDavid Greenman /* 70150ce2102SDavid Greenman * set pages COW and protect for read access only 70250ce2102SDavid Greenman */ 70350ce2102SDavid Greenman vm_object_pmap_copy(object, foff, foff + size); 70450ce2102SDavid Greenman 705df8bae1dSRodney W. Grimes } 7067fb0c17eSDavid Greenman 7077fb0c17eSDavid Greenman /* 7087fb0c17eSDavid Greenman * "Pre-fault" resident pages. 7097fb0c17eSDavid Greenman */ 71024a1cce3SDavid Greenman if ((type == OBJT_VNODE) && (map->pmap != NULL)) { 711a316d390SJohn Dyson pmap_object_init_pt(map->pmap, *addr, 712a316d390SJohn Dyson object, (vm_pindex_t) OFF_TO_IDX(foff), size); 713df8bae1dSRodney W. Grimes } 7147fb0c17eSDavid Greenman 715df8bae1dSRodney W. Grimes /* 7160d94caffSDavid Greenman * Correct protection (default is VM_PROT_ALL). If maxprot is 7170d94caffSDavid Greenman * different than prot, we must set both explicitly. 718df8bae1dSRodney W. Grimes */ 719df8bae1dSRodney W. Grimes rv = KERN_SUCCESS; 720df8bae1dSRodney W. Grimes if (maxprot != VM_PROT_ALL) 721df8bae1dSRodney W. Grimes rv = vm_map_protect(map, *addr, *addr + size, maxprot, TRUE); 722df8bae1dSRodney W. Grimes if (rv == KERN_SUCCESS && prot != maxprot) 723df8bae1dSRodney W. Grimes rv = vm_map_protect(map, *addr, *addr + size, prot, FALSE); 724df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 7257fb0c17eSDavid Greenman (void) vm_map_remove(map, *addr, *addr + size); 726df8bae1dSRodney W. Grimes goto out; 727df8bae1dSRodney W. Grimes } 728df8bae1dSRodney W. Grimes /* 729df8bae1dSRodney W. Grimes * Shared memory is also shared with children. 730df8bae1dSRodney W. Grimes */ 731df8bae1dSRodney W. Grimes if (flags & MAP_SHARED) { 732df8bae1dSRodney W. Grimes rv = vm_map_inherit(map, *addr, *addr + size, VM_INHERIT_SHARE); 733df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 7347fb0c17eSDavid Greenman (void) vm_map_remove(map, *addr, *addr + size); 735df8bae1dSRodney W. Grimes goto out; 736df8bae1dSRodney W. Grimes } 737df8bae1dSRodney W. Grimes } 738df8bae1dSRodney W. Grimes out: 739df8bae1dSRodney W. Grimes switch (rv) { 740df8bae1dSRodney W. Grimes case KERN_SUCCESS: 741df8bae1dSRodney W. Grimes return (0); 742df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 743df8bae1dSRodney W. Grimes case KERN_NO_SPACE: 744df8bae1dSRodney W. Grimes return (ENOMEM); 745df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 746df8bae1dSRodney W. Grimes return (EACCES); 747df8bae1dSRodney W. Grimes default: 748df8bae1dSRodney W. Grimes return (EINVAL); 749df8bae1dSRodney W. Grimes } 750df8bae1dSRodney W. Grimes } 751