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 41c8bdd56bSGuido van Rooij * $Id: vm_mmap.c,v 1.74 1998/03/07 21:37:01 dyson Exp $ 42df8bae1dSRodney W. Grimes */ 43df8bae1dSRodney W. Grimes 44df8bae1dSRodney W. Grimes /* 45df8bae1dSRodney W. Grimes * Mapped file (mmap) interface to VM 46df8bae1dSRodney W. Grimes */ 47df8bae1dSRodney W. Grimes 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 */ 298c8bdd56bSGuido van Rooij if (((flags & MAP_SHARED) != 0 || 299c8bdd56bSGuido van Rooij (vp->v_type == VCHR && disablexworkaround)) && 300c8bdd56bSGuido van Rooij (fp->f_flag & FWRITE) == 0 && (prot & PROT_WRITE) != 0) 301df8bae1dSRodney W. Grimes return (EACCES); 302c8bdd56bSGuido van Rooij else 303df8bae1dSRodney W. Grimes maxprot |= VM_PROT_WRITE; 304651bb817SAlexander Langer handle = (void *)vp; 305df8bae1dSRodney W. Grimes } 306df8bae1dSRodney W. Grimes } 307df8bae1dSRodney W. Grimes error = vm_mmap(&p->p_vmspace->vm_map, &addr, size, prot, maxprot, 30854f42e4bSPeter Wemm flags, handle, pos); 309df8bae1dSRodney W. Grimes if (error == 0) 310cb226aaaSPoul-Henning Kamp p->p_retval[0] = (int) (addr + pageoff); 311df8bae1dSRodney W. Grimes return (error); 312df8bae1dSRodney W. Grimes } 313df8bae1dSRodney W. Grimes 31405f0fdd2SPoul-Henning Kamp #ifdef COMPAT_43 315d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 31605f0fdd2SPoul-Henning Kamp struct ommap_args { 31705f0fdd2SPoul-Henning Kamp caddr_t addr; 31805f0fdd2SPoul-Henning Kamp int len; 31905f0fdd2SPoul-Henning Kamp int prot; 32005f0fdd2SPoul-Henning Kamp int flags; 32105f0fdd2SPoul-Henning Kamp int fd; 32205f0fdd2SPoul-Henning Kamp long pos; 32305f0fdd2SPoul-Henning Kamp }; 324d2d3e875SBruce Evans #endif 32505f0fdd2SPoul-Henning Kamp int 326cb226aaaSPoul-Henning Kamp ommap(p, uap) 32705f0fdd2SPoul-Henning Kamp struct proc *p; 32805f0fdd2SPoul-Henning Kamp register struct ommap_args *uap; 32905f0fdd2SPoul-Henning Kamp { 33005f0fdd2SPoul-Henning Kamp struct mmap_args nargs; 33105f0fdd2SPoul-Henning Kamp static const char cvtbsdprot[8] = { 33205f0fdd2SPoul-Henning Kamp 0, 33305f0fdd2SPoul-Henning Kamp PROT_EXEC, 33405f0fdd2SPoul-Henning Kamp PROT_WRITE, 33505f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE, 33605f0fdd2SPoul-Henning Kamp PROT_READ, 33705f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_READ, 33805f0fdd2SPoul-Henning Kamp PROT_WRITE | PROT_READ, 33905f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE | PROT_READ, 34005f0fdd2SPoul-Henning Kamp }; 3410d94caffSDavid Greenman 34205f0fdd2SPoul-Henning Kamp #define OMAP_ANON 0x0002 34305f0fdd2SPoul-Henning Kamp #define OMAP_COPY 0x0020 34405f0fdd2SPoul-Henning Kamp #define OMAP_SHARED 0x0010 34505f0fdd2SPoul-Henning Kamp #define OMAP_FIXED 0x0100 34605f0fdd2SPoul-Henning Kamp #define OMAP_INHERIT 0x0800 34705f0fdd2SPoul-Henning Kamp 34805f0fdd2SPoul-Henning Kamp nargs.addr = uap->addr; 34905f0fdd2SPoul-Henning Kamp nargs.len = uap->len; 35005f0fdd2SPoul-Henning Kamp nargs.prot = cvtbsdprot[uap->prot & 0x7]; 35105f0fdd2SPoul-Henning Kamp nargs.flags = 0; 35205f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_ANON) 35305f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_ANON; 35405f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_COPY) 35505f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_COPY; 35605f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_SHARED) 35705f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_SHARED; 35805f0fdd2SPoul-Henning Kamp else 35905f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_PRIVATE; 36005f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_FIXED) 36105f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_FIXED; 36205f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_INHERIT) 36305f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_INHERIT; 36405f0fdd2SPoul-Henning Kamp nargs.fd = uap->fd; 36505f0fdd2SPoul-Henning Kamp nargs.pos = uap->pos; 366cb226aaaSPoul-Henning Kamp return (mmap(p, &nargs)); 36705f0fdd2SPoul-Henning Kamp } 36805f0fdd2SPoul-Henning Kamp #endif /* COMPAT_43 */ 36905f0fdd2SPoul-Henning Kamp 37005f0fdd2SPoul-Henning Kamp 371d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 372df8bae1dSRodney W. Grimes struct msync_args { 373651bb817SAlexander Langer void *addr; 374df8bae1dSRodney W. Grimes int len; 375e6c6af11SDavid Greenman int flags; 376df8bae1dSRodney W. Grimes }; 377d2d3e875SBruce Evans #endif 378df8bae1dSRodney W. Grimes int 379cb226aaaSPoul-Henning Kamp msync(p, uap) 380df8bae1dSRodney W. Grimes struct proc *p; 381df8bae1dSRodney W. Grimes struct msync_args *uap; 382df8bae1dSRodney W. Grimes { 383df8bae1dSRodney W. Grimes vm_offset_t addr; 384dabee6feSPeter Wemm vm_size_t size, pageoff; 385e6c6af11SDavid Greenman int flags; 386df8bae1dSRodney W. Grimes vm_map_t map; 387df8bae1dSRodney W. Grimes int rv; 388df8bae1dSRodney W. Grimes 389df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 3909154ee6aSPeter Wemm size = uap->len; 391e6c6af11SDavid Greenman flags = uap->flags; 392e6c6af11SDavid Greenman 393dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 394dabee6feSPeter Wemm addr -= pageoff; 395dabee6feSPeter Wemm size += pageoff; 396dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 3979154ee6aSPeter Wemm if (addr + size < addr) 398dabee6feSPeter Wemm return(EINVAL); 399dabee6feSPeter Wemm 400dabee6feSPeter Wemm if ((flags & (MS_ASYNC|MS_INVALIDATE)) == (MS_ASYNC|MS_INVALIDATE)) 4011e62bc63SDavid Greenman return (EINVAL); 4021e62bc63SDavid Greenman 4039154ee6aSPeter Wemm map = &p->p_vmspace->vm_map; 4049154ee6aSPeter Wemm 405df8bae1dSRodney W. Grimes /* 406df8bae1dSRodney W. Grimes * XXX Gak! If size is zero we are supposed to sync "all modified 4070d94caffSDavid Greenman * pages with the region containing addr". Unfortunately, we don't 4080d94caffSDavid Greenman * really keep track of individual mmaps so we approximate by flushing 4090d94caffSDavid Greenman * the range of the map entry containing addr. This can be incorrect 4100d94caffSDavid Greenman * if the region splits or is coalesced with a neighbor. 411df8bae1dSRodney W. Grimes */ 412df8bae1dSRodney W. Grimes if (size == 0) { 413df8bae1dSRodney W. Grimes vm_map_entry_t entry; 414df8bae1dSRodney W. Grimes 415df8bae1dSRodney W. Grimes vm_map_lock_read(map); 416df8bae1dSRodney W. Grimes rv = vm_map_lookup_entry(map, addr, &entry); 417df8bae1dSRodney W. Grimes vm_map_unlock_read(map); 418fbcfcdf7SDavid Greenman if (rv == FALSE) 419df8bae1dSRodney W. Grimes return (EINVAL); 420df8bae1dSRodney W. Grimes addr = entry->start; 421df8bae1dSRodney W. Grimes size = entry->end - entry->start; 422df8bae1dSRodney W. Grimes } 423e6c6af11SDavid Greenman 424df8bae1dSRodney W. Grimes /* 425df8bae1dSRodney W. Grimes * Clean the pages and interpret the return value. 426df8bae1dSRodney W. Grimes */ 4276c534ad8SDavid Greenman rv = vm_map_clean(map, addr, addr + size, (flags & MS_ASYNC) == 0, 428e6c6af11SDavid Greenman (flags & MS_INVALIDATE) != 0); 429e6c6af11SDavid Greenman 430df8bae1dSRodney W. Grimes switch (rv) { 431df8bae1dSRodney W. Grimes case KERN_SUCCESS: 432df8bae1dSRodney W. Grimes break; 433df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 434df8bae1dSRodney W. Grimes return (EINVAL); /* Sun returns ENOMEM? */ 435df8bae1dSRodney W. Grimes case KERN_FAILURE: 436df8bae1dSRodney W. Grimes return (EIO); 437df8bae1dSRodney W. Grimes default: 438df8bae1dSRodney W. Grimes return (EINVAL); 439df8bae1dSRodney W. Grimes } 440e6c6af11SDavid Greenman 441df8bae1dSRodney W. Grimes return (0); 442df8bae1dSRodney W. Grimes } 443df8bae1dSRodney W. Grimes 444d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 445df8bae1dSRodney W. Grimes struct munmap_args { 446651bb817SAlexander Langer void *addr; 4479154ee6aSPeter Wemm size_t len; 448df8bae1dSRodney W. Grimes }; 449d2d3e875SBruce Evans #endif 450df8bae1dSRodney W. Grimes int 451cb226aaaSPoul-Henning Kamp munmap(p, uap) 452df8bae1dSRodney W. Grimes register struct proc *p; 453df8bae1dSRodney W. Grimes register struct munmap_args *uap; 454df8bae1dSRodney W. Grimes { 455df8bae1dSRodney W. Grimes vm_offset_t addr; 456dabee6feSPeter Wemm vm_size_t size, pageoff; 457df8bae1dSRodney W. Grimes vm_map_t map; 458df8bae1dSRodney W. Grimes 459df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 4609154ee6aSPeter Wemm size = uap->len; 461dabee6feSPeter Wemm 462dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 463dabee6feSPeter Wemm addr -= pageoff; 464dabee6feSPeter Wemm size += pageoff; 465dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 4669154ee6aSPeter Wemm if (addr + size < addr) 467df8bae1dSRodney W. Grimes return(EINVAL); 4689154ee6aSPeter Wemm 469df8bae1dSRodney W. Grimes if (size == 0) 470df8bae1dSRodney W. Grimes return (0); 471dabee6feSPeter Wemm 472df8bae1dSRodney W. Grimes /* 4730d94caffSDavid Greenman * Check for illegal addresses. Watch out for address wrap... Note 4740d94caffSDavid Greenman * that VM_*_ADDRESS are not constants due to casts (argh). 475df8bae1dSRodney W. Grimes */ 476bbc0ec52SDavid Greenman if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS) 477df8bae1dSRodney W. Grimes return (EINVAL); 47826f9a767SRodney W. Grimes #ifndef i386 479df8bae1dSRodney W. Grimes if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS) 480df8bae1dSRodney W. Grimes return (EINVAL); 48126f9a767SRodney W. Grimes #endif 482df8bae1dSRodney W. Grimes map = &p->p_vmspace->vm_map; 483df8bae1dSRodney W. Grimes /* 484df8bae1dSRodney W. Grimes * Make sure entire range is allocated. 485df8bae1dSRodney W. Grimes */ 486df8bae1dSRodney W. Grimes if (!vm_map_check_protection(map, addr, addr + size, VM_PROT_NONE)) 487df8bae1dSRodney W. Grimes return (EINVAL); 488df8bae1dSRodney W. Grimes /* returns nothing but KERN_SUCCESS anyway */ 489df8bae1dSRodney W. Grimes (void) vm_map_remove(map, addr, addr + size); 490df8bae1dSRodney W. Grimes return (0); 491df8bae1dSRodney W. Grimes } 492df8bae1dSRodney W. Grimes 493df8bae1dSRodney W. Grimes void 49490324b07SDavid Greenman munmapfd(p, fd) 49590324b07SDavid Greenman struct proc *p; 496df8bae1dSRodney W. Grimes int fd; 497df8bae1dSRodney W. Grimes { 498df8bae1dSRodney W. Grimes /* 499c4ed5a07SDavid Greenman * XXX should unmap any regions mapped to this file 500df8bae1dSRodney W. Grimes */ 50190324b07SDavid Greenman p->p_fd->fd_ofileflags[fd] &= ~UF_MAPPED; 502df8bae1dSRodney W. Grimes } 503df8bae1dSRodney W. Grimes 504d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 505df8bae1dSRodney W. Grimes struct mprotect_args { 506651bb817SAlexander Langer const void *addr; 5079154ee6aSPeter Wemm size_t len; 508df8bae1dSRodney W. Grimes int prot; 509df8bae1dSRodney W. Grimes }; 510d2d3e875SBruce Evans #endif 511df8bae1dSRodney W. Grimes int 512cb226aaaSPoul-Henning Kamp mprotect(p, uap) 513df8bae1dSRodney W. Grimes struct proc *p; 514df8bae1dSRodney W. Grimes struct mprotect_args *uap; 515df8bae1dSRodney W. Grimes { 516df8bae1dSRodney W. Grimes vm_offset_t addr; 517dabee6feSPeter Wemm vm_size_t size, pageoff; 518df8bae1dSRodney W. Grimes register vm_prot_t prot; 519df8bae1dSRodney W. Grimes 520df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 5219154ee6aSPeter Wemm size = uap->len; 522df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 523d0aea04fSJohn Dyson #if defined(VM_PROT_READ_IS_EXEC) 524d0aea04fSJohn Dyson if (prot & VM_PROT_READ) 525d0aea04fSJohn Dyson prot |= VM_PROT_EXECUTE; 526d0aea04fSJohn Dyson #endif 527df8bae1dSRodney W. Grimes 528dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 529dabee6feSPeter Wemm addr -= pageoff; 530dabee6feSPeter Wemm size += pageoff; 531dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 5329154ee6aSPeter Wemm if (addr + size < addr) 533dabee6feSPeter Wemm return(EINVAL); 534dabee6feSPeter Wemm 535df8bae1dSRodney W. Grimes switch (vm_map_protect(&p->p_vmspace->vm_map, addr, addr + size, prot, 536df8bae1dSRodney W. Grimes FALSE)) { 537df8bae1dSRodney W. Grimes case KERN_SUCCESS: 538df8bae1dSRodney W. Grimes return (0); 539df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 540df8bae1dSRodney W. Grimes return (EACCES); 541df8bae1dSRodney W. Grimes } 542df8bae1dSRodney W. Grimes return (EINVAL); 543df8bae1dSRodney W. Grimes } 544df8bae1dSRodney W. Grimes 545d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 546dabee6feSPeter Wemm struct minherit_args { 547651bb817SAlexander Langer void *addr; 5489154ee6aSPeter Wemm size_t len; 549dabee6feSPeter Wemm int inherit; 550dabee6feSPeter Wemm }; 551dabee6feSPeter Wemm #endif 552dabee6feSPeter Wemm int 553cb226aaaSPoul-Henning Kamp minherit(p, uap) 554dabee6feSPeter Wemm struct proc *p; 555dabee6feSPeter Wemm struct minherit_args *uap; 556dabee6feSPeter Wemm { 557dabee6feSPeter Wemm vm_offset_t addr; 558dabee6feSPeter Wemm vm_size_t size, pageoff; 559dabee6feSPeter Wemm register vm_inherit_t inherit; 560dabee6feSPeter Wemm 561dabee6feSPeter Wemm addr = (vm_offset_t)uap->addr; 5629154ee6aSPeter Wemm size = uap->len; 563dabee6feSPeter Wemm inherit = uap->inherit; 564dabee6feSPeter Wemm 565dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 566dabee6feSPeter Wemm addr -= pageoff; 567dabee6feSPeter Wemm size += pageoff; 568dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 5699154ee6aSPeter Wemm if (addr + size < addr) 570dabee6feSPeter Wemm return(EINVAL); 571dabee6feSPeter Wemm 572dabee6feSPeter Wemm switch (vm_map_inherit(&p->p_vmspace->vm_map, addr, addr+size, 573dabee6feSPeter Wemm inherit)) { 574dabee6feSPeter Wemm case KERN_SUCCESS: 575dabee6feSPeter Wemm return (0); 576dabee6feSPeter Wemm case KERN_PROTECTION_FAILURE: 577dabee6feSPeter Wemm return (EACCES); 578dabee6feSPeter Wemm } 579dabee6feSPeter Wemm return (EINVAL); 580dabee6feSPeter Wemm } 581dabee6feSPeter Wemm 582dabee6feSPeter Wemm #ifndef _SYS_SYSPROTO_H_ 583df8bae1dSRodney W. Grimes struct madvise_args { 584651bb817SAlexander Langer void *addr; 5859154ee6aSPeter Wemm size_t len; 586df8bae1dSRodney W. Grimes int behav; 587df8bae1dSRodney W. Grimes }; 588d2d3e875SBruce Evans #endif 5890d94caffSDavid Greenman 590df8bae1dSRodney W. Grimes /* ARGSUSED */ 591df8bae1dSRodney W. Grimes int 592cb226aaaSPoul-Henning Kamp madvise(p, uap) 593df8bae1dSRodney W. Grimes struct proc *p; 594df8bae1dSRodney W. Grimes struct madvise_args *uap; 595df8bae1dSRodney W. Grimes { 596867a482dSJohn Dyson vm_map_t map; 597867a482dSJohn Dyson pmap_t pmap; 598f35329acSJohn Dyson vm_offset_t start, end; 599867a482dSJohn Dyson /* 600867a482dSJohn Dyson * Check for illegal addresses. Watch out for address wrap... Note 601867a482dSJohn Dyson * that VM_*_ADDRESS are not constants due to casts (argh). 602867a482dSJohn Dyson */ 603867a482dSJohn Dyson if (VM_MAXUSER_ADDRESS > 0 && 604867a482dSJohn Dyson ((vm_offset_t) uap->addr + uap->len) > VM_MAXUSER_ADDRESS) 605867a482dSJohn Dyson return (EINVAL); 606867a482dSJohn Dyson #ifndef i386 607867a482dSJohn Dyson if (VM_MIN_ADDRESS > 0 && uap->addr < VM_MIN_ADDRESS) 608867a482dSJohn Dyson return (EINVAL); 609867a482dSJohn Dyson #endif 610867a482dSJohn Dyson if (((vm_offset_t) uap->addr + uap->len) < (vm_offset_t) uap->addr) 611867a482dSJohn Dyson return (EINVAL); 612867a482dSJohn Dyson 613867a482dSJohn Dyson /* 614867a482dSJohn Dyson * Since this routine is only advisory, we default to conservative 615867a482dSJohn Dyson * behavior. 616867a482dSJohn Dyson */ 617cd6eea25SDavid Greenman start = trunc_page((vm_offset_t) uap->addr); 618cd6eea25SDavid Greenman end = round_page((vm_offset_t) uap->addr + uap->len); 619867a482dSJohn Dyson 620867a482dSJohn Dyson map = &p->p_vmspace->vm_map; 621867a482dSJohn Dyson pmap = &p->p_vmspace->vm_pmap; 622867a482dSJohn Dyson 623867a482dSJohn Dyson vm_map_madvise(map, pmap, start, end, uap->behav); 624df8bae1dSRodney W. Grimes 625867a482dSJohn Dyson return (0); 626df8bae1dSRodney W. Grimes } 627df8bae1dSRodney W. Grimes 628d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 629df8bae1dSRodney W. Grimes struct mincore_args { 630651bb817SAlexander Langer const void *addr; 6319154ee6aSPeter Wemm size_t len; 632df8bae1dSRodney W. Grimes char *vec; 633df8bae1dSRodney W. Grimes }; 634d2d3e875SBruce Evans #endif 6350d94caffSDavid Greenman 636df8bae1dSRodney W. Grimes /* ARGSUSED */ 637df8bae1dSRodney W. Grimes int 638cb226aaaSPoul-Henning Kamp mincore(p, uap) 639df8bae1dSRodney W. Grimes struct proc *p; 640df8bae1dSRodney W. Grimes struct mincore_args *uap; 641df8bae1dSRodney W. Grimes { 642867a482dSJohn Dyson vm_offset_t addr, first_addr; 643867a482dSJohn Dyson vm_offset_t end, cend; 644867a482dSJohn Dyson pmap_t pmap; 645867a482dSJohn Dyson vm_map_t map; 64602c04a2fSJohn Dyson char *vec; 647867a482dSJohn Dyson int error; 648867a482dSJohn Dyson int vecindex, lastvecindex; 649867a482dSJohn Dyson register vm_map_entry_t current; 650867a482dSJohn Dyson vm_map_entry_t entry; 651867a482dSJohn Dyson int mincoreinfo; 652df8bae1dSRodney W. Grimes 653867a482dSJohn Dyson /* 654867a482dSJohn Dyson * Make sure that the addresses presented are valid for user 655867a482dSJohn Dyson * mode. 656867a482dSJohn Dyson */ 657867a482dSJohn Dyson first_addr = addr = trunc_page((vm_offset_t) uap->addr); 6589154ee6aSPeter Wemm end = addr + (vm_size_t)round_page(uap->len); 65902c04a2fSJohn Dyson if (VM_MAXUSER_ADDRESS > 0 && end > VM_MAXUSER_ADDRESS) 66002c04a2fSJohn Dyson return (EINVAL); 66102c04a2fSJohn Dyson if (end < addr) 66202c04a2fSJohn Dyson return (EINVAL); 66302c04a2fSJohn Dyson 664867a482dSJohn Dyson /* 665867a482dSJohn Dyson * Address of byte vector 666867a482dSJohn Dyson */ 66702c04a2fSJohn Dyson vec = uap->vec; 668867a482dSJohn Dyson 669867a482dSJohn Dyson map = &p->p_vmspace->vm_map; 670867a482dSJohn Dyson pmap = &p->p_vmspace->vm_pmap; 671867a482dSJohn Dyson 672867a482dSJohn Dyson vm_map_lock(map); 673867a482dSJohn Dyson 674867a482dSJohn Dyson if (!vm_map_lookup_entry(map, addr, &entry)) 675867a482dSJohn Dyson entry = entry->next; 676867a482dSJohn Dyson 677867a482dSJohn Dyson /* 678867a482dSJohn Dyson * Do this on a map entry basis so that if the pages are not 679867a482dSJohn Dyson * in the current processes address space, we can easily look 680867a482dSJohn Dyson * up the pages elsewhere. 681867a482dSJohn Dyson */ 682867a482dSJohn Dyson lastvecindex = -1; 683867a482dSJohn Dyson for(current = entry; 684867a482dSJohn Dyson (current != &map->header) && (current->start < end); 685867a482dSJohn Dyson current = current->next) { 686867a482dSJohn Dyson 687867a482dSJohn Dyson /* 688867a482dSJohn Dyson * ignore submaps (for now) or null objects 689867a482dSJohn Dyson */ 690afa07f7eSJohn Dyson if ((current->eflags & (MAP_ENTRY_IS_A_MAP|MAP_ENTRY_IS_SUB_MAP)) || 691867a482dSJohn Dyson current->object.vm_object == NULL) 692867a482dSJohn Dyson continue; 693867a482dSJohn Dyson 694867a482dSJohn Dyson /* 695867a482dSJohn Dyson * limit this scan to the current map entry and the 696867a482dSJohn Dyson * limits for the mincore call 697867a482dSJohn Dyson */ 698867a482dSJohn Dyson if (addr < current->start) 699867a482dSJohn Dyson addr = current->start; 700867a482dSJohn Dyson cend = current->end; 701867a482dSJohn Dyson if (cend > end) 702867a482dSJohn Dyson cend = end; 703867a482dSJohn Dyson 704867a482dSJohn Dyson /* 705867a482dSJohn Dyson * scan this entry one page at a time 706867a482dSJohn Dyson */ 707867a482dSJohn Dyson while(addr < cend) { 708867a482dSJohn Dyson /* 709867a482dSJohn Dyson * Check pmap first, it is likely faster, also 710867a482dSJohn Dyson * it can provide info as to whether we are the 711867a482dSJohn Dyson * one referencing or modifying the page. 712867a482dSJohn Dyson */ 713867a482dSJohn Dyson mincoreinfo = pmap_mincore(pmap, addr); 714867a482dSJohn Dyson if (!mincoreinfo) { 715867a482dSJohn Dyson vm_pindex_t pindex; 716867a482dSJohn Dyson vm_ooffset_t offset; 717867a482dSJohn Dyson vm_page_t m; 718867a482dSJohn Dyson /* 719867a482dSJohn Dyson * calculate the page index into the object 720867a482dSJohn Dyson */ 721867a482dSJohn Dyson offset = current->offset + (addr - current->start); 722867a482dSJohn Dyson pindex = OFF_TO_IDX(offset); 723867a482dSJohn Dyson m = vm_page_lookup(current->object.vm_object, 724867a482dSJohn Dyson pindex); 725867a482dSJohn Dyson /* 726867a482dSJohn Dyson * if the page is resident, then gather information about 727867a482dSJohn Dyson * it. 728867a482dSJohn Dyson */ 729867a482dSJohn Dyson if (m) { 730867a482dSJohn Dyson mincoreinfo = MINCORE_INCORE; 731867a482dSJohn Dyson if (m->dirty || 73267bf6868SJohn Dyson pmap_is_modified(VM_PAGE_TO_PHYS(m))) 733867a482dSJohn Dyson mincoreinfo |= MINCORE_MODIFIED_OTHER; 734867a482dSJohn Dyson if ((m->flags & PG_REFERENCED) || 7359b5a5d81SJohn Dyson pmap_ts_referenced(VM_PAGE_TO_PHYS(m))) { 7369b5a5d81SJohn Dyson m->flags |= PG_REFERENCED; 737867a482dSJohn Dyson mincoreinfo |= MINCORE_REFERENCED_OTHER; 73802c04a2fSJohn Dyson } 739867a482dSJohn Dyson } 7409b5a5d81SJohn Dyson } 741867a482dSJohn Dyson 742867a482dSJohn Dyson /* 743867a482dSJohn Dyson * calculate index into user supplied byte vector 744867a482dSJohn Dyson */ 745867a482dSJohn Dyson vecindex = OFF_TO_IDX(addr - first_addr); 746867a482dSJohn Dyson 747867a482dSJohn Dyson /* 748867a482dSJohn Dyson * If we have skipped map entries, we need to make sure that 749867a482dSJohn Dyson * the byte vector is zeroed for those skipped entries. 750867a482dSJohn Dyson */ 751867a482dSJohn Dyson while((lastvecindex + 1) < vecindex) { 752867a482dSJohn Dyson error = subyte( vec + lastvecindex, 0); 753867a482dSJohn Dyson if (error) { 754867a482dSJohn Dyson vm_map_unlock(map); 755867a482dSJohn Dyson return (EFAULT); 756867a482dSJohn Dyson } 757867a482dSJohn Dyson ++lastvecindex; 758867a482dSJohn Dyson } 759867a482dSJohn Dyson 760867a482dSJohn Dyson /* 761867a482dSJohn Dyson * Pass the page information to the user 762867a482dSJohn Dyson */ 763867a482dSJohn Dyson error = subyte( vec + vecindex, mincoreinfo); 764867a482dSJohn Dyson if (error) { 765867a482dSJohn Dyson vm_map_unlock(map); 766867a482dSJohn Dyson return (EFAULT); 767867a482dSJohn Dyson } 768867a482dSJohn Dyson lastvecindex = vecindex; 76902c04a2fSJohn Dyson addr += PAGE_SIZE; 77002c04a2fSJohn Dyson } 771867a482dSJohn Dyson } 772867a482dSJohn Dyson 773867a482dSJohn Dyson /* 774867a482dSJohn Dyson * Zero the last entries in the byte vector. 775867a482dSJohn Dyson */ 776867a482dSJohn Dyson vecindex = OFF_TO_IDX(end - first_addr); 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 vm_map_unlock(map); 78702c04a2fSJohn Dyson return (0); 788df8bae1dSRodney W. Grimes } 789df8bae1dSRodney W. Grimes 790d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 791df8bae1dSRodney W. Grimes struct mlock_args { 792651bb817SAlexander Langer const void *addr; 793df8bae1dSRodney W. Grimes size_t len; 794df8bae1dSRodney W. Grimes }; 795d2d3e875SBruce Evans #endif 796df8bae1dSRodney W. Grimes int 797cb226aaaSPoul-Henning Kamp mlock(p, uap) 798df8bae1dSRodney W. Grimes struct proc *p; 799df8bae1dSRodney W. Grimes struct mlock_args *uap; 800df8bae1dSRodney W. Grimes { 801df8bae1dSRodney W. Grimes vm_offset_t addr; 802dabee6feSPeter Wemm vm_size_t size, pageoff; 803df8bae1dSRodney W. Grimes int error; 804df8bae1dSRodney W. Grimes 805df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 8069154ee6aSPeter Wemm size = uap->len; 8079154ee6aSPeter Wemm 808dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 809dabee6feSPeter Wemm addr -= pageoff; 810dabee6feSPeter Wemm size += pageoff; 811dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 812dabee6feSPeter Wemm 813dabee6feSPeter Wemm /* disable wrap around */ 8149154ee6aSPeter Wemm if (addr + size < addr) 815df8bae1dSRodney W. Grimes return (EINVAL); 816dabee6feSPeter Wemm 817df8bae1dSRodney W. Grimes if (atop(size) + cnt.v_wire_count > vm_page_max_wired) 818df8bae1dSRodney W. Grimes return (EAGAIN); 8199154ee6aSPeter Wemm 820df8bae1dSRodney W. Grimes #ifdef pmap_wired_count 821df8bae1dSRodney W. Grimes if (size + ptoa(pmap_wired_count(vm_map_pmap(&p->p_vmspace->vm_map))) > 822df8bae1dSRodney W. Grimes p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur) 8234a40e3d4SJohn Dyson return (ENOMEM); 824df8bae1dSRodney W. Grimes #else 82505f0fdd2SPoul-Henning Kamp error = suser(p->p_ucred, &p->p_acflag); 82605f0fdd2SPoul-Henning Kamp if (error) 827df8bae1dSRodney W. Grimes return (error); 828df8bae1dSRodney W. Grimes #endif 829df8bae1dSRodney W. Grimes 8307aaaa4fdSJohn Dyson error = vm_map_user_pageable(&p->p_vmspace->vm_map, addr, addr + size, FALSE); 831df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 832df8bae1dSRodney W. Grimes } 833df8bae1dSRodney W. Grimes 834d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 8354a40e3d4SJohn Dyson struct mlockall_args { 8364a40e3d4SJohn Dyson int how; 8374a40e3d4SJohn Dyson }; 8384a40e3d4SJohn Dyson #endif 8394a40e3d4SJohn Dyson 8404a40e3d4SJohn Dyson int 841cb226aaaSPoul-Henning Kamp mlockall(p, uap) 8424a40e3d4SJohn Dyson struct proc *p; 8434a40e3d4SJohn Dyson struct mlockall_args *uap; 8444a40e3d4SJohn Dyson { 8454a40e3d4SJohn Dyson return 0; 8464a40e3d4SJohn Dyson } 8474a40e3d4SJohn Dyson 8484a40e3d4SJohn Dyson #ifndef _SYS_SYSPROTO_H_ 8494a40e3d4SJohn Dyson struct mlockall_args { 8504a40e3d4SJohn Dyson int how; 8514a40e3d4SJohn Dyson }; 8524a40e3d4SJohn Dyson #endif 8534a40e3d4SJohn Dyson 8544a40e3d4SJohn Dyson int 855cb226aaaSPoul-Henning Kamp munlockall(p, uap) 8564a40e3d4SJohn Dyson struct proc *p; 8574a40e3d4SJohn Dyson struct munlockall_args *uap; 8584a40e3d4SJohn Dyson { 8594a40e3d4SJohn Dyson return 0; 8604a40e3d4SJohn Dyson } 8614a40e3d4SJohn Dyson 8624a40e3d4SJohn Dyson #ifndef _SYS_SYSPROTO_H_ 863df8bae1dSRodney W. Grimes struct munlock_args { 864651bb817SAlexander Langer const void *addr; 865df8bae1dSRodney W. Grimes size_t len; 866df8bae1dSRodney W. Grimes }; 867d2d3e875SBruce Evans #endif 868df8bae1dSRodney W. Grimes int 869cb226aaaSPoul-Henning Kamp munlock(p, uap) 870df8bae1dSRodney W. Grimes struct proc *p; 871df8bae1dSRodney W. Grimes struct munlock_args *uap; 872df8bae1dSRodney W. Grimes { 873df8bae1dSRodney W. Grimes vm_offset_t addr; 874dabee6feSPeter Wemm vm_size_t size, pageoff; 875df8bae1dSRodney W. Grimes int error; 876df8bae1dSRodney W. Grimes 877df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 8789154ee6aSPeter Wemm size = uap->len; 8799154ee6aSPeter Wemm 880dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 881dabee6feSPeter Wemm addr -= pageoff; 882dabee6feSPeter Wemm size += pageoff; 883dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 884dabee6feSPeter Wemm 885dabee6feSPeter Wemm /* disable wrap around */ 8869154ee6aSPeter Wemm if (addr + size < addr) 887df8bae1dSRodney W. Grimes return (EINVAL); 888dabee6feSPeter Wemm 889df8bae1dSRodney W. Grimes #ifndef pmap_wired_count 89005f0fdd2SPoul-Henning Kamp error = suser(p->p_ucred, &p->p_acflag); 89105f0fdd2SPoul-Henning Kamp if (error) 892df8bae1dSRodney W. Grimes return (error); 893df8bae1dSRodney W. Grimes #endif 894df8bae1dSRodney W. Grimes 8957aaaa4fdSJohn Dyson error = vm_map_user_pageable(&p->p_vmspace->vm_map, addr, addr + size, TRUE); 896df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 897df8bae1dSRodney W. Grimes } 898df8bae1dSRodney W. Grimes 899df8bae1dSRodney W. Grimes /* 900df8bae1dSRodney W. Grimes * Internal version of mmap. 901df8bae1dSRodney W. Grimes * Currently used by mmap, exec, and sys5 shared memory. 902df8bae1dSRodney W. Grimes * Handle is either a vnode pointer or NULL for MAP_ANON. 903df8bae1dSRodney W. Grimes */ 904df8bae1dSRodney W. Grimes int 905b9dcd593SBruce Evans vm_mmap(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, 906b9dcd593SBruce Evans vm_prot_t maxprot, int flags, 907651bb817SAlexander Langer void *handle, 908b9dcd593SBruce Evans vm_ooffset_t foff) 909df8bae1dSRodney W. Grimes { 910df8bae1dSRodney W. Grimes boolean_t fitit; 911fcae040bSJohn Dyson vm_object_t object; 912df8bae1dSRodney W. Grimes struct vnode *vp = NULL; 91324a1cce3SDavid Greenman objtype_t type; 914df8bae1dSRodney W. Grimes int rv = KERN_SUCCESS; 915bd7e5f99SJohn Dyson vm_ooffset_t objsize; 916bd7e5f99SJohn Dyson int docow; 91706cb7259SDavid Greenman struct proc *p = curproc; 918df8bae1dSRodney W. Grimes 919df8bae1dSRodney W. Grimes if (size == 0) 920df8bae1dSRodney W. Grimes return (0); 921df8bae1dSRodney W. Grimes 92206cb7259SDavid Greenman objsize = size = round_page(size); 923df8bae1dSRodney W. Grimes 924df8bae1dSRodney W. Grimes /* 925bc9ad247SDavid Greenman * We currently can only deal with page aligned file offsets. 926bc9ad247SDavid Greenman * The check is here rather than in the syscall because the 927bc9ad247SDavid Greenman * kernel calls this function internally for other mmaping 928bc9ad247SDavid Greenman * operations (such as in exec) and non-aligned offsets will 929bc9ad247SDavid Greenman * cause pmap inconsistencies...so we want to be sure to 930bc9ad247SDavid Greenman * disallow this in all cases. 931bc9ad247SDavid Greenman */ 932bc9ad247SDavid Greenman if (foff & PAGE_MASK) 933bc9ad247SDavid Greenman return (EINVAL); 934bc9ad247SDavid Greenman 93506cb7259SDavid Greenman if ((flags & MAP_FIXED) == 0) { 93606cb7259SDavid Greenman fitit = TRUE; 93706cb7259SDavid Greenman *addr = round_page(*addr); 93806cb7259SDavid Greenman } else { 93906cb7259SDavid Greenman if (*addr != trunc_page(*addr)) 94006cb7259SDavid Greenman return (EINVAL); 94106cb7259SDavid Greenman fitit = FALSE; 94206cb7259SDavid Greenman (void) vm_map_remove(map, *addr, *addr + size); 94306cb7259SDavid Greenman } 94406cb7259SDavid Greenman 945bc9ad247SDavid Greenman /* 94624a1cce3SDavid Greenman * Lookup/allocate object. 947df8bae1dSRodney W. Grimes */ 9485f55e841SDavid Greenman if (flags & MAP_ANON) { 949851c12ffSJohn Dyson type = OBJT_DEFAULT; 9505f55e841SDavid Greenman /* 9515f55e841SDavid Greenman * Unnamed anonymous regions always start at 0. 9525f55e841SDavid Greenman */ 95367bf6868SJohn Dyson if (handle == 0) 9545f55e841SDavid Greenman foff = 0; 9555f55e841SDavid Greenman } else { 956df8bae1dSRodney W. Grimes vp = (struct vnode *) handle; 957df8bae1dSRodney W. Grimes if (vp->v_type == VCHR) { 95824a1cce3SDavid Greenman type = OBJT_DEVICE; 959651bb817SAlexander Langer handle = (void *)vp->v_rdev; 96006cb7259SDavid Greenman } else { 96106cb7259SDavid Greenman struct vattr vat; 96206cb7259SDavid Greenman int error; 96306cb7259SDavid Greenman 96406cb7259SDavid Greenman error = VOP_GETATTR(vp, &vat, p->p_ucred, p); 96506cb7259SDavid Greenman if (error) 96606cb7259SDavid Greenman return (error); 967bd7e5f99SJohn Dyson objsize = round_page(vat.va_size); 96824a1cce3SDavid Greenman type = OBJT_VNODE; 969df8bae1dSRodney W. Grimes } 97006cb7259SDavid Greenman } 97194328e90SJohn Dyson 97294328e90SJohn Dyson if (handle == NULL) { 97394328e90SJohn Dyson object = NULL; 97494328e90SJohn Dyson } else { 9750a0a85b3SJohn Dyson object = vm_pager_allocate(type, 9760a0a85b3SJohn Dyson handle, OFF_TO_IDX(objsize), prot, foff); 97724a1cce3SDavid Greenman if (object == NULL) 97824a1cce3SDavid Greenman return (type == OBJT_DEVICE ? EINVAL : ENOMEM); 97994328e90SJohn Dyson } 980df8bae1dSRodney W. Grimes 9815850152dSJohn Dyson /* 9828f2ec877SDavid Greenman * Force device mappings to be shared. 9835850152dSJohn Dyson */ 9848f2ec877SDavid Greenman if (type == OBJT_DEVICE) { 9858f2ec877SDavid Greenman flags &= ~(MAP_PRIVATE|MAP_COPY); 9865850152dSJohn Dyson flags |= MAP_SHARED; 9878f2ec877SDavid Greenman } 9885850152dSJohn Dyson 989bd7e5f99SJohn Dyson docow = 0; 9905850152dSJohn Dyson if ((flags & (MAP_ANON|MAP_SHARED)) == 0) { 991fcae040bSJohn Dyson docow = MAP_COPY_ON_WRITE | MAP_COPY_NEEDED; 992bd7e5f99SJohn Dyson } 9935850152dSJohn Dyson 994d0aea04fSJohn Dyson #if defined(VM_PROT_READ_IS_EXEC) 995d0aea04fSJohn Dyson if (prot & VM_PROT_READ) 996d0aea04fSJohn Dyson prot |= VM_PROT_EXECUTE; 997d0aea04fSJohn Dyson 998d0aea04fSJohn Dyson if (maxprot & VM_PROT_READ) 999d0aea04fSJohn Dyson maxprot |= VM_PROT_EXECUTE; 1000d0aea04fSJohn Dyson #endif 1001d0aea04fSJohn Dyson 10020a0a85b3SJohn Dyson if (fitit) { 10030a0a85b3SJohn Dyson *addr = pmap_addr_hint(object, *addr, size); 10040a0a85b3SJohn Dyson } 10050a0a85b3SJohn Dyson 1006bd7e5f99SJohn Dyson rv = vm_map_find(map, object, foff, addr, size, fitit, 1007bd7e5f99SJohn Dyson prot, maxprot, docow); 1008bd7e5f99SJohn Dyson 1009df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 10107fb0c17eSDavid Greenman /* 101124a1cce3SDavid Greenman * Lose the object reference. Will destroy the 101224a1cce3SDavid Greenman * object if it's an unnamed anonymous mapping 101324a1cce3SDavid Greenman * or named anonymous without other references. 10147fb0c17eSDavid Greenman */ 1015df8bae1dSRodney W. Grimes vm_object_deallocate(object); 1016df8bae1dSRodney W. Grimes goto out; 1017df8bae1dSRodney W. Grimes } 1018e17bed12SJohn Dyson 1019df8bae1dSRodney W. Grimes /* 10207fb0c17eSDavid Greenman * "Pre-fault" resident pages. 10217fb0c17eSDavid Greenman */ 10220a0a85b3SJohn Dyson if ((map->pmap != NULL) && (object != NULL)) { 1023a316d390SJohn Dyson pmap_object_init_pt(map->pmap, *addr, 1024867a482dSJohn Dyson object, (vm_pindex_t) OFF_TO_IDX(foff), size, 1); 1025df8bae1dSRodney W. Grimes } 10267fb0c17eSDavid Greenman 1027df8bae1dSRodney W. Grimes /* 1028df8bae1dSRodney W. Grimes * Shared memory is also shared with children. 1029df8bae1dSRodney W. Grimes */ 10305850152dSJohn Dyson if (flags & (MAP_SHARED|MAP_INHERIT)) { 1031df8bae1dSRodney W. Grimes rv = vm_map_inherit(map, *addr, *addr + size, VM_INHERIT_SHARE); 1032df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 10337fb0c17eSDavid Greenman (void) vm_map_remove(map, *addr, *addr + size); 1034df8bae1dSRodney W. Grimes goto out; 1035df8bae1dSRodney W. Grimes } 1036df8bae1dSRodney W. Grimes } 1037df8bae1dSRodney W. Grimes out: 1038df8bae1dSRodney W. Grimes switch (rv) { 1039df8bae1dSRodney W. Grimes case KERN_SUCCESS: 1040df8bae1dSRodney W. Grimes return (0); 1041df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 1042df8bae1dSRodney W. Grimes case KERN_NO_SPACE: 1043df8bae1dSRodney W. Grimes return (ENOMEM); 1044df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 1045df8bae1dSRodney W. Grimes return (EACCES); 1046df8bae1dSRodney W. Grimes default: 1047df8bae1dSRodney W. Grimes return (EINVAL); 1048df8bae1dSRodney W. Grimes } 1049df8bae1dSRodney W. Grimes } 1050