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 41b1028ad1SLuoqi Chen * $Id: vm_mmap.c,v 1.89 1999/02/07 21:48:22 dillon 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 485591b823SEivind Eklund #include "opt_compat.h" 49e9822d92SJoerg Wunsch #include "opt_rlimit.h" 50e9822d92SJoerg Wunsch 51df8bae1dSRodney W. Grimes #include <sys/param.h> 52df8bae1dSRodney W. Grimes #include <sys/systm.h> 53d2d3e875SBruce Evans #include <sys/sysproto.h> 54df8bae1dSRodney W. Grimes #include <sys/filedesc.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> 614183b6b6SPeter Wemm #include <sys/stat.h> 62efeaf95aSDavid Greenman #include <sys/vmmeter.h> 63df8bae1dSRodney W. Grimes 64df8bae1dSRodney W. Grimes #include <miscfs/specfs/specdev.h> 65df8bae1dSRodney W. Grimes 66df8bae1dSRodney W. Grimes #include <vm/vm.h> 67efeaf95aSDavid Greenman #include <vm/vm_param.h> 68efeaf95aSDavid Greenman #include <vm/vm_prot.h> 69efeaf95aSDavid Greenman #include <vm/vm_inherit.h> 70996c772fSJohn Dyson #include <sys/lock.h> 71efeaf95aSDavid Greenman #include <vm/pmap.h> 72efeaf95aSDavid Greenman #include <vm/vm_map.h> 73efeaf95aSDavid Greenman #include <vm/vm_object.h> 741c7c3c6aSMatthew Dillon #include <vm/vm_page.h> 75df8bae1dSRodney W. Grimes #include <vm/vm_pager.h> 76b5e8ce9fSBruce Evans #include <vm/vm_pageout.h> 77efeaf95aSDavid Greenman #include <vm/vm_extern.h> 78867a482dSJohn Dyson #include <vm/vm_page.h> 79df8bae1dSRodney W. Grimes 80d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 81df8bae1dSRodney W. Grimes struct sbrk_args { 82df8bae1dSRodney W. Grimes int incr; 83df8bae1dSRodney W. Grimes }; 84d2d3e875SBruce Evans #endif 850d94caffSDavid Greenman 86df8bae1dSRodney W. Grimes /* ARGSUSED */ 87df8bae1dSRodney W. Grimes int 88cb226aaaSPoul-Henning Kamp sbrk(p, uap) 89df8bae1dSRodney W. Grimes struct proc *p; 90df8bae1dSRodney W. Grimes struct sbrk_args *uap; 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 105cb226aaaSPoul-Henning Kamp sstk(p, uap) 106df8bae1dSRodney W. Grimes struct proc *p; 107df8bae1dSRodney W. Grimes struct sstk_args *uap; 108df8bae1dSRodney W. Grimes { 109df8bae1dSRodney W. Grimes 110df8bae1dSRodney W. Grimes /* Not yet implemented */ 111df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 112df8bae1dSRodney W. Grimes } 113df8bae1dSRodney W. Grimes 114df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 115d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 116df8bae1dSRodney W. Grimes struct getpagesize_args { 117df8bae1dSRodney W. Grimes int dummy; 118df8bae1dSRodney W. Grimes }; 119d2d3e875SBruce Evans #endif 1200d94caffSDavid Greenman 121df8bae1dSRodney W. Grimes /* ARGSUSED */ 122df8bae1dSRodney W. Grimes int 123cb226aaaSPoul-Henning Kamp ogetpagesize(p, uap) 124df8bae1dSRodney W. Grimes struct proc *p; 125df8bae1dSRodney W. Grimes struct getpagesize_args *uap; 126df8bae1dSRodney W. Grimes { 127df8bae1dSRodney W. Grimes 128cb226aaaSPoul-Henning Kamp p->p_retval[0] = PAGE_SIZE; 129df8bae1dSRodney W. Grimes return (0); 130df8bae1dSRodney W. Grimes } 131df8bae1dSRodney W. Grimes #endif /* COMPAT_43 || COMPAT_SUNOS */ 132df8bae1dSRodney W. Grimes 13354f42e4bSPeter Wemm 13454f42e4bSPeter Wemm /* 13554f42e4bSPeter Wemm * Memory Map (mmap) system call. Note that the file offset 13654f42e4bSPeter Wemm * and address are allowed to be NOT page aligned, though if 13754f42e4bSPeter Wemm * the MAP_FIXED flag it set, both must have the same remainder 13854f42e4bSPeter Wemm * modulo the PAGE_SIZE (POSIX 1003.1b). If the address is not 13954f42e4bSPeter Wemm * page-aligned, the actual mapping starts at trunc_page(addr) 14054f42e4bSPeter Wemm * and the return value is adjusted up by the page offset. 14154f42e4bSPeter Wemm */ 142d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 143df8bae1dSRodney W. Grimes struct mmap_args { 144651bb817SAlexander Langer void *addr; 145df8bae1dSRodney W. Grimes size_t len; 146df8bae1dSRodney W. Grimes int prot; 147df8bae1dSRodney W. Grimes int flags; 148df8bae1dSRodney W. Grimes int fd; 149df8bae1dSRodney W. Grimes long pad; 150df8bae1dSRodney W. Grimes off_t pos; 151df8bae1dSRodney W. Grimes }; 152d2d3e875SBruce Evans #endif 153df8bae1dSRodney W. Grimes 154df8bae1dSRodney W. Grimes int 155cb226aaaSPoul-Henning Kamp mmap(p, uap) 156df8bae1dSRodney W. Grimes struct proc *p; 157df8bae1dSRodney W. Grimes register struct mmap_args *uap; 158df8bae1dSRodney W. Grimes { 159df8bae1dSRodney W. Grimes register struct filedesc *fdp = p->p_fd; 160df8bae1dSRodney W. Grimes register struct file *fp; 161df8bae1dSRodney W. Grimes struct vnode *vp; 162df8bae1dSRodney W. Grimes vm_offset_t addr; 1639154ee6aSPeter Wemm vm_size_t size, pageoff; 164df8bae1dSRodney W. Grimes vm_prot_t prot, maxprot; 165651bb817SAlexander Langer void *handle; 166df8bae1dSRodney W. Grimes int flags, error; 167c8bdd56bSGuido van Rooij int disablexworkaround; 16854f42e4bSPeter Wemm off_t pos; 169df8bae1dSRodney W. Grimes 17054f42e4bSPeter Wemm addr = (vm_offset_t) uap->addr; 17154f42e4bSPeter Wemm size = uap->len; 172df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 173df8bae1dSRodney W. Grimes flags = uap->flags; 17454f42e4bSPeter Wemm pos = uap->pos; 17554f42e4bSPeter Wemm 17654f42e4bSPeter Wemm /* make sure mapping fits into numeric range etc */ 177fc565456SDmitrij Tejblum if ((ssize_t) uap->len < 0 || 17854f42e4bSPeter Wemm ((flags & MAP_ANON) && uap->fd != -1)) 179df8bae1dSRodney W. Grimes return (EINVAL); 1809154ee6aSPeter Wemm 1812267af78SJulian Elischer if (flags & MAP_STACK) { 1822907af2aSJulian Elischer #ifdef VM_STACK 1832267af78SJulian Elischer if ((uap->fd != -1) || 1842267af78SJulian Elischer ((prot & (PROT_READ | PROT_WRITE)) != (PROT_READ | PROT_WRITE))) 1852267af78SJulian Elischer return (EINVAL); 1862267af78SJulian Elischer flags |= MAP_ANON; 1872267af78SJulian Elischer pos = 0; 1882907af2aSJulian Elischer #else 1892907af2aSJulian Elischer return (EINVAL); 1902267af78SJulian Elischer #endif 1912907af2aSJulian Elischer } 1922907af2aSJulian Elischer 1939154ee6aSPeter Wemm /* 19454f42e4bSPeter Wemm * Align the file position to a page boundary, 19554f42e4bSPeter Wemm * and save its page offset component. 1969154ee6aSPeter Wemm */ 19754f42e4bSPeter Wemm pageoff = (pos & PAGE_MASK); 19854f42e4bSPeter Wemm pos -= pageoff; 19954f42e4bSPeter Wemm 20054f42e4bSPeter Wemm /* Adjust size for rounding (on both ends). */ 20154f42e4bSPeter Wemm size += pageoff; /* low end... */ 20254f42e4bSPeter Wemm size = (vm_size_t) round_page(size); /* hi end */ 2039154ee6aSPeter Wemm 204df8bae1dSRodney W. Grimes /* 2050d94caffSDavid Greenman * Check for illegal addresses. Watch out for address wrap... Note 2060d94caffSDavid Greenman * that VM_*_ADDRESS are not constants due to casts (argh). 207df8bae1dSRodney W. Grimes */ 208df8bae1dSRodney W. Grimes if (flags & MAP_FIXED) { 20954f42e4bSPeter Wemm /* 21054f42e4bSPeter Wemm * The specified address must have the same remainder 21154f42e4bSPeter Wemm * as the file offset taken modulo PAGE_SIZE, so it 21254f42e4bSPeter Wemm * should be aligned after adjustment by pageoff. 21354f42e4bSPeter Wemm */ 21454f42e4bSPeter Wemm addr -= pageoff; 21554f42e4bSPeter Wemm if (addr & PAGE_MASK) 21654f42e4bSPeter Wemm return (EINVAL); 21754f42e4bSPeter Wemm /* Address range must be all in user VM space. */ 218bbc0ec52SDavid Greenman if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS) 219df8bae1dSRodney W. Grimes return (EINVAL); 22026f9a767SRodney W. Grimes #ifndef i386 221df8bae1dSRodney W. Grimes if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS) 222df8bae1dSRodney W. Grimes return (EINVAL); 22326f9a767SRodney W. Grimes #endif 224bbc0ec52SDavid Greenman if (addr + size < addr) 225df8bae1dSRodney W. Grimes return (EINVAL); 226df8bae1dSRodney W. Grimes } 227df8bae1dSRodney W. Grimes /* 22854f42e4bSPeter Wemm * XXX for non-fixed mappings where no hint is provided or 22954f42e4bSPeter Wemm * the hint would fall in the potential heap space, 23054f42e4bSPeter Wemm * place it after the end of the largest possible heap. 231df8bae1dSRodney W. Grimes * 23254f42e4bSPeter Wemm * There should really be a pmap call to determine a reasonable 23354f42e4bSPeter Wemm * location. 234df8bae1dSRodney W. Grimes */ 2356cde7a16SDavid Greenman else if (addr < round_page((vm_offset_t)p->p_vmspace->vm_daddr + MAXDSIZ)) 2366cde7a16SDavid Greenman addr = round_page((vm_offset_t)p->p_vmspace->vm_daddr + MAXDSIZ); 23754f42e4bSPeter Wemm 238df8bae1dSRodney W. Grimes if (flags & MAP_ANON) { 239df8bae1dSRodney W. Grimes /* 240df8bae1dSRodney W. Grimes * Mapping blank space is trivial. 241df8bae1dSRodney W. Grimes */ 242df8bae1dSRodney W. Grimes handle = NULL; 243df8bae1dSRodney W. Grimes maxprot = VM_PROT_ALL; 24454f42e4bSPeter Wemm pos = 0; 245df8bae1dSRodney W. Grimes } else { 246df8bae1dSRodney W. Grimes /* 2470d94caffSDavid Greenman * Mapping file, get fp for validation. Obtain vnode and make 2480d94caffSDavid Greenman * 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 /* 2590d94caffSDavid Greenman * XXX hack to handle use of /dev/zero to map anon memory (ala 2600d94caffSDavid Greenman * 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; 26654f42e4bSPeter Wemm pos = 0; 267df8bae1dSRodney W. Grimes } else { 268df8bae1dSRodney W. Grimes /* 269c8bdd56bSGuido van Rooij * cdevs does not provide private mappings of any kind. 270c8bdd56bSGuido van Rooij */ 271c8bdd56bSGuido van Rooij /* 272c8bdd56bSGuido van Rooij * However, for XIG X server to continue to work, 273c8bdd56bSGuido van Rooij * we should allow the superuser to do it anyway. 274c8bdd56bSGuido van Rooij * We only allow it at securelevel < 1. 275c8bdd56bSGuido van Rooij * (Because the XIG X server writes directly to video 276c8bdd56bSGuido van Rooij * memory via /dev/mem, it should never work at any 277c8bdd56bSGuido van Rooij * other securelevel. 278c8bdd56bSGuido van Rooij * XXX this will have to go 279c8bdd56bSGuido van Rooij */ 280c8bdd56bSGuido van Rooij if (securelevel >= 1) 281c8bdd56bSGuido van Rooij disablexworkaround = 1; 282c8bdd56bSGuido van Rooij else 283c8bdd56bSGuido van Rooij disablexworkaround = suser(p->p_ucred, 284c8bdd56bSGuido van Rooij &p->p_acflag); 285c8bdd56bSGuido van Rooij if (vp->v_type == VCHR && disablexworkaround && 286c8bdd56bSGuido van Rooij (flags & (MAP_PRIVATE|MAP_COPY))) 287c8bdd56bSGuido van Rooij return (EINVAL); 288c8bdd56bSGuido van Rooij /* 289df8bae1dSRodney W. Grimes * Ensure that file and memory protections are 290df8bae1dSRodney W. Grimes * compatible. Note that we only worry about 291df8bae1dSRodney W. Grimes * writability if mapping is shared; in this case, 292df8bae1dSRodney W. Grimes * current and max prot are dictated by the open file. 293df8bae1dSRodney W. Grimes * XXX use the vnode instead? Problem is: what 2940d94caffSDavid Greenman * credentials do we use for determination? What if 2950d94caffSDavid Greenman * proc does a setuid? 296df8bae1dSRodney W. Grimes */ 297df8bae1dSRodney W. Grimes maxprot = VM_PROT_EXECUTE; /* ??? */ 298df8bae1dSRodney W. Grimes if (fp->f_flag & FREAD) 299df8bae1dSRodney W. Grimes maxprot |= VM_PROT_READ; 300df8bae1dSRodney W. Grimes else if (prot & PROT_READ) 301df8bae1dSRodney W. Grimes return (EACCES); 302c8bdd56bSGuido van Rooij /* 303c8bdd56bSGuido van Rooij * If we are sharing potential changes (either via 304c8bdd56bSGuido van Rooij * MAP_SHARED or via the implicit sharing of character 305c8bdd56bSGuido van Rooij * device mappings), and we are trying to get write 306c8bdd56bSGuido van Rooij * permission although we opened it without asking 307c8bdd56bSGuido van Rooij * for it, bail out. Check for superuser, only if 308c8bdd56bSGuido van Rooij * we're at securelevel < 1, to allow the XIG X server 309c8bdd56bSGuido van Rooij * to continue to work. 310c8bdd56bSGuido van Rooij */ 31105feb99fSGuido van Rooij 31205feb99fSGuido van Rooij if ((flags & MAP_SHARED) != 0 || 31305feb99fSGuido van Rooij (vp->v_type == VCHR && disablexworkaround)) { 31405feb99fSGuido van Rooij if ((fp->f_flag & FWRITE) != 0) { 3154183b6b6SPeter Wemm struct vattr va; 31605feb99fSGuido van Rooij if ((error = 31705feb99fSGuido van Rooij VOP_GETATTR(vp, &va, 31805feb99fSGuido van Rooij p->p_ucred, p))) 31905feb99fSGuido van Rooij return (error); 32005feb99fSGuido van Rooij if ((va.va_flags & 32105feb99fSGuido van Rooij (IMMUTABLE|APPEND)) == 0) 322df8bae1dSRodney W. Grimes maxprot |= VM_PROT_WRITE; 32305feb99fSGuido van Rooij else if (prot & PROT_WRITE) 32405feb99fSGuido van Rooij return (EPERM); 32505feb99fSGuido van Rooij } else if ((prot & PROT_WRITE) != 0) 32605feb99fSGuido van Rooij return (EACCES); 32705feb99fSGuido van Rooij } else 32805feb99fSGuido van Rooij maxprot |= VM_PROT_WRITE; 32905feb99fSGuido van Rooij 330651bb817SAlexander Langer handle = (void *)vp; 331df8bae1dSRodney W. Grimes } 332df8bae1dSRodney W. Grimes } 333df8bae1dSRodney W. Grimes error = vm_mmap(&p->p_vmspace->vm_map, &addr, size, prot, maxprot, 33454f42e4bSPeter Wemm flags, handle, pos); 335df8bae1dSRodney W. Grimes if (error == 0) 336711458e3SDoug Rabson p->p_retval[0] = (register_t) (addr + pageoff); 337df8bae1dSRodney W. Grimes return (error); 338df8bae1dSRodney W. Grimes } 339df8bae1dSRodney W. Grimes 34005f0fdd2SPoul-Henning Kamp #ifdef COMPAT_43 341d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 34205f0fdd2SPoul-Henning Kamp struct ommap_args { 34305f0fdd2SPoul-Henning Kamp caddr_t addr; 34405f0fdd2SPoul-Henning Kamp int len; 34505f0fdd2SPoul-Henning Kamp int prot; 34605f0fdd2SPoul-Henning Kamp int flags; 34705f0fdd2SPoul-Henning Kamp int fd; 34805f0fdd2SPoul-Henning Kamp long pos; 34905f0fdd2SPoul-Henning Kamp }; 350d2d3e875SBruce Evans #endif 35105f0fdd2SPoul-Henning Kamp int 352cb226aaaSPoul-Henning Kamp ommap(p, uap) 35305f0fdd2SPoul-Henning Kamp struct proc *p; 35405f0fdd2SPoul-Henning Kamp register struct ommap_args *uap; 35505f0fdd2SPoul-Henning Kamp { 35605f0fdd2SPoul-Henning Kamp struct mmap_args nargs; 35705f0fdd2SPoul-Henning Kamp static const char cvtbsdprot[8] = { 35805f0fdd2SPoul-Henning Kamp 0, 35905f0fdd2SPoul-Henning Kamp PROT_EXEC, 36005f0fdd2SPoul-Henning Kamp PROT_WRITE, 36105f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE, 36205f0fdd2SPoul-Henning Kamp PROT_READ, 36305f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_READ, 36405f0fdd2SPoul-Henning Kamp PROT_WRITE | PROT_READ, 36505f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE | PROT_READ, 36605f0fdd2SPoul-Henning Kamp }; 3670d94caffSDavid Greenman 36805f0fdd2SPoul-Henning Kamp #define OMAP_ANON 0x0002 36905f0fdd2SPoul-Henning Kamp #define OMAP_COPY 0x0020 37005f0fdd2SPoul-Henning Kamp #define OMAP_SHARED 0x0010 37105f0fdd2SPoul-Henning Kamp #define OMAP_FIXED 0x0100 37205f0fdd2SPoul-Henning Kamp #define OMAP_INHERIT 0x0800 37305f0fdd2SPoul-Henning Kamp 37405f0fdd2SPoul-Henning Kamp nargs.addr = uap->addr; 37505f0fdd2SPoul-Henning Kamp nargs.len = uap->len; 37605f0fdd2SPoul-Henning Kamp nargs.prot = cvtbsdprot[uap->prot & 0x7]; 37705f0fdd2SPoul-Henning Kamp nargs.flags = 0; 37805f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_ANON) 37905f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_ANON; 38005f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_COPY) 38105f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_COPY; 38205f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_SHARED) 38305f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_SHARED; 38405f0fdd2SPoul-Henning Kamp else 38505f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_PRIVATE; 38605f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_FIXED) 38705f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_FIXED; 38805f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_INHERIT) 38905f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_INHERIT; 39005f0fdd2SPoul-Henning Kamp nargs.fd = uap->fd; 39105f0fdd2SPoul-Henning Kamp nargs.pos = uap->pos; 392cb226aaaSPoul-Henning Kamp return (mmap(p, &nargs)); 39305f0fdd2SPoul-Henning Kamp } 39405f0fdd2SPoul-Henning Kamp #endif /* COMPAT_43 */ 39505f0fdd2SPoul-Henning Kamp 39605f0fdd2SPoul-Henning Kamp 397d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 398df8bae1dSRodney W. Grimes struct msync_args { 399651bb817SAlexander Langer void *addr; 400df8bae1dSRodney W. Grimes int len; 401e6c6af11SDavid Greenman int flags; 402df8bae1dSRodney W. Grimes }; 403d2d3e875SBruce Evans #endif 404df8bae1dSRodney W. Grimes int 405cb226aaaSPoul-Henning Kamp msync(p, uap) 406df8bae1dSRodney W. Grimes struct proc *p; 407df8bae1dSRodney W. Grimes struct msync_args *uap; 408df8bae1dSRodney W. Grimes { 409df8bae1dSRodney W. Grimes vm_offset_t addr; 410dabee6feSPeter Wemm vm_size_t size, pageoff; 411e6c6af11SDavid Greenman int flags; 412df8bae1dSRodney W. Grimes vm_map_t map; 413df8bae1dSRodney W. Grimes int rv; 414df8bae1dSRodney W. Grimes 415df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 4169154ee6aSPeter Wemm size = uap->len; 417e6c6af11SDavid Greenman flags = uap->flags; 418e6c6af11SDavid Greenman 419dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 420dabee6feSPeter Wemm addr -= pageoff; 421dabee6feSPeter Wemm size += pageoff; 422dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 4239154ee6aSPeter Wemm if (addr + size < addr) 424dabee6feSPeter Wemm return(EINVAL); 425dabee6feSPeter Wemm 426dabee6feSPeter Wemm if ((flags & (MS_ASYNC|MS_INVALIDATE)) == (MS_ASYNC|MS_INVALIDATE)) 4271e62bc63SDavid Greenman return (EINVAL); 4281e62bc63SDavid Greenman 4299154ee6aSPeter Wemm map = &p->p_vmspace->vm_map; 4309154ee6aSPeter Wemm 431df8bae1dSRodney W. Grimes /* 432df8bae1dSRodney W. Grimes * XXX Gak! If size is zero we are supposed to sync "all modified 4330d94caffSDavid Greenman * pages with the region containing addr". Unfortunately, we don't 4340d94caffSDavid Greenman * really keep track of individual mmaps so we approximate by flushing 4350d94caffSDavid Greenman * the range of the map entry containing addr. This can be incorrect 4360d94caffSDavid Greenman * if the region splits or is coalesced with a neighbor. 437df8bae1dSRodney W. Grimes */ 438df8bae1dSRodney W. Grimes if (size == 0) { 439df8bae1dSRodney W. Grimes vm_map_entry_t entry; 440df8bae1dSRodney W. Grimes 441df8bae1dSRodney W. Grimes vm_map_lock_read(map); 442df8bae1dSRodney W. Grimes rv = vm_map_lookup_entry(map, addr, &entry); 443df8bae1dSRodney W. Grimes vm_map_unlock_read(map); 444fbcfcdf7SDavid Greenman if (rv == FALSE) 445df8bae1dSRodney W. Grimes return (EINVAL); 446df8bae1dSRodney W. Grimes addr = entry->start; 447df8bae1dSRodney W. Grimes size = entry->end - entry->start; 448df8bae1dSRodney W. Grimes } 449e6c6af11SDavid Greenman 450df8bae1dSRodney W. Grimes /* 451df8bae1dSRodney W. Grimes * Clean the pages and interpret the return value. 452df8bae1dSRodney W. Grimes */ 4536c534ad8SDavid Greenman rv = vm_map_clean(map, addr, addr + size, (flags & MS_ASYNC) == 0, 454e6c6af11SDavid Greenman (flags & MS_INVALIDATE) != 0); 455e6c6af11SDavid Greenman 456df8bae1dSRodney W. Grimes switch (rv) { 457df8bae1dSRodney W. Grimes case KERN_SUCCESS: 458df8bae1dSRodney W. Grimes break; 459df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 460df8bae1dSRodney W. Grimes return (EINVAL); /* Sun returns ENOMEM? */ 461df8bae1dSRodney W. Grimes case KERN_FAILURE: 462df8bae1dSRodney W. Grimes return (EIO); 463df8bae1dSRodney W. Grimes default: 464df8bae1dSRodney W. Grimes return (EINVAL); 465df8bae1dSRodney W. Grimes } 466e6c6af11SDavid Greenman 467df8bae1dSRodney W. Grimes return (0); 468df8bae1dSRodney W. Grimes } 469df8bae1dSRodney W. Grimes 470d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 471df8bae1dSRodney W. Grimes struct munmap_args { 472651bb817SAlexander Langer void *addr; 4739154ee6aSPeter Wemm size_t len; 474df8bae1dSRodney W. Grimes }; 475d2d3e875SBruce Evans #endif 476df8bae1dSRodney W. Grimes int 477cb226aaaSPoul-Henning Kamp munmap(p, uap) 478df8bae1dSRodney W. Grimes register struct proc *p; 479df8bae1dSRodney W. Grimes register struct munmap_args *uap; 480df8bae1dSRodney W. Grimes { 481df8bae1dSRodney W. Grimes vm_offset_t addr; 482dabee6feSPeter Wemm vm_size_t size, pageoff; 483df8bae1dSRodney W. Grimes vm_map_t map; 484df8bae1dSRodney W. Grimes 485df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 4869154ee6aSPeter Wemm size = uap->len; 487dabee6feSPeter Wemm 488dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 489dabee6feSPeter Wemm addr -= pageoff; 490dabee6feSPeter Wemm size += pageoff; 491dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 4929154ee6aSPeter Wemm if (addr + size < addr) 493df8bae1dSRodney W. Grimes return(EINVAL); 4949154ee6aSPeter Wemm 495df8bae1dSRodney W. Grimes if (size == 0) 496df8bae1dSRodney W. Grimes return (0); 497dabee6feSPeter Wemm 498df8bae1dSRodney W. Grimes /* 4990d94caffSDavid Greenman * Check for illegal addresses. Watch out for address wrap... Note 5000d94caffSDavid Greenman * that VM_*_ADDRESS are not constants due to casts (argh). 501df8bae1dSRodney W. Grimes */ 502bbc0ec52SDavid Greenman if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS) 503df8bae1dSRodney W. Grimes return (EINVAL); 50426f9a767SRodney W. Grimes #ifndef i386 505df8bae1dSRodney W. Grimes if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS) 506df8bae1dSRodney W. Grimes return (EINVAL); 50726f9a767SRodney W. Grimes #endif 508df8bae1dSRodney W. Grimes map = &p->p_vmspace->vm_map; 509df8bae1dSRodney W. Grimes /* 510df8bae1dSRodney W. Grimes * Make sure entire range is allocated. 511df8bae1dSRodney W. Grimes */ 512df8bae1dSRodney W. Grimes if (!vm_map_check_protection(map, addr, addr + size, VM_PROT_NONE)) 513df8bae1dSRodney W. Grimes return (EINVAL); 514df8bae1dSRodney W. Grimes /* returns nothing but KERN_SUCCESS anyway */ 515df8bae1dSRodney W. Grimes (void) vm_map_remove(map, addr, addr + size); 516df8bae1dSRodney W. Grimes return (0); 517df8bae1dSRodney W. Grimes } 518df8bae1dSRodney W. Grimes 519df8bae1dSRodney W. Grimes void 52090324b07SDavid Greenman munmapfd(p, fd) 52190324b07SDavid Greenman struct proc *p; 522df8bae1dSRodney W. Grimes int fd; 523df8bae1dSRodney W. Grimes { 524df8bae1dSRodney W. Grimes /* 525c4ed5a07SDavid Greenman * XXX should unmap any regions mapped to this file 526df8bae1dSRodney W. Grimes */ 52790324b07SDavid Greenman p->p_fd->fd_ofileflags[fd] &= ~UF_MAPPED; 528df8bae1dSRodney W. Grimes } 529df8bae1dSRodney W. Grimes 530d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 531df8bae1dSRodney W. Grimes struct mprotect_args { 532651bb817SAlexander Langer const void *addr; 5339154ee6aSPeter Wemm size_t len; 534df8bae1dSRodney W. Grimes int prot; 535df8bae1dSRodney W. Grimes }; 536d2d3e875SBruce Evans #endif 537df8bae1dSRodney W. Grimes int 538cb226aaaSPoul-Henning Kamp mprotect(p, uap) 539df8bae1dSRodney W. Grimes struct proc *p; 540df8bae1dSRodney W. Grimes struct mprotect_args *uap; 541df8bae1dSRodney W. Grimes { 542df8bae1dSRodney W. Grimes vm_offset_t addr; 543dabee6feSPeter Wemm vm_size_t size, pageoff; 544df8bae1dSRodney W. Grimes register vm_prot_t prot; 545df8bae1dSRodney W. Grimes 546df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 5479154ee6aSPeter Wemm size = uap->len; 548df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 549d0aea04fSJohn Dyson #if defined(VM_PROT_READ_IS_EXEC) 550d0aea04fSJohn Dyson if (prot & VM_PROT_READ) 551d0aea04fSJohn Dyson prot |= VM_PROT_EXECUTE; 552d0aea04fSJohn Dyson #endif 553df8bae1dSRodney W. Grimes 554dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 555dabee6feSPeter Wemm addr -= pageoff; 556dabee6feSPeter Wemm size += pageoff; 557dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 5589154ee6aSPeter Wemm if (addr + size < addr) 559dabee6feSPeter Wemm return(EINVAL); 560dabee6feSPeter Wemm 561df8bae1dSRodney W. Grimes switch (vm_map_protect(&p->p_vmspace->vm_map, addr, addr + size, prot, 562df8bae1dSRodney W. Grimes FALSE)) { 563df8bae1dSRodney W. Grimes case KERN_SUCCESS: 564df8bae1dSRodney W. Grimes return (0); 565df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 566df8bae1dSRodney W. Grimes return (EACCES); 567df8bae1dSRodney W. Grimes } 568df8bae1dSRodney W. Grimes return (EINVAL); 569df8bae1dSRodney W. Grimes } 570df8bae1dSRodney W. Grimes 571d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 572dabee6feSPeter Wemm struct minherit_args { 573651bb817SAlexander Langer void *addr; 5749154ee6aSPeter Wemm size_t len; 575dabee6feSPeter Wemm int inherit; 576dabee6feSPeter Wemm }; 577dabee6feSPeter Wemm #endif 578dabee6feSPeter Wemm int 579cb226aaaSPoul-Henning Kamp minherit(p, uap) 580dabee6feSPeter Wemm struct proc *p; 581dabee6feSPeter Wemm struct minherit_args *uap; 582dabee6feSPeter Wemm { 583dabee6feSPeter Wemm vm_offset_t addr; 584dabee6feSPeter Wemm vm_size_t size, pageoff; 585dabee6feSPeter Wemm register vm_inherit_t inherit; 586dabee6feSPeter Wemm 587dabee6feSPeter Wemm addr = (vm_offset_t)uap->addr; 5889154ee6aSPeter Wemm size = uap->len; 589dabee6feSPeter Wemm inherit = uap->inherit; 590dabee6feSPeter Wemm 591dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 592dabee6feSPeter Wemm addr -= pageoff; 593dabee6feSPeter Wemm size += pageoff; 594dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 5959154ee6aSPeter Wemm if (addr + size < addr) 596dabee6feSPeter Wemm return(EINVAL); 597dabee6feSPeter Wemm 598dabee6feSPeter Wemm switch (vm_map_inherit(&p->p_vmspace->vm_map, addr, addr+size, 599dabee6feSPeter Wemm inherit)) { 600dabee6feSPeter Wemm case KERN_SUCCESS: 601dabee6feSPeter Wemm return (0); 602dabee6feSPeter Wemm case KERN_PROTECTION_FAILURE: 603dabee6feSPeter Wemm return (EACCES); 604dabee6feSPeter Wemm } 605dabee6feSPeter Wemm return (EINVAL); 606dabee6feSPeter Wemm } 607dabee6feSPeter Wemm 608dabee6feSPeter Wemm #ifndef _SYS_SYSPROTO_H_ 609df8bae1dSRodney W. Grimes struct madvise_args { 610651bb817SAlexander Langer void *addr; 6119154ee6aSPeter Wemm size_t len; 612df8bae1dSRodney W. Grimes int behav; 613df8bae1dSRodney W. Grimes }; 614d2d3e875SBruce Evans #endif 6150d94caffSDavid Greenman 616df8bae1dSRodney W. Grimes /* ARGSUSED */ 617df8bae1dSRodney W. Grimes int 618cb226aaaSPoul-Henning Kamp madvise(p, uap) 619df8bae1dSRodney W. Grimes struct proc *p; 620df8bae1dSRodney W. Grimes struct madvise_args *uap; 621df8bae1dSRodney W. Grimes { 622867a482dSJohn Dyson vm_map_t map; 623867a482dSJohn Dyson pmap_t pmap; 624f35329acSJohn Dyson vm_offset_t start, end; 625867a482dSJohn Dyson /* 626867a482dSJohn Dyson * Check for illegal addresses. Watch out for address wrap... Note 627867a482dSJohn Dyson * that VM_*_ADDRESS are not constants due to casts (argh). 628867a482dSJohn Dyson */ 629867a482dSJohn Dyson if (VM_MAXUSER_ADDRESS > 0 && 630867a482dSJohn Dyson ((vm_offset_t) uap->addr + uap->len) > VM_MAXUSER_ADDRESS) 631867a482dSJohn Dyson return (EINVAL); 632867a482dSJohn Dyson #ifndef i386 633867a482dSJohn Dyson if (VM_MIN_ADDRESS > 0 && uap->addr < VM_MIN_ADDRESS) 634867a482dSJohn Dyson return (EINVAL); 635867a482dSJohn Dyson #endif 636867a482dSJohn Dyson if (((vm_offset_t) uap->addr + uap->len) < (vm_offset_t) uap->addr) 637867a482dSJohn Dyson return (EINVAL); 638867a482dSJohn Dyson 639867a482dSJohn Dyson /* 640867a482dSJohn Dyson * Since this routine is only advisory, we default to conservative 641867a482dSJohn Dyson * behavior. 642867a482dSJohn Dyson */ 643cd6eea25SDavid Greenman start = trunc_page((vm_offset_t) uap->addr); 644cd6eea25SDavid Greenman end = round_page((vm_offset_t) uap->addr + uap->len); 645867a482dSJohn Dyson 646867a482dSJohn Dyson map = &p->p_vmspace->vm_map; 647b1028ad1SLuoqi Chen pmap = vmspace_pmap(p->p_vmspace); 648867a482dSJohn Dyson 649867a482dSJohn Dyson vm_map_madvise(map, pmap, start, end, uap->behav); 650df8bae1dSRodney W. Grimes 651867a482dSJohn Dyson return (0); 652df8bae1dSRodney W. Grimes } 653df8bae1dSRodney W. Grimes 654d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 655df8bae1dSRodney W. Grimes struct mincore_args { 656651bb817SAlexander Langer const void *addr; 6579154ee6aSPeter Wemm size_t len; 658df8bae1dSRodney W. Grimes char *vec; 659df8bae1dSRodney W. Grimes }; 660d2d3e875SBruce Evans #endif 6610d94caffSDavid Greenman 662df8bae1dSRodney W. Grimes /* ARGSUSED */ 663df8bae1dSRodney W. Grimes int 664cb226aaaSPoul-Henning Kamp mincore(p, uap) 665df8bae1dSRodney W. Grimes struct proc *p; 666df8bae1dSRodney W. Grimes struct mincore_args *uap; 667df8bae1dSRodney W. Grimes { 668867a482dSJohn Dyson vm_offset_t addr, first_addr; 669867a482dSJohn Dyson vm_offset_t end, cend; 670867a482dSJohn Dyson pmap_t pmap; 671867a482dSJohn Dyson vm_map_t map; 67202c04a2fSJohn Dyson char *vec; 673867a482dSJohn Dyson int error; 674867a482dSJohn Dyson int vecindex, lastvecindex; 675867a482dSJohn Dyson register vm_map_entry_t current; 676867a482dSJohn Dyson vm_map_entry_t entry; 677867a482dSJohn Dyson int mincoreinfo; 678df8bae1dSRodney W. Grimes 679867a482dSJohn Dyson /* 680867a482dSJohn Dyson * Make sure that the addresses presented are valid for user 681867a482dSJohn Dyson * mode. 682867a482dSJohn Dyson */ 683867a482dSJohn Dyson first_addr = addr = trunc_page((vm_offset_t) uap->addr); 6849154ee6aSPeter Wemm end = addr + (vm_size_t)round_page(uap->len); 68502c04a2fSJohn Dyson if (VM_MAXUSER_ADDRESS > 0 && end > VM_MAXUSER_ADDRESS) 68602c04a2fSJohn Dyson return (EINVAL); 68702c04a2fSJohn Dyson if (end < addr) 68802c04a2fSJohn Dyson return (EINVAL); 68902c04a2fSJohn Dyson 690867a482dSJohn Dyson /* 691867a482dSJohn Dyson * Address of byte vector 692867a482dSJohn Dyson */ 69302c04a2fSJohn Dyson vec = uap->vec; 694867a482dSJohn Dyson 695867a482dSJohn Dyson map = &p->p_vmspace->vm_map; 696b1028ad1SLuoqi Chen pmap = vmspace_pmap(p->p_vmspace); 697867a482dSJohn Dyson 698867a482dSJohn Dyson vm_map_lock(map); 699867a482dSJohn Dyson 700867a482dSJohn Dyson if (!vm_map_lookup_entry(map, addr, &entry)) 701867a482dSJohn Dyson entry = entry->next; 702867a482dSJohn Dyson 703867a482dSJohn Dyson /* 704867a482dSJohn Dyson * Do this on a map entry basis so that if the pages are not 705867a482dSJohn Dyson * in the current processes address space, we can easily look 706867a482dSJohn Dyson * up the pages elsewhere. 707867a482dSJohn Dyson */ 708867a482dSJohn Dyson lastvecindex = -1; 709867a482dSJohn Dyson for(current = entry; 710867a482dSJohn Dyson (current != &map->header) && (current->start < end); 711867a482dSJohn Dyson current = current->next) { 712867a482dSJohn Dyson 713867a482dSJohn Dyson /* 714867a482dSJohn Dyson * ignore submaps (for now) or null objects 715867a482dSJohn Dyson */ 7169fdfe602SMatthew Dillon if ((current->eflags & MAP_ENTRY_IS_SUB_MAP) || 717867a482dSJohn Dyson current->object.vm_object == NULL) 718867a482dSJohn Dyson continue; 719867a482dSJohn Dyson 720867a482dSJohn Dyson /* 721867a482dSJohn Dyson * limit this scan to the current map entry and the 722867a482dSJohn Dyson * limits for the mincore call 723867a482dSJohn Dyson */ 724867a482dSJohn Dyson if (addr < current->start) 725867a482dSJohn Dyson addr = current->start; 726867a482dSJohn Dyson cend = current->end; 727867a482dSJohn Dyson if (cend > end) 728867a482dSJohn Dyson cend = end; 729867a482dSJohn Dyson 730867a482dSJohn Dyson /* 731867a482dSJohn Dyson * scan this entry one page at a time 732867a482dSJohn Dyson */ 733867a482dSJohn Dyson while(addr < cend) { 734867a482dSJohn Dyson /* 735867a482dSJohn Dyson * Check pmap first, it is likely faster, also 736867a482dSJohn Dyson * it can provide info as to whether we are the 737867a482dSJohn Dyson * one referencing or modifying the page. 738867a482dSJohn Dyson */ 739867a482dSJohn Dyson mincoreinfo = pmap_mincore(pmap, addr); 740867a482dSJohn Dyson if (!mincoreinfo) { 741867a482dSJohn Dyson vm_pindex_t pindex; 742867a482dSJohn Dyson vm_ooffset_t offset; 743867a482dSJohn Dyson vm_page_t m; 744867a482dSJohn Dyson /* 745867a482dSJohn Dyson * calculate the page index into the object 746867a482dSJohn Dyson */ 747867a482dSJohn Dyson offset = current->offset + (addr - current->start); 748867a482dSJohn Dyson pindex = OFF_TO_IDX(offset); 749867a482dSJohn Dyson m = vm_page_lookup(current->object.vm_object, 750867a482dSJohn Dyson pindex); 751867a482dSJohn Dyson /* 752867a482dSJohn Dyson * if the page is resident, then gather information about 753867a482dSJohn Dyson * it. 754867a482dSJohn Dyson */ 755867a482dSJohn Dyson if (m) { 756867a482dSJohn Dyson mincoreinfo = MINCORE_INCORE; 757867a482dSJohn Dyson if (m->dirty || 75867bf6868SJohn Dyson pmap_is_modified(VM_PAGE_TO_PHYS(m))) 759867a482dSJohn Dyson mincoreinfo |= MINCORE_MODIFIED_OTHER; 760867a482dSJohn Dyson if ((m->flags & PG_REFERENCED) || 7619b5a5d81SJohn Dyson pmap_ts_referenced(VM_PAGE_TO_PHYS(m))) { 762e69763a3SDoug Rabson vm_page_flag_set(m, PG_REFERENCED); 763867a482dSJohn Dyson mincoreinfo |= MINCORE_REFERENCED_OTHER; 76402c04a2fSJohn Dyson } 765867a482dSJohn Dyson } 7669b5a5d81SJohn Dyson } 767867a482dSJohn Dyson 768867a482dSJohn Dyson /* 769867a482dSJohn Dyson * calculate index into user supplied byte vector 770867a482dSJohn Dyson */ 771867a482dSJohn Dyson vecindex = OFF_TO_IDX(addr - first_addr); 772867a482dSJohn Dyson 773867a482dSJohn Dyson /* 774867a482dSJohn Dyson * If we have skipped map entries, we need to make sure that 775867a482dSJohn Dyson * the byte vector is zeroed for those skipped entries. 776867a482dSJohn Dyson */ 777867a482dSJohn Dyson while((lastvecindex + 1) < vecindex) { 778867a482dSJohn Dyson error = subyte( vec + lastvecindex, 0); 779867a482dSJohn Dyson if (error) { 780867a482dSJohn Dyson vm_map_unlock(map); 781867a482dSJohn Dyson return (EFAULT); 782867a482dSJohn Dyson } 783867a482dSJohn Dyson ++lastvecindex; 784867a482dSJohn Dyson } 785867a482dSJohn Dyson 786867a482dSJohn Dyson /* 787867a482dSJohn Dyson * Pass the page information to the user 788867a482dSJohn Dyson */ 789867a482dSJohn Dyson error = subyte( vec + vecindex, mincoreinfo); 790867a482dSJohn Dyson if (error) { 791867a482dSJohn Dyson vm_map_unlock(map); 792867a482dSJohn Dyson return (EFAULT); 793867a482dSJohn Dyson } 794867a482dSJohn Dyson lastvecindex = vecindex; 79502c04a2fSJohn Dyson addr += PAGE_SIZE; 79602c04a2fSJohn Dyson } 797867a482dSJohn Dyson } 798867a482dSJohn Dyson 799867a482dSJohn Dyson /* 800867a482dSJohn Dyson * Zero the last entries in the byte vector. 801867a482dSJohn Dyson */ 802867a482dSJohn Dyson vecindex = OFF_TO_IDX(end - first_addr); 803867a482dSJohn Dyson while((lastvecindex + 1) < vecindex) { 804867a482dSJohn Dyson error = subyte( vec + lastvecindex, 0); 805867a482dSJohn Dyson if (error) { 806867a482dSJohn Dyson vm_map_unlock(map); 807867a482dSJohn Dyson return (EFAULT); 808867a482dSJohn Dyson } 809867a482dSJohn Dyson ++lastvecindex; 810867a482dSJohn Dyson } 811867a482dSJohn Dyson 812867a482dSJohn Dyson vm_map_unlock(map); 81302c04a2fSJohn Dyson return (0); 814df8bae1dSRodney W. Grimes } 815df8bae1dSRodney W. Grimes 816d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 817df8bae1dSRodney W. Grimes struct mlock_args { 818651bb817SAlexander Langer const void *addr; 819df8bae1dSRodney W. Grimes size_t len; 820df8bae1dSRodney W. Grimes }; 821d2d3e875SBruce Evans #endif 822df8bae1dSRodney W. Grimes int 823cb226aaaSPoul-Henning Kamp mlock(p, uap) 824df8bae1dSRodney W. Grimes struct proc *p; 825df8bae1dSRodney W. Grimes struct mlock_args *uap; 826df8bae1dSRodney W. Grimes { 827df8bae1dSRodney W. Grimes vm_offset_t addr; 828dabee6feSPeter Wemm vm_size_t size, pageoff; 829df8bae1dSRodney W. Grimes int error; 830df8bae1dSRodney W. Grimes 831df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 8329154ee6aSPeter Wemm size = uap->len; 8339154ee6aSPeter Wemm 834dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 835dabee6feSPeter Wemm addr -= pageoff; 836dabee6feSPeter Wemm size += pageoff; 837dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 838dabee6feSPeter Wemm 839dabee6feSPeter Wemm /* disable wrap around */ 8409154ee6aSPeter Wemm if (addr + size < addr) 841df8bae1dSRodney W. Grimes return (EINVAL); 842dabee6feSPeter Wemm 843df8bae1dSRodney W. Grimes if (atop(size) + cnt.v_wire_count > vm_page_max_wired) 844df8bae1dSRodney W. Grimes return (EAGAIN); 8459154ee6aSPeter Wemm 846df8bae1dSRodney W. Grimes #ifdef pmap_wired_count 847df8bae1dSRodney W. Grimes if (size + ptoa(pmap_wired_count(vm_map_pmap(&p->p_vmspace->vm_map))) > 848df8bae1dSRodney W. Grimes p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur) 8494a40e3d4SJohn Dyson return (ENOMEM); 850df8bae1dSRodney W. Grimes #else 85105f0fdd2SPoul-Henning Kamp error = suser(p->p_ucred, &p->p_acflag); 85205f0fdd2SPoul-Henning Kamp if (error) 853df8bae1dSRodney W. Grimes return (error); 854df8bae1dSRodney W. Grimes #endif 855df8bae1dSRodney W. Grimes 8567aaaa4fdSJohn Dyson error = vm_map_user_pageable(&p->p_vmspace->vm_map, addr, addr + size, FALSE); 857df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 858df8bae1dSRodney W. Grimes } 859df8bae1dSRodney W. Grimes 860d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 8614a40e3d4SJohn Dyson struct mlockall_args { 8624a40e3d4SJohn Dyson int how; 8634a40e3d4SJohn Dyson }; 8644a40e3d4SJohn Dyson #endif 8654a40e3d4SJohn Dyson 8664a40e3d4SJohn Dyson int 867cb226aaaSPoul-Henning Kamp mlockall(p, uap) 8684a40e3d4SJohn Dyson struct proc *p; 8694a40e3d4SJohn Dyson struct mlockall_args *uap; 8704a40e3d4SJohn Dyson { 8714a40e3d4SJohn Dyson return 0; 8724a40e3d4SJohn Dyson } 8734a40e3d4SJohn Dyson 8744a40e3d4SJohn Dyson #ifndef _SYS_SYSPROTO_H_ 8754a40e3d4SJohn Dyson struct mlockall_args { 8764a40e3d4SJohn Dyson int how; 8774a40e3d4SJohn Dyson }; 8784a40e3d4SJohn Dyson #endif 8794a40e3d4SJohn Dyson 8804a40e3d4SJohn Dyson int 881cb226aaaSPoul-Henning Kamp munlockall(p, uap) 8824a40e3d4SJohn Dyson struct proc *p; 8834a40e3d4SJohn Dyson struct munlockall_args *uap; 8844a40e3d4SJohn Dyson { 8854a40e3d4SJohn Dyson return 0; 8864a40e3d4SJohn Dyson } 8874a40e3d4SJohn Dyson 8884a40e3d4SJohn Dyson #ifndef _SYS_SYSPROTO_H_ 889df8bae1dSRodney W. Grimes struct munlock_args { 890651bb817SAlexander Langer const void *addr; 891df8bae1dSRodney W. Grimes size_t len; 892df8bae1dSRodney W. Grimes }; 893d2d3e875SBruce Evans #endif 894df8bae1dSRodney W. Grimes int 895cb226aaaSPoul-Henning Kamp munlock(p, uap) 896df8bae1dSRodney W. Grimes struct proc *p; 897df8bae1dSRodney W. Grimes struct munlock_args *uap; 898df8bae1dSRodney W. Grimes { 899df8bae1dSRodney W. Grimes vm_offset_t addr; 900dabee6feSPeter Wemm vm_size_t size, pageoff; 901df8bae1dSRodney W. Grimes int error; 902df8bae1dSRodney W. Grimes 903df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 9049154ee6aSPeter Wemm size = uap->len; 9059154ee6aSPeter Wemm 906dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 907dabee6feSPeter Wemm addr -= pageoff; 908dabee6feSPeter Wemm size += pageoff; 909dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 910dabee6feSPeter Wemm 911dabee6feSPeter Wemm /* disable wrap around */ 9129154ee6aSPeter Wemm if (addr + size < addr) 913df8bae1dSRodney W. Grimes return (EINVAL); 914dabee6feSPeter Wemm 915df8bae1dSRodney W. Grimes #ifndef pmap_wired_count 91605f0fdd2SPoul-Henning Kamp error = suser(p->p_ucred, &p->p_acflag); 91705f0fdd2SPoul-Henning Kamp if (error) 918df8bae1dSRodney W. Grimes return (error); 919df8bae1dSRodney W. Grimes #endif 920df8bae1dSRodney W. Grimes 9217aaaa4fdSJohn Dyson error = vm_map_user_pageable(&p->p_vmspace->vm_map, addr, addr + size, TRUE); 922df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 923df8bae1dSRodney W. Grimes } 924df8bae1dSRodney W. Grimes 925df8bae1dSRodney W. Grimes /* 926df8bae1dSRodney W. Grimes * Internal version of mmap. 927df8bae1dSRodney W. Grimes * Currently used by mmap, exec, and sys5 shared memory. 928df8bae1dSRodney W. Grimes * Handle is either a vnode pointer or NULL for MAP_ANON. 929df8bae1dSRodney W. Grimes */ 930df8bae1dSRodney W. Grimes int 931b9dcd593SBruce Evans vm_mmap(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, 932b9dcd593SBruce Evans vm_prot_t maxprot, int flags, 933651bb817SAlexander Langer void *handle, 934b9dcd593SBruce Evans vm_ooffset_t foff) 935df8bae1dSRodney W. Grimes { 936df8bae1dSRodney W. Grimes boolean_t fitit; 937fcae040bSJohn Dyson vm_object_t object; 938df8bae1dSRodney W. Grimes struct vnode *vp = NULL; 93924a1cce3SDavid Greenman objtype_t type; 940df8bae1dSRodney W. Grimes int rv = KERN_SUCCESS; 941bd7e5f99SJohn Dyson vm_ooffset_t objsize; 942bd7e5f99SJohn Dyson int docow; 94306cb7259SDavid Greenman struct proc *p = curproc; 944df8bae1dSRodney W. Grimes 945df8bae1dSRodney W. Grimes if (size == 0) 946df8bae1dSRodney W. Grimes return (0); 947df8bae1dSRodney W. Grimes 94806cb7259SDavid Greenman objsize = size = round_page(size); 949df8bae1dSRodney W. Grimes 950df8bae1dSRodney W. Grimes /* 951bc9ad247SDavid Greenman * We currently can only deal with page aligned file offsets. 952bc9ad247SDavid Greenman * The check is here rather than in the syscall because the 953bc9ad247SDavid Greenman * kernel calls this function internally for other mmaping 954bc9ad247SDavid Greenman * operations (such as in exec) and non-aligned offsets will 955bc9ad247SDavid Greenman * cause pmap inconsistencies...so we want to be sure to 956bc9ad247SDavid Greenman * disallow this in all cases. 957bc9ad247SDavid Greenman */ 958bc9ad247SDavid Greenman if (foff & PAGE_MASK) 959bc9ad247SDavid Greenman return (EINVAL); 960bc9ad247SDavid Greenman 96106cb7259SDavid Greenman if ((flags & MAP_FIXED) == 0) { 96206cb7259SDavid Greenman fitit = TRUE; 96306cb7259SDavid Greenman *addr = round_page(*addr); 96406cb7259SDavid Greenman } else { 96506cb7259SDavid Greenman if (*addr != trunc_page(*addr)) 96606cb7259SDavid Greenman return (EINVAL); 96706cb7259SDavid Greenman fitit = FALSE; 96806cb7259SDavid Greenman (void) vm_map_remove(map, *addr, *addr + size); 96906cb7259SDavid Greenman } 97006cb7259SDavid Greenman 971bc9ad247SDavid Greenman /* 97224a1cce3SDavid Greenman * Lookup/allocate object. 973df8bae1dSRodney W. Grimes */ 9745f55e841SDavid Greenman if (flags & MAP_ANON) { 975851c12ffSJohn Dyson type = OBJT_DEFAULT; 9765f55e841SDavid Greenman /* 9775f55e841SDavid Greenman * Unnamed anonymous regions always start at 0. 9785f55e841SDavid Greenman */ 97967bf6868SJohn Dyson if (handle == 0) 9805f55e841SDavid Greenman foff = 0; 9815f55e841SDavid Greenman } else { 982df8bae1dSRodney W. Grimes vp = (struct vnode *) handle; 983df8bae1dSRodney W. Grimes if (vp->v_type == VCHR) { 98424a1cce3SDavid Greenman type = OBJT_DEVICE; 985a23d65bfSBruce Evans handle = (void *)(intptr_t)vp->v_rdev; 98606cb7259SDavid Greenman } else { 98706cb7259SDavid Greenman struct vattr vat; 98806cb7259SDavid Greenman int error; 98906cb7259SDavid Greenman 99006cb7259SDavid Greenman error = VOP_GETATTR(vp, &vat, p->p_ucred, p); 99106cb7259SDavid Greenman if (error) 99206cb7259SDavid Greenman return (error); 993bd7e5f99SJohn Dyson objsize = round_page(vat.va_size); 99424a1cce3SDavid Greenman type = OBJT_VNODE; 995df8bae1dSRodney W. Grimes } 99606cb7259SDavid Greenman } 99794328e90SJohn Dyson 99894328e90SJohn Dyson if (handle == NULL) { 99994328e90SJohn Dyson object = NULL; 100094328e90SJohn Dyson } else { 10010a0a85b3SJohn Dyson object = vm_pager_allocate(type, 10026cde7a16SDavid Greenman handle, objsize, prot, foff); 100324a1cce3SDavid Greenman if (object == NULL) 100424a1cce3SDavid Greenman return (type == OBJT_DEVICE ? EINVAL : ENOMEM); 100594328e90SJohn Dyson } 1006df8bae1dSRodney W. Grimes 10075850152dSJohn Dyson /* 10088f2ec877SDavid Greenman * Force device mappings to be shared. 10095850152dSJohn Dyson */ 10108f2ec877SDavid Greenman if (type == OBJT_DEVICE) { 10118f2ec877SDavid Greenman flags &= ~(MAP_PRIVATE|MAP_COPY); 10125850152dSJohn Dyson flags |= MAP_SHARED; 10138f2ec877SDavid Greenman } 10145850152dSJohn Dyson 1015bd7e5f99SJohn Dyson docow = 0; 10165850152dSJohn Dyson if ((flags & (MAP_ANON|MAP_SHARED)) == 0) { 1017fcae040bSJohn Dyson docow = MAP_COPY_ON_WRITE | MAP_COPY_NEEDED; 1018bd7e5f99SJohn Dyson } 10195850152dSJohn Dyson 1020d0aea04fSJohn Dyson #if defined(VM_PROT_READ_IS_EXEC) 1021d0aea04fSJohn Dyson if (prot & VM_PROT_READ) 1022d0aea04fSJohn Dyson prot |= VM_PROT_EXECUTE; 1023d0aea04fSJohn Dyson 1024d0aea04fSJohn Dyson if (maxprot & VM_PROT_READ) 1025d0aea04fSJohn Dyson maxprot |= VM_PROT_EXECUTE; 1026d0aea04fSJohn Dyson #endif 1027d0aea04fSJohn Dyson 10280a0a85b3SJohn Dyson if (fitit) { 10290a0a85b3SJohn Dyson *addr = pmap_addr_hint(object, *addr, size); 10300a0a85b3SJohn Dyson } 10310a0a85b3SJohn Dyson 10322267af78SJulian Elischer #ifdef VM_STACK 10332267af78SJulian Elischer if (flags & MAP_STACK) 10342267af78SJulian Elischer rv = vm_map_stack (map, *addr, size, prot, 10352267af78SJulian Elischer maxprot, docow); 10362267af78SJulian Elischer else 10372267af78SJulian Elischer #endif 1038bd7e5f99SJohn Dyson rv = vm_map_find(map, object, foff, addr, size, fitit, 1039bd7e5f99SJohn Dyson prot, maxprot, docow); 1040bd7e5f99SJohn Dyson 1041df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 10427fb0c17eSDavid Greenman /* 104324a1cce3SDavid Greenman * Lose the object reference. Will destroy the 104424a1cce3SDavid Greenman * object if it's an unnamed anonymous mapping 104524a1cce3SDavid Greenman * or named anonymous without other references. 10467fb0c17eSDavid Greenman */ 1047df8bae1dSRodney W. Grimes vm_object_deallocate(object); 1048df8bae1dSRodney W. Grimes goto out; 1049df8bae1dSRodney W. Grimes } 1050e17bed12SJohn Dyson 1051df8bae1dSRodney W. Grimes /* 10527fb0c17eSDavid Greenman * "Pre-fault" resident pages. 10537fb0c17eSDavid Greenman */ 10540a0a85b3SJohn Dyson if ((map->pmap != NULL) && (object != NULL)) { 1055a316d390SJohn Dyson pmap_object_init_pt(map->pmap, *addr, 1056867a482dSJohn Dyson object, (vm_pindex_t) OFF_TO_IDX(foff), size, 1); 1057df8bae1dSRodney W. Grimes } 10587fb0c17eSDavid Greenman 1059df8bae1dSRodney W. Grimes /* 1060df8bae1dSRodney W. Grimes * Shared memory is also shared with children. 1061df8bae1dSRodney W. Grimes */ 10625850152dSJohn Dyson if (flags & (MAP_SHARED|MAP_INHERIT)) { 1063df8bae1dSRodney W. Grimes rv = vm_map_inherit(map, *addr, *addr + size, VM_INHERIT_SHARE); 1064df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 10657fb0c17eSDavid Greenman (void) vm_map_remove(map, *addr, *addr + size); 1066df8bae1dSRodney W. Grimes goto out; 1067df8bae1dSRodney W. Grimes } 1068df8bae1dSRodney W. Grimes } 1069df8bae1dSRodney W. Grimes out: 1070df8bae1dSRodney W. Grimes switch (rv) { 1071df8bae1dSRodney W. Grimes case KERN_SUCCESS: 1072df8bae1dSRodney W. Grimes return (0); 1073df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 1074df8bae1dSRodney W. Grimes case KERN_NO_SPACE: 1075df8bae1dSRodney W. Grimes return (ENOMEM); 1076df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 1077df8bae1dSRodney W. Grimes return (EACCES); 1078df8bae1dSRodney W. Grimes default: 1079df8bae1dSRodney W. Grimes return (EINVAL); 1080df8bae1dSRodney W. Grimes } 1081df8bae1dSRodney W. Grimes } 1082