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 41b18bfc3dSJohn Dyson * $Id: vm_mmap.c,v 1.41 1996/05/03 21:01:51 phk Exp $ 42df8bae1dSRodney W. Grimes */ 43df8bae1dSRodney W. Grimes 44df8bae1dSRodney W. Grimes /* 45df8bae1dSRodney W. Grimes * Mapped file (mmap) interface to VM 46df8bae1dSRodney W. Grimes */ 47df8bae1dSRodney W. Grimes 48df8bae1dSRodney W. Grimes #include <sys/param.h> 49df8bae1dSRodney W. Grimes #include <sys/systm.h> 50d2d3e875SBruce Evans #include <sys/sysproto.h> 51df8bae1dSRodney W. Grimes #include <sys/filedesc.h> 52df8bae1dSRodney W. Grimes #include <sys/resourcevar.h> 53df8bae1dSRodney W. Grimes #include <sys/proc.h> 54df8bae1dSRodney W. Grimes #include <sys/vnode.h> 55df8bae1dSRodney W. Grimes #include <sys/file.h> 56df8bae1dSRodney W. Grimes #include <sys/mman.h> 57df8bae1dSRodney W. Grimes #include <sys/conf.h> 58efeaf95aSDavid Greenman #include <sys/vmmeter.h> 59df8bae1dSRodney W. Grimes 60df8bae1dSRodney W. Grimes #include <miscfs/specfs/specdev.h> 61df8bae1dSRodney W. Grimes 62df8bae1dSRodney W. Grimes #include <vm/vm.h> 63efeaf95aSDavid Greenman #include <vm/vm_param.h> 64efeaf95aSDavid Greenman #include <vm/vm_prot.h> 65efeaf95aSDavid Greenman #include <vm/vm_inherit.h> 66efeaf95aSDavid Greenman #include <vm/lock.h> 67efeaf95aSDavid Greenman #include <vm/pmap.h> 68efeaf95aSDavid Greenman #include <vm/vm_map.h> 69efeaf95aSDavid Greenman #include <vm/vm_object.h> 70df8bae1dSRodney W. Grimes #include <vm/vm_pager.h> 71b5e8ce9fSBruce Evans #include <vm/vm_pageout.h> 72efeaf95aSDavid Greenman #include <vm/vm_extern.h> 73bd7e5f99SJohn Dyson #include <vm/vm_kern.h> 74df8bae1dSRodney W. Grimes 75d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 76df8bae1dSRodney W. Grimes struct sbrk_args { 77df8bae1dSRodney W. Grimes int incr; 78df8bae1dSRodney W. Grimes }; 79d2d3e875SBruce Evans #endif 800d94caffSDavid Greenman 81df8bae1dSRodney W. Grimes /* ARGSUSED */ 82df8bae1dSRodney W. Grimes int 83df8bae1dSRodney W. Grimes sbrk(p, uap, retval) 84df8bae1dSRodney W. Grimes struct proc *p; 85df8bae1dSRodney W. Grimes struct sbrk_args *uap; 86df8bae1dSRodney W. Grimes int *retval; 87df8bae1dSRodney W. Grimes { 88df8bae1dSRodney W. Grimes 89df8bae1dSRodney W. Grimes /* Not yet implemented */ 90df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 91df8bae1dSRodney W. Grimes } 92df8bae1dSRodney W. Grimes 93d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 94df8bae1dSRodney W. Grimes struct sstk_args { 95df8bae1dSRodney W. Grimes int incr; 96df8bae1dSRodney W. Grimes }; 97d2d3e875SBruce Evans #endif 980d94caffSDavid Greenman 99df8bae1dSRodney W. Grimes /* ARGSUSED */ 100df8bae1dSRodney W. Grimes int 101df8bae1dSRodney W. Grimes sstk(p, uap, retval) 102df8bae1dSRodney W. Grimes struct proc *p; 103df8bae1dSRodney W. Grimes struct sstk_args *uap; 104df8bae1dSRodney W. Grimes int *retval; 105df8bae1dSRodney W. Grimes { 106df8bae1dSRodney W. Grimes 107df8bae1dSRodney W. Grimes /* Not yet implemented */ 108df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 109df8bae1dSRodney W. Grimes } 110df8bae1dSRodney W. Grimes 111df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 112d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 113df8bae1dSRodney W. Grimes struct getpagesize_args { 114df8bae1dSRodney W. Grimes int dummy; 115df8bae1dSRodney W. Grimes }; 116d2d3e875SBruce Evans #endif 1170d94caffSDavid Greenman 118df8bae1dSRodney W. Grimes /* ARGSUSED */ 119df8bae1dSRodney W. Grimes int 120df8bae1dSRodney W. Grimes ogetpagesize(p, uap, retval) 121df8bae1dSRodney W. Grimes struct proc *p; 122df8bae1dSRodney W. Grimes struct getpagesize_args *uap; 123df8bae1dSRodney W. Grimes int *retval; 124df8bae1dSRodney W. Grimes { 125df8bae1dSRodney W. Grimes 126df8bae1dSRodney W. Grimes *retval = PAGE_SIZE; 127df8bae1dSRodney W. Grimes return (0); 128df8bae1dSRodney W. Grimes } 129df8bae1dSRodney W. Grimes #endif /* COMPAT_43 || COMPAT_SUNOS */ 130df8bae1dSRodney W. Grimes 131d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 132df8bae1dSRodney W. Grimes struct mmap_args { 133df8bae1dSRodney W. Grimes caddr_t addr; 134df8bae1dSRodney W. Grimes size_t len; 135df8bae1dSRodney W. Grimes int prot; 136df8bae1dSRodney W. Grimes int flags; 137df8bae1dSRodney W. Grimes int fd; 138df8bae1dSRodney W. Grimes long pad; 139df8bae1dSRodney W. Grimes off_t pos; 140df8bae1dSRodney W. Grimes }; 141d2d3e875SBruce Evans #endif 142df8bae1dSRodney W. Grimes 143df8bae1dSRodney W. Grimes int 144df8bae1dSRodney W. Grimes mmap(p, uap, retval) 145df8bae1dSRodney W. Grimes struct proc *p; 146df8bae1dSRodney W. Grimes register struct mmap_args *uap; 147df8bae1dSRodney W. Grimes int *retval; 148df8bae1dSRodney W. Grimes { 149df8bae1dSRodney W. Grimes register struct filedesc *fdp = p->p_fd; 150df8bae1dSRodney W. Grimes register struct file *fp; 151df8bae1dSRodney W. Grimes struct vnode *vp; 152df8bae1dSRodney W. Grimes vm_offset_t addr; 1539154ee6aSPeter Wemm vm_size_t size, pageoff; 154df8bae1dSRodney W. Grimes vm_prot_t prot, maxprot; 155df8bae1dSRodney W. Grimes caddr_t handle; 156df8bae1dSRodney W. Grimes int flags, error; 157df8bae1dSRodney W. Grimes 158df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 159df8bae1dSRodney W. Grimes flags = uap->flags; 160df8bae1dSRodney W. Grimes /* 1610d94caffSDavid Greenman * Address (if FIXED) must be page aligned. Size is implicitly rounded 1620d94caffSDavid Greenman * to a page boundary. 163df8bae1dSRodney W. Grimes */ 164df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 165df8bae1dSRodney W. Grimes if (((flags & MAP_FIXED) && (addr & PAGE_MASK)) || 166df8bae1dSRodney W. Grimes (ssize_t) uap->len < 0 || ((flags & MAP_ANON) && uap->fd != -1)) 167df8bae1dSRodney W. Grimes return (EINVAL); 1689154ee6aSPeter Wemm 1699154ee6aSPeter Wemm /* 1709154ee6aSPeter Wemm * Round page if not already disallowed by above test 1719154ee6aSPeter Wemm * XXX: Is there any point in the MAP_FIXED align requirement above? 1729154ee6aSPeter Wemm */ 1739154ee6aSPeter Wemm size = uap->len; 1749154ee6aSPeter Wemm pageoff = (addr & PAGE_MASK); 1759154ee6aSPeter Wemm addr -= pageoff; 1769154ee6aSPeter Wemm size += pageoff; 1779154ee6aSPeter Wemm size = (vm_size_t) round_page(size); 1789154ee6aSPeter Wemm 179df8bae1dSRodney W. Grimes /* 1800d94caffSDavid Greenman * Check for illegal addresses. Watch out for address wrap... Note 1810d94caffSDavid Greenman * that VM_*_ADDRESS are not constants due to casts (argh). 182df8bae1dSRodney W. Grimes */ 183df8bae1dSRodney W. Grimes if (flags & MAP_FIXED) { 184bbc0ec52SDavid Greenman if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS) 185df8bae1dSRodney W. Grimes return (EINVAL); 18626f9a767SRodney W. Grimes #ifndef i386 187df8bae1dSRodney W. Grimes if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS) 188df8bae1dSRodney W. Grimes return (EINVAL); 18926f9a767SRodney W. Grimes #endif 190bbc0ec52SDavid Greenman if (addr + size < addr) 191df8bae1dSRodney W. Grimes return (EINVAL); 192df8bae1dSRodney W. Grimes } 193df8bae1dSRodney W. Grimes /* 1940d94caffSDavid Greenman * XXX if no hint provided for a non-fixed mapping place it after the 1950d94caffSDavid Greenman * end of the largest possible heap. 196df8bae1dSRodney W. Grimes * 1970d94caffSDavid Greenman * There should really be a pmap call to determine a reasonable location. 198df8bae1dSRodney W. Grimes */ 199df8bae1dSRodney W. Grimes if (addr == 0 && (flags & MAP_FIXED) == 0) 200df8bae1dSRodney W. Grimes addr = round_page(p->p_vmspace->vm_daddr + MAXDSIZ); 201df8bae1dSRodney W. Grimes if (flags & MAP_ANON) { 202df8bae1dSRodney W. Grimes /* 203df8bae1dSRodney W. Grimes * Mapping blank space is trivial. 204df8bae1dSRodney W. Grimes */ 205df8bae1dSRodney W. Grimes handle = NULL; 206df8bae1dSRodney W. Grimes maxprot = VM_PROT_ALL; 207df8bae1dSRodney W. Grimes } else { 208df8bae1dSRodney W. Grimes /* 2090d94caffSDavid Greenman * Mapping file, get fp for validation. Obtain vnode and make 2100d94caffSDavid Greenman * sure it is of appropriate type. 211df8bae1dSRodney W. Grimes */ 212df8bae1dSRodney W. Grimes if (((unsigned) uap->fd) >= fdp->fd_nfiles || 213df8bae1dSRodney W. Grimes (fp = fdp->fd_ofiles[uap->fd]) == NULL) 214df8bae1dSRodney W. Grimes return (EBADF); 215df8bae1dSRodney W. Grimes if (fp->f_type != DTYPE_VNODE) 216df8bae1dSRodney W. Grimes return (EINVAL); 217df8bae1dSRodney W. Grimes vp = (struct vnode *) fp->f_data; 218df8bae1dSRodney W. Grimes if (vp->v_type != VREG && vp->v_type != VCHR) 219df8bae1dSRodney W. Grimes return (EINVAL); 220df8bae1dSRodney W. Grimes /* 2210d94caffSDavid Greenman * XXX hack to handle use of /dev/zero to map anon memory (ala 2220d94caffSDavid Greenman * SunOS). 223df8bae1dSRodney W. Grimes */ 224df8bae1dSRodney W. Grimes if (vp->v_type == VCHR && iszerodev(vp->v_rdev)) { 225df8bae1dSRodney W. Grimes handle = NULL; 226df8bae1dSRodney W. Grimes maxprot = VM_PROT_ALL; 227df8bae1dSRodney W. Grimes flags |= MAP_ANON; 228df8bae1dSRodney W. Grimes } else { 229df8bae1dSRodney W. Grimes /* 230df8bae1dSRodney W. Grimes * Ensure that file and memory protections are 231df8bae1dSRodney W. Grimes * compatible. Note that we only worry about 232df8bae1dSRodney W. Grimes * writability if mapping is shared; in this case, 233df8bae1dSRodney W. Grimes * current and max prot are dictated by the open file. 234df8bae1dSRodney W. Grimes * XXX use the vnode instead? Problem is: what 2350d94caffSDavid Greenman * credentials do we use for determination? What if 2360d94caffSDavid Greenman * proc does a setuid? 237df8bae1dSRodney W. Grimes */ 238df8bae1dSRodney W. Grimes maxprot = VM_PROT_EXECUTE; /* ??? */ 239df8bae1dSRodney W. Grimes if (fp->f_flag & FREAD) 240df8bae1dSRodney W. Grimes maxprot |= VM_PROT_READ; 241df8bae1dSRodney W. Grimes else if (prot & PROT_READ) 242df8bae1dSRodney W. Grimes return (EACCES); 243df8bae1dSRodney W. Grimes if (flags & MAP_SHARED) { 244df8bae1dSRodney W. Grimes if (fp->f_flag & FWRITE) 245df8bae1dSRodney W. Grimes maxprot |= VM_PROT_WRITE; 246df8bae1dSRodney W. Grimes else if (prot & PROT_WRITE) 247df8bae1dSRodney W. Grimes return (EACCES); 248df8bae1dSRodney W. Grimes } else 249df8bae1dSRodney W. Grimes maxprot |= VM_PROT_WRITE; 250df8bae1dSRodney W. Grimes handle = (caddr_t) vp; 251df8bae1dSRodney W. Grimes } 252df8bae1dSRodney W. Grimes } 253df8bae1dSRodney W. Grimes error = vm_mmap(&p->p_vmspace->vm_map, &addr, size, prot, maxprot, 254a316d390SJohn Dyson flags, handle, uap->pos); 255df8bae1dSRodney W. Grimes if (error == 0) 256df8bae1dSRodney W. Grimes *retval = (int) addr; 257df8bae1dSRodney W. Grimes return (error); 258df8bae1dSRodney W. Grimes } 259df8bae1dSRodney W. Grimes 26005f0fdd2SPoul-Henning Kamp #ifdef COMPAT_43 261d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 26205f0fdd2SPoul-Henning Kamp struct ommap_args { 26305f0fdd2SPoul-Henning Kamp caddr_t addr; 26405f0fdd2SPoul-Henning Kamp int len; 26505f0fdd2SPoul-Henning Kamp int prot; 26605f0fdd2SPoul-Henning Kamp int flags; 26705f0fdd2SPoul-Henning Kamp int fd; 26805f0fdd2SPoul-Henning Kamp long pos; 26905f0fdd2SPoul-Henning Kamp }; 270d2d3e875SBruce Evans #endif 27105f0fdd2SPoul-Henning Kamp int 27205f0fdd2SPoul-Henning Kamp ommap(p, uap, retval) 27305f0fdd2SPoul-Henning Kamp struct proc *p; 27405f0fdd2SPoul-Henning Kamp register struct ommap_args *uap; 27505f0fdd2SPoul-Henning Kamp int *retval; 27605f0fdd2SPoul-Henning Kamp { 27705f0fdd2SPoul-Henning Kamp struct mmap_args nargs; 27805f0fdd2SPoul-Henning Kamp static const char cvtbsdprot[8] = { 27905f0fdd2SPoul-Henning Kamp 0, 28005f0fdd2SPoul-Henning Kamp PROT_EXEC, 28105f0fdd2SPoul-Henning Kamp PROT_WRITE, 28205f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE, 28305f0fdd2SPoul-Henning Kamp PROT_READ, 28405f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_READ, 28505f0fdd2SPoul-Henning Kamp PROT_WRITE | PROT_READ, 28605f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE | PROT_READ, 28705f0fdd2SPoul-Henning Kamp }; 2880d94caffSDavid Greenman 28905f0fdd2SPoul-Henning Kamp #define OMAP_ANON 0x0002 29005f0fdd2SPoul-Henning Kamp #define OMAP_COPY 0x0020 29105f0fdd2SPoul-Henning Kamp #define OMAP_SHARED 0x0010 29205f0fdd2SPoul-Henning Kamp #define OMAP_FIXED 0x0100 29305f0fdd2SPoul-Henning Kamp #define OMAP_INHERIT 0x0800 29405f0fdd2SPoul-Henning Kamp 29505f0fdd2SPoul-Henning Kamp nargs.addr = uap->addr; 29605f0fdd2SPoul-Henning Kamp nargs.len = uap->len; 29705f0fdd2SPoul-Henning Kamp nargs.prot = cvtbsdprot[uap->prot & 0x7]; 29805f0fdd2SPoul-Henning Kamp nargs.flags = 0; 29905f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_ANON) 30005f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_ANON; 30105f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_COPY) 30205f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_COPY; 30305f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_SHARED) 30405f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_SHARED; 30505f0fdd2SPoul-Henning Kamp else 30605f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_PRIVATE; 30705f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_FIXED) 30805f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_FIXED; 30905f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_INHERIT) 31005f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_INHERIT; 31105f0fdd2SPoul-Henning Kamp nargs.fd = uap->fd; 31205f0fdd2SPoul-Henning Kamp nargs.pos = uap->pos; 31305f0fdd2SPoul-Henning Kamp return (mmap(p, &nargs, retval)); 31405f0fdd2SPoul-Henning Kamp } 31505f0fdd2SPoul-Henning Kamp #endif /* COMPAT_43 */ 31605f0fdd2SPoul-Henning Kamp 31705f0fdd2SPoul-Henning Kamp 318d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 319df8bae1dSRodney W. Grimes struct msync_args { 320df8bae1dSRodney W. Grimes caddr_t addr; 321df8bae1dSRodney W. Grimes int len; 322e6c6af11SDavid Greenman int flags; 323df8bae1dSRodney W. Grimes }; 324d2d3e875SBruce Evans #endif 325df8bae1dSRodney W. Grimes int 326df8bae1dSRodney W. Grimes msync(p, uap, retval) 327df8bae1dSRodney W. Grimes struct proc *p; 328df8bae1dSRodney W. Grimes struct msync_args *uap; 329df8bae1dSRodney W. Grimes int *retval; 330df8bae1dSRodney W. Grimes { 331df8bae1dSRodney W. Grimes vm_offset_t addr; 332dabee6feSPeter Wemm vm_size_t size, pageoff; 333e6c6af11SDavid Greenman int flags; 334df8bae1dSRodney W. Grimes vm_map_t map; 335df8bae1dSRodney W. Grimes int rv; 336df8bae1dSRodney W. Grimes 337df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 3389154ee6aSPeter Wemm size = uap->len; 339e6c6af11SDavid Greenman flags = uap->flags; 340e6c6af11SDavid Greenman 341dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 342dabee6feSPeter Wemm addr -= pageoff; 343dabee6feSPeter Wemm size += pageoff; 344dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 3459154ee6aSPeter Wemm if (addr + size < addr) 346dabee6feSPeter Wemm return(EINVAL); 347dabee6feSPeter Wemm 348dabee6feSPeter Wemm if ((flags & (MS_ASYNC|MS_INVALIDATE)) == (MS_ASYNC|MS_INVALIDATE)) 3491e62bc63SDavid Greenman return (EINVAL); 3501e62bc63SDavid Greenman 3519154ee6aSPeter Wemm map = &p->p_vmspace->vm_map; 3529154ee6aSPeter Wemm 353df8bae1dSRodney W. Grimes /* 354df8bae1dSRodney W. Grimes * XXX Gak! If size is zero we are supposed to sync "all modified 3550d94caffSDavid Greenman * pages with the region containing addr". Unfortunately, we don't 3560d94caffSDavid Greenman * really keep track of individual mmaps so we approximate by flushing 3570d94caffSDavid Greenman * the range of the map entry containing addr. This can be incorrect 3580d94caffSDavid Greenman * if the region splits or is coalesced with a neighbor. 359df8bae1dSRodney W. Grimes */ 360df8bae1dSRodney W. Grimes if (size == 0) { 361df8bae1dSRodney W. Grimes vm_map_entry_t entry; 362df8bae1dSRodney W. Grimes 363df8bae1dSRodney W. Grimes vm_map_lock_read(map); 364df8bae1dSRodney W. Grimes rv = vm_map_lookup_entry(map, addr, &entry); 365df8bae1dSRodney W. Grimes vm_map_unlock_read(map); 366fbcfcdf7SDavid Greenman if (rv == FALSE) 367df8bae1dSRodney W. Grimes return (EINVAL); 368df8bae1dSRodney W. Grimes addr = entry->start; 369df8bae1dSRodney W. Grimes size = entry->end - entry->start; 370df8bae1dSRodney W. Grimes } 371e6c6af11SDavid Greenman 372df8bae1dSRodney W. Grimes /* 373df8bae1dSRodney W. Grimes * Clean the pages and interpret the return value. 374df8bae1dSRodney W. Grimes */ 3756c534ad8SDavid Greenman rv = vm_map_clean(map, addr, addr + size, (flags & MS_ASYNC) == 0, 376e6c6af11SDavid Greenman (flags & MS_INVALIDATE) != 0); 377e6c6af11SDavid Greenman 378df8bae1dSRodney W. Grimes switch (rv) { 379df8bae1dSRodney W. Grimes case KERN_SUCCESS: 380df8bae1dSRodney W. Grimes break; 381df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 382df8bae1dSRodney W. Grimes return (EINVAL); /* Sun returns ENOMEM? */ 383df8bae1dSRodney W. Grimes case KERN_FAILURE: 384df8bae1dSRodney W. Grimes return (EIO); 385df8bae1dSRodney W. Grimes default: 386df8bae1dSRodney W. Grimes return (EINVAL); 387df8bae1dSRodney W. Grimes } 388e6c6af11SDavid Greenman 389df8bae1dSRodney W. Grimes return (0); 390df8bae1dSRodney W. Grimes } 391df8bae1dSRodney W. Grimes 392d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 393df8bae1dSRodney W. Grimes struct munmap_args { 394df8bae1dSRodney W. Grimes caddr_t addr; 3959154ee6aSPeter Wemm size_t len; 396df8bae1dSRodney W. Grimes }; 397d2d3e875SBruce Evans #endif 398df8bae1dSRodney W. Grimes int 399df8bae1dSRodney W. Grimes munmap(p, uap, retval) 400df8bae1dSRodney W. Grimes register struct proc *p; 401df8bae1dSRodney W. Grimes register struct munmap_args *uap; 402df8bae1dSRodney W. Grimes int *retval; 403df8bae1dSRodney W. Grimes { 404df8bae1dSRodney W. Grimes vm_offset_t addr; 405dabee6feSPeter Wemm vm_size_t size, pageoff; 406df8bae1dSRodney W. Grimes vm_map_t map; 407df8bae1dSRodney W. Grimes 408df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 4099154ee6aSPeter Wemm size = uap->len; 410dabee6feSPeter Wemm 411dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 412dabee6feSPeter Wemm addr -= pageoff; 413dabee6feSPeter Wemm size += pageoff; 414dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 4159154ee6aSPeter Wemm if (addr + size < addr) 416df8bae1dSRodney W. Grimes return(EINVAL); 4179154ee6aSPeter Wemm 418df8bae1dSRodney W. Grimes if (size == 0) 419df8bae1dSRodney W. Grimes return (0); 420dabee6feSPeter Wemm 421df8bae1dSRodney W. Grimes /* 4220d94caffSDavid Greenman * Check for illegal addresses. Watch out for address wrap... Note 4230d94caffSDavid Greenman * that VM_*_ADDRESS are not constants due to casts (argh). 424df8bae1dSRodney W. Grimes */ 425bbc0ec52SDavid Greenman if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS) 426df8bae1dSRodney W. Grimes return (EINVAL); 42726f9a767SRodney W. Grimes #ifndef i386 428df8bae1dSRodney W. Grimes if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS) 429df8bae1dSRodney W. Grimes return (EINVAL); 43026f9a767SRodney W. Grimes #endif 431bbc0ec52SDavid Greenman if (addr + size < addr) 432df8bae1dSRodney W. Grimes return (EINVAL); 433df8bae1dSRodney W. Grimes map = &p->p_vmspace->vm_map; 434df8bae1dSRodney W. Grimes /* 435df8bae1dSRodney W. Grimes * Make sure entire range is allocated. 436df8bae1dSRodney W. Grimes */ 437df8bae1dSRodney W. Grimes if (!vm_map_check_protection(map, addr, addr + size, VM_PROT_NONE)) 438df8bae1dSRodney W. Grimes return (EINVAL); 439df8bae1dSRodney W. Grimes /* returns nothing but KERN_SUCCESS anyway */ 440df8bae1dSRodney W. Grimes (void) vm_map_remove(map, addr, addr + size); 441df8bae1dSRodney W. Grimes return (0); 442df8bae1dSRodney W. Grimes } 443df8bae1dSRodney W. Grimes 444df8bae1dSRodney W. Grimes void 44590324b07SDavid Greenman munmapfd(p, fd) 44690324b07SDavid Greenman struct proc *p; 447df8bae1dSRodney W. Grimes int fd; 448df8bae1dSRodney W. Grimes { 449df8bae1dSRodney W. Grimes /* 450c4ed5a07SDavid Greenman * XXX should unmap any regions mapped to this file 451df8bae1dSRodney W. Grimes */ 45290324b07SDavid Greenman p->p_fd->fd_ofileflags[fd] &= ~UF_MAPPED; 453df8bae1dSRodney W. Grimes } 454df8bae1dSRodney W. Grimes 455d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 456df8bae1dSRodney W. Grimes struct mprotect_args { 457df8bae1dSRodney W. Grimes caddr_t addr; 4589154ee6aSPeter Wemm size_t len; 459df8bae1dSRodney W. Grimes int prot; 460df8bae1dSRodney W. Grimes }; 461d2d3e875SBruce Evans #endif 462df8bae1dSRodney W. Grimes int 463df8bae1dSRodney W. Grimes mprotect(p, uap, retval) 464df8bae1dSRodney W. Grimes struct proc *p; 465df8bae1dSRodney W. Grimes struct mprotect_args *uap; 466df8bae1dSRodney W. Grimes int *retval; 467df8bae1dSRodney W. Grimes { 468df8bae1dSRodney W. Grimes vm_offset_t addr; 469dabee6feSPeter Wemm vm_size_t size, pageoff; 470df8bae1dSRodney W. Grimes register vm_prot_t prot; 471df8bae1dSRodney W. Grimes 472df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 4739154ee6aSPeter Wemm size = uap->len; 474df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 475df8bae1dSRodney W. Grimes 476dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 477dabee6feSPeter Wemm addr -= pageoff; 478dabee6feSPeter Wemm size += pageoff; 479dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 4809154ee6aSPeter Wemm if (addr + size < addr) 481dabee6feSPeter Wemm return(EINVAL); 482dabee6feSPeter Wemm 483df8bae1dSRodney W. Grimes switch (vm_map_protect(&p->p_vmspace->vm_map, addr, addr + size, prot, 484df8bae1dSRodney W. Grimes FALSE)) { 485df8bae1dSRodney W. Grimes case KERN_SUCCESS: 486df8bae1dSRodney W. Grimes return (0); 487df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 488df8bae1dSRodney W. Grimes return (EACCES); 489df8bae1dSRodney W. Grimes } 490df8bae1dSRodney W. Grimes return (EINVAL); 491df8bae1dSRodney W. Grimes } 492df8bae1dSRodney W. Grimes 493d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 494dabee6feSPeter Wemm struct minherit_args { 495dabee6feSPeter Wemm caddr_t addr; 4969154ee6aSPeter Wemm size_t len; 497dabee6feSPeter Wemm int inherit; 498dabee6feSPeter Wemm }; 499dabee6feSPeter Wemm #endif 500dabee6feSPeter Wemm int 501dabee6feSPeter Wemm minherit(p, uap, retval) 502dabee6feSPeter Wemm struct proc *p; 503dabee6feSPeter Wemm struct minherit_args *uap; 504dabee6feSPeter Wemm int *retval; 505dabee6feSPeter Wemm { 506dabee6feSPeter Wemm vm_offset_t addr; 507dabee6feSPeter Wemm vm_size_t size, pageoff; 508dabee6feSPeter Wemm register vm_inherit_t inherit; 509dabee6feSPeter Wemm 510dabee6feSPeter Wemm addr = (vm_offset_t)uap->addr; 5119154ee6aSPeter Wemm size = uap->len; 512dabee6feSPeter Wemm inherit = uap->inherit; 513dabee6feSPeter Wemm 514dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 515dabee6feSPeter Wemm addr -= pageoff; 516dabee6feSPeter Wemm size += pageoff; 517dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 5189154ee6aSPeter Wemm if (addr + size < addr) 519dabee6feSPeter Wemm return(EINVAL); 520dabee6feSPeter Wemm 521dabee6feSPeter Wemm switch (vm_map_inherit(&p->p_vmspace->vm_map, addr, addr+size, 522dabee6feSPeter Wemm inherit)) { 523dabee6feSPeter Wemm case KERN_SUCCESS: 524dabee6feSPeter Wemm return (0); 525dabee6feSPeter Wemm case KERN_PROTECTION_FAILURE: 526dabee6feSPeter Wemm return (EACCES); 527dabee6feSPeter Wemm } 528dabee6feSPeter Wemm return (EINVAL); 529dabee6feSPeter Wemm } 530dabee6feSPeter Wemm 531dabee6feSPeter Wemm #ifndef _SYS_SYSPROTO_H_ 532df8bae1dSRodney W. Grimes struct madvise_args { 533df8bae1dSRodney W. Grimes caddr_t addr; 5349154ee6aSPeter Wemm size_t len; 535df8bae1dSRodney W. Grimes int behav; 536df8bae1dSRodney W. Grimes }; 537d2d3e875SBruce Evans #endif 5380d94caffSDavid Greenman 539df8bae1dSRodney W. Grimes /* ARGSUSED */ 540df8bae1dSRodney W. Grimes int 541df8bae1dSRodney W. Grimes madvise(p, uap, retval) 542df8bae1dSRodney W. Grimes struct proc *p; 543df8bae1dSRodney W. Grimes struct madvise_args *uap; 544df8bae1dSRodney W. Grimes int *retval; 545df8bae1dSRodney W. Grimes { 546df8bae1dSRodney W. Grimes 547df8bae1dSRodney W. Grimes /* Not yet implemented */ 548df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 549df8bae1dSRodney W. Grimes } 550df8bae1dSRodney W. Grimes 551d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 552df8bae1dSRodney W. Grimes struct mincore_args { 553df8bae1dSRodney W. Grimes caddr_t addr; 5549154ee6aSPeter Wemm size_t len; 555df8bae1dSRodney W. Grimes char *vec; 556df8bae1dSRodney W. Grimes }; 557d2d3e875SBruce Evans #endif 5580d94caffSDavid Greenman 559df8bae1dSRodney W. Grimes /* ARGSUSED */ 560df8bae1dSRodney W. Grimes int 561df8bae1dSRodney W. Grimes mincore(p, uap, retval) 562df8bae1dSRodney W. Grimes struct proc *p; 563df8bae1dSRodney W. Grimes struct mincore_args *uap; 564df8bae1dSRodney W. Grimes int *retval; 565df8bae1dSRodney W. Grimes { 56602c04a2fSJohn Dyson vm_offset_t addr; 56702c04a2fSJohn Dyson vm_offset_t end; 56802c04a2fSJohn Dyson char *vec; 569df8bae1dSRodney W. Grimes 57002c04a2fSJohn Dyson addr = trunc_page((vm_offset_t) uap->addr); 5719154ee6aSPeter Wemm end = addr + (vm_size_t)round_page(uap->len); 57202c04a2fSJohn Dyson if (VM_MAXUSER_ADDRESS > 0 && end > VM_MAXUSER_ADDRESS) 57302c04a2fSJohn Dyson return (EINVAL); 57402c04a2fSJohn Dyson if (end < addr) 57502c04a2fSJohn Dyson return (EINVAL); 57602c04a2fSJohn Dyson 57702c04a2fSJohn Dyson vec = uap->vec; 57802c04a2fSJohn Dyson while(addr < end) { 57902c04a2fSJohn Dyson int error; 58002c04a2fSJohn Dyson if (pmap_extract(&p->p_vmspace->vm_pmap, addr)) { 58102c04a2fSJohn Dyson error = subyte( vec, 1); 58202c04a2fSJohn Dyson } else { 58302c04a2fSJohn Dyson error = subyte( vec, 0); 58402c04a2fSJohn Dyson } 58502c04a2fSJohn Dyson if (error) 58602c04a2fSJohn Dyson return EFAULT; 58702c04a2fSJohn Dyson vec++; 58802c04a2fSJohn Dyson addr += PAGE_SIZE; 58902c04a2fSJohn Dyson } 59002c04a2fSJohn Dyson return (0); 591df8bae1dSRodney W. Grimes } 592df8bae1dSRodney W. Grimes 593d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 594df8bae1dSRodney W. Grimes struct mlock_args { 595df8bae1dSRodney W. Grimes caddr_t addr; 596df8bae1dSRodney W. Grimes size_t len; 597df8bae1dSRodney W. Grimes }; 598d2d3e875SBruce Evans #endif 599df8bae1dSRodney W. Grimes int 600df8bae1dSRodney W. Grimes mlock(p, uap, retval) 601df8bae1dSRodney W. Grimes struct proc *p; 602df8bae1dSRodney W. Grimes struct mlock_args *uap; 603df8bae1dSRodney W. Grimes int *retval; 604df8bae1dSRodney W. Grimes { 605df8bae1dSRodney W. Grimes vm_offset_t addr; 606dabee6feSPeter Wemm vm_size_t size, pageoff; 607df8bae1dSRodney W. Grimes int error; 608df8bae1dSRodney W. Grimes 609df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 6109154ee6aSPeter Wemm size = uap->len; 6119154ee6aSPeter Wemm 612dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 613dabee6feSPeter Wemm addr -= pageoff; 614dabee6feSPeter Wemm size += pageoff; 615dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 616dabee6feSPeter Wemm 617dabee6feSPeter Wemm /* disable wrap around */ 6189154ee6aSPeter Wemm if (addr + size < addr) 619df8bae1dSRodney W. Grimes return (EINVAL); 620dabee6feSPeter Wemm 621df8bae1dSRodney W. Grimes if (atop(size) + cnt.v_wire_count > vm_page_max_wired) 622df8bae1dSRodney W. Grimes return (EAGAIN); 6239154ee6aSPeter Wemm 624df8bae1dSRodney W. Grimes #ifdef pmap_wired_count 625df8bae1dSRodney W. Grimes if (size + ptoa(pmap_wired_count(vm_map_pmap(&p->p_vmspace->vm_map))) > 626df8bae1dSRodney W. Grimes p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur) 627df8bae1dSRodney W. Grimes return (EAGAIN); 628df8bae1dSRodney W. Grimes #else 62905f0fdd2SPoul-Henning Kamp error = suser(p->p_ucred, &p->p_acflag); 63005f0fdd2SPoul-Henning Kamp if (error) 631df8bae1dSRodney W. Grimes return (error); 632df8bae1dSRodney W. Grimes #endif 633df8bae1dSRodney W. Grimes 634df8bae1dSRodney W. Grimes error = vm_map_pageable(&p->p_vmspace->vm_map, addr, addr + size, FALSE); 635df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 636df8bae1dSRodney W. Grimes } 637df8bae1dSRodney W. Grimes 638d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 639df8bae1dSRodney W. Grimes struct munlock_args { 640df8bae1dSRodney W. Grimes caddr_t addr; 641df8bae1dSRodney W. Grimes size_t len; 642df8bae1dSRodney W. Grimes }; 643d2d3e875SBruce Evans #endif 644df8bae1dSRodney W. Grimes int 645df8bae1dSRodney W. Grimes munlock(p, uap, retval) 646df8bae1dSRodney W. Grimes struct proc *p; 647df8bae1dSRodney W. Grimes struct munlock_args *uap; 648df8bae1dSRodney W. Grimes int *retval; 649df8bae1dSRodney W. Grimes { 650df8bae1dSRodney W. Grimes vm_offset_t addr; 651dabee6feSPeter Wemm vm_size_t size, pageoff; 652df8bae1dSRodney W. Grimes int error; 653df8bae1dSRodney W. Grimes 654df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 6559154ee6aSPeter Wemm size = uap->len; 6569154ee6aSPeter Wemm 657dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 658dabee6feSPeter Wemm addr -= pageoff; 659dabee6feSPeter Wemm size += pageoff; 660dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 661dabee6feSPeter Wemm 662dabee6feSPeter Wemm /* disable wrap around */ 6639154ee6aSPeter Wemm if (addr + size < addr) 664df8bae1dSRodney W. Grimes return (EINVAL); 665dabee6feSPeter Wemm 666df8bae1dSRodney W. Grimes #ifndef pmap_wired_count 66705f0fdd2SPoul-Henning Kamp error = suser(p->p_ucred, &p->p_acflag); 66805f0fdd2SPoul-Henning Kamp if (error) 669df8bae1dSRodney W. Grimes return (error); 670df8bae1dSRodney W. Grimes #endif 671df8bae1dSRodney W. Grimes 672df8bae1dSRodney W. Grimes error = vm_map_pageable(&p->p_vmspace->vm_map, addr, addr + size, TRUE); 673df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 674df8bae1dSRodney W. Grimes } 675df8bae1dSRodney W. Grimes 676df8bae1dSRodney W. Grimes /* 677df8bae1dSRodney W. Grimes * Internal version of mmap. 678df8bae1dSRodney W. Grimes * Currently used by mmap, exec, and sys5 shared memory. 679df8bae1dSRodney W. Grimes * Handle is either a vnode pointer or NULL for MAP_ANON. 680df8bae1dSRodney W. Grimes */ 681df8bae1dSRodney W. Grimes int 682df8bae1dSRodney W. Grimes vm_mmap(map, addr, size, prot, maxprot, flags, handle, foff) 683df8bae1dSRodney W. Grimes register vm_map_t map; 684df8bae1dSRodney W. Grimes register vm_offset_t *addr; 685df8bae1dSRodney W. Grimes register vm_size_t size; 686df8bae1dSRodney W. Grimes vm_prot_t prot, maxprot; 687df8bae1dSRodney W. Grimes register int flags; 688df8bae1dSRodney W. Grimes caddr_t handle; /* XXX should be vp */ 689a316d390SJohn Dyson vm_ooffset_t foff; 690df8bae1dSRodney W. Grimes { 691df8bae1dSRodney W. Grimes boolean_t fitit; 692bd7e5f99SJohn Dyson vm_object_t object, object2; 693df8bae1dSRodney W. Grimes struct vnode *vp = NULL; 69424a1cce3SDavid Greenman objtype_t type; 695df8bae1dSRodney W. Grimes int rv = KERN_SUCCESS; 696bd7e5f99SJohn Dyson vm_ooffset_t objsize; 697bd7e5f99SJohn Dyson int docow; 69806cb7259SDavid Greenman struct proc *p = curproc; 699df8bae1dSRodney W. Grimes 700df8bae1dSRodney W. Grimes if (size == 0) 701df8bae1dSRodney W. Grimes return (0); 702df8bae1dSRodney W. Grimes 70306cb7259SDavid Greenman objsize = size = round_page(size); 704df8bae1dSRodney W. Grimes 705df8bae1dSRodney W. Grimes /* 706bc9ad247SDavid Greenman * We currently can only deal with page aligned file offsets. 707bc9ad247SDavid Greenman * The check is here rather than in the syscall because the 708bc9ad247SDavid Greenman * kernel calls this function internally for other mmaping 709bc9ad247SDavid Greenman * operations (such as in exec) and non-aligned offsets will 710bc9ad247SDavid Greenman * cause pmap inconsistencies...so we want to be sure to 711bc9ad247SDavid Greenman * disallow this in all cases. 712bc9ad247SDavid Greenman */ 713bc9ad247SDavid Greenman if (foff & PAGE_MASK) 714bc9ad247SDavid Greenman return (EINVAL); 715bc9ad247SDavid Greenman 71606cb7259SDavid Greenman if ((flags & MAP_FIXED) == 0) { 71706cb7259SDavid Greenman fitit = TRUE; 71806cb7259SDavid Greenman *addr = round_page(*addr); 71906cb7259SDavid Greenman } else { 72006cb7259SDavid Greenman if (*addr != trunc_page(*addr)) 72106cb7259SDavid Greenman return (EINVAL); 72206cb7259SDavid Greenman fitit = FALSE; 72306cb7259SDavid Greenman (void) vm_map_remove(map, *addr, *addr + size); 72406cb7259SDavid Greenman } 72506cb7259SDavid Greenman 726bc9ad247SDavid Greenman /* 72724a1cce3SDavid Greenman * Lookup/allocate object. 728df8bae1dSRodney W. Grimes */ 7295f55e841SDavid Greenman if (flags & MAP_ANON) { 73024a1cce3SDavid Greenman type = OBJT_SWAP; 7315f55e841SDavid Greenman /* 7325f55e841SDavid Greenman * Unnamed anonymous regions always start at 0. 7335f55e841SDavid Greenman */ 7345f55e841SDavid Greenman if (handle == 0) 7355f55e841SDavid Greenman foff = 0; 7365f55e841SDavid Greenman } else { 737df8bae1dSRodney W. Grimes vp = (struct vnode *) handle; 738df8bae1dSRodney W. Grimes if (vp->v_type == VCHR) { 73924a1cce3SDavid Greenman type = OBJT_DEVICE; 740df8bae1dSRodney W. Grimes handle = (caddr_t) vp->v_rdev; 74106cb7259SDavid Greenman } else { 74206cb7259SDavid Greenman struct vattr vat; 74306cb7259SDavid Greenman int error; 74406cb7259SDavid Greenman 74506cb7259SDavid Greenman error = VOP_GETATTR(vp, &vat, p->p_ucred, p); 74606cb7259SDavid Greenman if (error) 74706cb7259SDavid Greenman return (error); 748bd7e5f99SJohn Dyson objsize = round_page(vat.va_size); 74924a1cce3SDavid Greenman type = OBJT_VNODE; 750df8bae1dSRodney W. Grimes } 75106cb7259SDavid Greenman } 752bd7e5f99SJohn Dyson object = vm_pager_allocate(type, handle, OFF_TO_IDX(objsize), prot, foff); 75324a1cce3SDavid Greenman if (object == NULL) 75424a1cce3SDavid Greenman return (type == OBJT_DEVICE ? EINVAL : ENOMEM); 755df8bae1dSRodney W. Grimes 7565850152dSJohn Dyson /* 7578f2ec877SDavid Greenman * Force device mappings to be shared. 7585850152dSJohn Dyson */ 7598f2ec877SDavid Greenman if (type == OBJT_DEVICE) { 7608f2ec877SDavid Greenman flags &= ~(MAP_PRIVATE|MAP_COPY); 7615850152dSJohn Dyson flags |= MAP_SHARED; 7628f2ec877SDavid Greenman } 7635850152dSJohn Dyson 764bd7e5f99SJohn Dyson object2 = NULL; 765bd7e5f99SJohn Dyson docow = 0; 7665850152dSJohn Dyson if ((flags & (MAP_ANON|MAP_SHARED)) == 0) { 767bd7e5f99SJohn Dyson docow = MAP_COPY_ON_WRITE; 768bd7e5f99SJohn Dyson if (objsize < size) { 769bd7e5f99SJohn Dyson object2 = vm_object_allocate( OBJT_DEFAULT, 770aa8de40aSPoul-Henning Kamp OFF_TO_IDX(size - (foff & ~PAGE_MASK))); 771bd7e5f99SJohn Dyson object2->backing_object = object; 772bd7e5f99SJohn Dyson object2->backing_object_offset = foff; 773bd7e5f99SJohn Dyson TAILQ_INSERT_TAIL(&object->shadow_head, 774bd7e5f99SJohn Dyson object2, shadow_list); 775de5f6a77SJohn Dyson ++object->shadow_count; 776bd7e5f99SJohn Dyson } else { 777bd7e5f99SJohn Dyson docow |= MAP_COPY_NEEDED; 778bd7e5f99SJohn Dyson } 779bd7e5f99SJohn Dyson } 7805850152dSJohn Dyson 781bd7e5f99SJohn Dyson if (object2) 782bd7e5f99SJohn Dyson rv = vm_map_find(map, object2, 0, addr, size, fitit, 783bd7e5f99SJohn Dyson prot, maxprot, docow); 784bd7e5f99SJohn Dyson else 785bd7e5f99SJohn Dyson rv = vm_map_find(map, object, foff, addr, size, fitit, 786bd7e5f99SJohn Dyson prot, maxprot, docow); 787bd7e5f99SJohn Dyson 788bd7e5f99SJohn Dyson 789df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 7907fb0c17eSDavid Greenman /* 79124a1cce3SDavid Greenman * Lose the object reference. Will destroy the 79224a1cce3SDavid Greenman * object if it's an unnamed anonymous mapping 79324a1cce3SDavid Greenman * or named anonymous without other references. 7947fb0c17eSDavid Greenman */ 795bd7e5f99SJohn Dyson if (object2) 796bd7e5f99SJohn Dyson vm_object_deallocate(object2); 797bd7e5f99SJohn Dyson else 798df8bae1dSRodney W. Grimes vm_object_deallocate(object); 799df8bae1dSRodney W. Grimes goto out; 800df8bae1dSRodney W. Grimes } 801e17bed12SJohn Dyson 802df8bae1dSRodney W. Grimes /* 8037fb0c17eSDavid Greenman * "Pre-fault" resident pages. 8047fb0c17eSDavid Greenman */ 805b18bfc3dSJohn Dyson if ((type == OBJT_VNODE) && (map->pmap != NULL)) { 806a316d390SJohn Dyson pmap_object_init_pt(map->pmap, *addr, 807a316d390SJohn Dyson object, (vm_pindex_t) OFF_TO_IDX(foff), size); 808df8bae1dSRodney W. Grimes } 8097fb0c17eSDavid Greenman 810df8bae1dSRodney W. Grimes /* 811df8bae1dSRodney W. Grimes * Shared memory is also shared with children. 812df8bae1dSRodney W. Grimes */ 8135850152dSJohn Dyson if (flags & (MAP_SHARED|MAP_INHERIT)) { 814df8bae1dSRodney W. Grimes rv = vm_map_inherit(map, *addr, *addr + size, VM_INHERIT_SHARE); 815df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 8167fb0c17eSDavid Greenman (void) vm_map_remove(map, *addr, *addr + size); 817df8bae1dSRodney W. Grimes goto out; 818df8bae1dSRodney W. Grimes } 819df8bae1dSRodney W. Grimes } 820df8bae1dSRodney W. Grimes out: 821df8bae1dSRodney W. Grimes switch (rv) { 822df8bae1dSRodney W. Grimes case KERN_SUCCESS: 823df8bae1dSRodney W. Grimes return (0); 824df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 825df8bae1dSRodney W. Grimes case KERN_NO_SPACE: 826df8bae1dSRodney W. Grimes return (ENOMEM); 827df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 828df8bae1dSRodney W. Grimes return (EACCES); 829df8bae1dSRodney W. Grimes default: 830df8bae1dSRodney W. Grimes return (EINVAL); 831df8bae1dSRodney W. Grimes } 832df8bae1dSRodney W. Grimes } 833