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 4105feb99fSGuido van Rooij * $Id: vm_mmap.c,v 1.75 1998/03/12 19:36:18 guido 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> 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> 76867a482dSJohn Dyson #include <vm/vm_page.h> 77df8bae1dSRodney W. Grimes 78d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 79df8bae1dSRodney W. Grimes struct sbrk_args { 80df8bae1dSRodney W. Grimes int incr; 81df8bae1dSRodney W. Grimes }; 82d2d3e875SBruce Evans #endif 830d94caffSDavid Greenman 84df8bae1dSRodney W. Grimes /* ARGSUSED */ 85df8bae1dSRodney W. Grimes int 86cb226aaaSPoul-Henning Kamp sbrk(p, uap) 87df8bae1dSRodney W. Grimes struct proc *p; 88df8bae1dSRodney W. Grimes struct sbrk_args *uap; 89df8bae1dSRodney W. Grimes { 90df8bae1dSRodney W. Grimes 91df8bae1dSRodney W. Grimes /* Not yet implemented */ 92df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 93df8bae1dSRodney W. Grimes } 94df8bae1dSRodney W. Grimes 95d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 96df8bae1dSRodney W. Grimes struct sstk_args { 97df8bae1dSRodney W. Grimes int incr; 98df8bae1dSRodney W. Grimes }; 99d2d3e875SBruce Evans #endif 1000d94caffSDavid Greenman 101df8bae1dSRodney W. Grimes /* ARGSUSED */ 102df8bae1dSRodney W. Grimes int 103cb226aaaSPoul-Henning Kamp sstk(p, uap) 104df8bae1dSRodney W. Grimes struct proc *p; 105df8bae1dSRodney W. Grimes struct sstk_args *uap; 106df8bae1dSRodney W. Grimes { 107df8bae1dSRodney W. Grimes 108df8bae1dSRodney W. Grimes /* Not yet implemented */ 109df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 110df8bae1dSRodney W. Grimes } 111df8bae1dSRodney W. Grimes 112df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 113d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 114df8bae1dSRodney W. Grimes struct getpagesize_args { 115df8bae1dSRodney W. Grimes int dummy; 116df8bae1dSRodney W. Grimes }; 117d2d3e875SBruce Evans #endif 1180d94caffSDavid Greenman 119df8bae1dSRodney W. Grimes /* ARGSUSED */ 120df8bae1dSRodney W. Grimes int 121cb226aaaSPoul-Henning Kamp ogetpagesize(p, uap) 122df8bae1dSRodney W. Grimes struct proc *p; 123df8bae1dSRodney W. Grimes struct getpagesize_args *uap; 124df8bae1dSRodney W. Grimes { 125df8bae1dSRodney W. Grimes 126cb226aaaSPoul-Henning Kamp p->p_retval[0] = PAGE_SIZE; 127df8bae1dSRodney W. Grimes return (0); 128df8bae1dSRodney W. Grimes } 129df8bae1dSRodney W. Grimes #endif /* COMPAT_43 || COMPAT_SUNOS */ 130df8bae1dSRodney W. Grimes 13154f42e4bSPeter Wemm 13254f42e4bSPeter Wemm /* 13354f42e4bSPeter Wemm * Memory Map (mmap) system call. Note that the file offset 13454f42e4bSPeter Wemm * and address are allowed to be NOT page aligned, though if 13554f42e4bSPeter Wemm * the MAP_FIXED flag it set, both must have the same remainder 13654f42e4bSPeter Wemm * modulo the PAGE_SIZE (POSIX 1003.1b). If the address is not 13754f42e4bSPeter Wemm * page-aligned, the actual mapping starts at trunc_page(addr) 13854f42e4bSPeter Wemm * and the return value is adjusted up by the page offset. 13954f42e4bSPeter Wemm */ 140d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 141df8bae1dSRodney W. Grimes struct mmap_args { 142651bb817SAlexander Langer void *addr; 143df8bae1dSRodney W. Grimes size_t len; 144df8bae1dSRodney W. Grimes int prot; 145df8bae1dSRodney W. Grimes int flags; 146df8bae1dSRodney W. Grimes int fd; 147df8bae1dSRodney W. Grimes long pad; 148df8bae1dSRodney W. Grimes off_t pos; 149df8bae1dSRodney W. Grimes }; 150d2d3e875SBruce Evans #endif 151df8bae1dSRodney W. Grimes 152df8bae1dSRodney W. Grimes int 153cb226aaaSPoul-Henning Kamp mmap(p, uap) 154df8bae1dSRodney W. Grimes struct proc *p; 155df8bae1dSRodney W. Grimes register struct mmap_args *uap; 156df8bae1dSRodney W. Grimes { 157df8bae1dSRodney W. Grimes register struct filedesc *fdp = p->p_fd; 158df8bae1dSRodney W. Grimes register struct file *fp; 159df8bae1dSRodney W. Grimes struct vnode *vp; 160df8bae1dSRodney W. Grimes vm_offset_t addr; 1619154ee6aSPeter Wemm vm_size_t size, pageoff; 162df8bae1dSRodney W. Grimes vm_prot_t prot, maxprot; 163651bb817SAlexander Langer void *handle; 164df8bae1dSRodney W. Grimes int flags, error; 165c8bdd56bSGuido van Rooij int disablexworkaround; 16654f42e4bSPeter Wemm off_t pos; 167df8bae1dSRodney W. Grimes 16854f42e4bSPeter Wemm addr = (vm_offset_t) uap->addr; 16954f42e4bSPeter Wemm size = uap->len; 170df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 171df8bae1dSRodney W. Grimes flags = uap->flags; 17254f42e4bSPeter Wemm pos = uap->pos; 17354f42e4bSPeter Wemm 17454f42e4bSPeter Wemm /* make sure mapping fits into numeric range etc */ 17554f42e4bSPeter Wemm if ((pos + size > (vm_offset_t)-PAGE_SIZE) || 17654f42e4bSPeter Wemm (ssize_t) uap->len < 0 || 17754f42e4bSPeter Wemm ((flags & MAP_ANON) && uap->fd != -1)) 178df8bae1dSRodney W. Grimes return (EINVAL); 1799154ee6aSPeter Wemm 1809154ee6aSPeter Wemm /* 18154f42e4bSPeter Wemm * Align the file position to a page boundary, 18254f42e4bSPeter Wemm * and save its page offset component. 1839154ee6aSPeter Wemm */ 18454f42e4bSPeter Wemm pageoff = (pos & PAGE_MASK); 18554f42e4bSPeter Wemm pos -= pageoff; 18654f42e4bSPeter Wemm 18754f42e4bSPeter Wemm /* Adjust size for rounding (on both ends). */ 18854f42e4bSPeter Wemm size += pageoff; /* low end... */ 18954f42e4bSPeter Wemm size = (vm_size_t) round_page(size); /* hi end */ 1909154ee6aSPeter Wemm 191df8bae1dSRodney W. Grimes /* 1920d94caffSDavid Greenman * Check for illegal addresses. Watch out for address wrap... Note 1930d94caffSDavid Greenman * that VM_*_ADDRESS are not constants due to casts (argh). 194df8bae1dSRodney W. Grimes */ 195df8bae1dSRodney W. Grimes if (flags & MAP_FIXED) { 19654f42e4bSPeter Wemm /* 19754f42e4bSPeter Wemm * The specified address must have the same remainder 19854f42e4bSPeter Wemm * as the file offset taken modulo PAGE_SIZE, so it 19954f42e4bSPeter Wemm * should be aligned after adjustment by pageoff. 20054f42e4bSPeter Wemm */ 20154f42e4bSPeter Wemm addr -= pageoff; 20254f42e4bSPeter Wemm if (addr & PAGE_MASK) 20354f42e4bSPeter Wemm return (EINVAL); 20454f42e4bSPeter Wemm /* Address range must be all in user VM space. */ 205bbc0ec52SDavid Greenman if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS) 206df8bae1dSRodney W. Grimes return (EINVAL); 20726f9a767SRodney W. Grimes #ifndef i386 208df8bae1dSRodney W. Grimes if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS) 209df8bae1dSRodney W. Grimes return (EINVAL); 21026f9a767SRodney W. Grimes #endif 211bbc0ec52SDavid Greenman if (addr + size < addr) 212df8bae1dSRodney W. Grimes return (EINVAL); 213df8bae1dSRodney W. Grimes } 214df8bae1dSRodney W. Grimes /* 21554f42e4bSPeter Wemm * XXX for non-fixed mappings where no hint is provided or 21654f42e4bSPeter Wemm * the hint would fall in the potential heap space, 21754f42e4bSPeter Wemm * place it after the end of the largest possible heap. 218df8bae1dSRodney W. Grimes * 21954f42e4bSPeter Wemm * There should really be a pmap call to determine a reasonable 22054f42e4bSPeter Wemm * location. 221df8bae1dSRodney W. Grimes */ 22254f42e4bSPeter Wemm else if (addr < round_page(p->p_vmspace->vm_daddr + MAXDSIZ)) 223df8bae1dSRodney W. Grimes addr = round_page(p->p_vmspace->vm_daddr + MAXDSIZ); 22454f42e4bSPeter Wemm 225df8bae1dSRodney W. Grimes if (flags & MAP_ANON) { 226df8bae1dSRodney W. Grimes /* 227df8bae1dSRodney W. Grimes * Mapping blank space is trivial. 228df8bae1dSRodney W. Grimes */ 229df8bae1dSRodney W. Grimes handle = NULL; 230df8bae1dSRodney W. Grimes maxprot = VM_PROT_ALL; 23154f42e4bSPeter Wemm pos = 0; 232df8bae1dSRodney W. Grimes } else { 233df8bae1dSRodney W. Grimes /* 2340d94caffSDavid Greenman * Mapping file, get fp for validation. Obtain vnode and make 2350d94caffSDavid Greenman * sure it is of appropriate type. 236df8bae1dSRodney W. Grimes */ 237df8bae1dSRodney W. Grimes if (((unsigned) uap->fd) >= fdp->fd_nfiles || 238df8bae1dSRodney W. Grimes (fp = fdp->fd_ofiles[uap->fd]) == NULL) 239df8bae1dSRodney W. Grimes return (EBADF); 240df8bae1dSRodney W. Grimes if (fp->f_type != DTYPE_VNODE) 241df8bae1dSRodney W. Grimes return (EINVAL); 242df8bae1dSRodney W. Grimes vp = (struct vnode *) fp->f_data; 243df8bae1dSRodney W. Grimes if (vp->v_type != VREG && vp->v_type != VCHR) 244df8bae1dSRodney W. Grimes return (EINVAL); 245df8bae1dSRodney W. Grimes /* 2460d94caffSDavid Greenman * XXX hack to handle use of /dev/zero to map anon memory (ala 2470d94caffSDavid Greenman * SunOS). 248df8bae1dSRodney W. Grimes */ 249df8bae1dSRodney W. Grimes if (vp->v_type == VCHR && iszerodev(vp->v_rdev)) { 250df8bae1dSRodney W. Grimes handle = NULL; 251df8bae1dSRodney W. Grimes maxprot = VM_PROT_ALL; 252df8bae1dSRodney W. Grimes flags |= MAP_ANON; 25354f42e4bSPeter Wemm pos = 0; 254df8bae1dSRodney W. Grimes } else { 255df8bae1dSRodney W. Grimes /* 256c8bdd56bSGuido van Rooij * cdevs does not provide private mappings of any kind. 257c8bdd56bSGuido van Rooij */ 258c8bdd56bSGuido van Rooij /* 259c8bdd56bSGuido van Rooij * However, for XIG X server to continue to work, 260c8bdd56bSGuido van Rooij * we should allow the superuser to do it anyway. 261c8bdd56bSGuido van Rooij * We only allow it at securelevel < 1. 262c8bdd56bSGuido van Rooij * (Because the XIG X server writes directly to video 263c8bdd56bSGuido van Rooij * memory via /dev/mem, it should never work at any 264c8bdd56bSGuido van Rooij * other securelevel. 265c8bdd56bSGuido van Rooij * XXX this will have to go 266c8bdd56bSGuido van Rooij */ 267c8bdd56bSGuido van Rooij if (securelevel >= 1) 268c8bdd56bSGuido van Rooij disablexworkaround = 1; 269c8bdd56bSGuido van Rooij else 270c8bdd56bSGuido van Rooij disablexworkaround = suser(p->p_ucred, 271c8bdd56bSGuido van Rooij &p->p_acflag); 272c8bdd56bSGuido van Rooij if (vp->v_type == VCHR && disablexworkaround && 273c8bdd56bSGuido van Rooij (flags & (MAP_PRIVATE|MAP_COPY))) 274c8bdd56bSGuido van Rooij return (EINVAL); 275c8bdd56bSGuido van Rooij /* 276df8bae1dSRodney W. Grimes * Ensure that file and memory protections are 277df8bae1dSRodney W. Grimes * compatible. Note that we only worry about 278df8bae1dSRodney W. Grimes * writability if mapping is shared; in this case, 279df8bae1dSRodney W. Grimes * current and max prot are dictated by the open file. 280df8bae1dSRodney W. Grimes * XXX use the vnode instead? Problem is: what 2810d94caffSDavid Greenman * credentials do we use for determination? What if 2820d94caffSDavid Greenman * proc does a setuid? 283df8bae1dSRodney W. Grimes */ 284df8bae1dSRodney W. Grimes maxprot = VM_PROT_EXECUTE; /* ??? */ 285df8bae1dSRodney W. Grimes if (fp->f_flag & FREAD) 286df8bae1dSRodney W. Grimes maxprot |= VM_PROT_READ; 287df8bae1dSRodney W. Grimes else if (prot & PROT_READ) 288df8bae1dSRodney W. Grimes return (EACCES); 289c8bdd56bSGuido van Rooij /* 290c8bdd56bSGuido van Rooij * If we are sharing potential changes (either via 291c8bdd56bSGuido van Rooij * MAP_SHARED or via the implicit sharing of character 292c8bdd56bSGuido van Rooij * device mappings), and we are trying to get write 293c8bdd56bSGuido van Rooij * permission although we opened it without asking 294c8bdd56bSGuido van Rooij * for it, bail out. Check for superuser, only if 295c8bdd56bSGuido van Rooij * we're at securelevel < 1, to allow the XIG X server 296c8bdd56bSGuido van Rooij * to continue to work. 297c8bdd56bSGuido van Rooij */ 29805feb99fSGuido van Rooij 29905feb99fSGuido van Rooij if ((flags & MAP_SHARED) != 0 || 30005feb99fSGuido van Rooij (vp->v_type == VCHR && disablexworkaround)) { 30105feb99fSGuido van Rooij if ((fp->f_flag & FWRITE) != 0) { 30205feb99fSGuido van Rooij if ((error = 30305feb99fSGuido van Rooij VOP_GETATTR(vp, &va, 30405feb99fSGuido van Rooij p->p_ucred, p))) 30505feb99fSGuido van Rooij return (error); 30605feb99fSGuido van Rooij if ((va.va_flags & 30705feb99fSGuido van Rooij (IMMUTABLE|APPEND)) == 0) 308df8bae1dSRodney W. Grimes maxprot |= VM_PROT_WRITE; 30905feb99fSGuido van Rooij else if (prot & PROT_WRITE) 31005feb99fSGuido van Rooij return (EPERM); 31105feb99fSGuido van Rooij } else if ((prot & PROT_WRITE) != 0) 31205feb99fSGuido van Rooij return (EACCES); 31305feb99fSGuido van Rooij } else 31405feb99fSGuido van Rooij maxprot |= VM_PROT_WRITE; 31505feb99fSGuido van Rooij 316651bb817SAlexander Langer handle = (void *)vp; 317df8bae1dSRodney W. Grimes } 318df8bae1dSRodney W. Grimes } 319df8bae1dSRodney W. Grimes error = vm_mmap(&p->p_vmspace->vm_map, &addr, size, prot, maxprot, 32054f42e4bSPeter Wemm flags, handle, pos); 321df8bae1dSRodney W. Grimes if (error == 0) 322cb226aaaSPoul-Henning Kamp p->p_retval[0] = (int) (addr + pageoff); 323df8bae1dSRodney W. Grimes return (error); 324df8bae1dSRodney W. Grimes } 325df8bae1dSRodney W. Grimes 32605f0fdd2SPoul-Henning Kamp #ifdef COMPAT_43 327d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 32805f0fdd2SPoul-Henning Kamp struct ommap_args { 32905f0fdd2SPoul-Henning Kamp caddr_t addr; 33005f0fdd2SPoul-Henning Kamp int len; 33105f0fdd2SPoul-Henning Kamp int prot; 33205f0fdd2SPoul-Henning Kamp int flags; 33305f0fdd2SPoul-Henning Kamp int fd; 33405f0fdd2SPoul-Henning Kamp long pos; 33505f0fdd2SPoul-Henning Kamp }; 336d2d3e875SBruce Evans #endif 33705f0fdd2SPoul-Henning Kamp int 338cb226aaaSPoul-Henning Kamp ommap(p, uap) 33905f0fdd2SPoul-Henning Kamp struct proc *p; 34005f0fdd2SPoul-Henning Kamp register struct ommap_args *uap; 34105f0fdd2SPoul-Henning Kamp { 34205f0fdd2SPoul-Henning Kamp struct mmap_args nargs; 34305f0fdd2SPoul-Henning Kamp static const char cvtbsdprot[8] = { 34405f0fdd2SPoul-Henning Kamp 0, 34505f0fdd2SPoul-Henning Kamp PROT_EXEC, 34605f0fdd2SPoul-Henning Kamp PROT_WRITE, 34705f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE, 34805f0fdd2SPoul-Henning Kamp PROT_READ, 34905f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_READ, 35005f0fdd2SPoul-Henning Kamp PROT_WRITE | PROT_READ, 35105f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE | PROT_READ, 35205f0fdd2SPoul-Henning Kamp }; 3530d94caffSDavid Greenman 35405f0fdd2SPoul-Henning Kamp #define OMAP_ANON 0x0002 35505f0fdd2SPoul-Henning Kamp #define OMAP_COPY 0x0020 35605f0fdd2SPoul-Henning Kamp #define OMAP_SHARED 0x0010 35705f0fdd2SPoul-Henning Kamp #define OMAP_FIXED 0x0100 35805f0fdd2SPoul-Henning Kamp #define OMAP_INHERIT 0x0800 35905f0fdd2SPoul-Henning Kamp 36005f0fdd2SPoul-Henning Kamp nargs.addr = uap->addr; 36105f0fdd2SPoul-Henning Kamp nargs.len = uap->len; 36205f0fdd2SPoul-Henning Kamp nargs.prot = cvtbsdprot[uap->prot & 0x7]; 36305f0fdd2SPoul-Henning Kamp nargs.flags = 0; 36405f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_ANON) 36505f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_ANON; 36605f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_COPY) 36705f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_COPY; 36805f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_SHARED) 36905f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_SHARED; 37005f0fdd2SPoul-Henning Kamp else 37105f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_PRIVATE; 37205f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_FIXED) 37305f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_FIXED; 37405f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_INHERIT) 37505f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_INHERIT; 37605f0fdd2SPoul-Henning Kamp nargs.fd = uap->fd; 37705f0fdd2SPoul-Henning Kamp nargs.pos = uap->pos; 378cb226aaaSPoul-Henning Kamp return (mmap(p, &nargs)); 37905f0fdd2SPoul-Henning Kamp } 38005f0fdd2SPoul-Henning Kamp #endif /* COMPAT_43 */ 38105f0fdd2SPoul-Henning Kamp 38205f0fdd2SPoul-Henning Kamp 383d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 384df8bae1dSRodney W. Grimes struct msync_args { 385651bb817SAlexander Langer void *addr; 386df8bae1dSRodney W. Grimes int len; 387e6c6af11SDavid Greenman int flags; 388df8bae1dSRodney W. Grimes }; 389d2d3e875SBruce Evans #endif 390df8bae1dSRodney W. Grimes int 391cb226aaaSPoul-Henning Kamp msync(p, uap) 392df8bae1dSRodney W. Grimes struct proc *p; 393df8bae1dSRodney W. Grimes struct msync_args *uap; 394df8bae1dSRodney W. Grimes { 395df8bae1dSRodney W. Grimes vm_offset_t addr; 396dabee6feSPeter Wemm vm_size_t size, pageoff; 397e6c6af11SDavid Greenman int flags; 398df8bae1dSRodney W. Grimes vm_map_t map; 399df8bae1dSRodney W. Grimes int rv; 400df8bae1dSRodney W. Grimes 401df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 4029154ee6aSPeter Wemm size = uap->len; 403e6c6af11SDavid Greenman flags = uap->flags; 404e6c6af11SDavid Greenman 405dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 406dabee6feSPeter Wemm addr -= pageoff; 407dabee6feSPeter Wemm size += pageoff; 408dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 4099154ee6aSPeter Wemm if (addr + size < addr) 410dabee6feSPeter Wemm return(EINVAL); 411dabee6feSPeter Wemm 412dabee6feSPeter Wemm if ((flags & (MS_ASYNC|MS_INVALIDATE)) == (MS_ASYNC|MS_INVALIDATE)) 4131e62bc63SDavid Greenman return (EINVAL); 4141e62bc63SDavid Greenman 4159154ee6aSPeter Wemm map = &p->p_vmspace->vm_map; 4169154ee6aSPeter Wemm 417df8bae1dSRodney W. Grimes /* 418df8bae1dSRodney W. Grimes * XXX Gak! If size is zero we are supposed to sync "all modified 4190d94caffSDavid Greenman * pages with the region containing addr". Unfortunately, we don't 4200d94caffSDavid Greenman * really keep track of individual mmaps so we approximate by flushing 4210d94caffSDavid Greenman * the range of the map entry containing addr. This can be incorrect 4220d94caffSDavid Greenman * if the region splits or is coalesced with a neighbor. 423df8bae1dSRodney W. Grimes */ 424df8bae1dSRodney W. Grimes if (size == 0) { 425df8bae1dSRodney W. Grimes vm_map_entry_t entry; 426df8bae1dSRodney W. Grimes 427df8bae1dSRodney W. Grimes vm_map_lock_read(map); 428df8bae1dSRodney W. Grimes rv = vm_map_lookup_entry(map, addr, &entry); 429df8bae1dSRodney W. Grimes vm_map_unlock_read(map); 430fbcfcdf7SDavid Greenman if (rv == FALSE) 431df8bae1dSRodney W. Grimes return (EINVAL); 432df8bae1dSRodney W. Grimes addr = entry->start; 433df8bae1dSRodney W. Grimes size = entry->end - entry->start; 434df8bae1dSRodney W. Grimes } 435e6c6af11SDavid Greenman 436df8bae1dSRodney W. Grimes /* 437df8bae1dSRodney W. Grimes * Clean the pages and interpret the return value. 438df8bae1dSRodney W. Grimes */ 4396c534ad8SDavid Greenman rv = vm_map_clean(map, addr, addr + size, (flags & MS_ASYNC) == 0, 440e6c6af11SDavid Greenman (flags & MS_INVALIDATE) != 0); 441e6c6af11SDavid Greenman 442df8bae1dSRodney W. Grimes switch (rv) { 443df8bae1dSRodney W. Grimes case KERN_SUCCESS: 444df8bae1dSRodney W. Grimes break; 445df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 446df8bae1dSRodney W. Grimes return (EINVAL); /* Sun returns ENOMEM? */ 447df8bae1dSRodney W. Grimes case KERN_FAILURE: 448df8bae1dSRodney W. Grimes return (EIO); 449df8bae1dSRodney W. Grimes default: 450df8bae1dSRodney W. Grimes return (EINVAL); 451df8bae1dSRodney W. Grimes } 452e6c6af11SDavid Greenman 453df8bae1dSRodney W. Grimes return (0); 454df8bae1dSRodney W. Grimes } 455df8bae1dSRodney W. Grimes 456d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 457df8bae1dSRodney W. Grimes struct munmap_args { 458651bb817SAlexander Langer void *addr; 4599154ee6aSPeter Wemm size_t len; 460df8bae1dSRodney W. Grimes }; 461d2d3e875SBruce Evans #endif 462df8bae1dSRodney W. Grimes int 463cb226aaaSPoul-Henning Kamp munmap(p, uap) 464df8bae1dSRodney W. Grimes register struct proc *p; 465df8bae1dSRodney W. Grimes register struct munmap_args *uap; 466df8bae1dSRodney W. Grimes { 467df8bae1dSRodney W. Grimes vm_offset_t addr; 468dabee6feSPeter Wemm vm_size_t size, pageoff; 469df8bae1dSRodney W. Grimes vm_map_t map; 470df8bae1dSRodney W. Grimes 471df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 4729154ee6aSPeter Wemm size = uap->len; 473dabee6feSPeter Wemm 474dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 475dabee6feSPeter Wemm addr -= pageoff; 476dabee6feSPeter Wemm size += pageoff; 477dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 4789154ee6aSPeter Wemm if (addr + size < addr) 479df8bae1dSRodney W. Grimes return(EINVAL); 4809154ee6aSPeter Wemm 481df8bae1dSRodney W. Grimes if (size == 0) 482df8bae1dSRodney W. Grimes return (0); 483dabee6feSPeter Wemm 484df8bae1dSRodney W. Grimes /* 4850d94caffSDavid Greenman * Check for illegal addresses. Watch out for address wrap... Note 4860d94caffSDavid Greenman * that VM_*_ADDRESS are not constants due to casts (argh). 487df8bae1dSRodney W. Grimes */ 488bbc0ec52SDavid Greenman if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS) 489df8bae1dSRodney W. Grimes return (EINVAL); 49026f9a767SRodney W. Grimes #ifndef i386 491df8bae1dSRodney W. Grimes if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS) 492df8bae1dSRodney W. Grimes return (EINVAL); 49326f9a767SRodney W. Grimes #endif 494df8bae1dSRodney W. Grimes map = &p->p_vmspace->vm_map; 495df8bae1dSRodney W. Grimes /* 496df8bae1dSRodney W. Grimes * Make sure entire range is allocated. 497df8bae1dSRodney W. Grimes */ 498df8bae1dSRodney W. Grimes if (!vm_map_check_protection(map, addr, addr + size, VM_PROT_NONE)) 499df8bae1dSRodney W. Grimes return (EINVAL); 500df8bae1dSRodney W. Grimes /* returns nothing but KERN_SUCCESS anyway */ 501df8bae1dSRodney W. Grimes (void) vm_map_remove(map, addr, addr + size); 502df8bae1dSRodney W. Grimes return (0); 503df8bae1dSRodney W. Grimes } 504df8bae1dSRodney W. Grimes 505df8bae1dSRodney W. Grimes void 50690324b07SDavid Greenman munmapfd(p, fd) 50790324b07SDavid Greenman struct proc *p; 508df8bae1dSRodney W. Grimes int fd; 509df8bae1dSRodney W. Grimes { 510df8bae1dSRodney W. Grimes /* 511c4ed5a07SDavid Greenman * XXX should unmap any regions mapped to this file 512df8bae1dSRodney W. Grimes */ 51390324b07SDavid Greenman p->p_fd->fd_ofileflags[fd] &= ~UF_MAPPED; 514df8bae1dSRodney W. Grimes } 515df8bae1dSRodney W. Grimes 516d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 517df8bae1dSRodney W. Grimes struct mprotect_args { 518651bb817SAlexander Langer const void *addr; 5199154ee6aSPeter Wemm size_t len; 520df8bae1dSRodney W. Grimes int prot; 521df8bae1dSRodney W. Grimes }; 522d2d3e875SBruce Evans #endif 523df8bae1dSRodney W. Grimes int 524cb226aaaSPoul-Henning Kamp mprotect(p, uap) 525df8bae1dSRodney W. Grimes struct proc *p; 526df8bae1dSRodney W. Grimes struct mprotect_args *uap; 527df8bae1dSRodney W. Grimes { 528df8bae1dSRodney W. Grimes vm_offset_t addr; 529dabee6feSPeter Wemm vm_size_t size, pageoff; 530df8bae1dSRodney W. Grimes register vm_prot_t prot; 531df8bae1dSRodney W. Grimes 532df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 5339154ee6aSPeter Wemm size = uap->len; 534df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 535d0aea04fSJohn Dyson #if defined(VM_PROT_READ_IS_EXEC) 536d0aea04fSJohn Dyson if (prot & VM_PROT_READ) 537d0aea04fSJohn Dyson prot |= VM_PROT_EXECUTE; 538d0aea04fSJohn Dyson #endif 539df8bae1dSRodney W. Grimes 540dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 541dabee6feSPeter Wemm addr -= pageoff; 542dabee6feSPeter Wemm size += pageoff; 543dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 5449154ee6aSPeter Wemm if (addr + size < addr) 545dabee6feSPeter Wemm return(EINVAL); 546dabee6feSPeter Wemm 547df8bae1dSRodney W. Grimes switch (vm_map_protect(&p->p_vmspace->vm_map, addr, addr + size, prot, 548df8bae1dSRodney W. Grimes FALSE)) { 549df8bae1dSRodney W. Grimes case KERN_SUCCESS: 550df8bae1dSRodney W. Grimes return (0); 551df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 552df8bae1dSRodney W. Grimes return (EACCES); 553df8bae1dSRodney W. Grimes } 554df8bae1dSRodney W. Grimes return (EINVAL); 555df8bae1dSRodney W. Grimes } 556df8bae1dSRodney W. Grimes 557d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 558dabee6feSPeter Wemm struct minherit_args { 559651bb817SAlexander Langer void *addr; 5609154ee6aSPeter Wemm size_t len; 561dabee6feSPeter Wemm int inherit; 562dabee6feSPeter Wemm }; 563dabee6feSPeter Wemm #endif 564dabee6feSPeter Wemm int 565cb226aaaSPoul-Henning Kamp minherit(p, uap) 566dabee6feSPeter Wemm struct proc *p; 567dabee6feSPeter Wemm struct minherit_args *uap; 568dabee6feSPeter Wemm { 569dabee6feSPeter Wemm vm_offset_t addr; 570dabee6feSPeter Wemm vm_size_t size, pageoff; 571dabee6feSPeter Wemm register vm_inherit_t inherit; 572dabee6feSPeter Wemm 573dabee6feSPeter Wemm addr = (vm_offset_t)uap->addr; 5749154ee6aSPeter Wemm size = uap->len; 575dabee6feSPeter Wemm inherit = uap->inherit; 576dabee6feSPeter Wemm 577dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 578dabee6feSPeter Wemm addr -= pageoff; 579dabee6feSPeter Wemm size += pageoff; 580dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 5819154ee6aSPeter Wemm if (addr + size < addr) 582dabee6feSPeter Wemm return(EINVAL); 583dabee6feSPeter Wemm 584dabee6feSPeter Wemm switch (vm_map_inherit(&p->p_vmspace->vm_map, addr, addr+size, 585dabee6feSPeter Wemm inherit)) { 586dabee6feSPeter Wemm case KERN_SUCCESS: 587dabee6feSPeter Wemm return (0); 588dabee6feSPeter Wemm case KERN_PROTECTION_FAILURE: 589dabee6feSPeter Wemm return (EACCES); 590dabee6feSPeter Wemm } 591dabee6feSPeter Wemm return (EINVAL); 592dabee6feSPeter Wemm } 593dabee6feSPeter Wemm 594dabee6feSPeter Wemm #ifndef _SYS_SYSPROTO_H_ 595df8bae1dSRodney W. Grimes struct madvise_args { 596651bb817SAlexander Langer void *addr; 5979154ee6aSPeter Wemm size_t len; 598df8bae1dSRodney W. Grimes int behav; 599df8bae1dSRodney W. Grimes }; 600d2d3e875SBruce Evans #endif 6010d94caffSDavid Greenman 602df8bae1dSRodney W. Grimes /* ARGSUSED */ 603df8bae1dSRodney W. Grimes int 604cb226aaaSPoul-Henning Kamp madvise(p, uap) 605df8bae1dSRodney W. Grimes struct proc *p; 606df8bae1dSRodney W. Grimes struct madvise_args *uap; 607df8bae1dSRodney W. Grimes { 608867a482dSJohn Dyson vm_map_t map; 609867a482dSJohn Dyson pmap_t pmap; 610f35329acSJohn Dyson vm_offset_t start, end; 611867a482dSJohn Dyson /* 612867a482dSJohn Dyson * Check for illegal addresses. Watch out for address wrap... Note 613867a482dSJohn Dyson * that VM_*_ADDRESS are not constants due to casts (argh). 614867a482dSJohn Dyson */ 615867a482dSJohn Dyson if (VM_MAXUSER_ADDRESS > 0 && 616867a482dSJohn Dyson ((vm_offset_t) uap->addr + uap->len) > VM_MAXUSER_ADDRESS) 617867a482dSJohn Dyson return (EINVAL); 618867a482dSJohn Dyson #ifndef i386 619867a482dSJohn Dyson if (VM_MIN_ADDRESS > 0 && uap->addr < VM_MIN_ADDRESS) 620867a482dSJohn Dyson return (EINVAL); 621867a482dSJohn Dyson #endif 622867a482dSJohn Dyson if (((vm_offset_t) uap->addr + uap->len) < (vm_offset_t) uap->addr) 623867a482dSJohn Dyson return (EINVAL); 624867a482dSJohn Dyson 625867a482dSJohn Dyson /* 626867a482dSJohn Dyson * Since this routine is only advisory, we default to conservative 627867a482dSJohn Dyson * behavior. 628867a482dSJohn Dyson */ 629cd6eea25SDavid Greenman start = trunc_page((vm_offset_t) uap->addr); 630cd6eea25SDavid Greenman end = round_page((vm_offset_t) uap->addr + uap->len); 631867a482dSJohn Dyson 632867a482dSJohn Dyson map = &p->p_vmspace->vm_map; 633867a482dSJohn Dyson pmap = &p->p_vmspace->vm_pmap; 634867a482dSJohn Dyson 635867a482dSJohn Dyson vm_map_madvise(map, pmap, start, end, uap->behav); 636df8bae1dSRodney W. Grimes 637867a482dSJohn Dyson return (0); 638df8bae1dSRodney W. Grimes } 639df8bae1dSRodney W. Grimes 640d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 641df8bae1dSRodney W. Grimes struct mincore_args { 642651bb817SAlexander Langer const void *addr; 6439154ee6aSPeter Wemm size_t len; 644df8bae1dSRodney W. Grimes char *vec; 645df8bae1dSRodney W. Grimes }; 646d2d3e875SBruce Evans #endif 6470d94caffSDavid Greenman 648df8bae1dSRodney W. Grimes /* ARGSUSED */ 649df8bae1dSRodney W. Grimes int 650cb226aaaSPoul-Henning Kamp mincore(p, uap) 651df8bae1dSRodney W. Grimes struct proc *p; 652df8bae1dSRodney W. Grimes struct mincore_args *uap; 653df8bae1dSRodney W. Grimes { 654867a482dSJohn Dyson vm_offset_t addr, first_addr; 655867a482dSJohn Dyson vm_offset_t end, cend; 656867a482dSJohn Dyson pmap_t pmap; 657867a482dSJohn Dyson vm_map_t map; 65802c04a2fSJohn Dyson char *vec; 659867a482dSJohn Dyson int error; 660867a482dSJohn Dyson int vecindex, lastvecindex; 661867a482dSJohn Dyson register vm_map_entry_t current; 662867a482dSJohn Dyson vm_map_entry_t entry; 663867a482dSJohn Dyson int mincoreinfo; 664df8bae1dSRodney W. Grimes 665867a482dSJohn Dyson /* 666867a482dSJohn Dyson * Make sure that the addresses presented are valid for user 667867a482dSJohn Dyson * mode. 668867a482dSJohn Dyson */ 669867a482dSJohn Dyson first_addr = addr = trunc_page((vm_offset_t) uap->addr); 6709154ee6aSPeter Wemm end = addr + (vm_size_t)round_page(uap->len); 67102c04a2fSJohn Dyson if (VM_MAXUSER_ADDRESS > 0 && end > VM_MAXUSER_ADDRESS) 67202c04a2fSJohn Dyson return (EINVAL); 67302c04a2fSJohn Dyson if (end < addr) 67402c04a2fSJohn Dyson return (EINVAL); 67502c04a2fSJohn Dyson 676867a482dSJohn Dyson /* 677867a482dSJohn Dyson * Address of byte vector 678867a482dSJohn Dyson */ 67902c04a2fSJohn Dyson vec = uap->vec; 680867a482dSJohn Dyson 681867a482dSJohn Dyson map = &p->p_vmspace->vm_map; 682867a482dSJohn Dyson pmap = &p->p_vmspace->vm_pmap; 683867a482dSJohn Dyson 684867a482dSJohn Dyson vm_map_lock(map); 685867a482dSJohn Dyson 686867a482dSJohn Dyson if (!vm_map_lookup_entry(map, addr, &entry)) 687867a482dSJohn Dyson entry = entry->next; 688867a482dSJohn Dyson 689867a482dSJohn Dyson /* 690867a482dSJohn Dyson * Do this on a map entry basis so that if the pages are not 691867a482dSJohn Dyson * in the current processes address space, we can easily look 692867a482dSJohn Dyson * up the pages elsewhere. 693867a482dSJohn Dyson */ 694867a482dSJohn Dyson lastvecindex = -1; 695867a482dSJohn Dyson for(current = entry; 696867a482dSJohn Dyson (current != &map->header) && (current->start < end); 697867a482dSJohn Dyson current = current->next) { 698867a482dSJohn Dyson 699867a482dSJohn Dyson /* 700867a482dSJohn Dyson * ignore submaps (for now) or null objects 701867a482dSJohn Dyson */ 702afa07f7eSJohn Dyson if ((current->eflags & (MAP_ENTRY_IS_A_MAP|MAP_ENTRY_IS_SUB_MAP)) || 703867a482dSJohn Dyson current->object.vm_object == NULL) 704867a482dSJohn Dyson continue; 705867a482dSJohn Dyson 706867a482dSJohn Dyson /* 707867a482dSJohn Dyson * limit this scan to the current map entry and the 708867a482dSJohn Dyson * limits for the mincore call 709867a482dSJohn Dyson */ 710867a482dSJohn Dyson if (addr < current->start) 711867a482dSJohn Dyson addr = current->start; 712867a482dSJohn Dyson cend = current->end; 713867a482dSJohn Dyson if (cend > end) 714867a482dSJohn Dyson cend = end; 715867a482dSJohn Dyson 716867a482dSJohn Dyson /* 717867a482dSJohn Dyson * scan this entry one page at a time 718867a482dSJohn Dyson */ 719867a482dSJohn Dyson while(addr < cend) { 720867a482dSJohn Dyson /* 721867a482dSJohn Dyson * Check pmap first, it is likely faster, also 722867a482dSJohn Dyson * it can provide info as to whether we are the 723867a482dSJohn Dyson * one referencing or modifying the page. 724867a482dSJohn Dyson */ 725867a482dSJohn Dyson mincoreinfo = pmap_mincore(pmap, addr); 726867a482dSJohn Dyson if (!mincoreinfo) { 727867a482dSJohn Dyson vm_pindex_t pindex; 728867a482dSJohn Dyson vm_ooffset_t offset; 729867a482dSJohn Dyson vm_page_t m; 730867a482dSJohn Dyson /* 731867a482dSJohn Dyson * calculate the page index into the object 732867a482dSJohn Dyson */ 733867a482dSJohn Dyson offset = current->offset + (addr - current->start); 734867a482dSJohn Dyson pindex = OFF_TO_IDX(offset); 735867a482dSJohn Dyson m = vm_page_lookup(current->object.vm_object, 736867a482dSJohn Dyson pindex); 737867a482dSJohn Dyson /* 738867a482dSJohn Dyson * if the page is resident, then gather information about 739867a482dSJohn Dyson * it. 740867a482dSJohn Dyson */ 741867a482dSJohn Dyson if (m) { 742867a482dSJohn Dyson mincoreinfo = MINCORE_INCORE; 743867a482dSJohn Dyson if (m->dirty || 74467bf6868SJohn Dyson pmap_is_modified(VM_PAGE_TO_PHYS(m))) 745867a482dSJohn Dyson mincoreinfo |= MINCORE_MODIFIED_OTHER; 746867a482dSJohn Dyson if ((m->flags & PG_REFERENCED) || 7479b5a5d81SJohn Dyson pmap_ts_referenced(VM_PAGE_TO_PHYS(m))) { 7489b5a5d81SJohn Dyson m->flags |= PG_REFERENCED; 749867a482dSJohn Dyson mincoreinfo |= MINCORE_REFERENCED_OTHER; 75002c04a2fSJohn Dyson } 751867a482dSJohn Dyson } 7529b5a5d81SJohn Dyson } 753867a482dSJohn Dyson 754867a482dSJohn Dyson /* 755867a482dSJohn Dyson * calculate index into user supplied byte vector 756867a482dSJohn Dyson */ 757867a482dSJohn Dyson vecindex = OFF_TO_IDX(addr - first_addr); 758867a482dSJohn Dyson 759867a482dSJohn Dyson /* 760867a482dSJohn Dyson * If we have skipped map entries, we need to make sure that 761867a482dSJohn Dyson * the byte vector is zeroed for those skipped entries. 762867a482dSJohn Dyson */ 763867a482dSJohn Dyson while((lastvecindex + 1) < vecindex) { 764867a482dSJohn Dyson error = subyte( vec + lastvecindex, 0); 765867a482dSJohn Dyson if (error) { 766867a482dSJohn Dyson vm_map_unlock(map); 767867a482dSJohn Dyson return (EFAULT); 768867a482dSJohn Dyson } 769867a482dSJohn Dyson ++lastvecindex; 770867a482dSJohn Dyson } 771867a482dSJohn Dyson 772867a482dSJohn Dyson /* 773867a482dSJohn Dyson * Pass the page information to the user 774867a482dSJohn Dyson */ 775867a482dSJohn Dyson error = subyte( vec + vecindex, mincoreinfo); 776867a482dSJohn Dyson if (error) { 777867a482dSJohn Dyson vm_map_unlock(map); 778867a482dSJohn Dyson return (EFAULT); 779867a482dSJohn Dyson } 780867a482dSJohn Dyson lastvecindex = vecindex; 78102c04a2fSJohn Dyson addr += PAGE_SIZE; 78202c04a2fSJohn Dyson } 783867a482dSJohn Dyson } 784867a482dSJohn Dyson 785867a482dSJohn Dyson /* 786867a482dSJohn Dyson * Zero the last entries in the byte vector. 787867a482dSJohn Dyson */ 788867a482dSJohn Dyson vecindex = OFF_TO_IDX(end - first_addr); 789867a482dSJohn Dyson while((lastvecindex + 1) < vecindex) { 790867a482dSJohn Dyson error = subyte( vec + lastvecindex, 0); 791867a482dSJohn Dyson if (error) { 792867a482dSJohn Dyson vm_map_unlock(map); 793867a482dSJohn Dyson return (EFAULT); 794867a482dSJohn Dyson } 795867a482dSJohn Dyson ++lastvecindex; 796867a482dSJohn Dyson } 797867a482dSJohn Dyson 798867a482dSJohn Dyson vm_map_unlock(map); 79902c04a2fSJohn Dyson return (0); 800df8bae1dSRodney W. Grimes } 801df8bae1dSRodney W. Grimes 802d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 803df8bae1dSRodney W. Grimes struct mlock_args { 804651bb817SAlexander Langer const void *addr; 805df8bae1dSRodney W. Grimes size_t len; 806df8bae1dSRodney W. Grimes }; 807d2d3e875SBruce Evans #endif 808df8bae1dSRodney W. Grimes int 809cb226aaaSPoul-Henning Kamp mlock(p, uap) 810df8bae1dSRodney W. Grimes struct proc *p; 811df8bae1dSRodney W. Grimes struct mlock_args *uap; 812df8bae1dSRodney W. Grimes { 813df8bae1dSRodney W. Grimes vm_offset_t addr; 814dabee6feSPeter Wemm vm_size_t size, pageoff; 815df8bae1dSRodney W. Grimes int error; 816df8bae1dSRodney W. Grimes 817df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 8189154ee6aSPeter Wemm size = uap->len; 8199154ee6aSPeter Wemm 820dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 821dabee6feSPeter Wemm addr -= pageoff; 822dabee6feSPeter Wemm size += pageoff; 823dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 824dabee6feSPeter Wemm 825dabee6feSPeter Wemm /* disable wrap around */ 8269154ee6aSPeter Wemm if (addr + size < addr) 827df8bae1dSRodney W. Grimes return (EINVAL); 828dabee6feSPeter Wemm 829df8bae1dSRodney W. Grimes if (atop(size) + cnt.v_wire_count > vm_page_max_wired) 830df8bae1dSRodney W. Grimes return (EAGAIN); 8319154ee6aSPeter Wemm 832df8bae1dSRodney W. Grimes #ifdef pmap_wired_count 833df8bae1dSRodney W. Grimes if (size + ptoa(pmap_wired_count(vm_map_pmap(&p->p_vmspace->vm_map))) > 834df8bae1dSRodney W. Grimes p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur) 8354a40e3d4SJohn Dyson return (ENOMEM); 836df8bae1dSRodney W. Grimes #else 83705f0fdd2SPoul-Henning Kamp error = suser(p->p_ucred, &p->p_acflag); 83805f0fdd2SPoul-Henning Kamp if (error) 839df8bae1dSRodney W. Grimes return (error); 840df8bae1dSRodney W. Grimes #endif 841df8bae1dSRodney W. Grimes 8427aaaa4fdSJohn Dyson error = vm_map_user_pageable(&p->p_vmspace->vm_map, addr, addr + size, FALSE); 843df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 844df8bae1dSRodney W. Grimes } 845df8bae1dSRodney W. Grimes 846d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 8474a40e3d4SJohn Dyson struct mlockall_args { 8484a40e3d4SJohn Dyson int how; 8494a40e3d4SJohn Dyson }; 8504a40e3d4SJohn Dyson #endif 8514a40e3d4SJohn Dyson 8524a40e3d4SJohn Dyson int 853cb226aaaSPoul-Henning Kamp mlockall(p, uap) 8544a40e3d4SJohn Dyson struct proc *p; 8554a40e3d4SJohn Dyson struct mlockall_args *uap; 8564a40e3d4SJohn Dyson { 8574a40e3d4SJohn Dyson return 0; 8584a40e3d4SJohn Dyson } 8594a40e3d4SJohn Dyson 8604a40e3d4SJohn Dyson #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 munlockall(p, uap) 8684a40e3d4SJohn Dyson struct proc *p; 8694a40e3d4SJohn Dyson struct munlockall_args *uap; 8704a40e3d4SJohn Dyson { 8714a40e3d4SJohn Dyson return 0; 8724a40e3d4SJohn Dyson } 8734a40e3d4SJohn Dyson 8744a40e3d4SJohn Dyson #ifndef _SYS_SYSPROTO_H_ 875df8bae1dSRodney W. Grimes struct munlock_args { 876651bb817SAlexander Langer const void *addr; 877df8bae1dSRodney W. Grimes size_t len; 878df8bae1dSRodney W. Grimes }; 879d2d3e875SBruce Evans #endif 880df8bae1dSRodney W. Grimes int 881cb226aaaSPoul-Henning Kamp munlock(p, uap) 882df8bae1dSRodney W. Grimes struct proc *p; 883df8bae1dSRodney W. Grimes struct munlock_args *uap; 884df8bae1dSRodney W. Grimes { 885df8bae1dSRodney W. Grimes vm_offset_t addr; 886dabee6feSPeter Wemm vm_size_t size, pageoff; 887df8bae1dSRodney W. Grimes int error; 888df8bae1dSRodney W. Grimes 889df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 8909154ee6aSPeter Wemm size = uap->len; 8919154ee6aSPeter Wemm 892dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 893dabee6feSPeter Wemm addr -= pageoff; 894dabee6feSPeter Wemm size += pageoff; 895dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 896dabee6feSPeter Wemm 897dabee6feSPeter Wemm /* disable wrap around */ 8989154ee6aSPeter Wemm if (addr + size < addr) 899df8bae1dSRodney W. Grimes return (EINVAL); 900dabee6feSPeter Wemm 901df8bae1dSRodney W. Grimes #ifndef pmap_wired_count 90205f0fdd2SPoul-Henning Kamp error = suser(p->p_ucred, &p->p_acflag); 90305f0fdd2SPoul-Henning Kamp if (error) 904df8bae1dSRodney W. Grimes return (error); 905df8bae1dSRodney W. Grimes #endif 906df8bae1dSRodney W. Grimes 9077aaaa4fdSJohn Dyson error = vm_map_user_pageable(&p->p_vmspace->vm_map, addr, addr + size, TRUE); 908df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 909df8bae1dSRodney W. Grimes } 910df8bae1dSRodney W. Grimes 911df8bae1dSRodney W. Grimes /* 912df8bae1dSRodney W. Grimes * Internal version of mmap. 913df8bae1dSRodney W. Grimes * Currently used by mmap, exec, and sys5 shared memory. 914df8bae1dSRodney W. Grimes * Handle is either a vnode pointer or NULL for MAP_ANON. 915df8bae1dSRodney W. Grimes */ 916df8bae1dSRodney W. Grimes int 917b9dcd593SBruce Evans vm_mmap(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, 918b9dcd593SBruce Evans vm_prot_t maxprot, int flags, 919651bb817SAlexander Langer void *handle, 920b9dcd593SBruce Evans vm_ooffset_t foff) 921df8bae1dSRodney W. Grimes { 922df8bae1dSRodney W. Grimes boolean_t fitit; 923fcae040bSJohn Dyson vm_object_t object; 924df8bae1dSRodney W. Grimes struct vnode *vp = NULL; 92524a1cce3SDavid Greenman objtype_t type; 926df8bae1dSRodney W. Grimes int rv = KERN_SUCCESS; 927bd7e5f99SJohn Dyson vm_ooffset_t objsize; 928bd7e5f99SJohn Dyson int docow; 92906cb7259SDavid Greenman struct proc *p = curproc; 930df8bae1dSRodney W. Grimes 931df8bae1dSRodney W. Grimes if (size == 0) 932df8bae1dSRodney W. Grimes return (0); 933df8bae1dSRodney W. Grimes 93406cb7259SDavid Greenman objsize = size = round_page(size); 935df8bae1dSRodney W. Grimes 936df8bae1dSRodney W. Grimes /* 937bc9ad247SDavid Greenman * We currently can only deal with page aligned file offsets. 938bc9ad247SDavid Greenman * The check is here rather than in the syscall because the 939bc9ad247SDavid Greenman * kernel calls this function internally for other mmaping 940bc9ad247SDavid Greenman * operations (such as in exec) and non-aligned offsets will 941bc9ad247SDavid Greenman * cause pmap inconsistencies...so we want to be sure to 942bc9ad247SDavid Greenman * disallow this in all cases. 943bc9ad247SDavid Greenman */ 944bc9ad247SDavid Greenman if (foff & PAGE_MASK) 945bc9ad247SDavid Greenman return (EINVAL); 946bc9ad247SDavid Greenman 94706cb7259SDavid Greenman if ((flags & MAP_FIXED) == 0) { 94806cb7259SDavid Greenman fitit = TRUE; 94906cb7259SDavid Greenman *addr = round_page(*addr); 95006cb7259SDavid Greenman } else { 95106cb7259SDavid Greenman if (*addr != trunc_page(*addr)) 95206cb7259SDavid Greenman return (EINVAL); 95306cb7259SDavid Greenman fitit = FALSE; 95406cb7259SDavid Greenman (void) vm_map_remove(map, *addr, *addr + size); 95506cb7259SDavid Greenman } 95606cb7259SDavid Greenman 957bc9ad247SDavid Greenman /* 95824a1cce3SDavid Greenman * Lookup/allocate object. 959df8bae1dSRodney W. Grimes */ 9605f55e841SDavid Greenman if (flags & MAP_ANON) { 961851c12ffSJohn Dyson type = OBJT_DEFAULT; 9625f55e841SDavid Greenman /* 9635f55e841SDavid Greenman * Unnamed anonymous regions always start at 0. 9645f55e841SDavid Greenman */ 96567bf6868SJohn Dyson if (handle == 0) 9665f55e841SDavid Greenman foff = 0; 9675f55e841SDavid Greenman } else { 968df8bae1dSRodney W. Grimes vp = (struct vnode *) handle; 969df8bae1dSRodney W. Grimes if (vp->v_type == VCHR) { 97024a1cce3SDavid Greenman type = OBJT_DEVICE; 971651bb817SAlexander Langer handle = (void *)vp->v_rdev; 97206cb7259SDavid Greenman } else { 97306cb7259SDavid Greenman struct vattr vat; 97406cb7259SDavid Greenman int error; 97506cb7259SDavid Greenman 97606cb7259SDavid Greenman error = VOP_GETATTR(vp, &vat, p->p_ucred, p); 97706cb7259SDavid Greenman if (error) 97806cb7259SDavid Greenman return (error); 979bd7e5f99SJohn Dyson objsize = round_page(vat.va_size); 98024a1cce3SDavid Greenman type = OBJT_VNODE; 981df8bae1dSRodney W. Grimes } 98206cb7259SDavid Greenman } 98394328e90SJohn Dyson 98494328e90SJohn Dyson if (handle == NULL) { 98594328e90SJohn Dyson object = NULL; 98694328e90SJohn Dyson } else { 9870a0a85b3SJohn Dyson object = vm_pager_allocate(type, 9880a0a85b3SJohn Dyson handle, OFF_TO_IDX(objsize), prot, foff); 98924a1cce3SDavid Greenman if (object == NULL) 99024a1cce3SDavid Greenman return (type == OBJT_DEVICE ? EINVAL : ENOMEM); 99194328e90SJohn Dyson } 992df8bae1dSRodney W. Grimes 9935850152dSJohn Dyson /* 9948f2ec877SDavid Greenman * Force device mappings to be shared. 9955850152dSJohn Dyson */ 9968f2ec877SDavid Greenman if (type == OBJT_DEVICE) { 9978f2ec877SDavid Greenman flags &= ~(MAP_PRIVATE|MAP_COPY); 9985850152dSJohn Dyson flags |= MAP_SHARED; 9998f2ec877SDavid Greenman } 10005850152dSJohn Dyson 1001bd7e5f99SJohn Dyson docow = 0; 10025850152dSJohn Dyson if ((flags & (MAP_ANON|MAP_SHARED)) == 0) { 1003fcae040bSJohn Dyson docow = MAP_COPY_ON_WRITE | MAP_COPY_NEEDED; 1004bd7e5f99SJohn Dyson } 10055850152dSJohn Dyson 1006d0aea04fSJohn Dyson #if defined(VM_PROT_READ_IS_EXEC) 1007d0aea04fSJohn Dyson if (prot & VM_PROT_READ) 1008d0aea04fSJohn Dyson prot |= VM_PROT_EXECUTE; 1009d0aea04fSJohn Dyson 1010d0aea04fSJohn Dyson if (maxprot & VM_PROT_READ) 1011d0aea04fSJohn Dyson maxprot |= VM_PROT_EXECUTE; 1012d0aea04fSJohn Dyson #endif 1013d0aea04fSJohn Dyson 10140a0a85b3SJohn Dyson if (fitit) { 10150a0a85b3SJohn Dyson *addr = pmap_addr_hint(object, *addr, size); 10160a0a85b3SJohn Dyson } 10170a0a85b3SJohn Dyson 1018bd7e5f99SJohn Dyson rv = vm_map_find(map, object, foff, addr, size, fitit, 1019bd7e5f99SJohn Dyson prot, maxprot, docow); 1020bd7e5f99SJohn Dyson 1021df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 10227fb0c17eSDavid Greenman /* 102324a1cce3SDavid Greenman * Lose the object reference. Will destroy the 102424a1cce3SDavid Greenman * object if it's an unnamed anonymous mapping 102524a1cce3SDavid Greenman * or named anonymous without other references. 10267fb0c17eSDavid Greenman */ 1027df8bae1dSRodney W. Grimes vm_object_deallocate(object); 1028df8bae1dSRodney W. Grimes goto out; 1029df8bae1dSRodney W. Grimes } 1030e17bed12SJohn Dyson 1031df8bae1dSRodney W. Grimes /* 10327fb0c17eSDavid Greenman * "Pre-fault" resident pages. 10337fb0c17eSDavid Greenman */ 10340a0a85b3SJohn Dyson if ((map->pmap != NULL) && (object != NULL)) { 1035a316d390SJohn Dyson pmap_object_init_pt(map->pmap, *addr, 1036867a482dSJohn Dyson object, (vm_pindex_t) OFF_TO_IDX(foff), size, 1); 1037df8bae1dSRodney W. Grimes } 10387fb0c17eSDavid Greenman 1039df8bae1dSRodney W. Grimes /* 1040df8bae1dSRodney W. Grimes * Shared memory is also shared with children. 1041df8bae1dSRodney W. Grimes */ 10425850152dSJohn Dyson if (flags & (MAP_SHARED|MAP_INHERIT)) { 1043df8bae1dSRodney W. Grimes rv = vm_map_inherit(map, *addr, *addr + size, VM_INHERIT_SHARE); 1044df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 10457fb0c17eSDavid Greenman (void) vm_map_remove(map, *addr, *addr + size); 1046df8bae1dSRodney W. Grimes goto out; 1047df8bae1dSRodney W. Grimes } 1048df8bae1dSRodney W. Grimes } 1049df8bae1dSRodney W. Grimes out: 1050df8bae1dSRodney W. Grimes switch (rv) { 1051df8bae1dSRodney W. Grimes case KERN_SUCCESS: 1052df8bae1dSRodney W. Grimes return (0); 1053df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 1054df8bae1dSRodney W. Grimes case KERN_NO_SPACE: 1055df8bae1dSRodney W. Grimes return (ENOMEM); 1056df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 1057df8bae1dSRodney W. Grimes return (EACCES); 1058df8bae1dSRodney W. Grimes default: 1059df8bae1dSRodney W. Grimes return (EINVAL); 1060df8bae1dSRodney W. Grimes } 1061df8bae1dSRodney W. Grimes } 1062