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