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 410a0a85b3SJohn Dyson * $Id: vm_mmap.c,v 1.64 1997/06/15 23:35:32 dyson 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 48e9822d92SJoerg Wunsch #include "opt_rlimit.h" 49e9822d92SJoerg Wunsch 50df8bae1dSRodney W. Grimes #include <sys/param.h> 51df8bae1dSRodney W. Grimes #include <sys/systm.h> 52d2d3e875SBruce Evans #include <sys/sysproto.h> 53df8bae1dSRodney W. Grimes #include <sys/filedesc.h> 54df8bae1dSRodney W. Grimes #include <sys/resourcevar.h> 55df8bae1dSRodney W. Grimes #include <sys/proc.h> 56df8bae1dSRodney W. Grimes #include <sys/vnode.h> 573ac4d1efSBruce Evans #include <sys/fcntl.h> 58df8bae1dSRodney W. Grimes #include <sys/file.h> 59df8bae1dSRodney W. Grimes #include <sys/mman.h> 60df8bae1dSRodney W. Grimes #include <sys/conf.h> 61efeaf95aSDavid Greenman #include <sys/vmmeter.h> 62df8bae1dSRodney W. Grimes 63df8bae1dSRodney W. Grimes #include <miscfs/specfs/specdev.h> 64df8bae1dSRodney W. Grimes 65df8bae1dSRodney W. Grimes #include <vm/vm.h> 66efeaf95aSDavid Greenman #include <vm/vm_param.h> 67efeaf95aSDavid Greenman #include <vm/vm_prot.h> 68efeaf95aSDavid Greenman #include <vm/vm_inherit.h> 69996c772fSJohn Dyson #include <sys/lock.h> 70efeaf95aSDavid Greenman #include <vm/pmap.h> 71efeaf95aSDavid Greenman #include <vm/vm_map.h> 72efeaf95aSDavid Greenman #include <vm/vm_object.h> 73df8bae1dSRodney W. Grimes #include <vm/vm_pager.h> 74b5e8ce9fSBruce Evans #include <vm/vm_pageout.h> 75efeaf95aSDavid Greenman #include <vm/vm_extern.h> 76bd7e5f99SJohn Dyson #include <vm/vm_kern.h> 77867a482dSJohn Dyson #include <vm/vm_page.h> 78df8bae1dSRodney W. Grimes 79d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 80df8bae1dSRodney W. Grimes struct sbrk_args { 81df8bae1dSRodney W. Grimes int incr; 82df8bae1dSRodney W. Grimes }; 83d2d3e875SBruce Evans #endif 840d94caffSDavid Greenman 85df8bae1dSRodney W. Grimes /* ARGSUSED */ 86df8bae1dSRodney W. Grimes int 87df8bae1dSRodney W. Grimes sbrk(p, uap, retval) 88df8bae1dSRodney W. Grimes struct proc *p; 89df8bae1dSRodney W. Grimes struct sbrk_args *uap; 90df8bae1dSRodney W. Grimes int *retval; 91df8bae1dSRodney W. Grimes { 92df8bae1dSRodney W. Grimes 93df8bae1dSRodney W. Grimes /* Not yet implemented */ 94df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 95df8bae1dSRodney W. Grimes } 96df8bae1dSRodney W. Grimes 97d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 98df8bae1dSRodney W. Grimes struct sstk_args { 99df8bae1dSRodney W. Grimes int incr; 100df8bae1dSRodney W. Grimes }; 101d2d3e875SBruce Evans #endif 1020d94caffSDavid Greenman 103df8bae1dSRodney W. Grimes /* ARGSUSED */ 104df8bae1dSRodney W. Grimes int 105df8bae1dSRodney W. Grimes sstk(p, uap, retval) 106df8bae1dSRodney W. Grimes struct proc *p; 107df8bae1dSRodney W. Grimes struct sstk_args *uap; 108df8bae1dSRodney W. Grimes int *retval; 109df8bae1dSRodney W. Grimes { 110df8bae1dSRodney W. Grimes 111df8bae1dSRodney W. Grimes /* Not yet implemented */ 112df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 113df8bae1dSRodney W. Grimes } 114df8bae1dSRodney W. Grimes 115df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 116d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 117df8bae1dSRodney W. Grimes struct getpagesize_args { 118df8bae1dSRodney W. Grimes int dummy; 119df8bae1dSRodney W. Grimes }; 120d2d3e875SBruce Evans #endif 1210d94caffSDavid Greenman 122df8bae1dSRodney W. Grimes /* ARGSUSED */ 123df8bae1dSRodney W. Grimes int 124df8bae1dSRodney W. Grimes ogetpagesize(p, uap, retval) 125df8bae1dSRodney W. Grimes struct proc *p; 126df8bae1dSRodney W. Grimes struct getpagesize_args *uap; 127df8bae1dSRodney W. Grimes int *retval; 128df8bae1dSRodney W. Grimes { 129df8bae1dSRodney W. Grimes 130df8bae1dSRodney W. Grimes *retval = PAGE_SIZE; 131df8bae1dSRodney W. Grimes return (0); 132df8bae1dSRodney W. Grimes } 133df8bae1dSRodney W. Grimes #endif /* COMPAT_43 || COMPAT_SUNOS */ 134df8bae1dSRodney W. Grimes 135d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 136df8bae1dSRodney W. Grimes struct mmap_args { 137df8bae1dSRodney W. Grimes caddr_t addr; 138df8bae1dSRodney W. Grimes size_t len; 139df8bae1dSRodney W. Grimes int prot; 140df8bae1dSRodney W. Grimes int flags; 141df8bae1dSRodney W. Grimes int fd; 142df8bae1dSRodney W. Grimes long pad; 143df8bae1dSRodney W. Grimes off_t pos; 144df8bae1dSRodney W. Grimes }; 145d2d3e875SBruce Evans #endif 146df8bae1dSRodney W. Grimes 147df8bae1dSRodney W. Grimes int 148df8bae1dSRodney W. Grimes mmap(p, uap, retval) 149df8bae1dSRodney W. Grimes struct proc *p; 150df8bae1dSRodney W. Grimes register struct mmap_args *uap; 151df8bae1dSRodney W. Grimes int *retval; 152df8bae1dSRodney W. Grimes { 153df8bae1dSRodney W. Grimes register struct filedesc *fdp = p->p_fd; 154df8bae1dSRodney W. Grimes register struct file *fp; 155df8bae1dSRodney W. Grimes struct vnode *vp; 156df8bae1dSRodney W. Grimes vm_offset_t addr; 1579154ee6aSPeter Wemm vm_size_t size, pageoff; 158df8bae1dSRodney W. Grimes vm_prot_t prot, maxprot; 159df8bae1dSRodney W. Grimes caddr_t handle; 160df8bae1dSRodney W. Grimes int flags, error; 161df8bae1dSRodney W. Grimes 162df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 163df8bae1dSRodney W. Grimes flags = uap->flags; 164df8bae1dSRodney W. Grimes /* 1650d94caffSDavid Greenman * Address (if FIXED) must be page aligned. Size is implicitly rounded 1660d94caffSDavid Greenman * to a page boundary. 167df8bae1dSRodney W. Grimes */ 168df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 169df8bae1dSRodney W. Grimes if (((flags & MAP_FIXED) && (addr & PAGE_MASK)) || 170df8bae1dSRodney W. Grimes (ssize_t) uap->len < 0 || ((flags & MAP_ANON) && uap->fd != -1)) 171df8bae1dSRodney W. Grimes return (EINVAL); 1729154ee6aSPeter Wemm 1739154ee6aSPeter Wemm /* 1749154ee6aSPeter Wemm * Round page if not already disallowed by above test 1759154ee6aSPeter Wemm * XXX: Is there any point in the MAP_FIXED align requirement above? 1769154ee6aSPeter Wemm */ 1779154ee6aSPeter Wemm size = uap->len; 1789154ee6aSPeter Wemm pageoff = (addr & PAGE_MASK); 1799154ee6aSPeter Wemm addr -= pageoff; 1809154ee6aSPeter Wemm size += pageoff; 1819154ee6aSPeter Wemm size = (vm_size_t) round_page(size); 1829154ee6aSPeter Wemm 183df8bae1dSRodney W. Grimes /* 1840d94caffSDavid Greenman * Check for illegal addresses. Watch out for address wrap... Note 1850d94caffSDavid Greenman * that VM_*_ADDRESS are not constants due to casts (argh). 186df8bae1dSRodney W. Grimes */ 187df8bae1dSRodney W. Grimes if (flags & MAP_FIXED) { 188bbc0ec52SDavid Greenman if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS) 189df8bae1dSRodney W. Grimes return (EINVAL); 19026f9a767SRodney W. Grimes #ifndef i386 191df8bae1dSRodney W. Grimes if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS) 192df8bae1dSRodney W. Grimes return (EINVAL); 19326f9a767SRodney W. Grimes #endif 194bbc0ec52SDavid Greenman if (addr + size < addr) 195df8bae1dSRodney W. Grimes return (EINVAL); 196df8bae1dSRodney W. Grimes } 197df8bae1dSRodney W. Grimes /* 1980d94caffSDavid Greenman * XXX if no hint provided for a non-fixed mapping place it after the 1990d94caffSDavid Greenman * end of the largest possible heap. 200df8bae1dSRodney W. Grimes * 2010d94caffSDavid Greenman * There should really be a pmap call to determine a reasonable location. 202df8bae1dSRodney W. Grimes */ 203df8bae1dSRodney W. Grimes if (addr == 0 && (flags & MAP_FIXED) == 0) 204df8bae1dSRodney W. Grimes addr = round_page(p->p_vmspace->vm_daddr + MAXDSIZ); 205df8bae1dSRodney W. Grimes if (flags & MAP_ANON) { 206df8bae1dSRodney W. Grimes /* 207df8bae1dSRodney W. Grimes * Mapping blank space is trivial. 208df8bae1dSRodney W. Grimes */ 209df8bae1dSRodney W. Grimes handle = NULL; 210df8bae1dSRodney W. Grimes maxprot = VM_PROT_ALL; 211df8bae1dSRodney W. Grimes } else { 212df8bae1dSRodney W. Grimes /* 2130d94caffSDavid Greenman * Mapping file, get fp for validation. Obtain vnode and make 2140d94caffSDavid Greenman * sure it is of appropriate type. 215df8bae1dSRodney W. Grimes */ 216df8bae1dSRodney W. Grimes if (((unsigned) uap->fd) >= fdp->fd_nfiles || 217df8bae1dSRodney W. Grimes (fp = fdp->fd_ofiles[uap->fd]) == NULL) 218df8bae1dSRodney W. Grimes return (EBADF); 219df8bae1dSRodney W. Grimes if (fp->f_type != DTYPE_VNODE) 220df8bae1dSRodney W. Grimes return (EINVAL); 221df8bae1dSRodney W. Grimes vp = (struct vnode *) fp->f_data; 222df8bae1dSRodney W. Grimes if (vp->v_type != VREG && vp->v_type != VCHR) 223df8bae1dSRodney W. Grimes return (EINVAL); 224df8bae1dSRodney W. Grimes /* 2250d94caffSDavid Greenman * XXX hack to handle use of /dev/zero to map anon memory (ala 2260d94caffSDavid Greenman * SunOS). 227df8bae1dSRodney W. Grimes */ 228df8bae1dSRodney W. Grimes if (vp->v_type == VCHR && iszerodev(vp->v_rdev)) { 229df8bae1dSRodney W. Grimes handle = NULL; 230df8bae1dSRodney W. Grimes maxprot = VM_PROT_ALL; 231df8bae1dSRodney W. Grimes flags |= MAP_ANON; 232df8bae1dSRodney W. Grimes } else { 233df8bae1dSRodney W. Grimes /* 234df8bae1dSRodney W. Grimes * Ensure that file and memory protections are 235df8bae1dSRodney W. Grimes * compatible. Note that we only worry about 236df8bae1dSRodney W. Grimes * writability if mapping is shared; in this case, 237df8bae1dSRodney W. Grimes * current and max prot are dictated by the open file. 238df8bae1dSRodney W. Grimes * XXX use the vnode instead? Problem is: what 2390d94caffSDavid Greenman * credentials do we use for determination? What if 2400d94caffSDavid Greenman * proc does a setuid? 241df8bae1dSRodney W. Grimes */ 242df8bae1dSRodney W. Grimes maxprot = VM_PROT_EXECUTE; /* ??? */ 243df8bae1dSRodney W. Grimes if (fp->f_flag & FREAD) 244df8bae1dSRodney W. Grimes maxprot |= VM_PROT_READ; 245df8bae1dSRodney W. Grimes else if (prot & PROT_READ) 246df8bae1dSRodney W. Grimes return (EACCES); 247df8bae1dSRodney W. Grimes if (flags & MAP_SHARED) { 248df8bae1dSRodney W. Grimes if (fp->f_flag & FWRITE) 249df8bae1dSRodney W. Grimes maxprot |= VM_PROT_WRITE; 250df8bae1dSRodney W. Grimes else if (prot & PROT_WRITE) 251df8bae1dSRodney W. Grimes return (EACCES); 252df8bae1dSRodney W. Grimes } else 253df8bae1dSRodney W. Grimes maxprot |= VM_PROT_WRITE; 254df8bae1dSRodney W. Grimes handle = (caddr_t) vp; 255df8bae1dSRodney W. Grimes } 256df8bae1dSRodney W. Grimes } 257df8bae1dSRodney W. Grimes error = vm_mmap(&p->p_vmspace->vm_map, &addr, size, prot, maxprot, 258a316d390SJohn Dyson flags, handle, uap->pos); 259df8bae1dSRodney W. Grimes if (error == 0) 260df8bae1dSRodney W. Grimes *retval = (int) addr; 261df8bae1dSRodney W. Grimes return (error); 262df8bae1dSRodney W. Grimes } 263df8bae1dSRodney W. Grimes 26405f0fdd2SPoul-Henning Kamp #ifdef COMPAT_43 265d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 26605f0fdd2SPoul-Henning Kamp struct ommap_args { 26705f0fdd2SPoul-Henning Kamp caddr_t addr; 26805f0fdd2SPoul-Henning Kamp int len; 26905f0fdd2SPoul-Henning Kamp int prot; 27005f0fdd2SPoul-Henning Kamp int flags; 27105f0fdd2SPoul-Henning Kamp int fd; 27205f0fdd2SPoul-Henning Kamp long pos; 27305f0fdd2SPoul-Henning Kamp }; 274d2d3e875SBruce Evans #endif 27505f0fdd2SPoul-Henning Kamp int 27605f0fdd2SPoul-Henning Kamp ommap(p, uap, retval) 27705f0fdd2SPoul-Henning Kamp struct proc *p; 27805f0fdd2SPoul-Henning Kamp register struct ommap_args *uap; 27905f0fdd2SPoul-Henning Kamp int *retval; 28005f0fdd2SPoul-Henning Kamp { 28105f0fdd2SPoul-Henning Kamp struct mmap_args nargs; 28205f0fdd2SPoul-Henning Kamp static const char cvtbsdprot[8] = { 28305f0fdd2SPoul-Henning Kamp 0, 28405f0fdd2SPoul-Henning Kamp PROT_EXEC, 28505f0fdd2SPoul-Henning Kamp PROT_WRITE, 28605f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE, 28705f0fdd2SPoul-Henning Kamp PROT_READ, 28805f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_READ, 28905f0fdd2SPoul-Henning Kamp PROT_WRITE | PROT_READ, 29005f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE | PROT_READ, 29105f0fdd2SPoul-Henning Kamp }; 2920d94caffSDavid Greenman 29305f0fdd2SPoul-Henning Kamp #define OMAP_ANON 0x0002 29405f0fdd2SPoul-Henning Kamp #define OMAP_COPY 0x0020 29505f0fdd2SPoul-Henning Kamp #define OMAP_SHARED 0x0010 29605f0fdd2SPoul-Henning Kamp #define OMAP_FIXED 0x0100 29705f0fdd2SPoul-Henning Kamp #define OMAP_INHERIT 0x0800 29805f0fdd2SPoul-Henning Kamp 29905f0fdd2SPoul-Henning Kamp nargs.addr = uap->addr; 30005f0fdd2SPoul-Henning Kamp nargs.len = uap->len; 30105f0fdd2SPoul-Henning Kamp nargs.prot = cvtbsdprot[uap->prot & 0x7]; 30205f0fdd2SPoul-Henning Kamp nargs.flags = 0; 30305f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_ANON) 30405f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_ANON; 30505f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_COPY) 30605f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_COPY; 30705f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_SHARED) 30805f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_SHARED; 30905f0fdd2SPoul-Henning Kamp else 31005f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_PRIVATE; 31105f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_FIXED) 31205f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_FIXED; 31305f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_INHERIT) 31405f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_INHERIT; 31505f0fdd2SPoul-Henning Kamp nargs.fd = uap->fd; 31605f0fdd2SPoul-Henning Kamp nargs.pos = uap->pos; 31705f0fdd2SPoul-Henning Kamp return (mmap(p, &nargs, retval)); 31805f0fdd2SPoul-Henning Kamp } 31905f0fdd2SPoul-Henning Kamp #endif /* COMPAT_43 */ 32005f0fdd2SPoul-Henning Kamp 32105f0fdd2SPoul-Henning Kamp 322d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 323df8bae1dSRodney W. Grimes struct msync_args { 324df8bae1dSRodney W. Grimes caddr_t addr; 325df8bae1dSRodney W. Grimes int len; 326e6c6af11SDavid Greenman int flags; 327df8bae1dSRodney W. Grimes }; 328d2d3e875SBruce Evans #endif 329df8bae1dSRodney W. Grimes int 330df8bae1dSRodney W. Grimes msync(p, uap, retval) 331df8bae1dSRodney W. Grimes struct proc *p; 332df8bae1dSRodney W. Grimes struct msync_args *uap; 333df8bae1dSRodney W. Grimes int *retval; 334df8bae1dSRodney W. Grimes { 335df8bae1dSRodney W. Grimes vm_offset_t addr; 336dabee6feSPeter Wemm vm_size_t size, pageoff; 337e6c6af11SDavid Greenman int flags; 338df8bae1dSRodney W. Grimes vm_map_t map; 339df8bae1dSRodney W. Grimes int rv; 340df8bae1dSRodney W. Grimes 341df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 3429154ee6aSPeter Wemm size = uap->len; 343e6c6af11SDavid Greenman flags = uap->flags; 344e6c6af11SDavid Greenman 345dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 346dabee6feSPeter Wemm addr -= pageoff; 347dabee6feSPeter Wemm size += pageoff; 348dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 3499154ee6aSPeter Wemm if (addr + size < addr) 350dabee6feSPeter Wemm return(EINVAL); 351dabee6feSPeter Wemm 352dabee6feSPeter Wemm if ((flags & (MS_ASYNC|MS_INVALIDATE)) == (MS_ASYNC|MS_INVALIDATE)) 3531e62bc63SDavid Greenman return (EINVAL); 3541e62bc63SDavid Greenman 3559154ee6aSPeter Wemm map = &p->p_vmspace->vm_map; 3569154ee6aSPeter Wemm 357df8bae1dSRodney W. Grimes /* 358df8bae1dSRodney W. Grimes * XXX Gak! If size is zero we are supposed to sync "all modified 3590d94caffSDavid Greenman * pages with the region containing addr". Unfortunately, we don't 3600d94caffSDavid Greenman * really keep track of individual mmaps so we approximate by flushing 3610d94caffSDavid Greenman * the range of the map entry containing addr. This can be incorrect 3620d94caffSDavid Greenman * if the region splits or is coalesced with a neighbor. 363df8bae1dSRodney W. Grimes */ 364df8bae1dSRodney W. Grimes if (size == 0) { 365df8bae1dSRodney W. Grimes vm_map_entry_t entry; 366df8bae1dSRodney W. Grimes 367df8bae1dSRodney W. Grimes vm_map_lock_read(map); 368df8bae1dSRodney W. Grimes rv = vm_map_lookup_entry(map, addr, &entry); 369df8bae1dSRodney W. Grimes vm_map_unlock_read(map); 370fbcfcdf7SDavid Greenman if (rv == FALSE) 371df8bae1dSRodney W. Grimes return (EINVAL); 372df8bae1dSRodney W. Grimes addr = entry->start; 373df8bae1dSRodney W. Grimes size = entry->end - entry->start; 374df8bae1dSRodney W. Grimes } 375e6c6af11SDavid Greenman 376df8bae1dSRodney W. Grimes /* 377df8bae1dSRodney W. Grimes * Clean the pages and interpret the return value. 378df8bae1dSRodney W. Grimes */ 3796c534ad8SDavid Greenman rv = vm_map_clean(map, addr, addr + size, (flags & MS_ASYNC) == 0, 380e6c6af11SDavid Greenman (flags & MS_INVALIDATE) != 0); 381e6c6af11SDavid Greenman 382df8bae1dSRodney W. Grimes switch (rv) { 383df8bae1dSRodney W. Grimes case KERN_SUCCESS: 384df8bae1dSRodney W. Grimes break; 385df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 386df8bae1dSRodney W. Grimes return (EINVAL); /* Sun returns ENOMEM? */ 387df8bae1dSRodney W. Grimes case KERN_FAILURE: 388df8bae1dSRodney W. Grimes return (EIO); 389df8bae1dSRodney W. Grimes default: 390df8bae1dSRodney W. Grimes return (EINVAL); 391df8bae1dSRodney W. Grimes } 392e6c6af11SDavid Greenman 393df8bae1dSRodney W. Grimes return (0); 394df8bae1dSRodney W. Grimes } 395df8bae1dSRodney W. Grimes 396d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 397df8bae1dSRodney W. Grimes struct munmap_args { 398df8bae1dSRodney W. Grimes caddr_t addr; 3999154ee6aSPeter Wemm size_t len; 400df8bae1dSRodney W. Grimes }; 401d2d3e875SBruce Evans #endif 402df8bae1dSRodney W. Grimes int 403df8bae1dSRodney W. Grimes munmap(p, uap, retval) 404df8bae1dSRodney W. Grimes register struct proc *p; 405df8bae1dSRodney W. Grimes register struct munmap_args *uap; 406df8bae1dSRodney W. Grimes int *retval; 407df8bae1dSRodney W. Grimes { 408df8bae1dSRodney W. Grimes vm_offset_t addr; 409dabee6feSPeter Wemm vm_size_t size, pageoff; 410df8bae1dSRodney W. Grimes vm_map_t map; 411df8bae1dSRodney W. Grimes 412df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 4139154ee6aSPeter Wemm size = uap->len; 414dabee6feSPeter Wemm 415dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 416dabee6feSPeter Wemm addr -= pageoff; 417dabee6feSPeter Wemm size += pageoff; 418dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 4199154ee6aSPeter Wemm if (addr + size < addr) 420df8bae1dSRodney W. Grimes return(EINVAL); 4219154ee6aSPeter Wemm 422df8bae1dSRodney W. Grimes if (size == 0) 423df8bae1dSRodney W. Grimes return (0); 424dabee6feSPeter Wemm 425df8bae1dSRodney W. Grimes /* 4260d94caffSDavid Greenman * Check for illegal addresses. Watch out for address wrap... Note 4270d94caffSDavid Greenman * that VM_*_ADDRESS are not constants due to casts (argh). 428df8bae1dSRodney W. Grimes */ 429bbc0ec52SDavid Greenman if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS) 430df8bae1dSRodney W. Grimes return (EINVAL); 43126f9a767SRodney W. Grimes #ifndef i386 432df8bae1dSRodney W. Grimes if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS) 433df8bae1dSRodney W. Grimes return (EINVAL); 43426f9a767SRodney W. Grimes #endif 435bbc0ec52SDavid Greenman if (addr + size < addr) 436df8bae1dSRodney W. Grimes return (EINVAL); 437df8bae1dSRodney W. Grimes map = &p->p_vmspace->vm_map; 438df8bae1dSRodney W. Grimes /* 439df8bae1dSRodney W. Grimes * Make sure entire range is allocated. 440df8bae1dSRodney W. Grimes */ 441df8bae1dSRodney W. Grimes if (!vm_map_check_protection(map, addr, addr + size, VM_PROT_NONE)) 442df8bae1dSRodney W. Grimes return (EINVAL); 443df8bae1dSRodney W. Grimes /* returns nothing but KERN_SUCCESS anyway */ 444df8bae1dSRodney W. Grimes (void) vm_map_remove(map, addr, addr + size); 445df8bae1dSRodney W. Grimes return (0); 446df8bae1dSRodney W. Grimes } 447df8bae1dSRodney W. Grimes 448df8bae1dSRodney W. Grimes void 44990324b07SDavid Greenman munmapfd(p, fd) 45090324b07SDavid Greenman struct proc *p; 451df8bae1dSRodney W. Grimes int fd; 452df8bae1dSRodney W. Grimes { 453df8bae1dSRodney W. Grimes /* 454c4ed5a07SDavid Greenman * XXX should unmap any regions mapped to this file 455df8bae1dSRodney W. Grimes */ 45690324b07SDavid Greenman p->p_fd->fd_ofileflags[fd] &= ~UF_MAPPED; 457df8bae1dSRodney W. Grimes } 458df8bae1dSRodney W. Grimes 459d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 460df8bae1dSRodney W. Grimes struct mprotect_args { 461df8bae1dSRodney W. Grimes caddr_t addr; 4629154ee6aSPeter Wemm size_t len; 463df8bae1dSRodney W. Grimes int prot; 464df8bae1dSRodney W. Grimes }; 465d2d3e875SBruce Evans #endif 466df8bae1dSRodney W. Grimes int 467df8bae1dSRodney W. Grimes mprotect(p, uap, retval) 468df8bae1dSRodney W. Grimes struct proc *p; 469df8bae1dSRodney W. Grimes struct mprotect_args *uap; 470df8bae1dSRodney W. Grimes int *retval; 471df8bae1dSRodney W. Grimes { 472df8bae1dSRodney W. Grimes vm_offset_t addr; 473dabee6feSPeter Wemm vm_size_t size, pageoff; 474df8bae1dSRodney W. Grimes register vm_prot_t prot; 475df8bae1dSRodney W. Grimes 476df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 4779154ee6aSPeter Wemm size = uap->len; 478df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 479d0aea04fSJohn Dyson #if defined(VM_PROT_READ_IS_EXEC) 480d0aea04fSJohn Dyson if (prot & VM_PROT_READ) 481d0aea04fSJohn Dyson prot |= VM_PROT_EXECUTE; 482d0aea04fSJohn Dyson #endif 483df8bae1dSRodney W. Grimes 484dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 485dabee6feSPeter Wemm addr -= pageoff; 486dabee6feSPeter Wemm size += pageoff; 487dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 4889154ee6aSPeter Wemm if (addr + size < addr) 489dabee6feSPeter Wemm return(EINVAL); 490dabee6feSPeter Wemm 491df8bae1dSRodney W. Grimes switch (vm_map_protect(&p->p_vmspace->vm_map, addr, addr + size, prot, 492df8bae1dSRodney W. Grimes FALSE)) { 493df8bae1dSRodney W. Grimes case KERN_SUCCESS: 494df8bae1dSRodney W. Grimes return (0); 495df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 496df8bae1dSRodney W. Grimes return (EACCES); 497df8bae1dSRodney W. Grimes } 498df8bae1dSRodney W. Grimes return (EINVAL); 499df8bae1dSRodney W. Grimes } 500df8bae1dSRodney W. Grimes 501d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 502dabee6feSPeter Wemm struct minherit_args { 503dabee6feSPeter Wemm caddr_t addr; 5049154ee6aSPeter Wemm size_t len; 505dabee6feSPeter Wemm int inherit; 506dabee6feSPeter Wemm }; 507dabee6feSPeter Wemm #endif 508dabee6feSPeter Wemm int 509dabee6feSPeter Wemm minherit(p, uap, retval) 510dabee6feSPeter Wemm struct proc *p; 511dabee6feSPeter Wemm struct minherit_args *uap; 512dabee6feSPeter Wemm int *retval; 513dabee6feSPeter Wemm { 514dabee6feSPeter Wemm vm_offset_t addr; 515dabee6feSPeter Wemm vm_size_t size, pageoff; 516dabee6feSPeter Wemm register vm_inherit_t inherit; 517dabee6feSPeter Wemm 518dabee6feSPeter Wemm addr = (vm_offset_t)uap->addr; 5199154ee6aSPeter Wemm size = uap->len; 520dabee6feSPeter Wemm inherit = uap->inherit; 521dabee6feSPeter Wemm 522dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 523dabee6feSPeter Wemm addr -= pageoff; 524dabee6feSPeter Wemm size += pageoff; 525dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 5269154ee6aSPeter Wemm if (addr + size < addr) 527dabee6feSPeter Wemm return(EINVAL); 528dabee6feSPeter Wemm 529dabee6feSPeter Wemm switch (vm_map_inherit(&p->p_vmspace->vm_map, addr, addr+size, 530dabee6feSPeter Wemm inherit)) { 531dabee6feSPeter Wemm case KERN_SUCCESS: 532dabee6feSPeter Wemm return (0); 533dabee6feSPeter Wemm case KERN_PROTECTION_FAILURE: 534dabee6feSPeter Wemm return (EACCES); 535dabee6feSPeter Wemm } 536dabee6feSPeter Wemm return (EINVAL); 537dabee6feSPeter Wemm } 538dabee6feSPeter Wemm 539dabee6feSPeter Wemm #ifndef _SYS_SYSPROTO_H_ 540df8bae1dSRodney W. Grimes struct madvise_args { 541df8bae1dSRodney W. Grimes caddr_t addr; 5429154ee6aSPeter Wemm size_t len; 543df8bae1dSRodney W. Grimes int behav; 544df8bae1dSRodney W. Grimes }; 545d2d3e875SBruce Evans #endif 5460d94caffSDavid Greenman 547df8bae1dSRodney W. Grimes /* ARGSUSED */ 548df8bae1dSRodney W. Grimes int 549df8bae1dSRodney W. Grimes madvise(p, uap, retval) 550df8bae1dSRodney W. Grimes struct proc *p; 551df8bae1dSRodney W. Grimes struct madvise_args *uap; 552df8bae1dSRodney W. Grimes int *retval; 553df8bae1dSRodney W. Grimes { 554867a482dSJohn Dyson vm_map_t map; 555867a482dSJohn Dyson pmap_t pmap; 556f35329acSJohn Dyson vm_offset_t start, end; 557867a482dSJohn Dyson /* 558867a482dSJohn Dyson * Check for illegal addresses. Watch out for address wrap... Note 559867a482dSJohn Dyson * that VM_*_ADDRESS are not constants due to casts (argh). 560867a482dSJohn Dyson */ 561867a482dSJohn Dyson if (VM_MAXUSER_ADDRESS > 0 && 562867a482dSJohn Dyson ((vm_offset_t) uap->addr + uap->len) > VM_MAXUSER_ADDRESS) 563867a482dSJohn Dyson return (EINVAL); 564867a482dSJohn Dyson #ifndef i386 565867a482dSJohn Dyson if (VM_MIN_ADDRESS > 0 && uap->addr < VM_MIN_ADDRESS) 566867a482dSJohn Dyson return (EINVAL); 567867a482dSJohn Dyson #endif 568867a482dSJohn Dyson if (((vm_offset_t) uap->addr + uap->len) < (vm_offset_t) uap->addr) 569867a482dSJohn Dyson return (EINVAL); 570867a482dSJohn Dyson 571867a482dSJohn Dyson /* 572867a482dSJohn Dyson * Since this routine is only advisory, we default to conservative 573867a482dSJohn Dyson * behavior. 574867a482dSJohn Dyson */ 575cd6eea25SDavid Greenman start = trunc_page((vm_offset_t) uap->addr); 576cd6eea25SDavid Greenman end = round_page((vm_offset_t) uap->addr + uap->len); 577867a482dSJohn Dyson 578867a482dSJohn Dyson map = &p->p_vmspace->vm_map; 579867a482dSJohn Dyson pmap = &p->p_vmspace->vm_pmap; 580867a482dSJohn Dyson 581867a482dSJohn Dyson vm_map_madvise(map, pmap, start, end, uap->behav); 582df8bae1dSRodney W. Grimes 583867a482dSJohn Dyson return (0); 584df8bae1dSRodney W. Grimes } 585df8bae1dSRodney W. Grimes 586d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 587df8bae1dSRodney W. Grimes struct mincore_args { 588df8bae1dSRodney W. Grimes caddr_t addr; 5899154ee6aSPeter Wemm size_t len; 590df8bae1dSRodney W. Grimes char *vec; 591df8bae1dSRodney W. Grimes }; 592d2d3e875SBruce Evans #endif 5930d94caffSDavid Greenman 594df8bae1dSRodney W. Grimes /* ARGSUSED */ 595df8bae1dSRodney W. Grimes int 596df8bae1dSRodney W. Grimes mincore(p, uap, retval) 597df8bae1dSRodney W. Grimes struct proc *p; 598df8bae1dSRodney W. Grimes struct mincore_args *uap; 599df8bae1dSRodney W. Grimes int *retval; 600df8bae1dSRodney W. Grimes { 601867a482dSJohn Dyson vm_offset_t addr, first_addr; 602867a482dSJohn Dyson vm_offset_t end, cend; 603867a482dSJohn Dyson pmap_t pmap; 604867a482dSJohn Dyson vm_map_t map; 60502c04a2fSJohn Dyson char *vec; 606867a482dSJohn Dyson int error; 607867a482dSJohn Dyson int vecindex, lastvecindex; 608867a482dSJohn Dyson register vm_map_entry_t current; 609867a482dSJohn Dyson vm_map_entry_t entry; 610867a482dSJohn Dyson int mincoreinfo; 611df8bae1dSRodney W. Grimes 612867a482dSJohn Dyson /* 613867a482dSJohn Dyson * Make sure that the addresses presented are valid for user 614867a482dSJohn Dyson * mode. 615867a482dSJohn Dyson */ 616867a482dSJohn Dyson first_addr = addr = trunc_page((vm_offset_t) uap->addr); 6179154ee6aSPeter Wemm end = addr + (vm_size_t)round_page(uap->len); 61802c04a2fSJohn Dyson if (VM_MAXUSER_ADDRESS > 0 && end > VM_MAXUSER_ADDRESS) 61902c04a2fSJohn Dyson return (EINVAL); 62002c04a2fSJohn Dyson if (end < addr) 62102c04a2fSJohn Dyson return (EINVAL); 62202c04a2fSJohn Dyson 623867a482dSJohn Dyson /* 624867a482dSJohn Dyson * Address of byte vector 625867a482dSJohn Dyson */ 62602c04a2fSJohn Dyson vec = uap->vec; 627867a482dSJohn Dyson 628867a482dSJohn Dyson map = &p->p_vmspace->vm_map; 629867a482dSJohn Dyson pmap = &p->p_vmspace->vm_pmap; 630867a482dSJohn Dyson 631867a482dSJohn Dyson vm_map_lock(map); 632867a482dSJohn Dyson 633867a482dSJohn Dyson /* 634867a482dSJohn Dyson * Not needed here 635867a482dSJohn Dyson */ 636867a482dSJohn Dyson #if 0 637867a482dSJohn Dyson VM_MAP_RANGE_CHECK(map, addr, end); 638867a482dSJohn Dyson #endif 639867a482dSJohn Dyson 640867a482dSJohn Dyson if (!vm_map_lookup_entry(map, addr, &entry)) 641867a482dSJohn Dyson entry = entry->next; 642867a482dSJohn Dyson 643867a482dSJohn Dyson /* 644867a482dSJohn Dyson * Do this on a map entry basis so that if the pages are not 645867a482dSJohn Dyson * in the current processes address space, we can easily look 646867a482dSJohn Dyson * up the pages elsewhere. 647867a482dSJohn Dyson */ 648867a482dSJohn Dyson lastvecindex = -1; 649867a482dSJohn Dyson for(current = entry; 650867a482dSJohn Dyson (current != &map->header) && (current->start < end); 651867a482dSJohn Dyson current = current->next) { 652867a482dSJohn Dyson 653867a482dSJohn Dyson /* 654867a482dSJohn Dyson * ignore submaps (for now) or null objects 655867a482dSJohn Dyson */ 656afa07f7eSJohn Dyson if ((current->eflags & (MAP_ENTRY_IS_A_MAP|MAP_ENTRY_IS_SUB_MAP)) || 657867a482dSJohn Dyson current->object.vm_object == NULL) 658867a482dSJohn Dyson continue; 659867a482dSJohn Dyson 660867a482dSJohn Dyson /* 661867a482dSJohn Dyson * limit this scan to the current map entry and the 662867a482dSJohn Dyson * limits for the mincore call 663867a482dSJohn Dyson */ 664867a482dSJohn Dyson if (addr < current->start) 665867a482dSJohn Dyson addr = current->start; 666867a482dSJohn Dyson cend = current->end; 667867a482dSJohn Dyson if (cend > end) 668867a482dSJohn Dyson cend = end; 669867a482dSJohn Dyson 670867a482dSJohn Dyson /* 671867a482dSJohn Dyson * scan this entry one page at a time 672867a482dSJohn Dyson */ 673867a482dSJohn Dyson while(addr < cend) { 674867a482dSJohn Dyson /* 675867a482dSJohn Dyson * Check pmap first, it is likely faster, also 676867a482dSJohn Dyson * it can provide info as to whether we are the 677867a482dSJohn Dyson * one referencing or modifying the page. 678867a482dSJohn Dyson */ 679867a482dSJohn Dyson mincoreinfo = pmap_mincore(pmap, addr); 680867a482dSJohn Dyson if (!mincoreinfo) { 681867a482dSJohn Dyson vm_pindex_t pindex; 682867a482dSJohn Dyson vm_ooffset_t offset; 683867a482dSJohn Dyson vm_page_t m; 684867a482dSJohn Dyson /* 685867a482dSJohn Dyson * calculate the page index into the object 686867a482dSJohn Dyson */ 687867a482dSJohn Dyson offset = current->offset + (addr - current->start); 688867a482dSJohn Dyson pindex = OFF_TO_IDX(offset); 689867a482dSJohn Dyson m = vm_page_lookup(current->object.vm_object, 690867a482dSJohn Dyson pindex); 691867a482dSJohn Dyson /* 692867a482dSJohn Dyson * if the page is resident, then gather information about 693867a482dSJohn Dyson * it. 694867a482dSJohn Dyson */ 695867a482dSJohn Dyson if (m) { 696867a482dSJohn Dyson mincoreinfo = MINCORE_INCORE; 697867a482dSJohn Dyson if (m->dirty || 69867bf6868SJohn Dyson pmap_is_modified(VM_PAGE_TO_PHYS(m))) 699867a482dSJohn Dyson mincoreinfo |= MINCORE_MODIFIED_OTHER; 700867a482dSJohn Dyson if ((m->flags & PG_REFERENCED) || 7019b5a5d81SJohn Dyson pmap_ts_referenced(VM_PAGE_TO_PHYS(m))) { 7029b5a5d81SJohn Dyson m->flags |= PG_REFERENCED; 703867a482dSJohn Dyson mincoreinfo |= MINCORE_REFERENCED_OTHER; 70402c04a2fSJohn Dyson } 705867a482dSJohn Dyson } 7069b5a5d81SJohn Dyson } 707867a482dSJohn Dyson 708867a482dSJohn Dyson /* 709867a482dSJohn Dyson * calculate index into user supplied byte vector 710867a482dSJohn Dyson */ 711867a482dSJohn Dyson vecindex = OFF_TO_IDX(addr - first_addr); 712867a482dSJohn Dyson 713867a482dSJohn Dyson /* 714867a482dSJohn Dyson * If we have skipped map entries, we need to make sure that 715867a482dSJohn Dyson * the byte vector is zeroed for those skipped entries. 716867a482dSJohn Dyson */ 717867a482dSJohn Dyson while((lastvecindex + 1) < vecindex) { 718867a482dSJohn Dyson error = subyte( vec + lastvecindex, 0); 719867a482dSJohn Dyson if (error) { 720867a482dSJohn Dyson vm_map_unlock(map); 721867a482dSJohn Dyson return (EFAULT); 722867a482dSJohn Dyson } 723867a482dSJohn Dyson ++lastvecindex; 724867a482dSJohn Dyson } 725867a482dSJohn Dyson 726867a482dSJohn Dyson /* 727867a482dSJohn Dyson * Pass the page information to the user 728867a482dSJohn Dyson */ 729867a482dSJohn Dyson error = subyte( vec + vecindex, mincoreinfo); 730867a482dSJohn Dyson if (error) { 731867a482dSJohn Dyson vm_map_unlock(map); 732867a482dSJohn Dyson return (EFAULT); 733867a482dSJohn Dyson } 734867a482dSJohn Dyson lastvecindex = vecindex; 73502c04a2fSJohn Dyson addr += PAGE_SIZE; 73602c04a2fSJohn Dyson } 737867a482dSJohn Dyson } 738867a482dSJohn Dyson 739867a482dSJohn Dyson /* 740867a482dSJohn Dyson * Zero the last entries in the byte vector. 741867a482dSJohn Dyson */ 742867a482dSJohn Dyson vecindex = OFF_TO_IDX(end - first_addr); 743867a482dSJohn Dyson while((lastvecindex + 1) < vecindex) { 744867a482dSJohn Dyson error = subyte( vec + lastvecindex, 0); 745867a482dSJohn Dyson if (error) { 746867a482dSJohn Dyson vm_map_unlock(map); 747867a482dSJohn Dyson return (EFAULT); 748867a482dSJohn Dyson } 749867a482dSJohn Dyson ++lastvecindex; 750867a482dSJohn Dyson } 751867a482dSJohn Dyson 752867a482dSJohn Dyson vm_map_unlock(map); 75302c04a2fSJohn Dyson return (0); 754df8bae1dSRodney W. Grimes } 755df8bae1dSRodney W. Grimes 756d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 757df8bae1dSRodney W. Grimes struct mlock_args { 758df8bae1dSRodney W. Grimes caddr_t addr; 759df8bae1dSRodney W. Grimes size_t len; 760df8bae1dSRodney W. Grimes }; 761d2d3e875SBruce Evans #endif 762df8bae1dSRodney W. Grimes int 763df8bae1dSRodney W. Grimes mlock(p, uap, retval) 764df8bae1dSRodney W. Grimes struct proc *p; 765df8bae1dSRodney W. Grimes struct mlock_args *uap; 766df8bae1dSRodney W. Grimes int *retval; 767df8bae1dSRodney W. Grimes { 768df8bae1dSRodney W. Grimes vm_offset_t addr; 769dabee6feSPeter Wemm vm_size_t size, pageoff; 770df8bae1dSRodney W. Grimes int error; 771df8bae1dSRodney W. Grimes 772df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 7739154ee6aSPeter Wemm size = uap->len; 7749154ee6aSPeter Wemm 775dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 776dabee6feSPeter Wemm addr -= pageoff; 777dabee6feSPeter Wemm size += pageoff; 778dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 779dabee6feSPeter Wemm 780dabee6feSPeter Wemm /* disable wrap around */ 7819154ee6aSPeter Wemm if (addr + size < addr) 782df8bae1dSRodney W. Grimes return (EINVAL); 783dabee6feSPeter Wemm 784df8bae1dSRodney W. Grimes if (atop(size) + cnt.v_wire_count > vm_page_max_wired) 785df8bae1dSRodney W. Grimes return (EAGAIN); 7869154ee6aSPeter Wemm 787df8bae1dSRodney W. Grimes #ifdef pmap_wired_count 788df8bae1dSRodney W. Grimes if (size + ptoa(pmap_wired_count(vm_map_pmap(&p->p_vmspace->vm_map))) > 789df8bae1dSRodney W. Grimes p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur) 7904a40e3d4SJohn Dyson return (ENOMEM); 791df8bae1dSRodney W. Grimes #else 79205f0fdd2SPoul-Henning Kamp error = suser(p->p_ucred, &p->p_acflag); 79305f0fdd2SPoul-Henning Kamp if (error) 794df8bae1dSRodney W. Grimes return (error); 795df8bae1dSRodney W. Grimes #endif 796df8bae1dSRodney W. Grimes 7977aaaa4fdSJohn Dyson error = vm_map_user_pageable(&p->p_vmspace->vm_map, addr, addr + size, FALSE); 798df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 799df8bae1dSRodney W. Grimes } 800df8bae1dSRodney W. Grimes 801d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 8024a40e3d4SJohn Dyson struct mlockall_args { 8034a40e3d4SJohn Dyson int how; 8044a40e3d4SJohn Dyson }; 8054a40e3d4SJohn Dyson #endif 8064a40e3d4SJohn Dyson 8074a40e3d4SJohn Dyson int 8084a40e3d4SJohn Dyson mlockall(p, uap, retval) 8094a40e3d4SJohn Dyson struct proc *p; 8104a40e3d4SJohn Dyson struct mlockall_args *uap; 8114a40e3d4SJohn Dyson int *retval; 8124a40e3d4SJohn Dyson { 8134a40e3d4SJohn Dyson return 0; 8144a40e3d4SJohn Dyson } 8154a40e3d4SJohn Dyson 8164a40e3d4SJohn Dyson #ifndef _SYS_SYSPROTO_H_ 8174a40e3d4SJohn Dyson struct mlockall_args { 8184a40e3d4SJohn Dyson int how; 8194a40e3d4SJohn Dyson }; 8204a40e3d4SJohn Dyson #endif 8214a40e3d4SJohn Dyson 8224a40e3d4SJohn Dyson int 8234a40e3d4SJohn Dyson munlockall(p, uap, retval) 8244a40e3d4SJohn Dyson struct proc *p; 8254a40e3d4SJohn Dyson struct munlockall_args *uap; 8264a40e3d4SJohn Dyson int *retval; 8274a40e3d4SJohn Dyson { 8284a40e3d4SJohn Dyson return 0; 8294a40e3d4SJohn Dyson } 8304a40e3d4SJohn Dyson 8314a40e3d4SJohn Dyson #ifndef _SYS_SYSPROTO_H_ 832df8bae1dSRodney W. Grimes struct munlock_args { 833df8bae1dSRodney W. Grimes caddr_t addr; 834df8bae1dSRodney W. Grimes size_t len; 835df8bae1dSRodney W. Grimes }; 836d2d3e875SBruce Evans #endif 837df8bae1dSRodney W. Grimes int 838df8bae1dSRodney W. Grimes munlock(p, uap, retval) 839df8bae1dSRodney W. Grimes struct proc *p; 840df8bae1dSRodney W. Grimes struct munlock_args *uap; 841df8bae1dSRodney W. Grimes int *retval; 842df8bae1dSRodney W. Grimes { 843df8bae1dSRodney W. Grimes vm_offset_t addr; 844dabee6feSPeter Wemm vm_size_t size, pageoff; 845df8bae1dSRodney W. Grimes int error; 846df8bae1dSRodney W. Grimes 847df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 8489154ee6aSPeter Wemm size = uap->len; 8499154ee6aSPeter Wemm 850dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 851dabee6feSPeter Wemm addr -= pageoff; 852dabee6feSPeter Wemm size += pageoff; 853dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 854dabee6feSPeter Wemm 855dabee6feSPeter Wemm /* disable wrap around */ 8569154ee6aSPeter Wemm if (addr + size < addr) 857df8bae1dSRodney W. Grimes return (EINVAL); 858dabee6feSPeter Wemm 859df8bae1dSRodney W. Grimes #ifndef pmap_wired_count 86005f0fdd2SPoul-Henning Kamp error = suser(p->p_ucred, &p->p_acflag); 86105f0fdd2SPoul-Henning Kamp if (error) 862df8bae1dSRodney W. Grimes return (error); 863df8bae1dSRodney W. Grimes #endif 864df8bae1dSRodney W. Grimes 8657aaaa4fdSJohn Dyson error = vm_map_user_pageable(&p->p_vmspace->vm_map, addr, addr + size, TRUE); 866df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 867df8bae1dSRodney W. Grimes } 868df8bae1dSRodney W. Grimes 869df8bae1dSRodney W. Grimes /* 870df8bae1dSRodney W. Grimes * Internal version of mmap. 871df8bae1dSRodney W. Grimes * Currently used by mmap, exec, and sys5 shared memory. 872df8bae1dSRodney W. Grimes * Handle is either a vnode pointer or NULL for MAP_ANON. 873df8bae1dSRodney W. Grimes */ 874df8bae1dSRodney W. Grimes int 875df8bae1dSRodney W. Grimes vm_mmap(map, addr, size, prot, maxprot, flags, handle, foff) 876df8bae1dSRodney W. Grimes register vm_map_t map; 877df8bae1dSRodney W. Grimes register vm_offset_t *addr; 878df8bae1dSRodney W. Grimes register vm_size_t size; 879df8bae1dSRodney W. Grimes vm_prot_t prot, maxprot; 880df8bae1dSRodney W. Grimes register int flags; 881df8bae1dSRodney W. Grimes caddr_t handle; /* XXX should be vp */ 882a316d390SJohn Dyson vm_ooffset_t foff; 883df8bae1dSRodney W. Grimes { 884df8bae1dSRodney W. Grimes boolean_t fitit; 885fcae040bSJohn Dyson vm_object_t object; 886df8bae1dSRodney W. Grimes struct vnode *vp = NULL; 88724a1cce3SDavid Greenman objtype_t type; 888df8bae1dSRodney W. Grimes int rv = KERN_SUCCESS; 889bd7e5f99SJohn Dyson vm_ooffset_t objsize; 890bd7e5f99SJohn Dyson int docow; 89106cb7259SDavid Greenman struct proc *p = curproc; 892df8bae1dSRodney W. Grimes 893df8bae1dSRodney W. Grimes if (size == 0) 894df8bae1dSRodney W. Grimes return (0); 895df8bae1dSRodney W. Grimes 89606cb7259SDavid Greenman objsize = size = round_page(size); 897df8bae1dSRodney W. Grimes 898df8bae1dSRodney W. Grimes /* 899bc9ad247SDavid Greenman * We currently can only deal with page aligned file offsets. 900bc9ad247SDavid Greenman * The check is here rather than in the syscall because the 901bc9ad247SDavid Greenman * kernel calls this function internally for other mmaping 902bc9ad247SDavid Greenman * operations (such as in exec) and non-aligned offsets will 903bc9ad247SDavid Greenman * cause pmap inconsistencies...so we want to be sure to 904bc9ad247SDavid Greenman * disallow this in all cases. 905bc9ad247SDavid Greenman */ 906bc9ad247SDavid Greenman if (foff & PAGE_MASK) 907bc9ad247SDavid Greenman return (EINVAL); 908bc9ad247SDavid Greenman 90906cb7259SDavid Greenman if ((flags & MAP_FIXED) == 0) { 91006cb7259SDavid Greenman fitit = TRUE; 91106cb7259SDavid Greenman *addr = round_page(*addr); 91206cb7259SDavid Greenman } else { 91306cb7259SDavid Greenman if (*addr != trunc_page(*addr)) 91406cb7259SDavid Greenman return (EINVAL); 91506cb7259SDavid Greenman fitit = FALSE; 91606cb7259SDavid Greenman (void) vm_map_remove(map, *addr, *addr + size); 91706cb7259SDavid Greenman } 91806cb7259SDavid Greenman 919bc9ad247SDavid Greenman /* 92024a1cce3SDavid Greenman * Lookup/allocate object. 921df8bae1dSRodney W. Grimes */ 9225f55e841SDavid Greenman if (flags & MAP_ANON) { 923851c12ffSJohn Dyson type = OBJT_DEFAULT; 9245f55e841SDavid Greenman /* 9255f55e841SDavid Greenman * Unnamed anonymous regions always start at 0. 9265f55e841SDavid Greenman */ 92767bf6868SJohn Dyson if (handle == 0) 9285f55e841SDavid Greenman foff = 0; 9295f55e841SDavid Greenman } else { 930df8bae1dSRodney W. Grimes vp = (struct vnode *) handle; 931df8bae1dSRodney W. Grimes if (vp->v_type == VCHR) { 93224a1cce3SDavid Greenman type = OBJT_DEVICE; 933df8bae1dSRodney W. Grimes handle = (caddr_t) vp->v_rdev; 93406cb7259SDavid Greenman } else { 93506cb7259SDavid Greenman struct vattr vat; 93606cb7259SDavid Greenman int error; 93706cb7259SDavid Greenman 93806cb7259SDavid Greenman error = VOP_GETATTR(vp, &vat, p->p_ucred, p); 93906cb7259SDavid Greenman if (error) 94006cb7259SDavid Greenman return (error); 941bd7e5f99SJohn Dyson objsize = round_page(vat.va_size); 94224a1cce3SDavid Greenman type = OBJT_VNODE; 943df8bae1dSRodney W. Grimes } 94406cb7259SDavid Greenman } 94594328e90SJohn Dyson 94694328e90SJohn Dyson if (handle == NULL) { 94794328e90SJohn Dyson object = NULL; 94894328e90SJohn Dyson } else { 9490a0a85b3SJohn Dyson object = vm_pager_allocate(type, 9500a0a85b3SJohn Dyson handle, OFF_TO_IDX(objsize), prot, foff); 95124a1cce3SDavid Greenman if (object == NULL) 95224a1cce3SDavid Greenman return (type == OBJT_DEVICE ? EINVAL : ENOMEM); 95394328e90SJohn Dyson } 954df8bae1dSRodney W. Grimes 9555850152dSJohn Dyson /* 9568f2ec877SDavid Greenman * Force device mappings to be shared. 9575850152dSJohn Dyson */ 9588f2ec877SDavid Greenman if (type == OBJT_DEVICE) { 9598f2ec877SDavid Greenman flags &= ~(MAP_PRIVATE|MAP_COPY); 9605850152dSJohn Dyson flags |= MAP_SHARED; 9618f2ec877SDavid Greenman } 9625850152dSJohn Dyson 963bd7e5f99SJohn Dyson docow = 0; 9645850152dSJohn Dyson if ((flags & (MAP_ANON|MAP_SHARED)) == 0) { 965fcae040bSJohn Dyson docow = MAP_COPY_ON_WRITE | MAP_COPY_NEEDED; 966bd7e5f99SJohn Dyson } 9675850152dSJohn Dyson 968d0aea04fSJohn Dyson #if defined(VM_PROT_READ_IS_EXEC) 969d0aea04fSJohn Dyson if (prot & VM_PROT_READ) 970d0aea04fSJohn Dyson prot |= VM_PROT_EXECUTE; 971d0aea04fSJohn Dyson 972d0aea04fSJohn Dyson if (maxprot & VM_PROT_READ) 973d0aea04fSJohn Dyson maxprot |= VM_PROT_EXECUTE; 974d0aea04fSJohn Dyson #endif 975d0aea04fSJohn Dyson 9760a0a85b3SJohn Dyson if (fitit) { 9770a0a85b3SJohn Dyson *addr = pmap_addr_hint(object, *addr, size); 9780a0a85b3SJohn Dyson } 9790a0a85b3SJohn Dyson 980bd7e5f99SJohn Dyson rv = vm_map_find(map, object, foff, addr, size, fitit, 981bd7e5f99SJohn Dyson prot, maxprot, docow); 982bd7e5f99SJohn Dyson 983df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 9847fb0c17eSDavid Greenman /* 98524a1cce3SDavid Greenman * Lose the object reference. Will destroy the 98624a1cce3SDavid Greenman * object if it's an unnamed anonymous mapping 98724a1cce3SDavid Greenman * or named anonymous without other references. 9887fb0c17eSDavid Greenman */ 989df8bae1dSRodney W. Grimes vm_object_deallocate(object); 990df8bae1dSRodney W. Grimes goto out; 991df8bae1dSRodney W. Grimes } 992e17bed12SJohn Dyson 993df8bae1dSRodney W. Grimes /* 9947fb0c17eSDavid Greenman * "Pre-fault" resident pages. 9957fb0c17eSDavid Greenman */ 9960a0a85b3SJohn Dyson if ((map->pmap != NULL) && (object != NULL)) { 997a316d390SJohn Dyson pmap_object_init_pt(map->pmap, *addr, 998867a482dSJohn Dyson object, (vm_pindex_t) OFF_TO_IDX(foff), size, 1); 999df8bae1dSRodney W. Grimes } 10007fb0c17eSDavid Greenman 1001df8bae1dSRodney W. Grimes /* 1002df8bae1dSRodney W. Grimes * Shared memory is also shared with children. 1003df8bae1dSRodney W. Grimes */ 10045850152dSJohn Dyson if (flags & (MAP_SHARED|MAP_INHERIT)) { 1005df8bae1dSRodney W. Grimes rv = vm_map_inherit(map, *addr, *addr + size, VM_INHERIT_SHARE); 1006df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 10077fb0c17eSDavid Greenman (void) vm_map_remove(map, *addr, *addr + size); 1008df8bae1dSRodney W. Grimes goto out; 1009df8bae1dSRodney W. Grimes } 1010df8bae1dSRodney W. Grimes } 1011df8bae1dSRodney W. Grimes out: 1012df8bae1dSRodney W. Grimes switch (rv) { 1013df8bae1dSRodney W. Grimes case KERN_SUCCESS: 1014df8bae1dSRodney W. Grimes return (0); 1015df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 1016df8bae1dSRodney W. Grimes case KERN_NO_SPACE: 1017df8bae1dSRodney W. Grimes return (ENOMEM); 1018df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 1019df8bae1dSRodney W. Grimes return (EACCES); 1020df8bae1dSRodney W. Grimes default: 1021df8bae1dSRodney W. Grimes return (EINVAL); 1022df8bae1dSRodney W. Grimes } 1023df8bae1dSRodney W. Grimes } 1024