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