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 4105f0fdd2SPoul-Henning Kamp * $Id: vm_mmap.c,v 1.6 1994/09/02 15:06:51 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> 62df8bae1dSRodney W. Grimes #include <vm/vm_prot.h> 63df8bae1dSRodney W. Grimes 64df8bae1dSRodney W. Grimes #ifdef DEBUG 65df8bae1dSRodney W. Grimes int mmapdebug = 0; 66df8bae1dSRodney W. Grimes #define MDB_FOLLOW 0x01 67df8bae1dSRodney W. Grimes #define MDB_SYNC 0x02 68df8bae1dSRodney W. Grimes #define MDB_MAPIT 0x04 69df8bae1dSRodney W. Grimes #endif 70df8bae1dSRodney W. Grimes 71f720dc2cSDavid Greenman void pmap_object_init_pt(); 72f720dc2cSDavid Greenman 73df8bae1dSRodney W. Grimes struct sbrk_args { 74df8bae1dSRodney W. Grimes int incr; 75df8bae1dSRodney W. Grimes }; 76df8bae1dSRodney W. Grimes /* ARGSUSED */ 77df8bae1dSRodney W. Grimes int 78df8bae1dSRodney W. Grimes sbrk(p, uap, retval) 79df8bae1dSRodney W. Grimes struct proc *p; 80df8bae1dSRodney W. Grimes struct sbrk_args *uap; 81df8bae1dSRodney W. Grimes int *retval; 82df8bae1dSRodney W. Grimes { 83df8bae1dSRodney W. Grimes 84df8bae1dSRodney W. Grimes /* Not yet implemented */ 85df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 86df8bae1dSRodney W. Grimes } 87df8bae1dSRodney W. Grimes 88df8bae1dSRodney W. Grimes struct sstk_args { 89df8bae1dSRodney W. Grimes int incr; 90df8bae1dSRodney W. Grimes }; 91df8bae1dSRodney W. Grimes /* ARGSUSED */ 92df8bae1dSRodney W. Grimes int 93df8bae1dSRodney W. Grimes sstk(p, uap, retval) 94df8bae1dSRodney W. Grimes struct proc *p; 95df8bae1dSRodney W. Grimes struct sstk_args *uap; 96df8bae1dSRodney W. Grimes int *retval; 97df8bae1dSRodney W. Grimes { 98df8bae1dSRodney W. Grimes 99df8bae1dSRodney W. Grimes /* Not yet implemented */ 100df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 101df8bae1dSRodney W. Grimes } 102df8bae1dSRodney W. Grimes 103df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 104df8bae1dSRodney W. Grimes struct getpagesize_args { 105df8bae1dSRodney W. Grimes int dummy; 106df8bae1dSRodney W. Grimes }; 107df8bae1dSRodney W. Grimes /* ARGSUSED */ 108df8bae1dSRodney W. Grimes int 109df8bae1dSRodney W. Grimes ogetpagesize(p, uap, retval) 110df8bae1dSRodney W. Grimes struct proc *p; 111df8bae1dSRodney W. Grimes struct getpagesize_args *uap; 112df8bae1dSRodney W. Grimes int *retval; 113df8bae1dSRodney W. Grimes { 114df8bae1dSRodney W. Grimes 115df8bae1dSRodney W. Grimes *retval = PAGE_SIZE; 116df8bae1dSRodney W. Grimes return (0); 117df8bae1dSRodney W. Grimes } 118df8bae1dSRodney W. Grimes #endif /* COMPAT_43 || COMPAT_SUNOS */ 119df8bae1dSRodney W. Grimes 120df8bae1dSRodney W. Grimes struct mmap_args { 121df8bae1dSRodney W. Grimes caddr_t addr; 122df8bae1dSRodney W. Grimes size_t len; 123df8bae1dSRodney W. Grimes int prot; 124df8bae1dSRodney W. Grimes int flags; 125df8bae1dSRodney W. Grimes int fd; 126df8bae1dSRodney W. Grimes long pad; 127df8bae1dSRodney W. Grimes off_t pos; 128df8bae1dSRodney W. Grimes }; 129df8bae1dSRodney W. Grimes 130df8bae1dSRodney W. Grimes int 131df8bae1dSRodney W. Grimes mmap(p, uap, retval) 132df8bae1dSRodney W. Grimes struct proc *p; 133df8bae1dSRodney W. Grimes register struct mmap_args *uap; 134df8bae1dSRodney W. Grimes int *retval; 135df8bae1dSRodney W. Grimes { 136df8bae1dSRodney W. Grimes register struct filedesc *fdp = p->p_fd; 137df8bae1dSRodney W. Grimes register struct file *fp; 138df8bae1dSRodney W. Grimes struct vnode *vp; 139df8bae1dSRodney W. Grimes vm_offset_t addr; 140df8bae1dSRodney W. Grimes vm_size_t size; 141df8bae1dSRodney W. Grimes vm_prot_t prot, maxprot; 142df8bae1dSRodney W. Grimes caddr_t handle; 143df8bae1dSRodney W. Grimes int flags, error; 144df8bae1dSRodney W. Grimes 145df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 146df8bae1dSRodney W. Grimes flags = uap->flags; 147df8bae1dSRodney W. Grimes #ifdef DEBUG 148df8bae1dSRodney W. Grimes if (mmapdebug & MDB_FOLLOW) 149df8bae1dSRodney W. Grimes printf("mmap(%d): addr %x len %x pro %x flg %x fd %d pos %x\n", 150df8bae1dSRodney W. Grimes p->p_pid, uap->addr, uap->len, prot, 151df8bae1dSRodney W. Grimes flags, uap->fd, (vm_offset_t)uap->pos); 152df8bae1dSRodney W. Grimes #endif 153df8bae1dSRodney W. Grimes /* 154df8bae1dSRodney W. Grimes * Address (if FIXED) must be page aligned. 155df8bae1dSRodney W. Grimes * Size is implicitly rounded to a page boundary. 156df8bae1dSRodney W. Grimes */ 157df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 158df8bae1dSRodney W. Grimes if (((flags & MAP_FIXED) && (addr & PAGE_MASK)) || 159df8bae1dSRodney W. Grimes (ssize_t)uap->len < 0 || ((flags & MAP_ANON) && uap->fd != -1)) 160df8bae1dSRodney W. Grimes return (EINVAL); 161df8bae1dSRodney W. Grimes size = (vm_size_t) round_page(uap->len); 162df8bae1dSRodney W. Grimes /* 163df8bae1dSRodney W. Grimes * Check for illegal addresses. Watch out for address wrap... 164df8bae1dSRodney W. Grimes * Note that VM_*_ADDRESS are not constants due to casts (argh). 165df8bae1dSRodney W. Grimes */ 166df8bae1dSRodney W. Grimes if (flags & MAP_FIXED) { 167bbc0ec52SDavid Greenman if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS) 168df8bae1dSRodney W. Grimes return (EINVAL); 16926f9a767SRodney W. Grimes #ifndef i386 170df8bae1dSRodney W. Grimes if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS) 171df8bae1dSRodney W. Grimes return (EINVAL); 17226f9a767SRodney W. Grimes #endif 173bbc0ec52SDavid Greenman if (addr + size < addr) 174df8bae1dSRodney W. Grimes return (EINVAL); 175df8bae1dSRodney W. Grimes } 176df8bae1dSRodney W. Grimes /* 177df8bae1dSRodney W. Grimes * XXX if no hint provided for a non-fixed mapping place it after 178df8bae1dSRodney W. Grimes * the end of the largest possible heap. 179df8bae1dSRodney W. Grimes * 180df8bae1dSRodney W. Grimes * There should really be a pmap call to determine a reasonable 181df8bae1dSRodney W. Grimes * location. 182df8bae1dSRodney W. Grimes */ 183df8bae1dSRodney W. Grimes if (addr == 0 && (flags & MAP_FIXED) == 0) 184df8bae1dSRodney W. Grimes addr = round_page(p->p_vmspace->vm_daddr + MAXDSIZ); 185df8bae1dSRodney W. Grimes if (flags & MAP_ANON) { 186df8bae1dSRodney W. Grimes /* 187df8bae1dSRodney W. Grimes * Mapping blank space is trivial. 188df8bae1dSRodney W. Grimes */ 189df8bae1dSRodney W. Grimes handle = NULL; 190df8bae1dSRodney W. Grimes maxprot = VM_PROT_ALL; 191df8bae1dSRodney W. Grimes } else { 192df8bae1dSRodney W. Grimes /* 193df8bae1dSRodney W. Grimes * Mapping file, get fp for validation. 194df8bae1dSRodney W. Grimes * Obtain vnode and make sure it is of appropriate type. 195df8bae1dSRodney W. Grimes */ 196df8bae1dSRodney W. Grimes if (((unsigned)uap->fd) >= fdp->fd_nfiles || 197df8bae1dSRodney W. Grimes (fp = fdp->fd_ofiles[uap->fd]) == NULL) 198df8bae1dSRodney W. Grimes return (EBADF); 199df8bae1dSRodney W. Grimes if (fp->f_type != DTYPE_VNODE) 200df8bae1dSRodney W. Grimes return (EINVAL); 201df8bae1dSRodney W. Grimes vp = (struct vnode *)fp->f_data; 202df8bae1dSRodney W. Grimes if (vp->v_type != VREG && vp->v_type != VCHR) 203df8bae1dSRodney W. Grimes return (EINVAL); 204df8bae1dSRodney W. Grimes /* 205df8bae1dSRodney W. Grimes * XXX hack to handle use of /dev/zero to map anon 206df8bae1dSRodney W. Grimes * memory (ala SunOS). 207df8bae1dSRodney W. Grimes */ 208df8bae1dSRodney W. Grimes if (vp->v_type == VCHR && iszerodev(vp->v_rdev)) { 209df8bae1dSRodney W. Grimes handle = NULL; 210df8bae1dSRodney W. Grimes maxprot = VM_PROT_ALL; 211df8bae1dSRodney W. Grimes flags |= MAP_ANON; 212df8bae1dSRodney W. Grimes } else { 213df8bae1dSRodney W. Grimes /* 214df8bae1dSRodney W. Grimes * Ensure that file and memory protections are 215df8bae1dSRodney W. Grimes * compatible. Note that we only worry about 216df8bae1dSRodney W. Grimes * writability if mapping is shared; in this case, 217df8bae1dSRodney W. Grimes * current and max prot are dictated by the open file. 218df8bae1dSRodney W. Grimes * XXX use the vnode instead? Problem is: what 219df8bae1dSRodney W. Grimes * credentials do we use for determination? 220df8bae1dSRodney W. Grimes * What if proc does a setuid? 221df8bae1dSRodney W. Grimes */ 222df8bae1dSRodney W. Grimes maxprot = VM_PROT_EXECUTE; /* ??? */ 223df8bae1dSRodney W. Grimes if (fp->f_flag & FREAD) 224df8bae1dSRodney W. Grimes maxprot |= VM_PROT_READ; 225df8bae1dSRodney W. Grimes else if (prot & PROT_READ) 226df8bae1dSRodney W. Grimes return (EACCES); 227df8bae1dSRodney W. Grimes if (flags & MAP_SHARED) { 228df8bae1dSRodney W. Grimes if (fp->f_flag & FWRITE) 229df8bae1dSRodney W. Grimes maxprot |= VM_PROT_WRITE; 230df8bae1dSRodney W. Grimes else if (prot & PROT_WRITE) 231df8bae1dSRodney W. Grimes return (EACCES); 232df8bae1dSRodney W. Grimes } else 233df8bae1dSRodney W. Grimes maxprot |= VM_PROT_WRITE; 234df8bae1dSRodney W. Grimes handle = (caddr_t)vp; 235df8bae1dSRodney W. Grimes } 236df8bae1dSRodney W. Grimes } 237df8bae1dSRodney W. Grimes error = vm_mmap(&p->p_vmspace->vm_map, &addr, size, prot, maxprot, 238df8bae1dSRodney W. Grimes flags, handle, (vm_offset_t)uap->pos); 239df8bae1dSRodney W. Grimes if (error == 0) 240df8bae1dSRodney W. Grimes *retval = (int)addr; 241df8bae1dSRodney W. Grimes return (error); 242df8bae1dSRodney W. Grimes } 243df8bae1dSRodney W. Grimes 24405f0fdd2SPoul-Henning Kamp #ifdef COMPAT_43 24505f0fdd2SPoul-Henning Kamp struct ommap_args { 24605f0fdd2SPoul-Henning Kamp caddr_t addr; 24705f0fdd2SPoul-Henning Kamp int len; 24805f0fdd2SPoul-Henning Kamp int prot; 24905f0fdd2SPoul-Henning Kamp int flags; 25005f0fdd2SPoul-Henning Kamp int fd; 25105f0fdd2SPoul-Henning Kamp long pos; 25205f0fdd2SPoul-Henning Kamp }; 25305f0fdd2SPoul-Henning Kamp int 25405f0fdd2SPoul-Henning Kamp ommap(p, uap, retval) 25505f0fdd2SPoul-Henning Kamp struct proc *p; 25605f0fdd2SPoul-Henning Kamp register struct ommap_args *uap; 25705f0fdd2SPoul-Henning Kamp int *retval; 25805f0fdd2SPoul-Henning Kamp { 25905f0fdd2SPoul-Henning Kamp struct mmap_args nargs; 26005f0fdd2SPoul-Henning Kamp static const char cvtbsdprot[8] = { 26105f0fdd2SPoul-Henning Kamp 0, 26205f0fdd2SPoul-Henning Kamp PROT_EXEC, 26305f0fdd2SPoul-Henning Kamp PROT_WRITE, 26405f0fdd2SPoul-Henning Kamp PROT_EXEC|PROT_WRITE, 26505f0fdd2SPoul-Henning Kamp PROT_READ, 26605f0fdd2SPoul-Henning Kamp PROT_EXEC|PROT_READ, 26705f0fdd2SPoul-Henning Kamp PROT_WRITE|PROT_READ, 26805f0fdd2SPoul-Henning Kamp PROT_EXEC|PROT_WRITE|PROT_READ, 26905f0fdd2SPoul-Henning Kamp }; 27005f0fdd2SPoul-Henning Kamp #define OMAP_ANON 0x0002 27105f0fdd2SPoul-Henning Kamp #define OMAP_COPY 0x0020 27205f0fdd2SPoul-Henning Kamp #define OMAP_SHARED 0x0010 27305f0fdd2SPoul-Henning Kamp #define OMAP_FIXED 0x0100 27405f0fdd2SPoul-Henning Kamp #define OMAP_INHERIT 0x0800 27505f0fdd2SPoul-Henning Kamp 27605f0fdd2SPoul-Henning Kamp nargs.addr = uap->addr; 27705f0fdd2SPoul-Henning Kamp nargs.len = uap->len; 27805f0fdd2SPoul-Henning Kamp nargs.prot = cvtbsdprot[uap->prot&0x7]; 27905f0fdd2SPoul-Henning Kamp nargs.flags = 0; 28005f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_ANON) 28105f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_ANON; 28205f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_COPY) 28305f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_COPY; 28405f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_SHARED) 28505f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_SHARED; 28605f0fdd2SPoul-Henning Kamp else 28705f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_PRIVATE; 28805f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_FIXED) 28905f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_FIXED; 29005f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_INHERIT) 29105f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_INHERIT; 29205f0fdd2SPoul-Henning Kamp nargs.fd = uap->fd; 29305f0fdd2SPoul-Henning Kamp nargs.pos = uap->pos; 29405f0fdd2SPoul-Henning Kamp return (mmap(p, &nargs, retval)); 29505f0fdd2SPoul-Henning Kamp } 29605f0fdd2SPoul-Henning Kamp #endif /* COMPAT_43 */ 29705f0fdd2SPoul-Henning Kamp 29805f0fdd2SPoul-Henning Kamp 299df8bae1dSRodney W. Grimes struct msync_args { 300df8bae1dSRodney W. Grimes caddr_t addr; 301df8bae1dSRodney W. Grimes int len; 302df8bae1dSRodney W. Grimes }; 303df8bae1dSRodney W. Grimes int 304df8bae1dSRodney W. Grimes msync(p, uap, retval) 305df8bae1dSRodney W. Grimes struct proc *p; 306df8bae1dSRodney W. Grimes struct msync_args *uap; 307df8bae1dSRodney W. Grimes int *retval; 308df8bae1dSRodney W. Grimes { 309df8bae1dSRodney W. Grimes vm_offset_t addr; 310df8bae1dSRodney W. Grimes vm_size_t size; 311df8bae1dSRodney W. Grimes vm_map_t map; 312df8bae1dSRodney W. Grimes int rv; 313df8bae1dSRodney W. Grimes boolean_t syncio, invalidate; 314df8bae1dSRodney W. Grimes 315df8bae1dSRodney W. Grimes #ifdef DEBUG 316df8bae1dSRodney W. Grimes if (mmapdebug & (MDB_FOLLOW|MDB_SYNC)) 317df8bae1dSRodney W. Grimes printf("msync(%d): addr %x len %x\n", 318df8bae1dSRodney W. Grimes p->p_pid, uap->addr, uap->len); 319df8bae1dSRodney W. Grimes #endif 320df8bae1dSRodney W. Grimes if (((int)uap->addr & PAGE_MASK) || uap->addr + uap->len < uap->addr) 321df8bae1dSRodney W. Grimes return (EINVAL); 322df8bae1dSRodney W. Grimes map = &p->p_vmspace->vm_map; 323df8bae1dSRodney W. Grimes addr = (vm_offset_t)uap->addr; 324df8bae1dSRodney W. Grimes size = (vm_size_t)uap->len; 325df8bae1dSRodney W. Grimes /* 326df8bae1dSRodney W. Grimes * XXX Gak! If size is zero we are supposed to sync "all modified 327df8bae1dSRodney W. Grimes * pages with the region containing addr". Unfortunately, we 328df8bae1dSRodney W. Grimes * don't really keep track of individual mmaps so we approximate 329df8bae1dSRodney W. Grimes * by flushing the range of the map entry containing addr. 330df8bae1dSRodney W. Grimes * This can be incorrect if the region splits or is coalesced 331df8bae1dSRodney W. Grimes * with a neighbor. 332df8bae1dSRodney W. Grimes */ 333df8bae1dSRodney W. Grimes if (size == 0) { 334df8bae1dSRodney W. Grimes vm_map_entry_t entry; 335df8bae1dSRodney W. Grimes 336df8bae1dSRodney W. Grimes vm_map_lock_read(map); 337df8bae1dSRodney W. Grimes rv = vm_map_lookup_entry(map, addr, &entry); 338df8bae1dSRodney W. Grimes vm_map_unlock_read(map); 339df8bae1dSRodney W. Grimes if (rv) 340df8bae1dSRodney W. Grimes return (EINVAL); 341df8bae1dSRodney W. Grimes addr = entry->start; 342df8bae1dSRodney W. Grimes size = entry->end - entry->start; 343df8bae1dSRodney W. Grimes } 344df8bae1dSRodney W. Grimes #ifdef DEBUG 345df8bae1dSRodney W. Grimes if (mmapdebug & MDB_SYNC) 346df8bae1dSRodney W. Grimes printf("msync: cleaning/flushing address range [%x-%x)\n", 347df8bae1dSRodney W. Grimes addr, addr+size); 348df8bae1dSRodney W. Grimes #endif 349df8bae1dSRodney W. Grimes /* 350df8bae1dSRodney W. Grimes * Could pass this in as a third flag argument to implement 351df8bae1dSRodney W. Grimes * Sun's MS_ASYNC. 352df8bae1dSRodney W. Grimes */ 353df8bae1dSRodney W. Grimes syncio = TRUE; 354df8bae1dSRodney W. Grimes /* 355df8bae1dSRodney W. Grimes * XXX bummer, gotta flush all cached pages to ensure 356df8bae1dSRodney W. Grimes * consistency with the file system cache. Otherwise, we could 357df8bae1dSRodney W. Grimes * pass this in to implement Sun's MS_INVALIDATE. 358df8bae1dSRodney W. Grimes */ 359df8bae1dSRodney W. Grimes invalidate = TRUE; 360df8bae1dSRodney W. Grimes /* 361df8bae1dSRodney W. Grimes * Clean the pages and interpret the return value. 362df8bae1dSRodney W. Grimes */ 363df8bae1dSRodney W. Grimes rv = vm_map_clean(map, addr, addr+size, syncio, invalidate); 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 } 374df8bae1dSRodney W. Grimes return (0); 375df8bae1dSRodney W. Grimes } 376df8bae1dSRodney W. Grimes 377df8bae1dSRodney W. Grimes struct munmap_args { 378df8bae1dSRodney W. Grimes caddr_t addr; 379df8bae1dSRodney W. Grimes int len; 380df8bae1dSRodney W. Grimes }; 381df8bae1dSRodney W. Grimes int 382df8bae1dSRodney W. Grimes munmap(p, uap, retval) 383df8bae1dSRodney W. Grimes register struct proc *p; 384df8bae1dSRodney W. Grimes register struct munmap_args *uap; 385df8bae1dSRodney W. Grimes int *retval; 386df8bae1dSRodney W. Grimes { 387df8bae1dSRodney W. Grimes vm_offset_t addr; 388df8bae1dSRodney W. Grimes vm_size_t size; 389df8bae1dSRodney W. Grimes vm_map_t map; 390df8bae1dSRodney W. Grimes 391df8bae1dSRodney W. Grimes #ifdef DEBUG 392df8bae1dSRodney W. Grimes if (mmapdebug & MDB_FOLLOW) 393df8bae1dSRodney W. Grimes printf("munmap(%d): addr %x len %x\n", 394df8bae1dSRodney W. Grimes p->p_pid, uap->addr, uap->len); 395df8bae1dSRodney W. Grimes #endif 396df8bae1dSRodney W. Grimes 397df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 398df8bae1dSRodney W. Grimes if ((addr & PAGE_MASK) || uap->len < 0) 399df8bae1dSRodney W. Grimes return(EINVAL); 400df8bae1dSRodney W. Grimes size = (vm_size_t) round_page(uap->len); 401df8bae1dSRodney W. Grimes if (size == 0) 402df8bae1dSRodney W. Grimes return(0); 403df8bae1dSRodney W. Grimes /* 404df8bae1dSRodney W. Grimes * Check for illegal addresses. Watch out for address wrap... 405df8bae1dSRodney W. Grimes * Note that VM_*_ADDRESS are not constants due to casts (argh). 406df8bae1dSRodney W. Grimes */ 407bbc0ec52SDavid Greenman if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS) 408df8bae1dSRodney W. Grimes return (EINVAL); 40926f9a767SRodney W. Grimes #ifndef i386 410df8bae1dSRodney W. Grimes if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS) 411df8bae1dSRodney W. Grimes return (EINVAL); 41226f9a767SRodney W. Grimes #endif 413bbc0ec52SDavid Greenman if (addr + size < addr) 414df8bae1dSRodney W. Grimes return (EINVAL); 415df8bae1dSRodney W. Grimes map = &p->p_vmspace->vm_map; 416df8bae1dSRodney W. Grimes /* 417df8bae1dSRodney W. Grimes * Make sure entire range is allocated. 418df8bae1dSRodney W. Grimes */ 419df8bae1dSRodney W. Grimes if (!vm_map_check_protection(map, addr, addr + size, VM_PROT_NONE)) 420df8bae1dSRodney W. Grimes return(EINVAL); 421df8bae1dSRodney W. Grimes /* returns nothing but KERN_SUCCESS anyway */ 422df8bae1dSRodney W. Grimes (void) vm_map_remove(map, addr, addr+size); 423df8bae1dSRodney W. Grimes return(0); 424df8bae1dSRodney W. Grimes } 425df8bae1dSRodney W. Grimes 426df8bae1dSRodney W. Grimes void 42790324b07SDavid Greenman munmapfd(p, fd) 42890324b07SDavid Greenman struct proc *p; 429df8bae1dSRodney W. Grimes int fd; 430df8bae1dSRodney W. Grimes { 431df8bae1dSRodney W. Grimes #ifdef DEBUG 432df8bae1dSRodney W. Grimes if (mmapdebug & MDB_FOLLOW) 43390324b07SDavid Greenman printf("munmapfd(%d): fd %d\n", p->p_pid, fd); 434df8bae1dSRodney W. Grimes #endif 435df8bae1dSRodney W. Grimes 436df8bae1dSRodney W. Grimes /* 437df8bae1dSRodney W. Grimes * XXX should vm_deallocate any regions mapped to this file 438df8bae1dSRodney W. Grimes */ 43990324b07SDavid Greenman p->p_fd->fd_ofileflags[fd] &= ~UF_MAPPED; 440df8bae1dSRodney W. Grimes } 441df8bae1dSRodney W. Grimes 442df8bae1dSRodney W. Grimes struct mprotect_args { 443df8bae1dSRodney W. Grimes caddr_t addr; 444df8bae1dSRodney W. Grimes int len; 445df8bae1dSRodney W. Grimes int prot; 446df8bae1dSRodney W. Grimes }; 447df8bae1dSRodney W. Grimes int 448df8bae1dSRodney W. Grimes mprotect(p, uap, retval) 449df8bae1dSRodney W. Grimes struct proc *p; 450df8bae1dSRodney W. Grimes struct mprotect_args *uap; 451df8bae1dSRodney W. Grimes int *retval; 452df8bae1dSRodney W. Grimes { 453df8bae1dSRodney W. Grimes vm_offset_t addr; 454df8bae1dSRodney W. Grimes vm_size_t size; 455df8bae1dSRodney W. Grimes register vm_prot_t prot; 456df8bae1dSRodney W. Grimes 457df8bae1dSRodney W. Grimes #ifdef DEBUG 458df8bae1dSRodney W. Grimes if (mmapdebug & MDB_FOLLOW) 459df8bae1dSRodney W. Grimes printf("mprotect(%d): addr %x len %x prot %d\n", 460df8bae1dSRodney W. Grimes p->p_pid, uap->addr, uap->len, uap->prot); 461df8bae1dSRodney W. Grimes #endif 462df8bae1dSRodney W. Grimes 463df8bae1dSRodney W. Grimes addr = (vm_offset_t)uap->addr; 464df8bae1dSRodney W. Grimes if ((addr & PAGE_MASK) || uap->len < 0) 465df8bae1dSRodney W. Grimes return(EINVAL); 466df8bae1dSRodney W. Grimes size = (vm_size_t)uap->len; 467df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 468df8bae1dSRodney W. Grimes 469df8bae1dSRodney W. Grimes switch (vm_map_protect(&p->p_vmspace->vm_map, addr, addr+size, prot, 470df8bae1dSRodney W. Grimes FALSE)) { 471df8bae1dSRodney W. Grimes case KERN_SUCCESS: 472df8bae1dSRodney W. Grimes return (0); 473df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 474df8bae1dSRodney W. Grimes return (EACCES); 475df8bae1dSRodney W. Grimes } 476df8bae1dSRodney W. Grimes return (EINVAL); 477df8bae1dSRodney W. Grimes } 478df8bae1dSRodney W. Grimes 479df8bae1dSRodney W. Grimes struct madvise_args { 480df8bae1dSRodney W. Grimes caddr_t addr; 481df8bae1dSRodney W. Grimes int len; 482df8bae1dSRodney W. Grimes int behav; 483df8bae1dSRodney W. Grimes }; 484df8bae1dSRodney W. Grimes /* ARGSUSED */ 485df8bae1dSRodney W. Grimes int 486df8bae1dSRodney W. Grimes madvise(p, uap, retval) 487df8bae1dSRodney W. Grimes struct proc *p; 488df8bae1dSRodney W. Grimes struct madvise_args *uap; 489df8bae1dSRodney W. Grimes int *retval; 490df8bae1dSRodney W. Grimes { 491df8bae1dSRodney W. Grimes 492df8bae1dSRodney W. Grimes /* Not yet implemented */ 493df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 494df8bae1dSRodney W. Grimes } 495df8bae1dSRodney W. Grimes 496df8bae1dSRodney W. Grimes struct mincore_args { 497df8bae1dSRodney W. Grimes caddr_t addr; 498df8bae1dSRodney W. Grimes int len; 499df8bae1dSRodney W. Grimes char *vec; 500df8bae1dSRodney W. Grimes }; 501df8bae1dSRodney W. Grimes /* ARGSUSED */ 502df8bae1dSRodney W. Grimes int 503df8bae1dSRodney W. Grimes mincore(p, uap, retval) 504df8bae1dSRodney W. Grimes struct proc *p; 505df8bae1dSRodney W. Grimes struct mincore_args *uap; 506df8bae1dSRodney W. Grimes int *retval; 507df8bae1dSRodney W. Grimes { 508df8bae1dSRodney W. Grimes 509df8bae1dSRodney W. Grimes /* Not yet implemented */ 510df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 511df8bae1dSRodney W. Grimes } 512df8bae1dSRodney W. Grimes 513df8bae1dSRodney W. Grimes struct mlock_args { 514df8bae1dSRodney W. Grimes caddr_t addr; 515df8bae1dSRodney W. Grimes size_t len; 516df8bae1dSRodney W. Grimes }; 517df8bae1dSRodney W. Grimes int 518df8bae1dSRodney W. Grimes mlock(p, uap, retval) 519df8bae1dSRodney W. Grimes struct proc *p; 520df8bae1dSRodney W. Grimes struct mlock_args *uap; 521df8bae1dSRodney W. Grimes int *retval; 522df8bae1dSRodney W. Grimes { 523df8bae1dSRodney W. Grimes vm_offset_t addr; 524df8bae1dSRodney W. Grimes vm_size_t size; 525df8bae1dSRodney W. Grimes int error; 526df8bae1dSRodney W. Grimes extern int vm_page_max_wired; 527df8bae1dSRodney W. Grimes 528df8bae1dSRodney W. Grimes #ifdef DEBUG 529df8bae1dSRodney W. Grimes if (mmapdebug & MDB_FOLLOW) 530df8bae1dSRodney W. Grimes printf("mlock(%d): addr %x len %x\n", 531df8bae1dSRodney W. Grimes p->p_pid, uap->addr, uap->len); 532df8bae1dSRodney W. Grimes #endif 533df8bae1dSRodney W. Grimes addr = (vm_offset_t)uap->addr; 534df8bae1dSRodney W. Grimes if ((addr & PAGE_MASK) || uap->addr + uap->len < uap->addr) 535df8bae1dSRodney W. Grimes return (EINVAL); 536df8bae1dSRodney W. Grimes size = round_page((vm_size_t)uap->len); 537df8bae1dSRodney W. Grimes if (atop(size) + cnt.v_wire_count > vm_page_max_wired) 538df8bae1dSRodney W. Grimes return (EAGAIN); 539df8bae1dSRodney W. Grimes #ifdef pmap_wired_count 540df8bae1dSRodney W. Grimes if (size + ptoa(pmap_wired_count(vm_map_pmap(&p->p_vmspace->vm_map))) > 541df8bae1dSRodney W. Grimes p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur) 542df8bae1dSRodney W. Grimes return (EAGAIN); 543df8bae1dSRodney W. Grimes #else 54405f0fdd2SPoul-Henning Kamp error = suser(p->p_ucred, &p->p_acflag); 54505f0fdd2SPoul-Henning Kamp if (error) 546df8bae1dSRodney W. Grimes return (error); 547df8bae1dSRodney W. Grimes #endif 548df8bae1dSRodney W. Grimes 549df8bae1dSRodney W. Grimes error = vm_map_pageable(&p->p_vmspace->vm_map, addr, addr+size, FALSE); 550df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 551df8bae1dSRodney W. Grimes } 552df8bae1dSRodney W. Grimes 553df8bae1dSRodney W. Grimes struct munlock_args { 554df8bae1dSRodney W. Grimes caddr_t addr; 555df8bae1dSRodney W. Grimes size_t len; 556df8bae1dSRodney W. Grimes }; 557df8bae1dSRodney W. Grimes int 558df8bae1dSRodney W. Grimes munlock(p, uap, retval) 559df8bae1dSRodney W. Grimes struct proc *p; 560df8bae1dSRodney W. Grimes struct munlock_args *uap; 561df8bae1dSRodney W. Grimes int *retval; 562df8bae1dSRodney W. Grimes { 563df8bae1dSRodney W. Grimes vm_offset_t addr; 564df8bae1dSRodney W. Grimes vm_size_t size; 565df8bae1dSRodney W. Grimes int error; 566df8bae1dSRodney W. Grimes 567df8bae1dSRodney W. Grimes #ifdef DEBUG 568df8bae1dSRodney W. Grimes if (mmapdebug & MDB_FOLLOW) 569df8bae1dSRodney W. Grimes printf("munlock(%d): addr %x len %x\n", 570df8bae1dSRodney W. Grimes p->p_pid, uap->addr, uap->len); 571df8bae1dSRodney W. Grimes #endif 572df8bae1dSRodney W. Grimes addr = (vm_offset_t)uap->addr; 573df8bae1dSRodney W. Grimes if ((addr & PAGE_MASK) || uap->addr + uap->len < uap->addr) 574df8bae1dSRodney W. Grimes return (EINVAL); 575df8bae1dSRodney W. Grimes #ifndef pmap_wired_count 57605f0fdd2SPoul-Henning Kamp error = suser(p->p_ucred, &p->p_acflag); 57705f0fdd2SPoul-Henning Kamp if (error) 578df8bae1dSRodney W. Grimes return (error); 579df8bae1dSRodney W. Grimes #endif 580df8bae1dSRodney W. Grimes size = round_page((vm_size_t)uap->len); 581df8bae1dSRodney W. Grimes 582df8bae1dSRodney W. Grimes error = vm_map_pageable(&p->p_vmspace->vm_map, addr, addr+size, TRUE); 583df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 584df8bae1dSRodney W. Grimes } 585df8bae1dSRodney W. Grimes 586df8bae1dSRodney W. Grimes /* 587df8bae1dSRodney W. Grimes * Internal version of mmap. 588df8bae1dSRodney W. Grimes * Currently used by mmap, exec, and sys5 shared memory. 589df8bae1dSRodney W. Grimes * Handle is either a vnode pointer or NULL for MAP_ANON. 590df8bae1dSRodney W. Grimes */ 591df8bae1dSRodney W. Grimes int 592df8bae1dSRodney W. Grimes vm_mmap(map, addr, size, prot, maxprot, flags, handle, foff) 593df8bae1dSRodney W. Grimes register vm_map_t map; 594df8bae1dSRodney W. Grimes register vm_offset_t *addr; 595df8bae1dSRodney W. Grimes register vm_size_t size; 596df8bae1dSRodney W. Grimes vm_prot_t prot, maxprot; 597df8bae1dSRodney W. Grimes register int flags; 598df8bae1dSRodney W. Grimes caddr_t handle; /* XXX should be vp */ 599df8bae1dSRodney W. Grimes vm_offset_t foff; 600df8bae1dSRodney W. Grimes { 601df8bae1dSRodney W. Grimes register vm_pager_t pager; 602df8bae1dSRodney W. Grimes boolean_t fitit; 603df8bae1dSRodney W. Grimes vm_object_t object; 604df8bae1dSRodney W. Grimes struct vnode *vp = NULL; 605df8bae1dSRodney W. Grimes int type; 606df8bae1dSRodney W. Grimes int rv = KERN_SUCCESS; 607df8bae1dSRodney W. Grimes 608df8bae1dSRodney W. Grimes if (size == 0) 609df8bae1dSRodney W. Grimes return (0); 610df8bae1dSRodney W. Grimes 611df8bae1dSRodney W. Grimes if ((flags & MAP_FIXED) == 0) { 612df8bae1dSRodney W. Grimes fitit = TRUE; 613df8bae1dSRodney W. Grimes *addr = round_page(*addr); 614df8bae1dSRodney W. Grimes } else { 615df8bae1dSRodney W. Grimes fitit = FALSE; 616df8bae1dSRodney W. Grimes (void)vm_deallocate(map, *addr, size); 617df8bae1dSRodney W. Grimes } 618df8bae1dSRodney W. Grimes 619df8bae1dSRodney W. Grimes /* 620df8bae1dSRodney W. Grimes * Lookup/allocate pager. All except an unnamed anonymous lookup 621df8bae1dSRodney W. Grimes * gain a reference to ensure continued existance of the object. 622df8bae1dSRodney W. Grimes * (XXX the exception is to appease the pageout daemon) 623df8bae1dSRodney W. Grimes */ 624df8bae1dSRodney W. Grimes if (flags & MAP_ANON) 625df8bae1dSRodney W. Grimes type = PG_DFLT; 626df8bae1dSRodney W. Grimes else { 627df8bae1dSRodney W. Grimes vp = (struct vnode *)handle; 628df8bae1dSRodney W. Grimes if (vp->v_type == VCHR) { 629df8bae1dSRodney W. Grimes type = PG_DEVICE; 630df8bae1dSRodney W. Grimes handle = (caddr_t)vp->v_rdev; 631df8bae1dSRodney W. Grimes } else 632df8bae1dSRodney W. Grimes type = PG_VNODE; 633df8bae1dSRodney W. Grimes } 634df8bae1dSRodney W. Grimes pager = vm_pager_allocate(type, handle, size, prot, foff); 635df8bae1dSRodney W. Grimes if (pager == NULL) 636df8bae1dSRodney W. Grimes return (type == PG_DEVICE ? EINVAL : ENOMEM); 637df8bae1dSRodney W. Grimes /* 638df8bae1dSRodney W. Grimes * Find object and release extra reference gained by lookup 639df8bae1dSRodney W. Grimes */ 640df8bae1dSRodney W. Grimes object = vm_object_lookup(pager); 641df8bae1dSRodney W. Grimes vm_object_deallocate(object); 642df8bae1dSRodney W. Grimes 643df8bae1dSRodney W. Grimes /* 644df8bae1dSRodney W. Grimes * Anonymous memory. 645df8bae1dSRodney W. Grimes */ 646df8bae1dSRodney W. Grimes if (flags & MAP_ANON) { 647df8bae1dSRodney W. Grimes rv = vm_allocate_with_pager(map, addr, size, fitit, 648df8bae1dSRodney W. Grimes pager, foff, TRUE); 649df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 650df8bae1dSRodney W. Grimes if (handle == NULL) 651df8bae1dSRodney W. Grimes vm_pager_deallocate(pager); 652df8bae1dSRodney W. Grimes else 653df8bae1dSRodney W. Grimes vm_object_deallocate(object); 654df8bae1dSRodney W. Grimes goto out; 655df8bae1dSRodney W. Grimes } 656df8bae1dSRodney W. Grimes /* 657df8bae1dSRodney W. Grimes * Don't cache anonymous objects. 658df8bae1dSRodney W. Grimes * Loses the reference gained by vm_pager_allocate. 659df8bae1dSRodney W. Grimes * Note that object will be NULL when handle == NULL, 660df8bae1dSRodney W. Grimes * this is ok since vm_allocate_with_pager has made 661df8bae1dSRodney W. Grimes * sure that these objects are uncached. 662df8bae1dSRodney W. Grimes */ 663df8bae1dSRodney W. Grimes (void) pager_cache(object, FALSE); 664df8bae1dSRodney W. Grimes #ifdef DEBUG 665df8bae1dSRodney W. Grimes if (mmapdebug & MDB_MAPIT) 666df8bae1dSRodney W. Grimes printf("vm_mmap(%d): ANON *addr %x size %x pager %x\n", 667df8bae1dSRodney W. Grimes curproc->p_pid, *addr, size, pager); 668df8bae1dSRodney W. Grimes #endif 669df8bae1dSRodney W. Grimes } 670df8bae1dSRodney W. Grimes /* 671df8bae1dSRodney W. Grimes * Must be a mapped file. 672df8bae1dSRodney W. Grimes * Distinguish between character special and regular files. 673df8bae1dSRodney W. Grimes */ 674df8bae1dSRodney W. Grimes else if (vp->v_type == VCHR) { 675df8bae1dSRodney W. Grimes rv = vm_allocate_with_pager(map, addr, size, fitit, 676df8bae1dSRodney W. Grimes pager, foff, FALSE); 677df8bae1dSRodney W. Grimes /* 678df8bae1dSRodney W. Grimes * Uncache the object and lose the reference gained 679df8bae1dSRodney W. Grimes * by vm_pager_allocate(). If the call to 680df8bae1dSRodney W. Grimes * vm_allocate_with_pager() was sucessful, then we 681df8bae1dSRodney W. Grimes * gained an additional reference ensuring the object 682df8bae1dSRodney W. Grimes * will continue to exist. If the call failed then 683df8bae1dSRodney W. Grimes * the deallocate call below will terminate the 684df8bae1dSRodney W. Grimes * object which is fine. 685df8bae1dSRodney W. Grimes */ 686df8bae1dSRodney W. Grimes (void) pager_cache(object, FALSE); 687df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) 688df8bae1dSRodney W. Grimes goto out; 689df8bae1dSRodney W. Grimes } 690df8bae1dSRodney W. Grimes /* 691df8bae1dSRodney W. Grimes * A regular file 692df8bae1dSRodney W. Grimes */ 693df8bae1dSRodney W. Grimes else { 694df8bae1dSRodney W. Grimes #ifdef DEBUG 695df8bae1dSRodney W. Grimes if (object == NULL) 696df8bae1dSRodney W. Grimes printf("vm_mmap: no object: vp %x, pager %x\n", 697df8bae1dSRodney W. Grimes vp, pager); 698df8bae1dSRodney W. Grimes #endif 699df8bae1dSRodney W. Grimes /* 700df8bae1dSRodney W. Grimes * Map it directly. 701df8bae1dSRodney W. Grimes * Allows modifications to go out to the vnode. 702df8bae1dSRodney W. Grimes */ 703df8bae1dSRodney W. Grimes if (flags & MAP_SHARED) { 704df8bae1dSRodney W. Grimes rv = vm_allocate_with_pager(map, addr, size, 705df8bae1dSRodney W. Grimes fitit, pager, 706df8bae1dSRodney W. Grimes foff, FALSE); 707df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 708df8bae1dSRodney W. Grimes vm_object_deallocate(object); 709df8bae1dSRodney W. Grimes goto out; 710df8bae1dSRodney W. Grimes } 711df8bae1dSRodney W. Grimes /* 712df8bae1dSRodney W. Grimes * Don't cache the object. This is the easiest way 713df8bae1dSRodney W. Grimes * of ensuring that data gets back to the filesystem 714df8bae1dSRodney W. Grimes * because vnode_pager_deallocate() will fsync the 715df8bae1dSRodney W. Grimes * vnode. pager_cache() will lose the extra ref. 716df8bae1dSRodney W. Grimes */ 717df8bae1dSRodney W. Grimes if (prot & VM_PROT_WRITE) 718df8bae1dSRodney W. Grimes pager_cache(object, FALSE); 719df8bae1dSRodney W. Grimes else 720df8bae1dSRodney W. Grimes vm_object_deallocate(object); 721f720dc2cSDavid Greenman 722f720dc2cSDavid Greenman if( map->pmap) 723f720dc2cSDavid Greenman pmap_object_init_pt(map->pmap, *addr, object, foff, size); 724df8bae1dSRodney W. Grimes } 725df8bae1dSRodney W. Grimes /* 726df8bae1dSRodney W. Grimes * Copy-on-write of file. Two flavors. 727df8bae1dSRodney W. Grimes * MAP_COPY is true COW, you essentially get a snapshot of 728df8bae1dSRodney W. Grimes * the region at the time of mapping. MAP_PRIVATE means only 729df8bae1dSRodney W. Grimes * that your changes are not reflected back to the object. 730df8bae1dSRodney W. Grimes * Changes made by others will be seen. 731df8bae1dSRodney W. Grimes */ 732df8bae1dSRodney W. Grimes else { 733df8bae1dSRodney W. Grimes vm_map_t tmap; 734df8bae1dSRodney W. Grimes vm_offset_t off; 735df8bae1dSRodney W. Grimes 736df8bae1dSRodney W. Grimes /* locate and allocate the target address space */ 737df8bae1dSRodney W. Grimes rv = vm_map_find(map, NULL, (vm_offset_t)0, 738df8bae1dSRodney W. Grimes addr, size, fitit); 739df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 740df8bae1dSRodney W. Grimes vm_object_deallocate(object); 741df8bae1dSRodney W. Grimes goto out; 742df8bae1dSRodney W. Grimes } 743df8bae1dSRodney W. Grimes tmap = vm_map_create(pmap_create(size), VM_MIN_ADDRESS, 744df8bae1dSRodney W. Grimes VM_MIN_ADDRESS+size, TRUE); 745df8bae1dSRodney W. Grimes off = VM_MIN_ADDRESS; 746df8bae1dSRodney W. Grimes rv = vm_allocate_with_pager(tmap, &off, size, 747df8bae1dSRodney W. Grimes TRUE, pager, 748df8bae1dSRodney W. Grimes foff, FALSE); 749df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 750df8bae1dSRodney W. Grimes vm_object_deallocate(object); 751df8bae1dSRodney W. Grimes vm_map_deallocate(tmap); 752df8bae1dSRodney W. Grimes goto out; 753df8bae1dSRodney W. Grimes } 754df8bae1dSRodney W. Grimes /* 755df8bae1dSRodney W. Grimes * (XXX) 756df8bae1dSRodney W. Grimes * MAP_PRIVATE implies that we see changes made by 757df8bae1dSRodney W. Grimes * others. To ensure that we need to guarentee that 758df8bae1dSRodney W. Grimes * no copy object is created (otherwise original 759df8bae1dSRodney W. Grimes * pages would be pushed to the copy object and we 760df8bae1dSRodney W. Grimes * would never see changes made by others). We 761df8bae1dSRodney W. Grimes * totally sleeze it right now by marking the object 762df8bae1dSRodney W. Grimes * internal temporarily. 763df8bae1dSRodney W. Grimes */ 764df8bae1dSRodney W. Grimes if ((flags & MAP_COPY) == 0) 765df8bae1dSRodney W. Grimes object->flags |= OBJ_INTERNAL; 766df8bae1dSRodney W. Grimes rv = vm_map_copy(map, tmap, *addr, size, off, 767df8bae1dSRodney W. Grimes FALSE, FALSE); 768df8bae1dSRodney W. Grimes object->flags &= ~OBJ_INTERNAL; 769df8bae1dSRodney W. Grimes /* 770df8bae1dSRodney W. Grimes * (XXX) 771df8bae1dSRodney W. Grimes * My oh my, this only gets worse... 772df8bae1dSRodney W. Grimes * Force creation of a shadow object so that 773df8bae1dSRodney W. Grimes * vm_map_fork will do the right thing. 774df8bae1dSRodney W. Grimes */ 775df8bae1dSRodney W. Grimes if ((flags & MAP_COPY) == 0) { 776df8bae1dSRodney W. Grimes vm_map_t tmap; 777df8bae1dSRodney W. Grimes vm_map_entry_t tentry; 778df8bae1dSRodney W. Grimes vm_object_t tobject; 779df8bae1dSRodney W. Grimes vm_offset_t toffset; 780df8bae1dSRodney W. Grimes vm_prot_t tprot; 781df8bae1dSRodney W. Grimes boolean_t twired, tsu; 782df8bae1dSRodney W. Grimes 783df8bae1dSRodney W. Grimes tmap = map; 784df8bae1dSRodney W. Grimes vm_map_lookup(&tmap, *addr, VM_PROT_WRITE, 785df8bae1dSRodney W. Grimes &tentry, &tobject, &toffset, 786df8bae1dSRodney W. Grimes &tprot, &twired, &tsu); 787df8bae1dSRodney W. Grimes vm_map_lookup_done(tmap, tentry); 788df8bae1dSRodney W. Grimes } 789df8bae1dSRodney W. Grimes /* 790df8bae1dSRodney W. Grimes * (XXX) 791df8bae1dSRodney W. Grimes * Map copy code cannot detect sharing unless a 792df8bae1dSRodney W. Grimes * sharing map is involved. So we cheat and write 793df8bae1dSRodney W. Grimes * protect everything ourselves. 794df8bae1dSRodney W. Grimes */ 795df8bae1dSRodney W. Grimes vm_object_pmap_copy(object, foff, foff + size); 796f720dc2cSDavid Greenman if( map->pmap) 797f720dc2cSDavid Greenman pmap_object_init_pt(map->pmap, *addr, object, foff, size); 798df8bae1dSRodney W. Grimes vm_object_deallocate(object); 799df8bae1dSRodney W. Grimes vm_map_deallocate(tmap); 800df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) 801df8bae1dSRodney W. Grimes goto out; 802df8bae1dSRodney W. Grimes } 803df8bae1dSRodney W. Grimes #ifdef DEBUG 804df8bae1dSRodney W. Grimes if (mmapdebug & MDB_MAPIT) 805df8bae1dSRodney W. Grimes printf("vm_mmap(%d): FILE *addr %x size %x pager %x\n", 806df8bae1dSRodney W. Grimes curproc->p_pid, *addr, size, pager); 807df8bae1dSRodney W. Grimes #endif 808df8bae1dSRodney W. Grimes } 809df8bae1dSRodney W. Grimes /* 810df8bae1dSRodney W. Grimes * Correct protection (default is VM_PROT_ALL). 811df8bae1dSRodney W. Grimes * If maxprot is different than prot, we must set both explicitly. 812df8bae1dSRodney W. Grimes */ 813df8bae1dSRodney W. Grimes rv = KERN_SUCCESS; 814df8bae1dSRodney W. Grimes if (maxprot != VM_PROT_ALL) 815df8bae1dSRodney W. Grimes rv = vm_map_protect(map, *addr, *addr+size, maxprot, TRUE); 816df8bae1dSRodney W. Grimes if (rv == KERN_SUCCESS && prot != maxprot) 817df8bae1dSRodney W. Grimes rv = vm_map_protect(map, *addr, *addr+size, prot, FALSE); 818df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 819df8bae1dSRodney W. Grimes (void) vm_deallocate(map, *addr, size); 820df8bae1dSRodney W. Grimes goto out; 821df8bae1dSRodney W. Grimes } 822df8bae1dSRodney W. Grimes /* 823df8bae1dSRodney W. Grimes * Shared memory is also shared with children. 824df8bae1dSRodney W. Grimes */ 825df8bae1dSRodney W. Grimes if (flags & MAP_SHARED) { 826df8bae1dSRodney W. Grimes rv = vm_map_inherit(map, *addr, *addr+size, VM_INHERIT_SHARE); 827df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 828df8bae1dSRodney W. Grimes (void) vm_deallocate(map, *addr, size); 829df8bae1dSRodney W. Grimes goto out; 830df8bae1dSRodney W. Grimes } 831df8bae1dSRodney W. Grimes } 832df8bae1dSRodney W. Grimes out: 833df8bae1dSRodney W. Grimes #ifdef DEBUG 834df8bae1dSRodney W. Grimes if (mmapdebug & MDB_MAPIT) 835df8bae1dSRodney W. Grimes printf("vm_mmap: rv %d\n", rv); 836df8bae1dSRodney W. Grimes #endif 837df8bae1dSRodney W. Grimes switch (rv) { 838df8bae1dSRodney W. Grimes case KERN_SUCCESS: 839df8bae1dSRodney W. Grimes return (0); 840df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 841df8bae1dSRodney W. Grimes case KERN_NO_SPACE: 842df8bae1dSRodney W. Grimes return (ENOMEM); 843df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 844df8bae1dSRodney W. Grimes return (EACCES); 845df8bae1dSRodney W. Grimes default: 846df8bae1dSRodney W. Grimes return (EINVAL); 847df8bae1dSRodney W. Grimes } 848df8bae1dSRodney W. Grimes } 849