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 411e62bc63SDavid Greenman * $Id: vm_mmap.c,v 1.19 1995/03/25 16:55:46 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> 50df8bae1dSRodney W. Grimes #include <sys/filedesc.h> 51df8bae1dSRodney W. Grimes #include <sys/resourcevar.h> 52df8bae1dSRodney W. Grimes #include <sys/proc.h> 53df8bae1dSRodney W. Grimes #include <sys/vnode.h> 54df8bae1dSRodney W. Grimes #include <sys/file.h> 55df8bae1dSRodney W. Grimes #include <sys/mman.h> 56df8bae1dSRodney W. Grimes #include <sys/conf.h> 57df8bae1dSRodney W. Grimes 58df8bae1dSRodney W. Grimes #include <miscfs/specfs/specdev.h> 59df8bae1dSRodney W. Grimes 60df8bae1dSRodney W. Grimes #include <vm/vm.h> 61df8bae1dSRodney W. Grimes #include <vm/vm_pager.h> 62b5e8ce9fSBruce Evans #include <vm/vm_pageout.h> 63df8bae1dSRodney W. Grimes #include <vm/vm_prot.h> 64df8bae1dSRodney W. Grimes 65df8bae1dSRodney W. Grimes #ifdef DEBUG 66df8bae1dSRodney W. Grimes int mmapdebug = 0; 670d94caffSDavid Greenman 68df8bae1dSRodney W. Grimes #define MDB_FOLLOW 0x01 69df8bae1dSRodney W. Grimes #define MDB_SYNC 0x02 70df8bae1dSRodney W. Grimes #define MDB_MAPIT 0x04 71df8bae1dSRodney W. Grimes #endif 72df8bae1dSRodney W. Grimes 73f720dc2cSDavid Greenman void pmap_object_init_pt(); 74f720dc2cSDavid Greenman 75df8bae1dSRodney W. Grimes struct sbrk_args { 76df8bae1dSRodney W. Grimes int incr; 77df8bae1dSRodney W. Grimes }; 780d94caffSDavid Greenman 79df8bae1dSRodney W. Grimes /* ARGSUSED */ 80df8bae1dSRodney W. Grimes int 81df8bae1dSRodney W. Grimes sbrk(p, uap, retval) 82df8bae1dSRodney W. Grimes struct proc *p; 83df8bae1dSRodney W. Grimes struct sbrk_args *uap; 84df8bae1dSRodney W. Grimes int *retval; 85df8bae1dSRodney W. Grimes { 86df8bae1dSRodney W. Grimes 87df8bae1dSRodney W. Grimes /* Not yet implemented */ 88df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 89df8bae1dSRodney W. Grimes } 90df8bae1dSRodney W. Grimes 91df8bae1dSRodney W. Grimes struct sstk_args { 92df8bae1dSRodney W. Grimes int incr; 93df8bae1dSRodney W. Grimes }; 940d94caffSDavid Greenman 95df8bae1dSRodney W. Grimes /* ARGSUSED */ 96df8bae1dSRodney W. Grimes int 97df8bae1dSRodney W. Grimes sstk(p, uap, retval) 98df8bae1dSRodney W. Grimes struct proc *p; 99df8bae1dSRodney W. Grimes struct sstk_args *uap; 100df8bae1dSRodney W. Grimes int *retval; 101df8bae1dSRodney W. Grimes { 102df8bae1dSRodney W. Grimes 103df8bae1dSRodney W. Grimes /* Not yet implemented */ 104df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 105df8bae1dSRodney W. Grimes } 106df8bae1dSRodney W. Grimes 107df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 108df8bae1dSRodney W. Grimes struct getpagesize_args { 109df8bae1dSRodney W. Grimes int dummy; 110df8bae1dSRodney W. Grimes }; 1110d94caffSDavid Greenman 112df8bae1dSRodney W. Grimes /* ARGSUSED */ 113df8bae1dSRodney W. Grimes int 114df8bae1dSRodney W. Grimes ogetpagesize(p, uap, retval) 115df8bae1dSRodney W. Grimes struct proc *p; 116df8bae1dSRodney W. Grimes struct getpagesize_args *uap; 117df8bae1dSRodney W. Grimes int *retval; 118df8bae1dSRodney W. Grimes { 119df8bae1dSRodney W. Grimes 120df8bae1dSRodney W. Grimes *retval = PAGE_SIZE; 121df8bae1dSRodney W. Grimes return (0); 122df8bae1dSRodney W. Grimes } 123df8bae1dSRodney W. Grimes #endif /* COMPAT_43 || COMPAT_SUNOS */ 124df8bae1dSRodney W. Grimes 125df8bae1dSRodney W. Grimes struct mmap_args { 126df8bae1dSRodney W. Grimes caddr_t addr; 127df8bae1dSRodney W. Grimes size_t len; 128df8bae1dSRodney W. Grimes int prot; 129df8bae1dSRodney W. Grimes int flags; 130df8bae1dSRodney W. Grimes int fd; 131df8bae1dSRodney W. Grimes long pad; 132df8bae1dSRodney W. Grimes off_t pos; 133df8bae1dSRodney W. Grimes }; 134df8bae1dSRodney W. Grimes 135df8bae1dSRodney W. Grimes int 136df8bae1dSRodney W. Grimes mmap(p, uap, retval) 137df8bae1dSRodney W. Grimes struct proc *p; 138df8bae1dSRodney W. Grimes register struct mmap_args *uap; 139df8bae1dSRodney W. Grimes int *retval; 140df8bae1dSRodney W. Grimes { 141df8bae1dSRodney W. Grimes register struct filedesc *fdp = p->p_fd; 142df8bae1dSRodney W. Grimes register struct file *fp; 143df8bae1dSRodney W. Grimes struct vnode *vp; 144df8bae1dSRodney W. Grimes vm_offset_t addr; 145df8bae1dSRodney W. Grimes vm_size_t size; 146df8bae1dSRodney W. Grimes vm_prot_t prot, maxprot; 147df8bae1dSRodney W. Grimes caddr_t handle; 148df8bae1dSRodney W. Grimes int flags, error; 149df8bae1dSRodney W. Grimes 150df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 151df8bae1dSRodney W. Grimes flags = uap->flags; 152df8bae1dSRodney W. Grimes #ifdef DEBUG 153df8bae1dSRodney W. Grimes if (mmapdebug & MDB_FOLLOW) 154df8bae1dSRodney W. Grimes printf("mmap(%d): addr %x len %x pro %x flg %x fd %d pos %x\n", 155df8bae1dSRodney W. Grimes p->p_pid, uap->addr, uap->len, prot, 156df8bae1dSRodney W. Grimes flags, uap->fd, (vm_offset_t) uap->pos); 157df8bae1dSRodney W. Grimes #endif 158df8bae1dSRodney W. Grimes /* 1590d94caffSDavid Greenman * Address (if FIXED) must be page aligned. Size is implicitly rounded 1600d94caffSDavid Greenman * to a page boundary. 161df8bae1dSRodney W. Grimes */ 162df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 163df8bae1dSRodney W. Grimes if (((flags & MAP_FIXED) && (addr & PAGE_MASK)) || 164df8bae1dSRodney W. Grimes (ssize_t) uap->len < 0 || ((flags & MAP_ANON) && uap->fd != -1)) 165df8bae1dSRodney W. Grimes return (EINVAL); 166df8bae1dSRodney W. Grimes size = (vm_size_t) round_page(uap->len); 167df8bae1dSRodney W. Grimes /* 1680d94caffSDavid Greenman * Check for illegal addresses. Watch out for address wrap... Note 1690d94caffSDavid Greenman * that VM_*_ADDRESS are not constants due to casts (argh). 170df8bae1dSRodney W. Grimes */ 171df8bae1dSRodney W. Grimes if (flags & MAP_FIXED) { 172bbc0ec52SDavid Greenman if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS) 173df8bae1dSRodney W. Grimes return (EINVAL); 17426f9a767SRodney W. Grimes #ifndef i386 175df8bae1dSRodney W. Grimes if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS) 176df8bae1dSRodney W. Grimes return (EINVAL); 17726f9a767SRodney W. Grimes #endif 178bbc0ec52SDavid Greenman if (addr + size < addr) 179df8bae1dSRodney W. Grimes return (EINVAL); 180df8bae1dSRodney W. Grimes } 181df8bae1dSRodney W. Grimes /* 1820d94caffSDavid Greenman * XXX if no hint provided for a non-fixed mapping place it after the 1830d94caffSDavid Greenman * end of the largest possible heap. 184df8bae1dSRodney W. Grimes * 1850d94caffSDavid Greenman * There should really be a pmap call to determine a reasonable location. 186df8bae1dSRodney W. Grimes */ 187df8bae1dSRodney W. Grimes if (addr == 0 && (flags & MAP_FIXED) == 0) 188df8bae1dSRodney W. Grimes addr = round_page(p->p_vmspace->vm_daddr + MAXDSIZ); 189df8bae1dSRodney W. Grimes if (flags & MAP_ANON) { 190df8bae1dSRodney W. Grimes /* 191df8bae1dSRodney W. Grimes * Mapping blank space is trivial. 192df8bae1dSRodney W. Grimes */ 193df8bae1dSRodney W. Grimes handle = NULL; 194df8bae1dSRodney W. Grimes maxprot = VM_PROT_ALL; 195df8bae1dSRodney W. Grimes } else { 196df8bae1dSRodney W. Grimes /* 1970d94caffSDavid Greenman * Mapping file, get fp for validation. Obtain vnode and make 1980d94caffSDavid Greenman * sure it is of appropriate type. 199df8bae1dSRodney W. Grimes */ 200df8bae1dSRodney W. Grimes if (((unsigned) uap->fd) >= fdp->fd_nfiles || 201df8bae1dSRodney W. Grimes (fp = fdp->fd_ofiles[uap->fd]) == NULL) 202df8bae1dSRodney W. Grimes return (EBADF); 203df8bae1dSRodney W. Grimes if (fp->f_type != DTYPE_VNODE) 204df8bae1dSRodney W. Grimes return (EINVAL); 205df8bae1dSRodney W. Grimes vp = (struct vnode *) fp->f_data; 206df8bae1dSRodney W. Grimes if (vp->v_type != VREG && vp->v_type != VCHR) 207df8bae1dSRodney W. Grimes return (EINVAL); 208df8bae1dSRodney W. Grimes /* 2090d94caffSDavid Greenman * XXX hack to handle use of /dev/zero to map anon memory (ala 2100d94caffSDavid Greenman * SunOS). 211df8bae1dSRodney W. Grimes */ 212df8bae1dSRodney W. Grimes if (vp->v_type == VCHR && iszerodev(vp->v_rdev)) { 213df8bae1dSRodney W. Grimes handle = NULL; 214df8bae1dSRodney W. Grimes maxprot = VM_PROT_ALL; 215df8bae1dSRodney W. Grimes flags |= MAP_ANON; 216df8bae1dSRodney W. Grimes } else { 217df8bae1dSRodney W. Grimes /* 218df8bae1dSRodney W. Grimes * Ensure that file and memory protections are 219df8bae1dSRodney W. Grimes * compatible. Note that we only worry about 220df8bae1dSRodney W. Grimes * writability if mapping is shared; in this case, 221df8bae1dSRodney W. Grimes * current and max prot are dictated by the open file. 222df8bae1dSRodney W. Grimes * XXX use the vnode instead? Problem is: what 2230d94caffSDavid Greenman * credentials do we use for determination? What if 2240d94caffSDavid Greenman * proc does a setuid? 225df8bae1dSRodney W. Grimes */ 226df8bae1dSRodney W. Grimes maxprot = VM_PROT_EXECUTE; /* ??? */ 227df8bae1dSRodney W. Grimes if (fp->f_flag & FREAD) 228df8bae1dSRodney W. Grimes maxprot |= VM_PROT_READ; 229df8bae1dSRodney W. Grimes else if (prot & PROT_READ) 230df8bae1dSRodney W. Grimes return (EACCES); 231df8bae1dSRodney W. Grimes if (flags & MAP_SHARED) { 232df8bae1dSRodney W. Grimes if (fp->f_flag & FWRITE) 233df8bae1dSRodney W. Grimes maxprot |= VM_PROT_WRITE; 234df8bae1dSRodney W. Grimes else if (prot & PROT_WRITE) 235df8bae1dSRodney W. Grimes return (EACCES); 236df8bae1dSRodney W. Grimes } else 237df8bae1dSRodney W. Grimes maxprot |= VM_PROT_WRITE; 238df8bae1dSRodney W. Grimes handle = (caddr_t) vp; 239df8bae1dSRodney W. Grimes } 240df8bae1dSRodney W. Grimes } 241df8bae1dSRodney W. Grimes error = vm_mmap(&p->p_vmspace->vm_map, &addr, size, prot, maxprot, 242df8bae1dSRodney W. Grimes flags, handle, (vm_offset_t) uap->pos); 243df8bae1dSRodney W. Grimes if (error == 0) 244df8bae1dSRodney W. Grimes *retval = (int) addr; 245df8bae1dSRodney W. Grimes return (error); 246df8bae1dSRodney W. Grimes } 247df8bae1dSRodney W. Grimes 24805f0fdd2SPoul-Henning Kamp #ifdef COMPAT_43 24905f0fdd2SPoul-Henning Kamp struct ommap_args { 25005f0fdd2SPoul-Henning Kamp caddr_t addr; 25105f0fdd2SPoul-Henning Kamp int len; 25205f0fdd2SPoul-Henning Kamp int prot; 25305f0fdd2SPoul-Henning Kamp int flags; 25405f0fdd2SPoul-Henning Kamp int fd; 25505f0fdd2SPoul-Henning Kamp long pos; 25605f0fdd2SPoul-Henning Kamp }; 25705f0fdd2SPoul-Henning Kamp int 25805f0fdd2SPoul-Henning Kamp ommap(p, uap, retval) 25905f0fdd2SPoul-Henning Kamp struct proc *p; 26005f0fdd2SPoul-Henning Kamp register struct ommap_args *uap; 26105f0fdd2SPoul-Henning Kamp int *retval; 26205f0fdd2SPoul-Henning Kamp { 26305f0fdd2SPoul-Henning Kamp struct mmap_args nargs; 26405f0fdd2SPoul-Henning Kamp static const char cvtbsdprot[8] = { 26505f0fdd2SPoul-Henning Kamp 0, 26605f0fdd2SPoul-Henning Kamp PROT_EXEC, 26705f0fdd2SPoul-Henning Kamp PROT_WRITE, 26805f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE, 26905f0fdd2SPoul-Henning Kamp PROT_READ, 27005f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_READ, 27105f0fdd2SPoul-Henning Kamp PROT_WRITE | PROT_READ, 27205f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE | PROT_READ, 27305f0fdd2SPoul-Henning Kamp }; 2740d94caffSDavid Greenman 27505f0fdd2SPoul-Henning Kamp #define OMAP_ANON 0x0002 27605f0fdd2SPoul-Henning Kamp #define OMAP_COPY 0x0020 27705f0fdd2SPoul-Henning Kamp #define OMAP_SHARED 0x0010 27805f0fdd2SPoul-Henning Kamp #define OMAP_FIXED 0x0100 27905f0fdd2SPoul-Henning Kamp #define OMAP_INHERIT 0x0800 28005f0fdd2SPoul-Henning Kamp 28105f0fdd2SPoul-Henning Kamp nargs.addr = uap->addr; 28205f0fdd2SPoul-Henning Kamp nargs.len = uap->len; 28305f0fdd2SPoul-Henning Kamp nargs.prot = cvtbsdprot[uap->prot & 0x7]; 28405f0fdd2SPoul-Henning Kamp nargs.flags = 0; 28505f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_ANON) 28605f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_ANON; 28705f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_COPY) 28805f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_COPY; 28905f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_SHARED) 29005f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_SHARED; 29105f0fdd2SPoul-Henning Kamp else 29205f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_PRIVATE; 29305f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_FIXED) 29405f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_FIXED; 29505f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_INHERIT) 29605f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_INHERIT; 29705f0fdd2SPoul-Henning Kamp nargs.fd = uap->fd; 29805f0fdd2SPoul-Henning Kamp nargs.pos = uap->pos; 29905f0fdd2SPoul-Henning Kamp return (mmap(p, &nargs, retval)); 30005f0fdd2SPoul-Henning Kamp } 30105f0fdd2SPoul-Henning Kamp #endif /* COMPAT_43 */ 30205f0fdd2SPoul-Henning Kamp 30305f0fdd2SPoul-Henning Kamp 304df8bae1dSRodney W. Grimes struct msync_args { 305df8bae1dSRodney W. Grimes caddr_t addr; 306df8bae1dSRodney W. Grimes int len; 307e6c6af11SDavid Greenman int flags; 308df8bae1dSRodney W. Grimes }; 309df8bae1dSRodney W. Grimes int 310df8bae1dSRodney W. Grimes msync(p, uap, retval) 311df8bae1dSRodney W. Grimes struct proc *p; 312df8bae1dSRodney W. Grimes struct msync_args *uap; 313df8bae1dSRodney W. Grimes int *retval; 314df8bae1dSRodney W. Grimes { 315df8bae1dSRodney W. Grimes vm_offset_t addr; 316df8bae1dSRodney W. Grimes vm_size_t size; 317e6c6af11SDavid Greenman int flags; 318df8bae1dSRodney W. Grimes vm_map_t map; 319df8bae1dSRodney W. Grimes int rv; 320df8bae1dSRodney W. Grimes 321df8bae1dSRodney W. Grimes #ifdef DEBUG 322df8bae1dSRodney W. Grimes if (mmapdebug & (MDB_FOLLOW | MDB_SYNC)) 323df8bae1dSRodney W. Grimes printf("msync(%d): addr %x len %x\n", 324df8bae1dSRodney W. Grimes p->p_pid, uap->addr, uap->len); 325df8bae1dSRodney W. Grimes #endif 3261e62bc63SDavid Greenman 327df8bae1dSRodney W. Grimes map = &p->p_vmspace->vm_map; 328df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 329df8bae1dSRodney W. Grimes size = (vm_size_t) uap->len; 330e6c6af11SDavid Greenman flags = uap->flags; 331e6c6af11SDavid Greenman 3321e62bc63SDavid Greenman if (((int) addr & PAGE_MASK) || addr + size < addr || 3331e62bc63SDavid Greenman (flags & (MS_ASYNC|MS_INVALIDATE)) == (MS_ASYNC|MS_INVALIDATE)) 3341e62bc63SDavid Greenman return (EINVAL); 3351e62bc63SDavid Greenman 336df8bae1dSRodney W. Grimes /* 337df8bae1dSRodney W. Grimes * XXX Gak! If size is zero we are supposed to sync "all modified 3380d94caffSDavid Greenman * pages with the region containing addr". Unfortunately, we don't 3390d94caffSDavid Greenman * really keep track of individual mmaps so we approximate by flushing 3400d94caffSDavid Greenman * the range of the map entry containing addr. This can be incorrect 3410d94caffSDavid Greenman * if the region splits or is coalesced with a neighbor. 342df8bae1dSRodney W. Grimes */ 343df8bae1dSRodney W. Grimes if (size == 0) { 344df8bae1dSRodney W. Grimes vm_map_entry_t entry; 345df8bae1dSRodney W. Grimes 346df8bae1dSRodney W. Grimes vm_map_lock_read(map); 347df8bae1dSRodney W. Grimes rv = vm_map_lookup_entry(map, addr, &entry); 348df8bae1dSRodney W. Grimes vm_map_unlock_read(map); 349fbcfcdf7SDavid Greenman if (rv == FALSE) 350df8bae1dSRodney W. Grimes return (EINVAL); 351df8bae1dSRodney W. Grimes addr = entry->start; 352df8bae1dSRodney W. Grimes size = entry->end - entry->start; 353df8bae1dSRodney W. Grimes } 354e6c6af11SDavid Greenman 355df8bae1dSRodney W. Grimes #ifdef DEBUG 356df8bae1dSRodney W. Grimes if (mmapdebug & MDB_SYNC) 357df8bae1dSRodney W. Grimes printf("msync: cleaning/flushing address range [%x-%x)\n", 358df8bae1dSRodney W. Grimes addr, addr + size); 359df8bae1dSRodney W. Grimes #endif 360e6c6af11SDavid Greenman 361df8bae1dSRodney W. Grimes /* 362df8bae1dSRodney W. Grimes * Clean the pages and interpret the return value. 363df8bae1dSRodney W. Grimes */ 364e6c6af11SDavid Greenman rv = vm_map_clean(map, addr, addr + size, (flags & MS_ASYNC) != 0, 365e6c6af11SDavid Greenman (flags & MS_INVALIDATE) != 0); 366e6c6af11SDavid Greenman 367df8bae1dSRodney W. Grimes switch (rv) { 368df8bae1dSRodney W. Grimes case KERN_SUCCESS: 369df8bae1dSRodney W. Grimes break; 370df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 371df8bae1dSRodney W. Grimes return (EINVAL); /* Sun returns ENOMEM? */ 372df8bae1dSRodney W. Grimes case KERN_FAILURE: 373df8bae1dSRodney W. Grimes return (EIO); 374df8bae1dSRodney W. Grimes default: 375df8bae1dSRodney W. Grimes return (EINVAL); 376df8bae1dSRodney W. Grimes } 377e6c6af11SDavid Greenman 378df8bae1dSRodney W. Grimes return (0); 379df8bae1dSRodney W. Grimes } 380df8bae1dSRodney W. Grimes 381df8bae1dSRodney W. Grimes struct munmap_args { 382df8bae1dSRodney W. Grimes caddr_t addr; 383df8bae1dSRodney W. Grimes int len; 384df8bae1dSRodney W. Grimes }; 385df8bae1dSRodney W. Grimes int 386df8bae1dSRodney W. Grimes munmap(p, uap, retval) 387df8bae1dSRodney W. Grimes register struct proc *p; 388df8bae1dSRodney W. Grimes register struct munmap_args *uap; 389df8bae1dSRodney W. Grimes int *retval; 390df8bae1dSRodney W. Grimes { 391df8bae1dSRodney W. Grimes vm_offset_t addr; 392df8bae1dSRodney W. Grimes vm_size_t size; 393df8bae1dSRodney W. Grimes vm_map_t map; 394df8bae1dSRodney W. Grimes 395df8bae1dSRodney W. Grimes #ifdef DEBUG 396df8bae1dSRodney W. Grimes if (mmapdebug & MDB_FOLLOW) 397df8bae1dSRodney W. Grimes printf("munmap(%d): addr %x len %x\n", 398df8bae1dSRodney W. Grimes p->p_pid, uap->addr, uap->len); 399df8bae1dSRodney W. Grimes #endif 400df8bae1dSRodney W. Grimes 401df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 402df8bae1dSRodney W. Grimes if ((addr & PAGE_MASK) || uap->len < 0) 403df8bae1dSRodney W. Grimes return (EINVAL); 404df8bae1dSRodney W. Grimes size = (vm_size_t) round_page(uap->len); 405df8bae1dSRodney W. Grimes if (size == 0) 406df8bae1dSRodney W. Grimes return (0); 407df8bae1dSRodney W. Grimes /* 4080d94caffSDavid Greenman * Check for illegal addresses. Watch out for address wrap... Note 4090d94caffSDavid Greenman * that VM_*_ADDRESS are not constants due to casts (argh). 410df8bae1dSRodney W. Grimes */ 411bbc0ec52SDavid Greenman if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS) 412df8bae1dSRodney W. Grimes return (EINVAL); 41326f9a767SRodney W. Grimes #ifndef i386 414df8bae1dSRodney W. Grimes if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS) 415df8bae1dSRodney W. Grimes return (EINVAL); 41626f9a767SRodney W. Grimes #endif 417bbc0ec52SDavid Greenman if (addr + size < addr) 418df8bae1dSRodney W. Grimes return (EINVAL); 419df8bae1dSRodney W. Grimes map = &p->p_vmspace->vm_map; 420df8bae1dSRodney W. Grimes /* 421df8bae1dSRodney W. Grimes * Make sure entire range is allocated. 422df8bae1dSRodney W. Grimes */ 423df8bae1dSRodney W. Grimes if (!vm_map_check_protection(map, addr, addr + size, VM_PROT_NONE)) 424df8bae1dSRodney W. Grimes return (EINVAL); 425df8bae1dSRodney W. Grimes /* returns nothing but KERN_SUCCESS anyway */ 426df8bae1dSRodney W. Grimes (void) vm_map_remove(map, addr, addr + size); 427df8bae1dSRodney W. Grimes return (0); 428df8bae1dSRodney W. Grimes } 429df8bae1dSRodney W. Grimes 430df8bae1dSRodney W. Grimes void 43190324b07SDavid Greenman munmapfd(p, fd) 43290324b07SDavid Greenman struct proc *p; 433df8bae1dSRodney W. Grimes int fd; 434df8bae1dSRodney W. Grimes { 435df8bae1dSRodney W. Grimes #ifdef DEBUG 436df8bae1dSRodney W. Grimes if (mmapdebug & MDB_FOLLOW) 43790324b07SDavid Greenman printf("munmapfd(%d): fd %d\n", p->p_pid, fd); 438df8bae1dSRodney W. Grimes #endif 439df8bae1dSRodney W. Grimes 440df8bae1dSRodney W. Grimes /* 441c4ed5a07SDavid Greenman * XXX should unmap any regions mapped to this file 442df8bae1dSRodney W. Grimes */ 44390324b07SDavid Greenman p->p_fd->fd_ofileflags[fd] &= ~UF_MAPPED; 444df8bae1dSRodney W. Grimes } 445df8bae1dSRodney W. Grimes 446df8bae1dSRodney W. Grimes struct mprotect_args { 447df8bae1dSRodney W. Grimes caddr_t addr; 448df8bae1dSRodney W. Grimes int len; 449df8bae1dSRodney W. Grimes int prot; 450df8bae1dSRodney W. Grimes }; 451df8bae1dSRodney W. Grimes int 452df8bae1dSRodney W. Grimes mprotect(p, uap, retval) 453df8bae1dSRodney W. Grimes struct proc *p; 454df8bae1dSRodney W. Grimes struct mprotect_args *uap; 455df8bae1dSRodney W. Grimes int *retval; 456df8bae1dSRodney W. Grimes { 457df8bae1dSRodney W. Grimes vm_offset_t addr; 458df8bae1dSRodney W. Grimes vm_size_t size; 459df8bae1dSRodney W. Grimes register vm_prot_t prot; 460df8bae1dSRodney W. Grimes 461df8bae1dSRodney W. Grimes #ifdef DEBUG 462df8bae1dSRodney W. Grimes if (mmapdebug & MDB_FOLLOW) 463df8bae1dSRodney W. Grimes printf("mprotect(%d): addr %x len %x prot %d\n", 464df8bae1dSRodney W. Grimes p->p_pid, uap->addr, uap->len, uap->prot); 465df8bae1dSRodney W. Grimes #endif 466df8bae1dSRodney W. Grimes 467df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 468df8bae1dSRodney W. Grimes if ((addr & PAGE_MASK) || uap->len < 0) 469df8bae1dSRodney W. Grimes return (EINVAL); 470df8bae1dSRodney W. Grimes size = (vm_size_t) uap->len; 471df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 472df8bae1dSRodney W. Grimes 473df8bae1dSRodney W. Grimes switch (vm_map_protect(&p->p_vmspace->vm_map, addr, addr + size, prot, 474df8bae1dSRodney W. Grimes FALSE)) { 475df8bae1dSRodney W. Grimes case KERN_SUCCESS: 476df8bae1dSRodney W. Grimes return (0); 477df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 478df8bae1dSRodney W. Grimes return (EACCES); 479df8bae1dSRodney W. Grimes } 480df8bae1dSRodney W. Grimes return (EINVAL); 481df8bae1dSRodney W. Grimes } 482df8bae1dSRodney W. Grimes 483df8bae1dSRodney W. Grimes struct madvise_args { 484df8bae1dSRodney W. Grimes caddr_t addr; 485df8bae1dSRodney W. Grimes int len; 486df8bae1dSRodney W. Grimes int behav; 487df8bae1dSRodney W. Grimes }; 4880d94caffSDavid Greenman 489df8bae1dSRodney W. Grimes /* ARGSUSED */ 490df8bae1dSRodney W. Grimes int 491df8bae1dSRodney W. Grimes madvise(p, uap, retval) 492df8bae1dSRodney W. Grimes struct proc *p; 493df8bae1dSRodney W. Grimes struct madvise_args *uap; 494df8bae1dSRodney W. Grimes int *retval; 495df8bae1dSRodney W. Grimes { 496df8bae1dSRodney W. Grimes 497df8bae1dSRodney W. Grimes /* Not yet implemented */ 498df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 499df8bae1dSRodney W. Grimes } 500df8bae1dSRodney W. Grimes 501df8bae1dSRodney W. Grimes struct mincore_args { 502df8bae1dSRodney W. Grimes caddr_t addr; 503df8bae1dSRodney W. Grimes int len; 504df8bae1dSRodney W. Grimes char *vec; 505df8bae1dSRodney W. Grimes }; 5060d94caffSDavid Greenman 507df8bae1dSRodney W. Grimes /* ARGSUSED */ 508df8bae1dSRodney W. Grimes int 509df8bae1dSRodney W. Grimes mincore(p, uap, retval) 510df8bae1dSRodney W. Grimes struct proc *p; 511df8bae1dSRodney W. Grimes struct mincore_args *uap; 512df8bae1dSRodney W. Grimes int *retval; 513df8bae1dSRodney W. Grimes { 514df8bae1dSRodney W. Grimes 515df8bae1dSRodney W. Grimes /* Not yet implemented */ 516df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 517df8bae1dSRodney W. Grimes } 518df8bae1dSRodney W. Grimes 519df8bae1dSRodney W. Grimes struct mlock_args { 520df8bae1dSRodney W. Grimes caddr_t addr; 521df8bae1dSRodney W. Grimes size_t len; 522df8bae1dSRodney W. Grimes }; 523df8bae1dSRodney W. Grimes int 524df8bae1dSRodney W. Grimes mlock(p, uap, retval) 525df8bae1dSRodney W. Grimes struct proc *p; 526df8bae1dSRodney W. Grimes struct mlock_args *uap; 527df8bae1dSRodney W. Grimes int *retval; 528df8bae1dSRodney W. Grimes { 529df8bae1dSRodney W. Grimes vm_offset_t addr; 530df8bae1dSRodney W. Grimes vm_size_t size; 531df8bae1dSRodney W. Grimes int error; 532df8bae1dSRodney W. Grimes 533df8bae1dSRodney W. Grimes #ifdef DEBUG 534df8bae1dSRodney W. Grimes if (mmapdebug & MDB_FOLLOW) 535df8bae1dSRodney W. Grimes printf("mlock(%d): addr %x len %x\n", 536df8bae1dSRodney W. Grimes p->p_pid, uap->addr, uap->len); 537df8bae1dSRodney W. Grimes #endif 538df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 539df8bae1dSRodney W. Grimes if ((addr & PAGE_MASK) || uap->addr + uap->len < uap->addr) 540df8bae1dSRodney W. Grimes return (EINVAL); 541df8bae1dSRodney W. Grimes size = round_page((vm_size_t) uap->len); 542df8bae1dSRodney W. Grimes if (atop(size) + cnt.v_wire_count > vm_page_max_wired) 543df8bae1dSRodney W. Grimes return (EAGAIN); 544df8bae1dSRodney W. Grimes #ifdef pmap_wired_count 545df8bae1dSRodney W. Grimes if (size + ptoa(pmap_wired_count(vm_map_pmap(&p->p_vmspace->vm_map))) > 546df8bae1dSRodney W. Grimes p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur) 547df8bae1dSRodney W. Grimes return (EAGAIN); 548df8bae1dSRodney W. Grimes #else 54905f0fdd2SPoul-Henning Kamp error = suser(p->p_ucred, &p->p_acflag); 55005f0fdd2SPoul-Henning Kamp if (error) 551df8bae1dSRodney W. Grimes return (error); 552df8bae1dSRodney W. Grimes #endif 553df8bae1dSRodney W. Grimes 554df8bae1dSRodney W. Grimes error = vm_map_pageable(&p->p_vmspace->vm_map, addr, addr + size, FALSE); 555df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 556df8bae1dSRodney W. Grimes } 557df8bae1dSRodney W. Grimes 558df8bae1dSRodney W. Grimes struct munlock_args { 559df8bae1dSRodney W. Grimes caddr_t addr; 560df8bae1dSRodney W. Grimes size_t len; 561df8bae1dSRodney W. Grimes }; 562df8bae1dSRodney W. Grimes int 563df8bae1dSRodney W. Grimes munlock(p, uap, retval) 564df8bae1dSRodney W. Grimes struct proc *p; 565df8bae1dSRodney W. Grimes struct munlock_args *uap; 566df8bae1dSRodney W. Grimes int *retval; 567df8bae1dSRodney W. Grimes { 568df8bae1dSRodney W. Grimes vm_offset_t addr; 569df8bae1dSRodney W. Grimes vm_size_t size; 570df8bae1dSRodney W. Grimes int error; 571df8bae1dSRodney W. Grimes 572df8bae1dSRodney W. Grimes #ifdef DEBUG 573df8bae1dSRodney W. Grimes if (mmapdebug & MDB_FOLLOW) 574df8bae1dSRodney W. Grimes printf("munlock(%d): addr %x len %x\n", 575df8bae1dSRodney W. Grimes p->p_pid, uap->addr, uap->len); 576df8bae1dSRodney W. Grimes #endif 577df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 578df8bae1dSRodney W. Grimes if ((addr & PAGE_MASK) || uap->addr + uap->len < uap->addr) 579df8bae1dSRodney W. Grimes return (EINVAL); 580df8bae1dSRodney W. Grimes #ifndef pmap_wired_count 58105f0fdd2SPoul-Henning Kamp error = suser(p->p_ucred, &p->p_acflag); 58205f0fdd2SPoul-Henning Kamp if (error) 583df8bae1dSRodney W. Grimes return (error); 584df8bae1dSRodney W. Grimes #endif 585df8bae1dSRodney W. Grimes size = round_page((vm_size_t) uap->len); 586df8bae1dSRodney W. Grimes 587df8bae1dSRodney W. Grimes error = vm_map_pageable(&p->p_vmspace->vm_map, addr, addr + size, TRUE); 588df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 589df8bae1dSRodney W. Grimes } 590df8bae1dSRodney W. Grimes 591df8bae1dSRodney W. Grimes /* 592df8bae1dSRodney W. Grimes * Internal version of mmap. 593df8bae1dSRodney W. Grimes * Currently used by mmap, exec, and sys5 shared memory. 594df8bae1dSRodney W. Grimes * Handle is either a vnode pointer or NULL for MAP_ANON. 595df8bae1dSRodney W. Grimes */ 596df8bae1dSRodney W. Grimes int 597df8bae1dSRodney W. Grimes vm_mmap(map, addr, size, prot, maxprot, flags, handle, foff) 598df8bae1dSRodney W. Grimes register vm_map_t map; 599df8bae1dSRodney W. Grimes register vm_offset_t *addr; 600df8bae1dSRodney W. Grimes register vm_size_t size; 601df8bae1dSRodney W. Grimes vm_prot_t prot, maxprot; 602df8bae1dSRodney W. Grimes register int flags; 603df8bae1dSRodney W. Grimes caddr_t handle; /* XXX should be vp */ 604df8bae1dSRodney W. Grimes vm_offset_t foff; 605df8bae1dSRodney W. Grimes { 606df8bae1dSRodney W. Grimes register vm_pager_t pager; 607df8bae1dSRodney W. Grimes boolean_t fitit; 608df8bae1dSRodney W. Grimes vm_object_t object; 609df8bae1dSRodney W. Grimes struct vnode *vp = NULL; 610df8bae1dSRodney W. Grimes int type; 611df8bae1dSRodney W. Grimes int rv = KERN_SUCCESS; 612df8bae1dSRodney W. Grimes 613df8bae1dSRodney W. Grimes if (size == 0) 614df8bae1dSRodney W. Grimes return (0); 615df8bae1dSRodney W. Grimes 6167fb0c17eSDavid Greenman size = round_page(size); 6177fb0c17eSDavid Greenman 618df8bae1dSRodney W. Grimes if ((flags & MAP_FIXED) == 0) { 619df8bae1dSRodney W. Grimes fitit = TRUE; 620df8bae1dSRodney W. Grimes *addr = round_page(*addr); 621df8bae1dSRodney W. Grimes } else { 6227fb0c17eSDavid Greenman if (*addr != trunc_page(*addr)) 6237fb0c17eSDavid Greenman return (EINVAL); 624df8bae1dSRodney W. Grimes fitit = FALSE; 6257fb0c17eSDavid Greenman (void) vm_map_remove(map, *addr, *addr + size); 626df8bae1dSRodney W. Grimes } 627df8bae1dSRodney W. Grimes 628df8bae1dSRodney W. Grimes /* 629bc9ad247SDavid Greenman * We currently can only deal with page aligned file offsets. 630bc9ad247SDavid Greenman * The check is here rather than in the syscall because the 631bc9ad247SDavid Greenman * kernel calls this function internally for other mmaping 632bc9ad247SDavid Greenman * operations (such as in exec) and non-aligned offsets will 633bc9ad247SDavid Greenman * cause pmap inconsistencies...so we want to be sure to 634bc9ad247SDavid Greenman * disallow this in all cases. 635bc9ad247SDavid Greenman */ 636bc9ad247SDavid Greenman if (foff & PAGE_MASK) 637bc9ad247SDavid Greenman return (EINVAL); 638bc9ad247SDavid Greenman 639bc9ad247SDavid Greenman /* 6400d94caffSDavid Greenman * Lookup/allocate pager. All except an unnamed anonymous lookup gain 6410d94caffSDavid Greenman * a reference to ensure continued existance of the object. (XXX the 6420d94caffSDavid Greenman * exception is to appease the pageout daemon) 643df8bae1dSRodney W. Grimes */ 644df8bae1dSRodney W. Grimes if (flags & MAP_ANON) 645df8bae1dSRodney W. Grimes type = PG_DFLT; 646df8bae1dSRodney W. Grimes else { 647df8bae1dSRodney W. Grimes vp = (struct vnode *) handle; 648df8bae1dSRodney W. Grimes if (vp->v_type == VCHR) { 649df8bae1dSRodney W. Grimes type = PG_DEVICE; 650df8bae1dSRodney W. Grimes handle = (caddr_t) vp->v_rdev; 651df8bae1dSRodney W. Grimes } else 652df8bae1dSRodney W. Grimes type = PG_VNODE; 653df8bae1dSRodney W. Grimes } 654df8bae1dSRodney W. Grimes pager = vm_pager_allocate(type, handle, size, prot, foff); 655df8bae1dSRodney W. Grimes if (pager == NULL) 656df8bae1dSRodney W. Grimes return (type == PG_DEVICE ? EINVAL : ENOMEM); 657df8bae1dSRodney W. Grimes /* 6587fb0c17eSDavid Greenman * Guarantee that the pager has an object. 659df8bae1dSRodney W. Grimes */ 660df8bae1dSRodney W. Grimes object = vm_object_lookup(pager); 6617fb0c17eSDavid Greenman if (object == NULL) { 6627fb0c17eSDavid Greenman if (handle != NULL) 6637fb0c17eSDavid Greenman panic("vm_mmap: pager didn't allocate an object (and should have)"); 6647fb0c17eSDavid Greenman /* 6657fb0c17eSDavid Greenman * Should only happen for unnamed anonymous regions. 6667fb0c17eSDavid Greenman */ 6677fb0c17eSDavid Greenman object = vm_object_allocate(size); 6687fb0c17eSDavid Greenman object->pager = pager; 6697fb0c17eSDavid Greenman } else { 6707fb0c17eSDavid Greenman /* 671f2da180fSDavid Greenman * Lose vm_object_lookup() reference. Retain reference 672f2da180fSDavid Greenman * gained by vm_pager_allocate(). 6737fb0c17eSDavid Greenman */ 674df8bae1dSRodney W. Grimes vm_object_deallocate(object); 6757fb0c17eSDavid Greenman } 676f2da180fSDavid Greenman /* 677f2da180fSDavid Greenman * At this point, our actions above have gained a total of 678f2da180fSDavid Greenman * one reference to the object, and we have a pager. 679f2da180fSDavid Greenman */ 680df8bae1dSRodney W. Grimes 681df8bae1dSRodney W. Grimes /* 6827fb0c17eSDavid Greenman * Anonymous memory, shared file, or character special file. 683df8bae1dSRodney W. Grimes */ 6847fb0c17eSDavid Greenman if ((flags & (MAP_ANON|MAP_SHARED)) || (type == PG_DEVICE)) { 6857fb0c17eSDavid Greenman rv = vm_map_find(map, object, foff, addr, size, fitit); 686df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 6877fb0c17eSDavid Greenman /* 688f2da180fSDavid Greenman * Lose the object reference. This will also destroy 689f2da180fSDavid Greenman * the pager if there are no other references. 6907fb0c17eSDavid Greenman */ 691df8bae1dSRodney W. Grimes vm_object_deallocate(object); 692df8bae1dSRodney W. Grimes goto out; 693df8bae1dSRodney W. Grimes } 694df8bae1dSRodney W. Grimes } 695df8bae1dSRodney W. Grimes /* 69650ce2102SDavid Greenman * mmap a COW regular file 697df8bae1dSRodney W. Grimes */ 698df8bae1dSRodney W. Grimes else { 699df8bae1dSRodney W. Grimes vm_map_t tmap; 700df8bae1dSRodney W. Grimes vm_offset_t off; 70150ce2102SDavid Greenman vm_map_entry_t entry; 702df8bae1dSRodney W. Grimes 70350ce2102SDavid Greenman if (flags & MAP_COPY) { 704df8bae1dSRodney W. Grimes /* locate and allocate the target address space */ 7057fb0c17eSDavid Greenman rv = vm_map_find(map, NULL, 0, addr, size, fitit); 706df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 707df8bae1dSRodney W. Grimes vm_object_deallocate(object); 708df8bae1dSRodney W. Grimes goto out; 709df8bae1dSRodney W. Grimes } 7107fb0c17eSDavid Greenman 711df8bae1dSRodney W. Grimes off = VM_MIN_ADDRESS; 7127fb0c17eSDavid Greenman tmap = vm_map_create(NULL, off, off + size, TRUE); 7137fb0c17eSDavid Greenman rv = vm_map_find(tmap, object, foff, &off, size, FALSE); 714df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 715f2da180fSDavid Greenman /* 716f2da180fSDavid Greenman * Deallocate and delete the temporary map. 717f2da180fSDavid Greenman * Note that since the object insertion 718f2da180fSDavid Greenman * above has failed, the vm_map_deallocate 719f2da180fSDavid Greenman * doesn't lose the object reference - we 720f2da180fSDavid Greenman * must do it explicitly. 721f2da180fSDavid Greenman */ 722df8bae1dSRodney W. Grimes vm_object_deallocate(object); 723df8bae1dSRodney W. Grimes vm_map_deallocate(tmap); 724df8bae1dSRodney W. Grimes goto out; 725df8bae1dSRodney W. Grimes } 726df8bae1dSRodney W. Grimes rv = vm_map_copy(map, tmap, *addr, size, off, 727df8bae1dSRodney W. Grimes FALSE, FALSE); 728f2da180fSDavid Greenman /* 729f2da180fSDavid Greenman * Deallocate temporary map. XXX - depending 730f2da180fSDavid Greenman * on events, this may leave the object with 731f2da180fSDavid Greenman * no net gain in reference count! ...this 732f2da180fSDavid Greenman * needs to be looked at! 733f2da180fSDavid Greenman */ 734df8bae1dSRodney W. Grimes vm_map_deallocate(tmap); 735df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) 736df8bae1dSRodney W. Grimes goto out; 73750ce2102SDavid Greenman 73850ce2102SDavid Greenman } else { 73950ce2102SDavid Greenman vm_object_t user_object; 74050ce2102SDavid Greenman 741f2da180fSDavid Greenman /* 742f2da180fSDavid Greenman * Create a new object and make the original object 743f2da180fSDavid Greenman * the backing object. NOTE: the object reference gained 744f2da180fSDavid Greenman * above is now changed into the reference held by 745f2da180fSDavid Greenman * user_object. Since we don't map 'object', we want 746f2da180fSDavid Greenman * only this one reference. 747f2da180fSDavid Greenman */ 7488f4e17d4SDavid Greenman user_object = vm_object_allocate(object->size); 74950ce2102SDavid Greenman user_object->shadow = object; 75050ce2102SDavid Greenman TAILQ_INSERT_TAIL(&object->reverse_shadow_head, 75150ce2102SDavid Greenman user_object, reverse_shadow_list); 75250ce2102SDavid Greenman 75350ce2102SDavid Greenman rv = vm_map_find(map, user_object, foff, addr, size, fitit); 75450ce2102SDavid Greenman if( rv != KERN_SUCCESS) { 75550ce2102SDavid Greenman vm_object_deallocate(user_object); 75650ce2102SDavid Greenman goto out; 75750ce2102SDavid Greenman } 75850ce2102SDavid Greenman 75950ce2102SDavid Greenman /* 76050ce2102SDavid Greenman * this is a consistancy check, gets the map entry, and should 76150ce2102SDavid Greenman * never fail 76250ce2102SDavid Greenman */ 76350ce2102SDavid Greenman if (!vm_map_lookup_entry(map, *addr, &entry)) { 764edf8a815SDavid Greenman panic("vm_mmap: missing map entry!!!"); 76550ce2102SDavid Greenman } 76650ce2102SDavid Greenman 76750ce2102SDavid Greenman entry->copy_on_write = TRUE; 76850ce2102SDavid Greenman } 76950ce2102SDavid Greenman 77050ce2102SDavid Greenman /* 77150ce2102SDavid Greenman * set pages COW and protect for read access only 77250ce2102SDavid Greenman */ 77350ce2102SDavid Greenman vm_object_pmap_copy(object, foff, foff + size); 77450ce2102SDavid Greenman 775df8bae1dSRodney W. Grimes } 7767fb0c17eSDavid Greenman 7777fb0c17eSDavid Greenman /* 7787fb0c17eSDavid Greenman * "Pre-fault" resident pages. 7797fb0c17eSDavid Greenman */ 7807fb0c17eSDavid Greenman if ((type == PG_VNODE) && (map->pmap != NULL)) { 7817fb0c17eSDavid Greenman pmap_object_init_pt(map->pmap, *addr, object, foff, size); 782df8bae1dSRodney W. Grimes } 7837fb0c17eSDavid Greenman 784df8bae1dSRodney W. Grimes /* 7850d94caffSDavid Greenman * Correct protection (default is VM_PROT_ALL). If maxprot is 7860d94caffSDavid Greenman * different than prot, we must set both explicitly. 787df8bae1dSRodney W. Grimes */ 788df8bae1dSRodney W. Grimes rv = KERN_SUCCESS; 789df8bae1dSRodney W. Grimes if (maxprot != VM_PROT_ALL) 790df8bae1dSRodney W. Grimes rv = vm_map_protect(map, *addr, *addr + size, maxprot, TRUE); 791df8bae1dSRodney W. Grimes if (rv == KERN_SUCCESS && prot != maxprot) 792df8bae1dSRodney W. Grimes rv = vm_map_protect(map, *addr, *addr + size, prot, FALSE); 793df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 7947fb0c17eSDavid Greenman (void) vm_map_remove(map, *addr, *addr + size); 795df8bae1dSRodney W. Grimes goto out; 796df8bae1dSRodney W. Grimes } 797df8bae1dSRodney W. Grimes /* 798df8bae1dSRodney W. Grimes * Shared memory is also shared with children. 799df8bae1dSRodney W. Grimes */ 800df8bae1dSRodney W. Grimes if (flags & MAP_SHARED) { 801df8bae1dSRodney W. Grimes rv = vm_map_inherit(map, *addr, *addr + size, VM_INHERIT_SHARE); 802df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 8037fb0c17eSDavid Greenman (void) vm_map_remove(map, *addr, *addr + size); 804df8bae1dSRodney W. Grimes goto out; 805df8bae1dSRodney W. Grimes } 806df8bae1dSRodney W. Grimes } 807df8bae1dSRodney W. Grimes out: 808df8bae1dSRodney W. Grimes #ifdef DEBUG 809df8bae1dSRodney W. Grimes if (mmapdebug & MDB_MAPIT) 810df8bae1dSRodney W. Grimes printf("vm_mmap: rv %d\n", rv); 811df8bae1dSRodney W. Grimes #endif 812df8bae1dSRodney W. Grimes switch (rv) { 813df8bae1dSRodney W. Grimes case KERN_SUCCESS: 814df8bae1dSRodney W. Grimes return (0); 815df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 816df8bae1dSRodney W. Grimes case KERN_NO_SPACE: 817df8bae1dSRodney W. Grimes return (ENOMEM); 818df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 819df8bae1dSRodney W. Grimes return (EACCES); 820df8bae1dSRodney W. Grimes default: 821df8bae1dSRodney W. Grimes return (EINVAL); 822df8bae1dSRodney W. Grimes } 823df8bae1dSRodney W. Grimes } 824