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 415591b823SEivind Eklund * $Id: vm_mmap.c,v 1.69 1997/11/06 19:29:54 phk Exp $ 42df8bae1dSRodney W. Grimes */ 43df8bae1dSRodney W. Grimes 44df8bae1dSRodney W. Grimes /* 45df8bae1dSRodney W. Grimes * Mapped file (mmap) interface to VM 46df8bae1dSRodney W. Grimes */ 47df8bae1dSRodney W. Grimes 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 { 142df8bae1dSRodney W. Grimes caddr_t 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; 163df8bae1dSRodney W. Grimes caddr_t handle; 164df8bae1dSRodney W. Grimes int flags, error; 16554f42e4bSPeter Wemm off_t pos; 166df8bae1dSRodney W. Grimes 16754f42e4bSPeter Wemm addr = (vm_offset_t) uap->addr; 16854f42e4bSPeter Wemm size = uap->len; 169df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 170df8bae1dSRodney W. Grimes flags = uap->flags; 17154f42e4bSPeter Wemm pos = uap->pos; 17254f42e4bSPeter Wemm 17354f42e4bSPeter Wemm /* make sure mapping fits into numeric range etc */ 17454f42e4bSPeter Wemm if ((pos + size > (vm_offset_t)-PAGE_SIZE) || 17554f42e4bSPeter Wemm (ssize_t) uap->len < 0 || 17654f42e4bSPeter Wemm ((flags & MAP_ANON) && uap->fd != -1)) 177df8bae1dSRodney W. Grimes return (EINVAL); 1789154ee6aSPeter Wemm 1799154ee6aSPeter Wemm /* 18054f42e4bSPeter Wemm * Align the file position to a page boundary, 18154f42e4bSPeter Wemm * and save its page offset component. 1829154ee6aSPeter Wemm */ 18354f42e4bSPeter Wemm pageoff = (pos & PAGE_MASK); 18454f42e4bSPeter Wemm pos -= pageoff; 18554f42e4bSPeter Wemm 18654f42e4bSPeter Wemm /* Adjust size for rounding (on both ends). */ 18754f42e4bSPeter Wemm size += pageoff; /* low end... */ 18854f42e4bSPeter Wemm size = (vm_size_t) round_page(size); /* hi end */ 1899154ee6aSPeter Wemm 190df8bae1dSRodney W. Grimes /* 1910d94caffSDavid Greenman * Check for illegal addresses. Watch out for address wrap... Note 1920d94caffSDavid Greenman * that VM_*_ADDRESS are not constants due to casts (argh). 193df8bae1dSRodney W. Grimes */ 194df8bae1dSRodney W. Grimes if (flags & MAP_FIXED) { 19554f42e4bSPeter Wemm /* 19654f42e4bSPeter Wemm * The specified address must have the same remainder 19754f42e4bSPeter Wemm * as the file offset taken modulo PAGE_SIZE, so it 19854f42e4bSPeter Wemm * should be aligned after adjustment by pageoff. 19954f42e4bSPeter Wemm */ 20054f42e4bSPeter Wemm addr -= pageoff; 20154f42e4bSPeter Wemm if (addr & PAGE_MASK) 20254f42e4bSPeter Wemm return (EINVAL); 20354f42e4bSPeter Wemm /* Address range must be all in user VM space. */ 204bbc0ec52SDavid Greenman if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS) 205df8bae1dSRodney W. Grimes return (EINVAL); 20626f9a767SRodney W. Grimes #ifndef i386 207df8bae1dSRodney W. Grimes if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS) 208df8bae1dSRodney W. Grimes return (EINVAL); 20926f9a767SRodney W. Grimes #endif 210bbc0ec52SDavid Greenman if (addr + size < addr) 211df8bae1dSRodney W. Grimes return (EINVAL); 212df8bae1dSRodney W. Grimes } 213df8bae1dSRodney W. Grimes /* 21454f42e4bSPeter Wemm * XXX for non-fixed mappings where no hint is provided or 21554f42e4bSPeter Wemm * the hint would fall in the potential heap space, 21654f42e4bSPeter Wemm * place it after the end of the largest possible heap. 217df8bae1dSRodney W. Grimes * 21854f42e4bSPeter Wemm * There should really be a pmap call to determine a reasonable 21954f42e4bSPeter Wemm * location. 220df8bae1dSRodney W. Grimes */ 22154f42e4bSPeter Wemm else if (addr < round_page(p->p_vmspace->vm_daddr + MAXDSIZ)) 222df8bae1dSRodney W. Grimes addr = round_page(p->p_vmspace->vm_daddr + MAXDSIZ); 22354f42e4bSPeter Wemm 224df8bae1dSRodney W. Grimes if (flags & MAP_ANON) { 225df8bae1dSRodney W. Grimes /* 226df8bae1dSRodney W. Grimes * Mapping blank space is trivial. 227df8bae1dSRodney W. Grimes */ 228df8bae1dSRodney W. Grimes handle = NULL; 229df8bae1dSRodney W. Grimes maxprot = VM_PROT_ALL; 23054f42e4bSPeter Wemm pos = 0; 231df8bae1dSRodney W. Grimes } else { 232df8bae1dSRodney W. Grimes /* 2330d94caffSDavid Greenman * Mapping file, get fp for validation. Obtain vnode and make 2340d94caffSDavid Greenman * sure it is of appropriate type. 235df8bae1dSRodney W. Grimes */ 236df8bae1dSRodney W. Grimes if (((unsigned) uap->fd) >= fdp->fd_nfiles || 237df8bae1dSRodney W. Grimes (fp = fdp->fd_ofiles[uap->fd]) == NULL) 238df8bae1dSRodney W. Grimes return (EBADF); 239df8bae1dSRodney W. Grimes if (fp->f_type != DTYPE_VNODE) 240df8bae1dSRodney W. Grimes return (EINVAL); 241df8bae1dSRodney W. Grimes vp = (struct vnode *) fp->f_data; 242df8bae1dSRodney W. Grimes if (vp->v_type != VREG && vp->v_type != VCHR) 243df8bae1dSRodney W. Grimes return (EINVAL); 244df8bae1dSRodney W. Grimes /* 2450d94caffSDavid Greenman * XXX hack to handle use of /dev/zero to map anon memory (ala 2460d94caffSDavid Greenman * SunOS). 247df8bae1dSRodney W. Grimes */ 248df8bae1dSRodney W. Grimes if (vp->v_type == VCHR && iszerodev(vp->v_rdev)) { 249df8bae1dSRodney W. Grimes handle = NULL; 250df8bae1dSRodney W. Grimes maxprot = VM_PROT_ALL; 251df8bae1dSRodney W. Grimes flags |= MAP_ANON; 25254f42e4bSPeter Wemm pos = 0; 253df8bae1dSRodney W. Grimes } else { 254df8bae1dSRodney W. Grimes /* 255df8bae1dSRodney W. Grimes * Ensure that file and memory protections are 256df8bae1dSRodney W. Grimes * compatible. Note that we only worry about 257df8bae1dSRodney W. Grimes * writability if mapping is shared; in this case, 258df8bae1dSRodney W. Grimes * current and max prot are dictated by the open file. 259df8bae1dSRodney W. Grimes * XXX use the vnode instead? Problem is: what 2600d94caffSDavid Greenman * credentials do we use for determination? What if 2610d94caffSDavid Greenman * proc does a setuid? 262df8bae1dSRodney W. Grimes */ 263df8bae1dSRodney W. Grimes maxprot = VM_PROT_EXECUTE; /* ??? */ 264df8bae1dSRodney W. Grimes if (fp->f_flag & FREAD) 265df8bae1dSRodney W. Grimes maxprot |= VM_PROT_READ; 266df8bae1dSRodney W. Grimes else if (prot & PROT_READ) 267df8bae1dSRodney W. Grimes return (EACCES); 268df8bae1dSRodney W. Grimes if (flags & MAP_SHARED) { 269df8bae1dSRodney W. Grimes if (fp->f_flag & FWRITE) 270df8bae1dSRodney W. Grimes maxprot |= VM_PROT_WRITE; 271df8bae1dSRodney W. Grimes else if (prot & PROT_WRITE) 272df8bae1dSRodney W. Grimes return (EACCES); 273df8bae1dSRodney W. Grimes } else 274df8bae1dSRodney W. Grimes maxprot |= VM_PROT_WRITE; 275df8bae1dSRodney W. Grimes handle = (caddr_t) vp; 276df8bae1dSRodney W. Grimes } 277df8bae1dSRodney W. Grimes } 278df8bae1dSRodney W. Grimes error = vm_mmap(&p->p_vmspace->vm_map, &addr, size, prot, maxprot, 27954f42e4bSPeter Wemm flags, handle, pos); 280df8bae1dSRodney W. Grimes if (error == 0) 281cb226aaaSPoul-Henning Kamp p->p_retval[0] = (int) (addr + pageoff); 282df8bae1dSRodney W. Grimes return (error); 283df8bae1dSRodney W. Grimes } 284df8bae1dSRodney W. Grimes 28505f0fdd2SPoul-Henning Kamp #ifdef COMPAT_43 286d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 28705f0fdd2SPoul-Henning Kamp struct ommap_args { 28805f0fdd2SPoul-Henning Kamp caddr_t addr; 28905f0fdd2SPoul-Henning Kamp int len; 29005f0fdd2SPoul-Henning Kamp int prot; 29105f0fdd2SPoul-Henning Kamp int flags; 29205f0fdd2SPoul-Henning Kamp int fd; 29305f0fdd2SPoul-Henning Kamp long pos; 29405f0fdd2SPoul-Henning Kamp }; 295d2d3e875SBruce Evans #endif 29605f0fdd2SPoul-Henning Kamp int 297cb226aaaSPoul-Henning Kamp ommap(p, uap) 29805f0fdd2SPoul-Henning Kamp struct proc *p; 29905f0fdd2SPoul-Henning Kamp register struct ommap_args *uap; 30005f0fdd2SPoul-Henning Kamp { 30105f0fdd2SPoul-Henning Kamp struct mmap_args nargs; 30205f0fdd2SPoul-Henning Kamp static const char cvtbsdprot[8] = { 30305f0fdd2SPoul-Henning Kamp 0, 30405f0fdd2SPoul-Henning Kamp PROT_EXEC, 30505f0fdd2SPoul-Henning Kamp PROT_WRITE, 30605f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE, 30705f0fdd2SPoul-Henning Kamp PROT_READ, 30805f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_READ, 30905f0fdd2SPoul-Henning Kamp PROT_WRITE | PROT_READ, 31005f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE | PROT_READ, 31105f0fdd2SPoul-Henning Kamp }; 3120d94caffSDavid Greenman 31305f0fdd2SPoul-Henning Kamp #define OMAP_ANON 0x0002 31405f0fdd2SPoul-Henning Kamp #define OMAP_COPY 0x0020 31505f0fdd2SPoul-Henning Kamp #define OMAP_SHARED 0x0010 31605f0fdd2SPoul-Henning Kamp #define OMAP_FIXED 0x0100 31705f0fdd2SPoul-Henning Kamp #define OMAP_INHERIT 0x0800 31805f0fdd2SPoul-Henning Kamp 31905f0fdd2SPoul-Henning Kamp nargs.addr = uap->addr; 32005f0fdd2SPoul-Henning Kamp nargs.len = uap->len; 32105f0fdd2SPoul-Henning Kamp nargs.prot = cvtbsdprot[uap->prot & 0x7]; 32205f0fdd2SPoul-Henning Kamp nargs.flags = 0; 32305f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_ANON) 32405f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_ANON; 32505f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_COPY) 32605f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_COPY; 32705f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_SHARED) 32805f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_SHARED; 32905f0fdd2SPoul-Henning Kamp else 33005f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_PRIVATE; 33105f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_FIXED) 33205f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_FIXED; 33305f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_INHERIT) 33405f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_INHERIT; 33505f0fdd2SPoul-Henning Kamp nargs.fd = uap->fd; 33605f0fdd2SPoul-Henning Kamp nargs.pos = uap->pos; 337cb226aaaSPoul-Henning Kamp return (mmap(p, &nargs)); 33805f0fdd2SPoul-Henning Kamp } 33905f0fdd2SPoul-Henning Kamp #endif /* COMPAT_43 */ 34005f0fdd2SPoul-Henning Kamp 34105f0fdd2SPoul-Henning Kamp 342d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 343df8bae1dSRodney W. Grimes struct msync_args { 344df8bae1dSRodney W. Grimes caddr_t addr; 345df8bae1dSRodney W. Grimes int len; 346e6c6af11SDavid Greenman int flags; 347df8bae1dSRodney W. Grimes }; 348d2d3e875SBruce Evans #endif 349df8bae1dSRodney W. Grimes int 350cb226aaaSPoul-Henning Kamp msync(p, uap) 351df8bae1dSRodney W. Grimes struct proc *p; 352df8bae1dSRodney W. Grimes struct msync_args *uap; 353df8bae1dSRodney W. Grimes { 354df8bae1dSRodney W. Grimes vm_offset_t addr; 355dabee6feSPeter Wemm vm_size_t size, pageoff; 356e6c6af11SDavid Greenman int flags; 357df8bae1dSRodney W. Grimes vm_map_t map; 358df8bae1dSRodney W. Grimes int rv; 359df8bae1dSRodney W. Grimes 360df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 3619154ee6aSPeter Wemm size = uap->len; 362e6c6af11SDavid Greenman flags = uap->flags; 363e6c6af11SDavid Greenman 364dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 365dabee6feSPeter Wemm addr -= pageoff; 366dabee6feSPeter Wemm size += pageoff; 367dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 3689154ee6aSPeter Wemm if (addr + size < addr) 369dabee6feSPeter Wemm return(EINVAL); 370dabee6feSPeter Wemm 371dabee6feSPeter Wemm if ((flags & (MS_ASYNC|MS_INVALIDATE)) == (MS_ASYNC|MS_INVALIDATE)) 3721e62bc63SDavid Greenman return (EINVAL); 3731e62bc63SDavid Greenman 3749154ee6aSPeter Wemm map = &p->p_vmspace->vm_map; 3759154ee6aSPeter Wemm 376df8bae1dSRodney W. Grimes /* 377df8bae1dSRodney W. Grimes * XXX Gak! If size is zero we are supposed to sync "all modified 3780d94caffSDavid Greenman * pages with the region containing addr". Unfortunately, we don't 3790d94caffSDavid Greenman * really keep track of individual mmaps so we approximate by flushing 3800d94caffSDavid Greenman * the range of the map entry containing addr. This can be incorrect 3810d94caffSDavid Greenman * if the region splits or is coalesced with a neighbor. 382df8bae1dSRodney W. Grimes */ 383df8bae1dSRodney W. Grimes if (size == 0) { 384df8bae1dSRodney W. Grimes vm_map_entry_t entry; 385df8bae1dSRodney W. Grimes 386df8bae1dSRodney W. Grimes vm_map_lock_read(map); 387df8bae1dSRodney W. Grimes rv = vm_map_lookup_entry(map, addr, &entry); 388df8bae1dSRodney W. Grimes vm_map_unlock_read(map); 389fbcfcdf7SDavid Greenman if (rv == FALSE) 390df8bae1dSRodney W. Grimes return (EINVAL); 391df8bae1dSRodney W. Grimes addr = entry->start; 392df8bae1dSRodney W. Grimes size = entry->end - entry->start; 393df8bae1dSRodney W. Grimes } 394e6c6af11SDavid Greenman 395df8bae1dSRodney W. Grimes /* 396df8bae1dSRodney W. Grimes * Clean the pages and interpret the return value. 397df8bae1dSRodney W. Grimes */ 3986c534ad8SDavid Greenman rv = vm_map_clean(map, addr, addr + size, (flags & MS_ASYNC) == 0, 399e6c6af11SDavid Greenman (flags & MS_INVALIDATE) != 0); 400e6c6af11SDavid Greenman 401df8bae1dSRodney W. Grimes switch (rv) { 402df8bae1dSRodney W. Grimes case KERN_SUCCESS: 403df8bae1dSRodney W. Grimes break; 404df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 405df8bae1dSRodney W. Grimes return (EINVAL); /* Sun returns ENOMEM? */ 406df8bae1dSRodney W. Grimes case KERN_FAILURE: 407df8bae1dSRodney W. Grimes return (EIO); 408df8bae1dSRodney W. Grimes default: 409df8bae1dSRodney W. Grimes return (EINVAL); 410df8bae1dSRodney W. Grimes } 411e6c6af11SDavid Greenman 412df8bae1dSRodney W. Grimes return (0); 413df8bae1dSRodney W. Grimes } 414df8bae1dSRodney W. Grimes 415d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 416df8bae1dSRodney W. Grimes struct munmap_args { 417df8bae1dSRodney W. Grimes caddr_t addr; 4189154ee6aSPeter Wemm size_t len; 419df8bae1dSRodney W. Grimes }; 420d2d3e875SBruce Evans #endif 421df8bae1dSRodney W. Grimes int 422cb226aaaSPoul-Henning Kamp munmap(p, uap) 423df8bae1dSRodney W. Grimes register struct proc *p; 424df8bae1dSRodney W. Grimes register struct munmap_args *uap; 425df8bae1dSRodney W. Grimes { 426df8bae1dSRodney W. Grimes vm_offset_t addr; 427dabee6feSPeter Wemm vm_size_t size, pageoff; 428df8bae1dSRodney W. Grimes vm_map_t map; 429df8bae1dSRodney W. Grimes 430df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 4319154ee6aSPeter Wemm size = uap->len; 432dabee6feSPeter Wemm 433dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 434dabee6feSPeter Wemm addr -= pageoff; 435dabee6feSPeter Wemm size += pageoff; 436dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 4379154ee6aSPeter Wemm if (addr + size < addr) 438df8bae1dSRodney W. Grimes return(EINVAL); 4399154ee6aSPeter Wemm 440df8bae1dSRodney W. Grimes if (size == 0) 441df8bae1dSRodney W. Grimes return (0); 442dabee6feSPeter Wemm 443df8bae1dSRodney W. Grimes /* 4440d94caffSDavid Greenman * Check for illegal addresses. Watch out for address wrap... Note 4450d94caffSDavid Greenman * that VM_*_ADDRESS are not constants due to casts (argh). 446df8bae1dSRodney W. Grimes */ 447bbc0ec52SDavid Greenman if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS) 448df8bae1dSRodney W. Grimes return (EINVAL); 44926f9a767SRodney W. Grimes #ifndef i386 450df8bae1dSRodney W. Grimes if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS) 451df8bae1dSRodney W. Grimes return (EINVAL); 45226f9a767SRodney W. Grimes #endif 453df8bae1dSRodney W. Grimes map = &p->p_vmspace->vm_map; 454df8bae1dSRodney W. Grimes /* 455df8bae1dSRodney W. Grimes * Make sure entire range is allocated. 456df8bae1dSRodney W. Grimes */ 457df8bae1dSRodney W. Grimes if (!vm_map_check_protection(map, addr, addr + size, VM_PROT_NONE)) 458df8bae1dSRodney W. Grimes return (EINVAL); 459df8bae1dSRodney W. Grimes /* returns nothing but KERN_SUCCESS anyway */ 460df8bae1dSRodney W. Grimes (void) vm_map_remove(map, addr, addr + size); 461df8bae1dSRodney W. Grimes return (0); 462df8bae1dSRodney W. Grimes } 463df8bae1dSRodney W. Grimes 464df8bae1dSRodney W. Grimes void 46590324b07SDavid Greenman munmapfd(p, fd) 46690324b07SDavid Greenman struct proc *p; 467df8bae1dSRodney W. Grimes int fd; 468df8bae1dSRodney W. Grimes { 469df8bae1dSRodney W. Grimes /* 470c4ed5a07SDavid Greenman * XXX should unmap any regions mapped to this file 471df8bae1dSRodney W. Grimes */ 47290324b07SDavid Greenman p->p_fd->fd_ofileflags[fd] &= ~UF_MAPPED; 473df8bae1dSRodney W. Grimes } 474df8bae1dSRodney W. Grimes 475d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 476df8bae1dSRodney W. Grimes struct mprotect_args { 477df8bae1dSRodney W. Grimes caddr_t addr; 4789154ee6aSPeter Wemm size_t len; 479df8bae1dSRodney W. Grimes int prot; 480df8bae1dSRodney W. Grimes }; 481d2d3e875SBruce Evans #endif 482df8bae1dSRodney W. Grimes int 483cb226aaaSPoul-Henning Kamp mprotect(p, uap) 484df8bae1dSRodney W. Grimes struct proc *p; 485df8bae1dSRodney W. Grimes struct mprotect_args *uap; 486df8bae1dSRodney W. Grimes { 487df8bae1dSRodney W. Grimes vm_offset_t addr; 488dabee6feSPeter Wemm vm_size_t size, pageoff; 489df8bae1dSRodney W. Grimes register vm_prot_t prot; 490df8bae1dSRodney W. Grimes 491df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 4929154ee6aSPeter Wemm size = uap->len; 493df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 494d0aea04fSJohn Dyson #if defined(VM_PROT_READ_IS_EXEC) 495d0aea04fSJohn Dyson if (prot & VM_PROT_READ) 496d0aea04fSJohn Dyson prot |= VM_PROT_EXECUTE; 497d0aea04fSJohn Dyson #endif 498df8bae1dSRodney W. Grimes 499dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 500dabee6feSPeter Wemm addr -= pageoff; 501dabee6feSPeter Wemm size += pageoff; 502dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 5039154ee6aSPeter Wemm if (addr + size < addr) 504dabee6feSPeter Wemm return(EINVAL); 505dabee6feSPeter Wemm 506df8bae1dSRodney W. Grimes switch (vm_map_protect(&p->p_vmspace->vm_map, addr, addr + size, prot, 507df8bae1dSRodney W. Grimes FALSE)) { 508df8bae1dSRodney W. Grimes case KERN_SUCCESS: 509df8bae1dSRodney W. Grimes return (0); 510df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 511df8bae1dSRodney W. Grimes return (EACCES); 512df8bae1dSRodney W. Grimes } 513df8bae1dSRodney W. Grimes return (EINVAL); 514df8bae1dSRodney W. Grimes } 515df8bae1dSRodney W. Grimes 516d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 517dabee6feSPeter Wemm struct minherit_args { 518dabee6feSPeter Wemm caddr_t addr; 5199154ee6aSPeter Wemm size_t len; 520dabee6feSPeter Wemm int inherit; 521dabee6feSPeter Wemm }; 522dabee6feSPeter Wemm #endif 523dabee6feSPeter Wemm int 524cb226aaaSPoul-Henning Kamp minherit(p, uap) 525dabee6feSPeter Wemm struct proc *p; 526dabee6feSPeter Wemm struct minherit_args *uap; 527dabee6feSPeter Wemm { 528dabee6feSPeter Wemm vm_offset_t addr; 529dabee6feSPeter Wemm vm_size_t size, pageoff; 530dabee6feSPeter Wemm register vm_inherit_t inherit; 531dabee6feSPeter Wemm 532dabee6feSPeter Wemm addr = (vm_offset_t)uap->addr; 5339154ee6aSPeter Wemm size = uap->len; 534dabee6feSPeter Wemm inherit = uap->inherit; 535dabee6feSPeter Wemm 536dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 537dabee6feSPeter Wemm addr -= pageoff; 538dabee6feSPeter Wemm size += pageoff; 539dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 5409154ee6aSPeter Wemm if (addr + size < addr) 541dabee6feSPeter Wemm return(EINVAL); 542dabee6feSPeter Wemm 543dabee6feSPeter Wemm switch (vm_map_inherit(&p->p_vmspace->vm_map, addr, addr+size, 544dabee6feSPeter Wemm inherit)) { 545dabee6feSPeter Wemm case KERN_SUCCESS: 546dabee6feSPeter Wemm return (0); 547dabee6feSPeter Wemm case KERN_PROTECTION_FAILURE: 548dabee6feSPeter Wemm return (EACCES); 549dabee6feSPeter Wemm } 550dabee6feSPeter Wemm return (EINVAL); 551dabee6feSPeter Wemm } 552dabee6feSPeter Wemm 553dabee6feSPeter Wemm #ifndef _SYS_SYSPROTO_H_ 554df8bae1dSRodney W. Grimes struct madvise_args { 555df8bae1dSRodney W. Grimes caddr_t addr; 5569154ee6aSPeter Wemm size_t len; 557df8bae1dSRodney W. Grimes int behav; 558df8bae1dSRodney W. Grimes }; 559d2d3e875SBruce Evans #endif 5600d94caffSDavid Greenman 561df8bae1dSRodney W. Grimes /* ARGSUSED */ 562df8bae1dSRodney W. Grimes int 563cb226aaaSPoul-Henning Kamp madvise(p, uap) 564df8bae1dSRodney W. Grimes struct proc *p; 565df8bae1dSRodney W. Grimes struct madvise_args *uap; 566df8bae1dSRodney W. Grimes { 567867a482dSJohn Dyson vm_map_t map; 568867a482dSJohn Dyson pmap_t pmap; 569f35329acSJohn Dyson vm_offset_t start, end; 570867a482dSJohn Dyson /* 571867a482dSJohn Dyson * Check for illegal addresses. Watch out for address wrap... Note 572867a482dSJohn Dyson * that VM_*_ADDRESS are not constants due to casts (argh). 573867a482dSJohn Dyson */ 574867a482dSJohn Dyson if (VM_MAXUSER_ADDRESS > 0 && 575867a482dSJohn Dyson ((vm_offset_t) uap->addr + uap->len) > VM_MAXUSER_ADDRESS) 576867a482dSJohn Dyson return (EINVAL); 577867a482dSJohn Dyson #ifndef i386 578867a482dSJohn Dyson if (VM_MIN_ADDRESS > 0 && uap->addr < VM_MIN_ADDRESS) 579867a482dSJohn Dyson return (EINVAL); 580867a482dSJohn Dyson #endif 581867a482dSJohn Dyson if (((vm_offset_t) uap->addr + uap->len) < (vm_offset_t) uap->addr) 582867a482dSJohn Dyson return (EINVAL); 583867a482dSJohn Dyson 584867a482dSJohn Dyson /* 585867a482dSJohn Dyson * Since this routine is only advisory, we default to conservative 586867a482dSJohn Dyson * behavior. 587867a482dSJohn Dyson */ 588cd6eea25SDavid Greenman start = trunc_page((vm_offset_t) uap->addr); 589cd6eea25SDavid Greenman end = round_page((vm_offset_t) uap->addr + uap->len); 590867a482dSJohn Dyson 591867a482dSJohn Dyson map = &p->p_vmspace->vm_map; 592867a482dSJohn Dyson pmap = &p->p_vmspace->vm_pmap; 593867a482dSJohn Dyson 594867a482dSJohn Dyson vm_map_madvise(map, pmap, start, end, uap->behav); 595df8bae1dSRodney W. Grimes 596867a482dSJohn Dyson return (0); 597df8bae1dSRodney W. Grimes } 598df8bae1dSRodney W. Grimes 599d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 600df8bae1dSRodney W. Grimes struct mincore_args { 601df8bae1dSRodney W. Grimes caddr_t addr; 6029154ee6aSPeter Wemm size_t len; 603df8bae1dSRodney W. Grimes char *vec; 604df8bae1dSRodney W. Grimes }; 605d2d3e875SBruce Evans #endif 6060d94caffSDavid Greenman 607df8bae1dSRodney W. Grimes /* ARGSUSED */ 608df8bae1dSRodney W. Grimes int 609cb226aaaSPoul-Henning Kamp mincore(p, uap) 610df8bae1dSRodney W. Grimes struct proc *p; 611df8bae1dSRodney W. Grimes struct mincore_args *uap; 612df8bae1dSRodney W. Grimes { 613867a482dSJohn Dyson vm_offset_t addr, first_addr; 614867a482dSJohn Dyson vm_offset_t end, cend; 615867a482dSJohn Dyson pmap_t pmap; 616867a482dSJohn Dyson vm_map_t map; 61702c04a2fSJohn Dyson char *vec; 618867a482dSJohn Dyson int error; 619867a482dSJohn Dyson int vecindex, lastvecindex; 620867a482dSJohn Dyson register vm_map_entry_t current; 621867a482dSJohn Dyson vm_map_entry_t entry; 622867a482dSJohn Dyson int mincoreinfo; 623df8bae1dSRodney W. Grimes 624867a482dSJohn Dyson /* 625867a482dSJohn Dyson * Make sure that the addresses presented are valid for user 626867a482dSJohn Dyson * mode. 627867a482dSJohn Dyson */ 628867a482dSJohn Dyson first_addr = addr = trunc_page((vm_offset_t) uap->addr); 6299154ee6aSPeter Wemm end = addr + (vm_size_t)round_page(uap->len); 63002c04a2fSJohn Dyson if (VM_MAXUSER_ADDRESS > 0 && end > VM_MAXUSER_ADDRESS) 63102c04a2fSJohn Dyson return (EINVAL); 63202c04a2fSJohn Dyson if (end < addr) 63302c04a2fSJohn Dyson return (EINVAL); 63402c04a2fSJohn Dyson 635867a482dSJohn Dyson /* 636867a482dSJohn Dyson * Address of byte vector 637867a482dSJohn Dyson */ 63802c04a2fSJohn Dyson vec = uap->vec; 639867a482dSJohn Dyson 640867a482dSJohn Dyson map = &p->p_vmspace->vm_map; 641867a482dSJohn Dyson pmap = &p->p_vmspace->vm_pmap; 642867a482dSJohn Dyson 643867a482dSJohn Dyson vm_map_lock(map); 644867a482dSJohn Dyson 645867a482dSJohn Dyson /* 646867a482dSJohn Dyson * Not needed here 647867a482dSJohn Dyson */ 648867a482dSJohn Dyson #if 0 649867a482dSJohn Dyson VM_MAP_RANGE_CHECK(map, addr, end); 650867a482dSJohn Dyson #endif 651867a482dSJohn Dyson 652867a482dSJohn Dyson if (!vm_map_lookup_entry(map, addr, &entry)) 653867a482dSJohn Dyson entry = entry->next; 654867a482dSJohn Dyson 655867a482dSJohn Dyson /* 656867a482dSJohn Dyson * Do this on a map entry basis so that if the pages are not 657867a482dSJohn Dyson * in the current processes address space, we can easily look 658867a482dSJohn Dyson * up the pages elsewhere. 659867a482dSJohn Dyson */ 660867a482dSJohn Dyson lastvecindex = -1; 661867a482dSJohn Dyson for(current = entry; 662867a482dSJohn Dyson (current != &map->header) && (current->start < end); 663867a482dSJohn Dyson current = current->next) { 664867a482dSJohn Dyson 665867a482dSJohn Dyson /* 666867a482dSJohn Dyson * ignore submaps (for now) or null objects 667867a482dSJohn Dyson */ 668afa07f7eSJohn Dyson if ((current->eflags & (MAP_ENTRY_IS_A_MAP|MAP_ENTRY_IS_SUB_MAP)) || 669867a482dSJohn Dyson current->object.vm_object == NULL) 670867a482dSJohn Dyson continue; 671867a482dSJohn Dyson 672867a482dSJohn Dyson /* 673867a482dSJohn Dyson * limit this scan to the current map entry and the 674867a482dSJohn Dyson * limits for the mincore call 675867a482dSJohn Dyson */ 676867a482dSJohn Dyson if (addr < current->start) 677867a482dSJohn Dyson addr = current->start; 678867a482dSJohn Dyson cend = current->end; 679867a482dSJohn Dyson if (cend > end) 680867a482dSJohn Dyson cend = end; 681867a482dSJohn Dyson 682867a482dSJohn Dyson /* 683867a482dSJohn Dyson * scan this entry one page at a time 684867a482dSJohn Dyson */ 685867a482dSJohn Dyson while(addr < cend) { 686867a482dSJohn Dyson /* 687867a482dSJohn Dyson * Check pmap first, it is likely faster, also 688867a482dSJohn Dyson * it can provide info as to whether we are the 689867a482dSJohn Dyson * one referencing or modifying the page. 690867a482dSJohn Dyson */ 691867a482dSJohn Dyson mincoreinfo = pmap_mincore(pmap, addr); 692867a482dSJohn Dyson if (!mincoreinfo) { 693867a482dSJohn Dyson vm_pindex_t pindex; 694867a482dSJohn Dyson vm_ooffset_t offset; 695867a482dSJohn Dyson vm_page_t m; 696867a482dSJohn Dyson /* 697867a482dSJohn Dyson * calculate the page index into the object 698867a482dSJohn Dyson */ 699867a482dSJohn Dyson offset = current->offset + (addr - current->start); 700867a482dSJohn Dyson pindex = OFF_TO_IDX(offset); 701867a482dSJohn Dyson m = vm_page_lookup(current->object.vm_object, 702867a482dSJohn Dyson pindex); 703867a482dSJohn Dyson /* 704867a482dSJohn Dyson * if the page is resident, then gather information about 705867a482dSJohn Dyson * it. 706867a482dSJohn Dyson */ 707867a482dSJohn Dyson if (m) { 708867a482dSJohn Dyson mincoreinfo = MINCORE_INCORE; 709867a482dSJohn Dyson if (m->dirty || 71067bf6868SJohn Dyson pmap_is_modified(VM_PAGE_TO_PHYS(m))) 711867a482dSJohn Dyson mincoreinfo |= MINCORE_MODIFIED_OTHER; 712867a482dSJohn Dyson if ((m->flags & PG_REFERENCED) || 7139b5a5d81SJohn Dyson pmap_ts_referenced(VM_PAGE_TO_PHYS(m))) { 7149b5a5d81SJohn Dyson m->flags |= PG_REFERENCED; 715867a482dSJohn Dyson mincoreinfo |= MINCORE_REFERENCED_OTHER; 71602c04a2fSJohn Dyson } 717867a482dSJohn Dyson } 7189b5a5d81SJohn Dyson } 719867a482dSJohn Dyson 720867a482dSJohn Dyson /* 721867a482dSJohn Dyson * calculate index into user supplied byte vector 722867a482dSJohn Dyson */ 723867a482dSJohn Dyson vecindex = OFF_TO_IDX(addr - first_addr); 724867a482dSJohn Dyson 725867a482dSJohn Dyson /* 726867a482dSJohn Dyson * If we have skipped map entries, we need to make sure that 727867a482dSJohn Dyson * the byte vector is zeroed for those skipped entries. 728867a482dSJohn Dyson */ 729867a482dSJohn Dyson while((lastvecindex + 1) < vecindex) { 730867a482dSJohn Dyson error = subyte( vec + lastvecindex, 0); 731867a482dSJohn Dyson if (error) { 732867a482dSJohn Dyson vm_map_unlock(map); 733867a482dSJohn Dyson return (EFAULT); 734867a482dSJohn Dyson } 735867a482dSJohn Dyson ++lastvecindex; 736867a482dSJohn Dyson } 737867a482dSJohn Dyson 738867a482dSJohn Dyson /* 739867a482dSJohn Dyson * Pass the page information to the user 740867a482dSJohn Dyson */ 741867a482dSJohn Dyson error = subyte( vec + vecindex, mincoreinfo); 742867a482dSJohn Dyson if (error) { 743867a482dSJohn Dyson vm_map_unlock(map); 744867a482dSJohn Dyson return (EFAULT); 745867a482dSJohn Dyson } 746867a482dSJohn Dyson lastvecindex = vecindex; 74702c04a2fSJohn Dyson addr += PAGE_SIZE; 74802c04a2fSJohn Dyson } 749867a482dSJohn Dyson } 750867a482dSJohn Dyson 751867a482dSJohn Dyson /* 752867a482dSJohn Dyson * Zero the last entries in the byte vector. 753867a482dSJohn Dyson */ 754867a482dSJohn Dyson vecindex = OFF_TO_IDX(end - first_addr); 755867a482dSJohn Dyson while((lastvecindex + 1) < vecindex) { 756867a482dSJohn Dyson error = subyte( vec + lastvecindex, 0); 757867a482dSJohn Dyson if (error) { 758867a482dSJohn Dyson vm_map_unlock(map); 759867a482dSJohn Dyson return (EFAULT); 760867a482dSJohn Dyson } 761867a482dSJohn Dyson ++lastvecindex; 762867a482dSJohn Dyson } 763867a482dSJohn Dyson 764867a482dSJohn Dyson vm_map_unlock(map); 76502c04a2fSJohn Dyson return (0); 766df8bae1dSRodney W. Grimes } 767df8bae1dSRodney W. Grimes 768d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 769df8bae1dSRodney W. Grimes struct mlock_args { 770df8bae1dSRodney W. Grimes caddr_t addr; 771df8bae1dSRodney W. Grimes size_t len; 772df8bae1dSRodney W. Grimes }; 773d2d3e875SBruce Evans #endif 774df8bae1dSRodney W. Grimes int 775cb226aaaSPoul-Henning Kamp mlock(p, uap) 776df8bae1dSRodney W. Grimes struct proc *p; 777df8bae1dSRodney W. Grimes struct mlock_args *uap; 778df8bae1dSRodney W. Grimes { 779df8bae1dSRodney W. Grimes vm_offset_t addr; 780dabee6feSPeter Wemm vm_size_t size, pageoff; 781df8bae1dSRodney W. Grimes int error; 782df8bae1dSRodney W. Grimes 783df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 7849154ee6aSPeter Wemm size = uap->len; 7859154ee6aSPeter Wemm 786dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 787dabee6feSPeter Wemm addr -= pageoff; 788dabee6feSPeter Wemm size += pageoff; 789dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 790dabee6feSPeter Wemm 791dabee6feSPeter Wemm /* disable wrap around */ 7929154ee6aSPeter Wemm if (addr + size < addr) 793df8bae1dSRodney W. Grimes return (EINVAL); 794dabee6feSPeter Wemm 795df8bae1dSRodney W. Grimes if (atop(size) + cnt.v_wire_count > vm_page_max_wired) 796df8bae1dSRodney W. Grimes return (EAGAIN); 7979154ee6aSPeter Wemm 798df8bae1dSRodney W. Grimes #ifdef pmap_wired_count 799df8bae1dSRodney W. Grimes if (size + ptoa(pmap_wired_count(vm_map_pmap(&p->p_vmspace->vm_map))) > 800df8bae1dSRodney W. Grimes p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur) 8014a40e3d4SJohn Dyson return (ENOMEM); 802df8bae1dSRodney W. Grimes #else 80305f0fdd2SPoul-Henning Kamp error = suser(p->p_ucred, &p->p_acflag); 80405f0fdd2SPoul-Henning Kamp if (error) 805df8bae1dSRodney W. Grimes return (error); 806df8bae1dSRodney W. Grimes #endif 807df8bae1dSRodney W. Grimes 8087aaaa4fdSJohn Dyson error = vm_map_user_pageable(&p->p_vmspace->vm_map, addr, addr + size, FALSE); 809df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 810df8bae1dSRodney W. Grimes } 811df8bae1dSRodney W. Grimes 812d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 8134a40e3d4SJohn Dyson struct mlockall_args { 8144a40e3d4SJohn Dyson int how; 8154a40e3d4SJohn Dyson }; 8164a40e3d4SJohn Dyson #endif 8174a40e3d4SJohn Dyson 8184a40e3d4SJohn Dyson int 819cb226aaaSPoul-Henning Kamp mlockall(p, uap) 8204a40e3d4SJohn Dyson struct proc *p; 8214a40e3d4SJohn Dyson struct mlockall_args *uap; 8224a40e3d4SJohn Dyson { 8234a40e3d4SJohn Dyson return 0; 8244a40e3d4SJohn Dyson } 8254a40e3d4SJohn Dyson 8264a40e3d4SJohn Dyson #ifndef _SYS_SYSPROTO_H_ 8274a40e3d4SJohn Dyson struct mlockall_args { 8284a40e3d4SJohn Dyson int how; 8294a40e3d4SJohn Dyson }; 8304a40e3d4SJohn Dyson #endif 8314a40e3d4SJohn Dyson 8324a40e3d4SJohn Dyson int 833cb226aaaSPoul-Henning Kamp munlockall(p, uap) 8344a40e3d4SJohn Dyson struct proc *p; 8354a40e3d4SJohn Dyson struct munlockall_args *uap; 8364a40e3d4SJohn Dyson { 8374a40e3d4SJohn Dyson return 0; 8384a40e3d4SJohn Dyson } 8394a40e3d4SJohn Dyson 8404a40e3d4SJohn Dyson #ifndef _SYS_SYSPROTO_H_ 841df8bae1dSRodney W. Grimes struct munlock_args { 842df8bae1dSRodney W. Grimes caddr_t addr; 843df8bae1dSRodney W. Grimes size_t len; 844df8bae1dSRodney W. Grimes }; 845d2d3e875SBruce Evans #endif 846df8bae1dSRodney W. Grimes int 847cb226aaaSPoul-Henning Kamp munlock(p, uap) 848df8bae1dSRodney W. Grimes struct proc *p; 849df8bae1dSRodney W. Grimes struct munlock_args *uap; 850df8bae1dSRodney W. Grimes { 851df8bae1dSRodney W. Grimes vm_offset_t addr; 852dabee6feSPeter Wemm vm_size_t size, pageoff; 853df8bae1dSRodney W. Grimes int error; 854df8bae1dSRodney W. Grimes 855df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 8569154ee6aSPeter Wemm size = uap->len; 8579154ee6aSPeter Wemm 858dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 859dabee6feSPeter Wemm addr -= pageoff; 860dabee6feSPeter Wemm size += pageoff; 861dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 862dabee6feSPeter Wemm 863dabee6feSPeter Wemm /* disable wrap around */ 8649154ee6aSPeter Wemm if (addr + size < addr) 865df8bae1dSRodney W. Grimes return (EINVAL); 866dabee6feSPeter Wemm 867df8bae1dSRodney W. Grimes #ifndef pmap_wired_count 86805f0fdd2SPoul-Henning Kamp error = suser(p->p_ucred, &p->p_acflag); 86905f0fdd2SPoul-Henning Kamp if (error) 870df8bae1dSRodney W. Grimes return (error); 871df8bae1dSRodney W. Grimes #endif 872df8bae1dSRodney W. Grimes 8737aaaa4fdSJohn Dyson error = vm_map_user_pageable(&p->p_vmspace->vm_map, addr, addr + size, TRUE); 874df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 875df8bae1dSRodney W. Grimes } 876df8bae1dSRodney W. Grimes 877df8bae1dSRodney W. Grimes /* 878df8bae1dSRodney W. Grimes * Internal version of mmap. 879df8bae1dSRodney W. Grimes * Currently used by mmap, exec, and sys5 shared memory. 880df8bae1dSRodney W. Grimes * Handle is either a vnode pointer or NULL for MAP_ANON. 881df8bae1dSRodney W. Grimes */ 882df8bae1dSRodney W. Grimes int 883b9dcd593SBruce Evans vm_mmap(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, 884b9dcd593SBruce Evans vm_prot_t maxprot, int flags, 885b9dcd593SBruce Evans caddr_t handle, /* XXX should be vp */ 886b9dcd593SBruce Evans vm_ooffset_t foff) 887df8bae1dSRodney W. Grimes { 888df8bae1dSRodney W. Grimes boolean_t fitit; 889fcae040bSJohn Dyson vm_object_t object; 890df8bae1dSRodney W. Grimes struct vnode *vp = NULL; 89124a1cce3SDavid Greenman objtype_t type; 892df8bae1dSRodney W. Grimes int rv = KERN_SUCCESS; 893bd7e5f99SJohn Dyson vm_ooffset_t objsize; 894bd7e5f99SJohn Dyson int docow; 89506cb7259SDavid Greenman struct proc *p = curproc; 896df8bae1dSRodney W. Grimes 897df8bae1dSRodney W. Grimes if (size == 0) 898df8bae1dSRodney W. Grimes return (0); 899df8bae1dSRodney W. Grimes 90006cb7259SDavid Greenman objsize = size = round_page(size); 901df8bae1dSRodney W. Grimes 902df8bae1dSRodney W. Grimes /* 903bc9ad247SDavid Greenman * We currently can only deal with page aligned file offsets. 904bc9ad247SDavid Greenman * The check is here rather than in the syscall because the 905bc9ad247SDavid Greenman * kernel calls this function internally for other mmaping 906bc9ad247SDavid Greenman * operations (such as in exec) and non-aligned offsets will 907bc9ad247SDavid Greenman * cause pmap inconsistencies...so we want to be sure to 908bc9ad247SDavid Greenman * disallow this in all cases. 909bc9ad247SDavid Greenman */ 910bc9ad247SDavid Greenman if (foff & PAGE_MASK) 911bc9ad247SDavid Greenman return (EINVAL); 912bc9ad247SDavid Greenman 91306cb7259SDavid Greenman if ((flags & MAP_FIXED) == 0) { 91406cb7259SDavid Greenman fitit = TRUE; 91506cb7259SDavid Greenman *addr = round_page(*addr); 91606cb7259SDavid Greenman } else { 91706cb7259SDavid Greenman if (*addr != trunc_page(*addr)) 91806cb7259SDavid Greenman return (EINVAL); 91906cb7259SDavid Greenman fitit = FALSE; 92006cb7259SDavid Greenman (void) vm_map_remove(map, *addr, *addr + size); 92106cb7259SDavid Greenman } 92206cb7259SDavid Greenman 923bc9ad247SDavid Greenman /* 92424a1cce3SDavid Greenman * Lookup/allocate object. 925df8bae1dSRodney W. Grimes */ 9265f55e841SDavid Greenman if (flags & MAP_ANON) { 927851c12ffSJohn Dyson type = OBJT_DEFAULT; 9285f55e841SDavid Greenman /* 9295f55e841SDavid Greenman * Unnamed anonymous regions always start at 0. 9305f55e841SDavid Greenman */ 93167bf6868SJohn Dyson if (handle == 0) 9325f55e841SDavid Greenman foff = 0; 9335f55e841SDavid Greenman } else { 934df8bae1dSRodney W. Grimes vp = (struct vnode *) handle; 935df8bae1dSRodney W. Grimes if (vp->v_type == VCHR) { 93624a1cce3SDavid Greenman type = OBJT_DEVICE; 937df8bae1dSRodney W. Grimes handle = (caddr_t) vp->v_rdev; 93806cb7259SDavid Greenman } else { 93906cb7259SDavid Greenman struct vattr vat; 94006cb7259SDavid Greenman int error; 94106cb7259SDavid Greenman 94206cb7259SDavid Greenman error = VOP_GETATTR(vp, &vat, p->p_ucred, p); 94306cb7259SDavid Greenman if (error) 94406cb7259SDavid Greenman return (error); 945bd7e5f99SJohn Dyson objsize = round_page(vat.va_size); 94624a1cce3SDavid Greenman type = OBJT_VNODE; 947df8bae1dSRodney W. Grimes } 94806cb7259SDavid Greenman } 94994328e90SJohn Dyson 95094328e90SJohn Dyson if (handle == NULL) { 95194328e90SJohn Dyson object = NULL; 95294328e90SJohn Dyson } else { 9530a0a85b3SJohn Dyson object = vm_pager_allocate(type, 9540a0a85b3SJohn Dyson handle, OFF_TO_IDX(objsize), prot, foff); 95524a1cce3SDavid Greenman if (object == NULL) 95624a1cce3SDavid Greenman return (type == OBJT_DEVICE ? EINVAL : ENOMEM); 95794328e90SJohn Dyson } 958df8bae1dSRodney W. Grimes 9595850152dSJohn Dyson /* 9608f2ec877SDavid Greenman * Force device mappings to be shared. 9615850152dSJohn Dyson */ 9628f2ec877SDavid Greenman if (type == OBJT_DEVICE) { 9638f2ec877SDavid Greenman flags &= ~(MAP_PRIVATE|MAP_COPY); 9645850152dSJohn Dyson flags |= MAP_SHARED; 9658f2ec877SDavid Greenman } 9665850152dSJohn Dyson 967bd7e5f99SJohn Dyson docow = 0; 9685850152dSJohn Dyson if ((flags & (MAP_ANON|MAP_SHARED)) == 0) { 969fcae040bSJohn Dyson docow = MAP_COPY_ON_WRITE | MAP_COPY_NEEDED; 970bd7e5f99SJohn Dyson } 9715850152dSJohn Dyson 972d0aea04fSJohn Dyson #if defined(VM_PROT_READ_IS_EXEC) 973d0aea04fSJohn Dyson if (prot & VM_PROT_READ) 974d0aea04fSJohn Dyson prot |= VM_PROT_EXECUTE; 975d0aea04fSJohn Dyson 976d0aea04fSJohn Dyson if (maxprot & VM_PROT_READ) 977d0aea04fSJohn Dyson maxprot |= VM_PROT_EXECUTE; 978d0aea04fSJohn Dyson #endif 979d0aea04fSJohn Dyson 9800a0a85b3SJohn Dyson if (fitit) { 9810a0a85b3SJohn Dyson *addr = pmap_addr_hint(object, *addr, size); 9820a0a85b3SJohn Dyson } 9830a0a85b3SJohn Dyson 984bd7e5f99SJohn Dyson rv = vm_map_find(map, object, foff, addr, size, fitit, 985bd7e5f99SJohn Dyson prot, maxprot, docow); 986bd7e5f99SJohn Dyson 987df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 9887fb0c17eSDavid Greenman /* 98924a1cce3SDavid Greenman * Lose the object reference. Will destroy the 99024a1cce3SDavid Greenman * object if it's an unnamed anonymous mapping 99124a1cce3SDavid Greenman * or named anonymous without other references. 9927fb0c17eSDavid Greenman */ 993df8bae1dSRodney W. Grimes vm_object_deallocate(object); 994df8bae1dSRodney W. Grimes goto out; 995df8bae1dSRodney W. Grimes } 996e17bed12SJohn Dyson 997df8bae1dSRodney W. Grimes /* 9987fb0c17eSDavid Greenman * "Pre-fault" resident pages. 9997fb0c17eSDavid Greenman */ 10000a0a85b3SJohn Dyson if ((map->pmap != NULL) && (object != NULL)) { 1001a316d390SJohn Dyson pmap_object_init_pt(map->pmap, *addr, 1002867a482dSJohn Dyson object, (vm_pindex_t) OFF_TO_IDX(foff), size, 1); 1003df8bae1dSRodney W. Grimes } 10047fb0c17eSDavid Greenman 1005df8bae1dSRodney W. Grimes /* 1006df8bae1dSRodney W. Grimes * Shared memory is also shared with children. 1007df8bae1dSRodney W. Grimes */ 10085850152dSJohn Dyson if (flags & (MAP_SHARED|MAP_INHERIT)) { 1009df8bae1dSRodney W. Grimes rv = vm_map_inherit(map, *addr, *addr + size, VM_INHERIT_SHARE); 1010df8bae1dSRodney W. Grimes if (rv != KERN_SUCCESS) { 10117fb0c17eSDavid Greenman (void) vm_map_remove(map, *addr, *addr + size); 1012df8bae1dSRodney W. Grimes goto out; 1013df8bae1dSRodney W. Grimes } 1014df8bae1dSRodney W. Grimes } 1015df8bae1dSRodney W. Grimes out: 1016df8bae1dSRodney W. Grimes switch (rv) { 1017df8bae1dSRodney W. Grimes case KERN_SUCCESS: 1018df8bae1dSRodney W. Grimes return (0); 1019df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 1020df8bae1dSRodney W. Grimes case KERN_NO_SPACE: 1021df8bae1dSRodney W. Grimes return (ENOMEM); 1022df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 1023df8bae1dSRodney W. Grimes return (EACCES); 1024df8bae1dSRodney W. Grimes default: 1025df8bae1dSRodney W. Grimes return (EINVAL); 1026df8bae1dSRodney W. Grimes } 1027df8bae1dSRodney W. Grimes } 1028