160727d8bSWarner Losh /*- 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 * 4. Neither the name of the University nor the names of its contributors 19df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 20df8bae1dSRodney W. Grimes * without specific prior written permission. 21df8bae1dSRodney W. Grimes * 22df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32df8bae1dSRodney W. Grimes * SUCH DAMAGE. 33df8bae1dSRodney W. Grimes * 34df8bae1dSRodney W. Grimes * from: Utah $Hdr: vm_mmap.c 1.6 91/10/21$ 35df8bae1dSRodney W. Grimes * 36df8bae1dSRodney W. Grimes * @(#)vm_mmap.c 8.4 (Berkeley) 1/12/94 37df8bae1dSRodney W. Grimes */ 38df8bae1dSRodney W. Grimes 39df8bae1dSRodney W. Grimes /* 40df8bae1dSRodney W. Grimes * Mapped file (mmap) interface to VM 41df8bae1dSRodney W. Grimes */ 42df8bae1dSRodney W. Grimes 43874651b1SDavid E. O'Brien #include <sys/cdefs.h> 44874651b1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 45874651b1SDavid E. O'Brien 465591b823SEivind Eklund #include "opt_compat.h" 4749874f6eSJoseph Koshy #include "opt_hwpmc_hooks.h" 48e9822d92SJoerg Wunsch 49df8bae1dSRodney W. Grimes #include <sys/param.h> 50df8bae1dSRodney W. Grimes #include <sys/systm.h> 51a9d2f8d8SRobert Watson #include <sys/capability.h> 52a9d2f8d8SRobert Watson #include <sys/kernel.h> 53fb919e4dSMark Murray #include <sys/lock.h> 5423955314SAlfred Perlstein #include <sys/mutex.h> 55d2d3e875SBruce Evans #include <sys/sysproto.h> 56df8bae1dSRodney W. Grimes #include <sys/filedesc.h> 57acd3428bSRobert Watson #include <sys/priv.h> 58df8bae1dSRodney W. Grimes #include <sys/proc.h> 591ba5ad42SEdward Tomasz Napierala #include <sys/racct.h> 60070f64feSMatthew Dillon #include <sys/resource.h> 61070f64feSMatthew Dillon #include <sys/resourcevar.h> 62df8bae1dSRodney W. Grimes #include <sys/vnode.h> 633ac4d1efSBruce Evans #include <sys/fcntl.h> 64df8bae1dSRodney W. Grimes #include <sys/file.h> 65df8bae1dSRodney W. Grimes #include <sys/mman.h> 66b483c7f6SGuido van Rooij #include <sys/mount.h> 67df8bae1dSRodney W. Grimes #include <sys/conf.h> 684183b6b6SPeter Wemm #include <sys/stat.h> 69497a8238SKonstantin Belousov #include <sys/sysent.h> 70efeaf95aSDavid Greenman #include <sys/vmmeter.h> 71df8bae1dSRodney W. Grimes 72aed55708SRobert Watson #include <security/mac/mac_framework.h> 73aed55708SRobert Watson 74df8bae1dSRodney W. Grimes #include <vm/vm.h> 75efeaf95aSDavid Greenman #include <vm/vm_param.h> 76efeaf95aSDavid Greenman #include <vm/pmap.h> 77efeaf95aSDavid Greenman #include <vm/vm_map.h> 78efeaf95aSDavid Greenman #include <vm/vm_object.h> 791c7c3c6aSMatthew Dillon #include <vm/vm_page.h> 80df8bae1dSRodney W. Grimes #include <vm/vm_pager.h> 81b5e8ce9fSBruce Evans #include <vm/vm_pageout.h> 82efeaf95aSDavid Greenman #include <vm/vm_extern.h> 83867a482dSJohn Dyson #include <vm/vm_page.h> 84df8bae1dSRodney W. Grimes 8549874f6eSJoseph Koshy #ifdef HWPMC_HOOKS 8649874f6eSJoseph Koshy #include <sys/pmckern.h> 8749874f6eSJoseph Koshy #endif 8849874f6eSJoseph Koshy 89d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 90df8bae1dSRodney W. Grimes struct sbrk_args { 91df8bae1dSRodney W. Grimes int incr; 92df8bae1dSRodney W. Grimes }; 93d2d3e875SBruce Evans #endif 940d94caffSDavid Greenman 95c8daea13SAlexander Kabaev static int vm_mmap_vnode(struct thread *, vm_size_t, vm_prot_t, vm_prot_t *, 9664345f0bSJohn Baldwin int *, struct vnode *, vm_ooffset_t *, vm_object_t *); 9798df9218SJohn Baldwin static int vm_mmap_cdev(struct thread *, vm_size_t, vm_prot_t, vm_prot_t *, 9864345f0bSJohn Baldwin int *, struct cdev *, vm_ooffset_t *, vm_object_t *); 998e38aeffSJohn Baldwin static int vm_mmap_shm(struct thread *, vm_size_t, vm_prot_t, vm_prot_t *, 1008e38aeffSJohn Baldwin int *, struct shmfd *, vm_ooffset_t, vm_object_t *); 101c8daea13SAlexander Kabaev 102d2c60af8SMatthew Dillon /* 103d2c60af8SMatthew Dillon * MPSAFE 104d2c60af8SMatthew Dillon */ 105df8bae1dSRodney W. Grimes /* ARGSUSED */ 106df8bae1dSRodney W. Grimes int 1078451d0ddSKip Macy sys_sbrk(td, uap) 108b40ce416SJulian Elischer struct thread *td; 109df8bae1dSRodney W. Grimes struct sbrk_args *uap; 110df8bae1dSRodney W. Grimes { 111df8bae1dSRodney W. Grimes /* Not yet implemented */ 112df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 113df8bae1dSRodney W. Grimes } 114df8bae1dSRodney W. Grimes 115d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 116df8bae1dSRodney W. Grimes struct sstk_args { 117df8bae1dSRodney W. Grimes int incr; 118df8bae1dSRodney W. Grimes }; 119d2d3e875SBruce Evans #endif 1200d94caffSDavid Greenman 121d2c60af8SMatthew Dillon /* 122d2c60af8SMatthew Dillon * MPSAFE 123d2c60af8SMatthew Dillon */ 124df8bae1dSRodney W. Grimes /* ARGSUSED */ 125df8bae1dSRodney W. Grimes int 1268451d0ddSKip Macy sys_sstk(td, uap) 127b40ce416SJulian Elischer struct thread *td; 128df8bae1dSRodney W. Grimes struct sstk_args *uap; 129df8bae1dSRodney W. Grimes { 130df8bae1dSRodney W. Grimes /* Not yet implemented */ 131df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 132df8bae1dSRodney W. Grimes } 133df8bae1dSRodney W. Grimes 1341930e303SPoul-Henning Kamp #if defined(COMPAT_43) 135d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 136df8bae1dSRodney W. Grimes struct getpagesize_args { 137df8bae1dSRodney W. Grimes int dummy; 138df8bae1dSRodney W. Grimes }; 139d2d3e875SBruce Evans #endif 1400d94caffSDavid Greenman 141df8bae1dSRodney W. Grimes /* ARGSUSED */ 142df8bae1dSRodney W. Grimes int 143b40ce416SJulian Elischer ogetpagesize(td, uap) 144b40ce416SJulian Elischer struct thread *td; 145df8bae1dSRodney W. Grimes struct getpagesize_args *uap; 146df8bae1dSRodney W. Grimes { 1470cddd8f0SMatthew Dillon /* MP SAFE */ 148b40ce416SJulian Elischer td->td_retval[0] = PAGE_SIZE; 149df8bae1dSRodney W. Grimes return (0); 150df8bae1dSRodney W. Grimes } 1511930e303SPoul-Henning Kamp #endif /* COMPAT_43 */ 152df8bae1dSRodney W. Grimes 15354f42e4bSPeter Wemm 15454f42e4bSPeter Wemm /* 15554f42e4bSPeter Wemm * Memory Map (mmap) system call. Note that the file offset 15654f42e4bSPeter Wemm * and address are allowed to be NOT page aligned, though if 15754f42e4bSPeter Wemm * the MAP_FIXED flag it set, both must have the same remainder 15854f42e4bSPeter Wemm * modulo the PAGE_SIZE (POSIX 1003.1b). If the address is not 15954f42e4bSPeter Wemm * page-aligned, the actual mapping starts at trunc_page(addr) 16054f42e4bSPeter Wemm * and the return value is adjusted up by the page offset. 161b4309055SMatthew Dillon * 162b4309055SMatthew Dillon * Generally speaking, only character devices which are themselves 163b4309055SMatthew Dillon * memory-based, such as a video framebuffer, can be mmap'd. Otherwise 164b4309055SMatthew Dillon * there would be no cache coherency between a descriptor and a VM mapping 165b4309055SMatthew Dillon * both to the same character device. 16654f42e4bSPeter Wemm */ 167d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 168df8bae1dSRodney W. Grimes struct mmap_args { 169651bb817SAlexander Langer void *addr; 170df8bae1dSRodney W. Grimes size_t len; 171df8bae1dSRodney W. Grimes int prot; 172df8bae1dSRodney W. Grimes int flags; 173df8bae1dSRodney W. Grimes int fd; 174df8bae1dSRodney W. Grimes long pad; 175df8bae1dSRodney W. Grimes off_t pos; 176df8bae1dSRodney W. Grimes }; 177d2d3e875SBruce Evans #endif 178df8bae1dSRodney W. Grimes 179d2c60af8SMatthew Dillon /* 180d2c60af8SMatthew Dillon * MPSAFE 181d2c60af8SMatthew Dillon */ 182df8bae1dSRodney W. Grimes int 1838451d0ddSKip Macy sys_mmap(td, uap) 184b40ce416SJulian Elischer struct thread *td; 18554d92145SMatthew Dillon struct mmap_args *uap; 186df8bae1dSRodney W. Grimes { 18749874f6eSJoseph Koshy #ifdef HWPMC_HOOKS 18849874f6eSJoseph Koshy struct pmckern_map_in pkm; 18949874f6eSJoseph Koshy #endif 190c8daea13SAlexander Kabaev struct file *fp; 191df8bae1dSRodney W. Grimes struct vnode *vp; 192df8bae1dSRodney W. Grimes vm_offset_t addr; 1939154ee6aSPeter Wemm vm_size_t size, pageoff; 194a9d2f8d8SRobert Watson vm_prot_t cap_maxprot, prot, maxprot; 195651bb817SAlexander Langer void *handle; 19698df9218SJohn Baldwin objtype_t handle_type; 197df8bae1dSRodney W. Grimes int flags, error; 19854f42e4bSPeter Wemm off_t pos; 199b40ce416SJulian Elischer struct vmspace *vms = td->td_proc->p_vmspace; 200a9d2f8d8SRobert Watson cap_rights_t rights; 201df8bae1dSRodney W. Grimes 20254f42e4bSPeter Wemm addr = (vm_offset_t) uap->addr; 20354f42e4bSPeter Wemm size = uap->len; 204df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 205df8bae1dSRodney W. Grimes flags = uap->flags; 20654f42e4bSPeter Wemm pos = uap->pos; 20754f42e4bSPeter Wemm 208426da3bcSAlfred Perlstein fp = NULL; 20927bfa958SSimon L. B. Nielsen 21027bfa958SSimon L. B. Nielsen /* Make sure mapping fits into numeric range, etc. */ 211497a8238SKonstantin Belousov if ((uap->len == 0 && !SV_CURPROC_FLAG(SV_AOUT) && 2127022f954SKonstantin Belousov curproc->p_osrel >= P_OSREL_MAP_ANON) || 2135711bf30SJohn Baldwin ((flags & MAP_ANON) && (uap->fd != -1 || pos != 0))) 214df8bae1dSRodney W. Grimes return (EINVAL); 2159154ee6aSPeter Wemm 2162267af78SJulian Elischer if (flags & MAP_STACK) { 2172267af78SJulian Elischer if ((uap->fd != -1) || 2182267af78SJulian Elischer ((prot & (PROT_READ | PROT_WRITE)) != (PROT_READ | PROT_WRITE))) 2192267af78SJulian Elischer return (EINVAL); 2202267af78SJulian Elischer flags |= MAP_ANON; 2212267af78SJulian Elischer pos = 0; 2222907af2aSJulian Elischer } 2232907af2aSJulian Elischer 2249154ee6aSPeter Wemm /* 22554f42e4bSPeter Wemm * Align the file position to a page boundary, 22654f42e4bSPeter Wemm * and save its page offset component. 2279154ee6aSPeter Wemm */ 22854f42e4bSPeter Wemm pageoff = (pos & PAGE_MASK); 22954f42e4bSPeter Wemm pos -= pageoff; 23054f42e4bSPeter Wemm 23154f42e4bSPeter Wemm /* Adjust size for rounding (on both ends). */ 23254f42e4bSPeter Wemm size += pageoff; /* low end... */ 23354f42e4bSPeter Wemm size = (vm_size_t) round_page(size); /* hi end */ 2349154ee6aSPeter Wemm 235df8bae1dSRodney W. Grimes /* 2360d94caffSDavid Greenman * Check for illegal addresses. Watch out for address wrap... Note 2370d94caffSDavid Greenman * that VM_*_ADDRESS are not constants due to casts (argh). 238df8bae1dSRodney W. Grimes */ 239df8bae1dSRodney W. Grimes if (flags & MAP_FIXED) { 24054f42e4bSPeter Wemm /* 24154f42e4bSPeter Wemm * The specified address must have the same remainder 24254f42e4bSPeter Wemm * as the file offset taken modulo PAGE_SIZE, so it 24354f42e4bSPeter Wemm * should be aligned after adjustment by pageoff. 24454f42e4bSPeter Wemm */ 24554f42e4bSPeter Wemm addr -= pageoff; 24654f42e4bSPeter Wemm if (addr & PAGE_MASK) 24754f42e4bSPeter Wemm return (EINVAL); 24827bfa958SSimon L. B. Nielsen 24954f42e4bSPeter Wemm /* Address range must be all in user VM space. */ 25005ba50f5SJake Burkholder if (addr < vm_map_min(&vms->vm_map) || 25105ba50f5SJake Burkholder addr + size > vm_map_max(&vms->vm_map)) 252df8bae1dSRodney W. Grimes return (EINVAL); 253bbc0ec52SDavid Greenman if (addr + size < addr) 254df8bae1dSRodney W. Grimes return (EINVAL); 25591d5354aSJohn Baldwin } else { 256df8bae1dSRodney W. Grimes /* 25754f42e4bSPeter Wemm * XXX for non-fixed mappings where no hint is provided or 25854f42e4bSPeter Wemm * the hint would fall in the potential heap space, 25954f42e4bSPeter Wemm * place it after the end of the largest possible heap. 260df8bae1dSRodney W. Grimes * 26154f42e4bSPeter Wemm * There should really be a pmap call to determine a reasonable 26254f42e4bSPeter Wemm * location. 263df8bae1dSRodney W. Grimes */ 26491d5354aSJohn Baldwin PROC_LOCK(td->td_proc); 26591d5354aSJohn Baldwin if (addr == 0 || 2661f6889a1SMatthew Dillon (addr >= round_page((vm_offset_t)vms->vm_taddr) && 267c460ac3aSPeter Wemm addr < round_page((vm_offset_t)vms->vm_daddr + 26891d5354aSJohn Baldwin lim_max(td->td_proc, RLIMIT_DATA)))) 269c460ac3aSPeter Wemm addr = round_page((vm_offset_t)vms->vm_daddr + 27091d5354aSJohn Baldwin lim_max(td->td_proc, RLIMIT_DATA)); 27191d5354aSJohn Baldwin PROC_UNLOCK(td->td_proc); 27291d5354aSJohn Baldwin } 273df8bae1dSRodney W. Grimes if (flags & MAP_ANON) { 274df8bae1dSRodney W. Grimes /* 275df8bae1dSRodney W. Grimes * Mapping blank space is trivial. 276df8bae1dSRodney W. Grimes */ 277df8bae1dSRodney W. Grimes handle = NULL; 27898df9218SJohn Baldwin handle_type = OBJT_DEFAULT; 279df8bae1dSRodney W. Grimes maxprot = VM_PROT_ALL; 280a9d2f8d8SRobert Watson cap_maxprot = VM_PROT_ALL; 28130d4dd7eSAlexander Kabaev } else { 282df8bae1dSRodney W. Grimes /* 283a9d2f8d8SRobert Watson * Mapping file, get fp for validation and don't let the 284a9d2f8d8SRobert Watson * descriptor disappear on us if we block. Check capability 285a9d2f8d8SRobert Watson * rights, but also return the maximum rights to be combined 286a9d2f8d8SRobert Watson * with maxprot later. 287df8bae1dSRodney W. Grimes */ 288a9d2f8d8SRobert Watson rights = CAP_MMAP; 289a9d2f8d8SRobert Watson if (prot & PROT_READ) 290a9d2f8d8SRobert Watson rights |= CAP_READ; 291a9d2f8d8SRobert Watson if ((flags & MAP_SHARED) != 0) { 292a9d2f8d8SRobert Watson if (prot & PROT_WRITE) 293a9d2f8d8SRobert Watson rights |= CAP_WRITE; 294a9d2f8d8SRobert Watson } 295a9d2f8d8SRobert Watson if (prot & PROT_EXEC) 296a9d2f8d8SRobert Watson rights |= CAP_MAPEXEC; 297a9d2f8d8SRobert Watson if ((error = fget_mmap(td, uap->fd, rights, &cap_maxprot, 298a9d2f8d8SRobert Watson &fp)) != 0) 299426da3bcSAlfred Perlstein goto done; 3008e38aeffSJohn Baldwin if (fp->f_type == DTYPE_SHM) { 3018e38aeffSJohn Baldwin handle = fp->f_data; 3028e38aeffSJohn Baldwin handle_type = OBJT_SWAP; 3038e38aeffSJohn Baldwin maxprot = VM_PROT_NONE; 3048e38aeffSJohn Baldwin 3058e38aeffSJohn Baldwin /* FREAD should always be set. */ 3068e38aeffSJohn Baldwin if (fp->f_flag & FREAD) 3078e38aeffSJohn Baldwin maxprot |= VM_PROT_EXECUTE | VM_PROT_READ; 3088e38aeffSJohn Baldwin if (fp->f_flag & FWRITE) 3098e38aeffSJohn Baldwin maxprot |= VM_PROT_WRITE; 3108e38aeffSJohn Baldwin goto map; 3118e38aeffSJohn Baldwin } 312e4ca250dSJohn Baldwin if (fp->f_type != DTYPE_VNODE) { 31389eae00bSTom Rhodes error = ENODEV; 314426da3bcSAlfred Perlstein goto done; 315e4ca250dSJohn Baldwin } 3168e38aeffSJohn Baldwin #if defined(COMPAT_FREEBSD7) || defined(COMPAT_FREEBSD6) || \ 3178e38aeffSJohn Baldwin defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) 318279d7226SMatthew Dillon /* 319aa543039SGarrett Wollman * POSIX shared-memory objects are defined to have 320aa543039SGarrett Wollman * kernel persistence, and are not defined to support 321aa543039SGarrett Wollman * read(2)/write(2) -- or even open(2). Thus, we can 322aa543039SGarrett Wollman * use MAP_ASYNC to trade on-disk coherence for speed. 323aa543039SGarrett Wollman * The shm_open(3) library routine turns on the FPOSIXSHM 324aa543039SGarrett Wollman * flag to request this behavior. 325aa543039SGarrett Wollman */ 326aa543039SGarrett Wollman if (fp->f_flag & FPOSIXSHM) 327aa543039SGarrett Wollman flags |= MAP_NOSYNC; 3288e38aeffSJohn Baldwin #endif 3293b6d9652SPoul-Henning Kamp vp = fp->f_vnode; 330c8bdd56bSGuido van Rooij /* 331df8bae1dSRodney W. Grimes * Ensure that file and memory protections are 332df8bae1dSRodney W. Grimes * compatible. Note that we only worry about 333df8bae1dSRodney W. Grimes * writability if mapping is shared; in this case, 334df8bae1dSRodney W. Grimes * current and max prot are dictated by the open file. 335df8bae1dSRodney W. Grimes * XXX use the vnode instead? Problem is: what 3360d94caffSDavid Greenman * credentials do we use for determination? What if 3370d94caffSDavid Greenman * proc does a setuid? 338df8bae1dSRodney W. Grimes */ 3398eec77b0STim J. Robbins if (vp->v_mount != NULL && vp->v_mount->mnt_flag & MNT_NOEXEC) 340b483c7f6SGuido van Rooij maxprot = VM_PROT_NONE; 341b483c7f6SGuido van Rooij else 342b483c7f6SGuido van Rooij maxprot = VM_PROT_EXECUTE; 343279d7226SMatthew Dillon if (fp->f_flag & FREAD) { 344df8bae1dSRodney W. Grimes maxprot |= VM_PROT_READ; 345279d7226SMatthew Dillon } else if (prot & PROT_READ) { 346279d7226SMatthew Dillon error = EACCES; 347279d7226SMatthew Dillon goto done; 348279d7226SMatthew Dillon } 349c8bdd56bSGuido van Rooij /* 350c8bdd56bSGuido van Rooij * If we are sharing potential changes (either via 351c8bdd56bSGuido van Rooij * MAP_SHARED or via the implicit sharing of character 352c8bdd56bSGuido van Rooij * device mappings), and we are trying to get write 353c8bdd56bSGuido van Rooij * permission although we opened it without asking 354c8daea13SAlexander Kabaev * for it, bail out. 355c8bdd56bSGuido van Rooij */ 356ce7a036dSAlexander Kabaev if ((flags & MAP_SHARED) != 0) { 35705feb99fSGuido van Rooij if ((fp->f_flag & FWRITE) != 0) { 358df8bae1dSRodney W. Grimes maxprot |= VM_PROT_WRITE; 359279d7226SMatthew Dillon } else if ((prot & PROT_WRITE) != 0) { 360279d7226SMatthew Dillon error = EACCES; 361279d7226SMatthew Dillon goto done; 362279d7226SMatthew Dillon } 363ce7a036dSAlexander Kabaev } else if (vp->v_type != VCHR || (fp->f_flag & FWRITE) != 0) { 36405feb99fSGuido van Rooij maxprot |= VM_PROT_WRITE; 365a9d2f8d8SRobert Watson cap_maxprot |= VM_PROT_WRITE; 366279d7226SMatthew Dillon } 367651bb817SAlexander Langer handle = (void *)vp; 36898df9218SJohn Baldwin handle_type = OBJT_VNODE; 36930d4dd7eSAlexander Kabaev } 3708e38aeffSJohn Baldwin map: 37136b90789SKonstantin Belousov td->td_fpop = fp; 372a9d2f8d8SRobert Watson maxprot &= cap_maxprot; 3731f6889a1SMatthew Dillon error = vm_mmap(&vms->vm_map, &addr, size, prot, maxprot, 37498df9218SJohn Baldwin flags, handle_type, handle, pos); 37536b90789SKonstantin Belousov td->td_fpop = NULL; 37649874f6eSJoseph Koshy #ifdef HWPMC_HOOKS 37749874f6eSJoseph Koshy /* inform hwpmc(4) if an executable is being mapped */ 37849874f6eSJoseph Koshy if (error == 0 && handle_type == OBJT_VNODE && 37949874f6eSJoseph Koshy (prot & PROT_EXEC)) { 38049874f6eSJoseph Koshy pkm.pm_file = handle; 38149874f6eSJoseph Koshy pkm.pm_address = (uintptr_t) addr; 38249874f6eSJoseph Koshy PMC_CALL_HOOK(td, PMC_FN_MMAP, (void *) &pkm); 38349874f6eSJoseph Koshy } 38449874f6eSJoseph Koshy #endif 385df8bae1dSRodney W. Grimes if (error == 0) 386b40ce416SJulian Elischer td->td_retval[0] = (register_t) (addr + pageoff); 387279d7226SMatthew Dillon done: 388279d7226SMatthew Dillon if (fp) 389b40ce416SJulian Elischer fdrop(fp, td); 390f6b5b182SJeff Roberson 391df8bae1dSRodney W. Grimes return (error); 392df8bae1dSRodney W. Grimes } 393df8bae1dSRodney W. Grimes 394c2815ad5SPeter Wemm int 395c2815ad5SPeter Wemm freebsd6_mmap(struct thread *td, struct freebsd6_mmap_args *uap) 396c2815ad5SPeter Wemm { 397c2815ad5SPeter Wemm struct mmap_args oargs; 398c2815ad5SPeter Wemm 399c2815ad5SPeter Wemm oargs.addr = uap->addr; 400c2815ad5SPeter Wemm oargs.len = uap->len; 401c2815ad5SPeter Wemm oargs.prot = uap->prot; 402c2815ad5SPeter Wemm oargs.flags = uap->flags; 403c2815ad5SPeter Wemm oargs.fd = uap->fd; 404c2815ad5SPeter Wemm oargs.pos = uap->pos; 4058451d0ddSKip Macy return (sys_mmap(td, &oargs)); 406c2815ad5SPeter Wemm } 407c2815ad5SPeter Wemm 40805f0fdd2SPoul-Henning Kamp #ifdef COMPAT_43 409d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 41005f0fdd2SPoul-Henning Kamp struct ommap_args { 41105f0fdd2SPoul-Henning Kamp caddr_t addr; 41205f0fdd2SPoul-Henning Kamp int len; 41305f0fdd2SPoul-Henning Kamp int prot; 41405f0fdd2SPoul-Henning Kamp int flags; 41505f0fdd2SPoul-Henning Kamp int fd; 41605f0fdd2SPoul-Henning Kamp long pos; 41705f0fdd2SPoul-Henning Kamp }; 418d2d3e875SBruce Evans #endif 41905f0fdd2SPoul-Henning Kamp int 420b40ce416SJulian Elischer ommap(td, uap) 421b40ce416SJulian Elischer struct thread *td; 42254d92145SMatthew Dillon struct ommap_args *uap; 42305f0fdd2SPoul-Henning Kamp { 42405f0fdd2SPoul-Henning Kamp struct mmap_args nargs; 42505f0fdd2SPoul-Henning Kamp static const char cvtbsdprot[8] = { 42605f0fdd2SPoul-Henning Kamp 0, 42705f0fdd2SPoul-Henning Kamp PROT_EXEC, 42805f0fdd2SPoul-Henning Kamp PROT_WRITE, 42905f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE, 43005f0fdd2SPoul-Henning Kamp PROT_READ, 43105f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_READ, 43205f0fdd2SPoul-Henning Kamp PROT_WRITE | PROT_READ, 43305f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE | PROT_READ, 43405f0fdd2SPoul-Henning Kamp }; 4350d94caffSDavid Greenman 43605f0fdd2SPoul-Henning Kamp #define OMAP_ANON 0x0002 43705f0fdd2SPoul-Henning Kamp #define OMAP_COPY 0x0020 43805f0fdd2SPoul-Henning Kamp #define OMAP_SHARED 0x0010 43905f0fdd2SPoul-Henning Kamp #define OMAP_FIXED 0x0100 44005f0fdd2SPoul-Henning Kamp 44105f0fdd2SPoul-Henning Kamp nargs.addr = uap->addr; 44205f0fdd2SPoul-Henning Kamp nargs.len = uap->len; 44305f0fdd2SPoul-Henning Kamp nargs.prot = cvtbsdprot[uap->prot & 0x7]; 44405f0fdd2SPoul-Henning Kamp nargs.flags = 0; 44505f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_ANON) 44605f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_ANON; 44705f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_COPY) 44805f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_COPY; 44905f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_SHARED) 45005f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_SHARED; 45105f0fdd2SPoul-Henning Kamp else 45205f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_PRIVATE; 45305f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_FIXED) 45405f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_FIXED; 45505f0fdd2SPoul-Henning Kamp nargs.fd = uap->fd; 45605f0fdd2SPoul-Henning Kamp nargs.pos = uap->pos; 4578451d0ddSKip Macy return (sys_mmap(td, &nargs)); 45805f0fdd2SPoul-Henning Kamp } 45905f0fdd2SPoul-Henning Kamp #endif /* COMPAT_43 */ 46005f0fdd2SPoul-Henning Kamp 46105f0fdd2SPoul-Henning Kamp 462d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 463df8bae1dSRodney W. Grimes struct msync_args { 464651bb817SAlexander Langer void *addr; 465c899450bSPeter Wemm size_t len; 466e6c6af11SDavid Greenman int flags; 467df8bae1dSRodney W. Grimes }; 468d2d3e875SBruce Evans #endif 469d2c60af8SMatthew Dillon /* 470d2c60af8SMatthew Dillon * MPSAFE 471d2c60af8SMatthew Dillon */ 472df8bae1dSRodney W. Grimes int 4738451d0ddSKip Macy sys_msync(td, uap) 474b40ce416SJulian Elischer struct thread *td; 475df8bae1dSRodney W. Grimes struct msync_args *uap; 476df8bae1dSRodney W. Grimes { 477df8bae1dSRodney W. Grimes vm_offset_t addr; 478dabee6feSPeter Wemm vm_size_t size, pageoff; 479e6c6af11SDavid Greenman int flags; 480df8bae1dSRodney W. Grimes vm_map_t map; 481df8bae1dSRodney W. Grimes int rv; 482df8bae1dSRodney W. Grimes 483df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 4849154ee6aSPeter Wemm size = uap->len; 485e6c6af11SDavid Greenman flags = uap->flags; 486e6c6af11SDavid Greenman 487dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 488dabee6feSPeter Wemm addr -= pageoff; 489dabee6feSPeter Wemm size += pageoff; 490dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 4919154ee6aSPeter Wemm if (addr + size < addr) 492dabee6feSPeter Wemm return (EINVAL); 493dabee6feSPeter Wemm 494dabee6feSPeter Wemm if ((flags & (MS_ASYNC|MS_INVALIDATE)) == (MS_ASYNC|MS_INVALIDATE)) 4951e62bc63SDavid Greenman return (EINVAL); 4961e62bc63SDavid Greenman 497b40ce416SJulian Elischer map = &td->td_proc->p_vmspace->vm_map; 4989154ee6aSPeter Wemm 499df8bae1dSRodney W. Grimes /* 500df8bae1dSRodney W. Grimes * Clean the pages and interpret the return value. 501df8bae1dSRodney W. Grimes */ 502950f8459SAlan Cox rv = vm_map_sync(map, addr, addr + size, (flags & MS_ASYNC) == 0, 503e6c6af11SDavid Greenman (flags & MS_INVALIDATE) != 0); 504df8bae1dSRodney W. Grimes switch (rv) { 505df8bae1dSRodney W. Grimes case KERN_SUCCESS: 506d2c60af8SMatthew Dillon return (0); 507df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 508df8bae1dSRodney W. Grimes return (EINVAL); /* Sun returns ENOMEM? */ 509b7b7cd44SAlan Cox case KERN_INVALID_ARGUMENT: 510b7b7cd44SAlan Cox return (EBUSY); 511df8bae1dSRodney W. Grimes default: 512df8bae1dSRodney W. Grimes return (EINVAL); 513df8bae1dSRodney W. Grimes } 514df8bae1dSRodney W. Grimes } 515df8bae1dSRodney W. Grimes 516d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 517df8bae1dSRodney W. Grimes struct munmap_args { 518651bb817SAlexander Langer void *addr; 5199154ee6aSPeter Wemm size_t len; 520df8bae1dSRodney W. Grimes }; 521d2d3e875SBruce Evans #endif 522d2c60af8SMatthew Dillon /* 523d2c60af8SMatthew Dillon * MPSAFE 524d2c60af8SMatthew Dillon */ 525df8bae1dSRodney W. Grimes int 5268451d0ddSKip Macy sys_munmap(td, uap) 527b40ce416SJulian Elischer struct thread *td; 52854d92145SMatthew Dillon struct munmap_args *uap; 529df8bae1dSRodney W. Grimes { 53049874f6eSJoseph Koshy #ifdef HWPMC_HOOKS 53149874f6eSJoseph Koshy struct pmckern_map_out pkm; 53249874f6eSJoseph Koshy vm_map_entry_t entry; 53349874f6eSJoseph Koshy #endif 534df8bae1dSRodney W. Grimes vm_offset_t addr; 535dabee6feSPeter Wemm vm_size_t size, pageoff; 536df8bae1dSRodney W. Grimes vm_map_t map; 537df8bae1dSRodney W. Grimes 538df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 5399154ee6aSPeter Wemm size = uap->len; 540d8834602SAlan Cox if (size == 0) 541d8834602SAlan Cox return (EINVAL); 542dabee6feSPeter Wemm 543dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 544dabee6feSPeter Wemm addr -= pageoff; 545dabee6feSPeter Wemm size += pageoff; 546dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 5479154ee6aSPeter Wemm if (addr + size < addr) 548df8bae1dSRodney W. Grimes return (EINVAL); 5499154ee6aSPeter Wemm 550df8bae1dSRodney W. Grimes /* 55105ba50f5SJake Burkholder * Check for illegal addresses. Watch out for address wrap... 552df8bae1dSRodney W. Grimes */ 553b40ce416SJulian Elischer map = &td->td_proc->p_vmspace->vm_map; 55405ba50f5SJake Burkholder if (addr < vm_map_min(map) || addr + size > vm_map_max(map)) 55505ba50f5SJake Burkholder return (EINVAL); 556d8834602SAlan Cox vm_map_lock(map); 55749874f6eSJoseph Koshy #ifdef HWPMC_HOOKS 55849874f6eSJoseph Koshy /* 55949874f6eSJoseph Koshy * Inform hwpmc if the address range being unmapped contains 56049874f6eSJoseph Koshy * an executable region. 56149874f6eSJoseph Koshy */ 5620d419640SRyan Stone pkm.pm_address = (uintptr_t) NULL; 56349874f6eSJoseph Koshy if (vm_map_lookup_entry(map, addr, &entry)) { 56449874f6eSJoseph Koshy for (; 56549874f6eSJoseph Koshy entry != &map->header && entry->start < addr + size; 56649874f6eSJoseph Koshy entry = entry->next) { 56749874f6eSJoseph Koshy if (vm_map_check_protection(map, entry->start, 56849874f6eSJoseph Koshy entry->end, VM_PROT_EXECUTE) == TRUE) { 56949874f6eSJoseph Koshy pkm.pm_address = (uintptr_t) addr; 57049874f6eSJoseph Koshy pkm.pm_size = (size_t) size; 57149874f6eSJoseph Koshy break; 57249874f6eSJoseph Koshy } 57349874f6eSJoseph Koshy } 57449874f6eSJoseph Koshy } 57549874f6eSJoseph Koshy #endif 576655c3490SKonstantin Belousov vm_map_delete(map, addr, addr + size); 5770d419640SRyan Stone 5780d419640SRyan Stone #ifdef HWPMC_HOOKS 5790d419640SRyan Stone /* downgrade the lock to prevent a LOR with the pmc-sx lock */ 5800d419640SRyan Stone vm_map_lock_downgrade(map); 581d473d3a1SRyan Stone if (pkm.pm_address != (uintptr_t) NULL) 5820d419640SRyan Stone PMC_CALL_HOOK(td, PMC_FN_MUNMAP, (void *) &pkm); 5830d419640SRyan Stone vm_map_unlock_read(map); 5840d419640SRyan Stone #else 585d8834602SAlan Cox vm_map_unlock(map); 5860d419640SRyan Stone #endif 5870d419640SRyan Stone /* vm_map_delete returns nothing but KERN_SUCCESS anyway */ 588df8bae1dSRodney W. Grimes return (0); 589df8bae1dSRodney W. Grimes } 590df8bae1dSRodney W. Grimes 591d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 592df8bae1dSRodney W. Grimes struct mprotect_args { 593651bb817SAlexander Langer const void *addr; 5949154ee6aSPeter Wemm size_t len; 595df8bae1dSRodney W. Grimes int prot; 596df8bae1dSRodney W. Grimes }; 597d2d3e875SBruce Evans #endif 598d2c60af8SMatthew Dillon /* 599d2c60af8SMatthew Dillon * MPSAFE 600d2c60af8SMatthew Dillon */ 601df8bae1dSRodney W. Grimes int 6028451d0ddSKip Macy sys_mprotect(td, uap) 603b40ce416SJulian Elischer struct thread *td; 604df8bae1dSRodney W. Grimes struct mprotect_args *uap; 605df8bae1dSRodney W. Grimes { 606df8bae1dSRodney W. Grimes vm_offset_t addr; 607dabee6feSPeter Wemm vm_size_t size, pageoff; 60854d92145SMatthew Dillon vm_prot_t prot; 609df8bae1dSRodney W. Grimes 610df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 6119154ee6aSPeter Wemm size = uap->len; 612df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 613df8bae1dSRodney W. Grimes 614dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 615dabee6feSPeter Wemm addr -= pageoff; 616dabee6feSPeter Wemm size += pageoff; 617dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 6189154ee6aSPeter Wemm if (addr + size < addr) 619dabee6feSPeter Wemm return (EINVAL); 620dabee6feSPeter Wemm 62143285049SAlan Cox switch (vm_map_protect(&td->td_proc->p_vmspace->vm_map, addr, 62243285049SAlan Cox addr + size, prot, FALSE)) { 623df8bae1dSRodney W. Grimes case KERN_SUCCESS: 624df8bae1dSRodney W. Grimes return (0); 625df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 626df8bae1dSRodney W. Grimes return (EACCES); 6273364c323SKonstantin Belousov case KERN_RESOURCE_SHORTAGE: 6283364c323SKonstantin Belousov return (ENOMEM); 629df8bae1dSRodney W. Grimes } 630df8bae1dSRodney W. Grimes return (EINVAL); 631df8bae1dSRodney W. Grimes } 632df8bae1dSRodney W. Grimes 633d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 634dabee6feSPeter Wemm struct minherit_args { 635651bb817SAlexander Langer void *addr; 6369154ee6aSPeter Wemm size_t len; 637dabee6feSPeter Wemm int inherit; 638dabee6feSPeter Wemm }; 639dabee6feSPeter Wemm #endif 640d2c60af8SMatthew Dillon /* 641d2c60af8SMatthew Dillon * MPSAFE 642d2c60af8SMatthew Dillon */ 643dabee6feSPeter Wemm int 6448451d0ddSKip Macy sys_minherit(td, uap) 645b40ce416SJulian Elischer struct thread *td; 646dabee6feSPeter Wemm struct minherit_args *uap; 647dabee6feSPeter Wemm { 648dabee6feSPeter Wemm vm_offset_t addr; 649dabee6feSPeter Wemm vm_size_t size, pageoff; 65054d92145SMatthew Dillon vm_inherit_t inherit; 651dabee6feSPeter Wemm 652dabee6feSPeter Wemm addr = (vm_offset_t)uap->addr; 6539154ee6aSPeter Wemm size = uap->len; 654dabee6feSPeter Wemm inherit = uap->inherit; 655dabee6feSPeter Wemm 656dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 657dabee6feSPeter Wemm addr -= pageoff; 658dabee6feSPeter Wemm size += pageoff; 659dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 6609154ee6aSPeter Wemm if (addr + size < addr) 661dabee6feSPeter Wemm return (EINVAL); 662dabee6feSPeter Wemm 663e0be79afSAlan Cox switch (vm_map_inherit(&td->td_proc->p_vmspace->vm_map, addr, 664e0be79afSAlan Cox addr + size, inherit)) { 665dabee6feSPeter Wemm case KERN_SUCCESS: 666dabee6feSPeter Wemm return (0); 667dabee6feSPeter Wemm case KERN_PROTECTION_FAILURE: 668dabee6feSPeter Wemm return (EACCES); 669dabee6feSPeter Wemm } 670dabee6feSPeter Wemm return (EINVAL); 671dabee6feSPeter Wemm } 672dabee6feSPeter Wemm 673dabee6feSPeter Wemm #ifndef _SYS_SYSPROTO_H_ 674df8bae1dSRodney W. Grimes struct madvise_args { 675651bb817SAlexander Langer void *addr; 6769154ee6aSPeter Wemm size_t len; 677df8bae1dSRodney W. Grimes int behav; 678df8bae1dSRodney W. Grimes }; 679d2d3e875SBruce Evans #endif 6800d94caffSDavid Greenman 681d2c60af8SMatthew Dillon /* 682d2c60af8SMatthew Dillon * MPSAFE 683d2c60af8SMatthew Dillon */ 684df8bae1dSRodney W. Grimes /* ARGSUSED */ 685df8bae1dSRodney W. Grimes int 6868451d0ddSKip Macy sys_madvise(td, uap) 687b40ce416SJulian Elischer struct thread *td; 688df8bae1dSRodney W. Grimes struct madvise_args *uap; 689df8bae1dSRodney W. Grimes { 690f35329acSJohn Dyson vm_offset_t start, end; 69105ba50f5SJake Burkholder vm_map_t map; 692f4cf2141SWes Peters struct proc *p; 693f4cf2141SWes Peters int error; 694b4309055SMatthew Dillon 695b4309055SMatthew Dillon /* 696f4cf2141SWes Peters * Check for our special case, advising the swap pager we are 697f4cf2141SWes Peters * "immortal." 698f4cf2141SWes Peters */ 699f4cf2141SWes Peters if (uap->behav == MADV_PROTECT) { 700acd3428bSRobert Watson error = priv_check(td, PRIV_VM_MADV_PROTECT); 70169297bf8SJohn Baldwin if (error == 0) { 702f4cf2141SWes Peters p = td->td_proc; 703f4cf2141SWes Peters PROC_LOCK(p); 704f4cf2141SWes Peters p->p_flag |= P_PROTECTED; 705f4cf2141SWes Peters PROC_UNLOCK(p); 70669297bf8SJohn Baldwin } 707f4cf2141SWes Peters return (error); 708f4cf2141SWes Peters } 709f4cf2141SWes Peters /* 710b4309055SMatthew Dillon * Check for illegal behavior 711b4309055SMatthew Dillon */ 7129730a5daSPaul Saab if (uap->behav < 0 || uap->behav > MADV_CORE) 713b4309055SMatthew Dillon return (EINVAL); 714867a482dSJohn Dyson /* 715867a482dSJohn Dyson * Check for illegal addresses. Watch out for address wrap... Note 716867a482dSJohn Dyson * that VM_*_ADDRESS are not constants due to casts (argh). 717867a482dSJohn Dyson */ 71805ba50f5SJake Burkholder map = &td->td_proc->p_vmspace->vm_map; 71905ba50f5SJake Burkholder if ((vm_offset_t)uap->addr < vm_map_min(map) || 72005ba50f5SJake Burkholder (vm_offset_t)uap->addr + uap->len > vm_map_max(map)) 721867a482dSJohn Dyson return (EINVAL); 722867a482dSJohn Dyson if (((vm_offset_t) uap->addr + uap->len) < (vm_offset_t) uap->addr) 723867a482dSJohn Dyson return (EINVAL); 724867a482dSJohn Dyson 725867a482dSJohn Dyson /* 726867a482dSJohn Dyson * Since this routine is only advisory, we default to conservative 727867a482dSJohn Dyson * behavior. 728867a482dSJohn Dyson */ 729cd6eea25SDavid Greenman start = trunc_page((vm_offset_t) uap->addr); 730cd6eea25SDavid Greenman end = round_page((vm_offset_t) uap->addr + uap->len); 731867a482dSJohn Dyson 73205ba50f5SJake Burkholder if (vm_map_madvise(map, start, end, uap->behav)) 733094f6d26SAlan Cox return (EINVAL); 734094f6d26SAlan Cox return (0); 735df8bae1dSRodney W. Grimes } 736df8bae1dSRodney W. Grimes 737d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 738df8bae1dSRodney W. Grimes struct mincore_args { 739651bb817SAlexander Langer const void *addr; 7409154ee6aSPeter Wemm size_t len; 741df8bae1dSRodney W. Grimes char *vec; 742df8bae1dSRodney W. Grimes }; 743d2d3e875SBruce Evans #endif 7440d94caffSDavid Greenman 745d2c60af8SMatthew Dillon /* 746d2c60af8SMatthew Dillon * MPSAFE 747d2c60af8SMatthew Dillon */ 748df8bae1dSRodney W. Grimes /* ARGSUSED */ 749df8bae1dSRodney W. Grimes int 7508451d0ddSKip Macy sys_mincore(td, uap) 751b40ce416SJulian Elischer struct thread *td; 752df8bae1dSRodney W. Grimes struct mincore_args *uap; 753df8bae1dSRodney W. Grimes { 754867a482dSJohn Dyson vm_offset_t addr, first_addr; 755867a482dSJohn Dyson vm_offset_t end, cend; 756867a482dSJohn Dyson pmap_t pmap; 757867a482dSJohn Dyson vm_map_t map; 75802c04a2fSJohn Dyson char *vec; 759d2c60af8SMatthew Dillon int error = 0; 760867a482dSJohn Dyson int vecindex, lastvecindex; 76154d92145SMatthew Dillon vm_map_entry_t current; 762867a482dSJohn Dyson vm_map_entry_t entry; 763567e51e1SAlan Cox vm_object_t object; 764567e51e1SAlan Cox vm_paddr_t locked_pa; 765567e51e1SAlan Cox vm_page_t m; 766567e51e1SAlan Cox vm_pindex_t pindex; 767867a482dSJohn Dyson int mincoreinfo; 768dd2622a8SAlan Cox unsigned int timestamp; 769567e51e1SAlan Cox boolean_t locked; 770df8bae1dSRodney W. Grimes 771867a482dSJohn Dyson /* 772867a482dSJohn Dyson * Make sure that the addresses presented are valid for user 773867a482dSJohn Dyson * mode. 774867a482dSJohn Dyson */ 775867a482dSJohn Dyson first_addr = addr = trunc_page((vm_offset_t) uap->addr); 7769154ee6aSPeter Wemm end = addr + (vm_size_t)round_page(uap->len); 77705ba50f5SJake Burkholder map = &td->td_proc->p_vmspace->vm_map; 77805ba50f5SJake Burkholder if (end > vm_map_max(map) || end < addr) 779455dd7d4SKonstantin Belousov return (ENOMEM); 78002c04a2fSJohn Dyson 781867a482dSJohn Dyson /* 782867a482dSJohn Dyson * Address of byte vector 783867a482dSJohn Dyson */ 78402c04a2fSJohn Dyson vec = uap->vec; 785867a482dSJohn Dyson 786b40ce416SJulian Elischer pmap = vmspace_pmap(td->td_proc->p_vmspace); 787867a482dSJohn Dyson 788eff50fcdSAlan Cox vm_map_lock_read(map); 789dd2622a8SAlan Cox RestartScan: 790dd2622a8SAlan Cox timestamp = map->timestamp; 791867a482dSJohn Dyson 792455dd7d4SKonstantin Belousov if (!vm_map_lookup_entry(map, addr, &entry)) { 793455dd7d4SKonstantin Belousov vm_map_unlock_read(map); 794455dd7d4SKonstantin Belousov return (ENOMEM); 795455dd7d4SKonstantin Belousov } 796867a482dSJohn Dyson 797867a482dSJohn Dyson /* 798867a482dSJohn Dyson * Do this on a map entry basis so that if the pages are not 799867a482dSJohn Dyson * in the current processes address space, we can easily look 800867a482dSJohn Dyson * up the pages elsewhere. 801867a482dSJohn Dyson */ 802867a482dSJohn Dyson lastvecindex = -1; 803867a482dSJohn Dyson for (current = entry; 804867a482dSJohn Dyson (current != &map->header) && (current->start < end); 805867a482dSJohn Dyson current = current->next) { 806867a482dSJohn Dyson 807867a482dSJohn Dyson /* 808455dd7d4SKonstantin Belousov * check for contiguity 809455dd7d4SKonstantin Belousov */ 810455dd7d4SKonstantin Belousov if (current->end < end && 811455dd7d4SKonstantin Belousov (entry->next == &map->header || 812455dd7d4SKonstantin Belousov current->next->start > current->end)) { 813455dd7d4SKonstantin Belousov vm_map_unlock_read(map); 814455dd7d4SKonstantin Belousov return (ENOMEM); 815455dd7d4SKonstantin Belousov } 816455dd7d4SKonstantin Belousov 817455dd7d4SKonstantin Belousov /* 818867a482dSJohn Dyson * ignore submaps (for now) or null objects 819867a482dSJohn Dyson */ 8209fdfe602SMatthew Dillon if ((current->eflags & MAP_ENTRY_IS_SUB_MAP) || 821867a482dSJohn Dyson current->object.vm_object == NULL) 822867a482dSJohn Dyson continue; 823867a482dSJohn Dyson 824867a482dSJohn Dyson /* 825867a482dSJohn Dyson * limit this scan to the current map entry and the 826867a482dSJohn Dyson * limits for the mincore call 827867a482dSJohn Dyson */ 828867a482dSJohn Dyson if (addr < current->start) 829867a482dSJohn Dyson addr = current->start; 830867a482dSJohn Dyson cend = current->end; 831867a482dSJohn Dyson if (cend > end) 832867a482dSJohn Dyson cend = end; 833867a482dSJohn Dyson 834867a482dSJohn Dyson /* 835867a482dSJohn Dyson * scan this entry one page at a time 836867a482dSJohn Dyson */ 837867a482dSJohn Dyson while (addr < cend) { 838867a482dSJohn Dyson /* 839867a482dSJohn Dyson * Check pmap first, it is likely faster, also 840867a482dSJohn Dyson * it can provide info as to whether we are the 841867a482dSJohn Dyson * one referencing or modifying the page. 842867a482dSJohn Dyson */ 843567e51e1SAlan Cox object = NULL; 844567e51e1SAlan Cox locked_pa = 0; 845567e51e1SAlan Cox retry: 846567e51e1SAlan Cox m = NULL; 847567e51e1SAlan Cox mincoreinfo = pmap_mincore(pmap, addr, &locked_pa); 848567e51e1SAlan Cox if (locked_pa != 0) { 849867a482dSJohn Dyson /* 850567e51e1SAlan Cox * The page is mapped by this process but not 851567e51e1SAlan Cox * both accessed and modified. It is also 852567e51e1SAlan Cox * managed. Acquire the object lock so that 853567e51e1SAlan Cox * other mappings might be examined. 854867a482dSJohn Dyson */ 855567e51e1SAlan Cox m = PHYS_TO_VM_PAGE(locked_pa); 856567e51e1SAlan Cox if (m->object != object) { 857567e51e1SAlan Cox if (object != NULL) 858567e51e1SAlan Cox VM_OBJECT_UNLOCK(object); 859567e51e1SAlan Cox object = m->object; 860567e51e1SAlan Cox locked = VM_OBJECT_TRYLOCK(object); 861567e51e1SAlan Cox vm_page_unlock(m); 862567e51e1SAlan Cox if (!locked) { 863567e51e1SAlan Cox VM_OBJECT_LOCK(object); 8642965a453SKip Macy vm_page_lock(m); 865567e51e1SAlan Cox goto retry; 866567e51e1SAlan Cox } 867567e51e1SAlan Cox } else 868567e51e1SAlan Cox vm_page_unlock(m); 869567e51e1SAlan Cox KASSERT(m->valid == VM_PAGE_BITS_ALL, 870567e51e1SAlan Cox ("mincore: page %p is mapped but invalid", 871567e51e1SAlan Cox m)); 872567e51e1SAlan Cox } else if (mincoreinfo == 0) { 873567e51e1SAlan Cox /* 874567e51e1SAlan Cox * The page is not mapped by this process. If 875567e51e1SAlan Cox * the object implements managed pages, then 876567e51e1SAlan Cox * determine if the page is resident so that 877567e51e1SAlan Cox * the mappings might be examined. 878567e51e1SAlan Cox */ 879567e51e1SAlan Cox if (current->object.vm_object != object) { 880567e51e1SAlan Cox if (object != NULL) 881567e51e1SAlan Cox VM_OBJECT_UNLOCK(object); 882567e51e1SAlan Cox object = current->object.vm_object; 883567e51e1SAlan Cox VM_OBJECT_LOCK(object); 884567e51e1SAlan Cox } 885567e51e1SAlan Cox if (object->type == OBJT_DEFAULT || 886567e51e1SAlan Cox object->type == OBJT_SWAP || 887567e51e1SAlan Cox object->type == OBJT_VNODE) { 888567e51e1SAlan Cox pindex = OFF_TO_IDX(current->offset + 889567e51e1SAlan Cox (addr - current->start)); 890567e51e1SAlan Cox m = vm_page_lookup(object, pindex); 891567e51e1SAlan Cox if (m != NULL && m->valid == 0) 892567e51e1SAlan Cox m = NULL; 893567e51e1SAlan Cox if (m != NULL) 894567e51e1SAlan Cox mincoreinfo = MINCORE_INCORE; 895567e51e1SAlan Cox } 896567e51e1SAlan Cox } 897567e51e1SAlan Cox if (m != NULL) { 898567e51e1SAlan Cox /* Examine other mappings to the page. */ 899567e51e1SAlan Cox if (m->dirty == 0 && pmap_is_modified(m)) 900567e51e1SAlan Cox vm_page_dirty(m); 901567e51e1SAlan Cox if (m->dirty != 0) 902867a482dSJohn Dyson mincoreinfo |= MINCORE_MODIFIED_OTHER; 903c46b90e9SAlan Cox /* 9043407fefeSKonstantin Belousov * The first test for PGA_REFERENCED is an 905c46b90e9SAlan Cox * optimization. The second test is 906c46b90e9SAlan Cox * required because a concurrent pmap 907c46b90e9SAlan Cox * operation could clear the last reference 9083407fefeSKonstantin Belousov * and set PGA_REFERENCED before the call to 909c46b90e9SAlan Cox * pmap_is_referenced(). 910c46b90e9SAlan Cox */ 9113407fefeSKonstantin Belousov if ((m->aflags & PGA_REFERENCED) != 0 || 912c46b90e9SAlan Cox pmap_is_referenced(m) || 9133407fefeSKonstantin Belousov (m->aflags & PGA_REFERENCED) != 0) 914867a482dSJohn Dyson mincoreinfo |= MINCORE_REFERENCED_OTHER; 9159b5a5d81SJohn Dyson } 916567e51e1SAlan Cox if (object != NULL) 917567e51e1SAlan Cox VM_OBJECT_UNLOCK(object); 918867a482dSJohn Dyson 919867a482dSJohn Dyson /* 920dd2622a8SAlan Cox * subyte may page fault. In case it needs to modify 921dd2622a8SAlan Cox * the map, we release the lock. 922dd2622a8SAlan Cox */ 923dd2622a8SAlan Cox vm_map_unlock_read(map); 924dd2622a8SAlan Cox 925dd2622a8SAlan Cox /* 926867a482dSJohn Dyson * calculate index into user supplied byte vector 927867a482dSJohn Dyson */ 928867a482dSJohn Dyson vecindex = OFF_TO_IDX(addr - first_addr); 929867a482dSJohn Dyson 930867a482dSJohn Dyson /* 931867a482dSJohn Dyson * If we have skipped map entries, we need to make sure that 932867a482dSJohn Dyson * the byte vector is zeroed for those skipped entries. 933867a482dSJohn Dyson */ 934867a482dSJohn Dyson while ((lastvecindex + 1) < vecindex) { 935867a482dSJohn Dyson error = subyte(vec + lastvecindex, 0); 936867a482dSJohn Dyson if (error) { 937d2c60af8SMatthew Dillon error = EFAULT; 938d2c60af8SMatthew Dillon goto done2; 939867a482dSJohn Dyson } 940867a482dSJohn Dyson ++lastvecindex; 941867a482dSJohn Dyson } 942867a482dSJohn Dyson 943867a482dSJohn Dyson /* 944867a482dSJohn Dyson * Pass the page information to the user 945867a482dSJohn Dyson */ 946867a482dSJohn Dyson error = subyte(vec + vecindex, mincoreinfo); 947867a482dSJohn Dyson if (error) { 948d2c60af8SMatthew Dillon error = EFAULT; 949d2c60af8SMatthew Dillon goto done2; 950867a482dSJohn Dyson } 951dd2622a8SAlan Cox 952dd2622a8SAlan Cox /* 953dd2622a8SAlan Cox * If the map has changed, due to the subyte, the previous 954dd2622a8SAlan Cox * output may be invalid. 955dd2622a8SAlan Cox */ 956dd2622a8SAlan Cox vm_map_lock_read(map); 957dd2622a8SAlan Cox if (timestamp != map->timestamp) 958dd2622a8SAlan Cox goto RestartScan; 959dd2622a8SAlan Cox 960867a482dSJohn Dyson lastvecindex = vecindex; 96102c04a2fSJohn Dyson addr += PAGE_SIZE; 96202c04a2fSJohn Dyson } 963867a482dSJohn Dyson } 964867a482dSJohn Dyson 965867a482dSJohn Dyson /* 966dd2622a8SAlan Cox * subyte may page fault. In case it needs to modify 967dd2622a8SAlan Cox * the map, we release the lock. 968dd2622a8SAlan Cox */ 969dd2622a8SAlan Cox vm_map_unlock_read(map); 970dd2622a8SAlan Cox 971dd2622a8SAlan Cox /* 972867a482dSJohn Dyson * Zero the last entries in the byte vector. 973867a482dSJohn Dyson */ 974867a482dSJohn Dyson vecindex = OFF_TO_IDX(end - first_addr); 975867a482dSJohn Dyson while ((lastvecindex + 1) < vecindex) { 976867a482dSJohn Dyson error = subyte(vec + lastvecindex, 0); 977867a482dSJohn Dyson if (error) { 978d2c60af8SMatthew Dillon error = EFAULT; 979d2c60af8SMatthew Dillon goto done2; 980867a482dSJohn Dyson } 981867a482dSJohn Dyson ++lastvecindex; 982867a482dSJohn Dyson } 983867a482dSJohn Dyson 984dd2622a8SAlan Cox /* 985dd2622a8SAlan Cox * If the map has changed, due to the subyte, the previous 986dd2622a8SAlan Cox * output may be invalid. 987dd2622a8SAlan Cox */ 988dd2622a8SAlan Cox vm_map_lock_read(map); 989dd2622a8SAlan Cox if (timestamp != map->timestamp) 990dd2622a8SAlan Cox goto RestartScan; 991eff50fcdSAlan Cox vm_map_unlock_read(map); 992d2c60af8SMatthew Dillon done2: 993d2c60af8SMatthew Dillon return (error); 994df8bae1dSRodney W. Grimes } 995df8bae1dSRodney W. Grimes 996d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 997df8bae1dSRodney W. Grimes struct mlock_args { 998651bb817SAlexander Langer const void *addr; 999df8bae1dSRodney W. Grimes size_t len; 1000df8bae1dSRodney W. Grimes }; 1001d2d3e875SBruce Evans #endif 1002d2c60af8SMatthew Dillon /* 1003d2c60af8SMatthew Dillon * MPSAFE 1004d2c60af8SMatthew Dillon */ 1005df8bae1dSRodney W. Grimes int 10068451d0ddSKip Macy sys_mlock(td, uap) 1007b40ce416SJulian Elischer struct thread *td; 1008df8bae1dSRodney W. Grimes struct mlock_args *uap; 1009df8bae1dSRodney W. Grimes { 1010f0ea4612SDon Lewis struct proc *proc; 1011bb734798SDon Lewis vm_offset_t addr, end, last, start; 1012bb734798SDon Lewis vm_size_t npages, size; 10131ba5ad42SEdward Tomasz Napierala unsigned long nsize; 1014bb734798SDon Lewis int error; 1015df8bae1dSRodney W. Grimes 1016acd3428bSRobert Watson error = priv_check(td, PRIV_VM_MLOCK); 101747934cefSDon Lewis if (error) 101847934cefSDon Lewis return (error); 101916929939SDon Lewis addr = (vm_offset_t)uap->addr; 102016929939SDon Lewis size = uap->len; 1021bb734798SDon Lewis last = addr + size; 102216929939SDon Lewis start = trunc_page(addr); 1023bb734798SDon Lewis end = round_page(last); 1024bb734798SDon Lewis if (last < addr || end < addr) 1025df8bae1dSRodney W. Grimes return (EINVAL); 102616929939SDon Lewis npages = atop(end - start); 102716929939SDon Lewis if (npages > vm_page_max_wired) 102816929939SDon Lewis return (ENOMEM); 1029f0ea4612SDon Lewis proc = td->td_proc; 103047934cefSDon Lewis PROC_LOCK(proc); 10311ba5ad42SEdward Tomasz Napierala nsize = ptoa(npages + 10321ba5ad42SEdward Tomasz Napierala pmap_wired_count(vm_map_pmap(&proc->p_vmspace->vm_map))); 10331ba5ad42SEdward Tomasz Napierala if (nsize > lim_cur(proc, RLIMIT_MEMLOCK)) { 103447934cefSDon Lewis PROC_UNLOCK(proc); 10354a40e3d4SJohn Dyson return (ENOMEM); 103691d5354aSJohn Baldwin } 103747934cefSDon Lewis PROC_UNLOCK(proc); 10382feb50bfSAttilio Rao if (npages + cnt.v_wire_count > vm_page_max_wired) 103916929939SDon Lewis return (EAGAIN); 1040afcc55f3SEdward Tomasz Napierala #ifdef RACCT 10411ba5ad42SEdward Tomasz Napierala PROC_LOCK(proc); 10421ba5ad42SEdward Tomasz Napierala error = racct_set(proc, RACCT_MEMLOCK, nsize); 10431ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(proc); 10441ba5ad42SEdward Tomasz Napierala if (error != 0) 10451ba5ad42SEdward Tomasz Napierala return (ENOMEM); 1046afcc55f3SEdward Tomasz Napierala #endif 104716929939SDon Lewis error = vm_map_wire(&proc->p_vmspace->vm_map, start, end, 104816929939SDon Lewis VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); 1049afcc55f3SEdward Tomasz Napierala #ifdef RACCT 10501ba5ad42SEdward Tomasz Napierala if (error != KERN_SUCCESS) { 10511ba5ad42SEdward Tomasz Napierala PROC_LOCK(proc); 10521ba5ad42SEdward Tomasz Napierala racct_set(proc, RACCT_MEMLOCK, 10531ba5ad42SEdward Tomasz Napierala ptoa(pmap_wired_count(vm_map_pmap(&proc->p_vmspace->vm_map)))); 10541ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(proc); 10551ba5ad42SEdward Tomasz Napierala } 1056afcc55f3SEdward Tomasz Napierala #endif 1057df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 1058df8bae1dSRodney W. Grimes } 1059df8bae1dSRodney W. Grimes 1060d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 10614a40e3d4SJohn Dyson struct mlockall_args { 10624a40e3d4SJohn Dyson int how; 10634a40e3d4SJohn Dyson }; 10644a40e3d4SJohn Dyson #endif 10654a40e3d4SJohn Dyson 1066d2c60af8SMatthew Dillon /* 1067d2c60af8SMatthew Dillon * MPSAFE 1068d2c60af8SMatthew Dillon */ 10694a40e3d4SJohn Dyson int 10708451d0ddSKip Macy sys_mlockall(td, uap) 1071b40ce416SJulian Elischer struct thread *td; 10724a40e3d4SJohn Dyson struct mlockall_args *uap; 10734a40e3d4SJohn Dyson { 1074abd498aaSBruce M Simpson vm_map_t map; 1075abd498aaSBruce M Simpson int error; 1076abd498aaSBruce M Simpson 1077abd498aaSBruce M Simpson map = &td->td_proc->p_vmspace->vm_map; 1078abd498aaSBruce M Simpson error = 0; 1079abd498aaSBruce M Simpson 1080abd498aaSBruce M Simpson if ((uap->how == 0) || ((uap->how & ~(MCL_CURRENT|MCL_FUTURE)) != 0)) 1081abd498aaSBruce M Simpson return (EINVAL); 1082abd498aaSBruce M Simpson 108311f7ddc5SBruce M Simpson #if 0 1084abd498aaSBruce M Simpson /* 1085abd498aaSBruce M Simpson * If wiring all pages in the process would cause it to exceed 1086abd498aaSBruce M Simpson * a hard resource limit, return ENOMEM. 1087abd498aaSBruce M Simpson */ 108891d5354aSJohn Baldwin PROC_LOCK(td->td_proc); 1089fd6f4ffbSEdward Tomasz Napierala if (map->size > lim_cur(td->td_proc, RLIMIT_MEMLOCK)) { 109091d5354aSJohn Baldwin PROC_UNLOCK(td->td_proc); 1091abd498aaSBruce M Simpson return (ENOMEM); 109291d5354aSJohn Baldwin } 109391d5354aSJohn Baldwin PROC_UNLOCK(td->td_proc); 1094abd498aaSBruce M Simpson #else 1095acd3428bSRobert Watson error = priv_check(td, PRIV_VM_MLOCK); 1096abd498aaSBruce M Simpson if (error) 1097abd498aaSBruce M Simpson return (error); 1098abd498aaSBruce M Simpson #endif 1099afcc55f3SEdward Tomasz Napierala #ifdef RACCT 11001ba5ad42SEdward Tomasz Napierala PROC_LOCK(td->td_proc); 11011ba5ad42SEdward Tomasz Napierala error = racct_set(td->td_proc, RACCT_MEMLOCK, map->size); 11021ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc); 11031ba5ad42SEdward Tomasz Napierala if (error != 0) 11041ba5ad42SEdward Tomasz Napierala return (ENOMEM); 1105afcc55f3SEdward Tomasz Napierala #endif 1106abd498aaSBruce M Simpson 1107abd498aaSBruce M Simpson if (uap->how & MCL_FUTURE) { 1108abd498aaSBruce M Simpson vm_map_lock(map); 1109abd498aaSBruce M Simpson vm_map_modflags(map, MAP_WIREFUTURE, 0); 1110abd498aaSBruce M Simpson vm_map_unlock(map); 1111abd498aaSBruce M Simpson error = 0; 1112abd498aaSBruce M Simpson } 1113abd498aaSBruce M Simpson 1114abd498aaSBruce M Simpson if (uap->how & MCL_CURRENT) { 1115abd498aaSBruce M Simpson /* 1116abd498aaSBruce M Simpson * P1003.1-2001 mandates that all currently mapped pages 1117abd498aaSBruce M Simpson * will be memory resident and locked (wired) upon return 1118abd498aaSBruce M Simpson * from mlockall(). vm_map_wire() will wire pages, by 1119abd498aaSBruce M Simpson * calling vm_fault_wire() for each page in the region. 1120abd498aaSBruce M Simpson */ 1121abd498aaSBruce M Simpson error = vm_map_wire(map, vm_map_min(map), vm_map_max(map), 1122abd498aaSBruce M Simpson VM_MAP_WIRE_USER|VM_MAP_WIRE_HOLESOK); 1123abd498aaSBruce M Simpson error = (error == KERN_SUCCESS ? 0 : EAGAIN); 1124abd498aaSBruce M Simpson } 1125afcc55f3SEdward Tomasz Napierala #ifdef RACCT 11261ba5ad42SEdward Tomasz Napierala if (error != KERN_SUCCESS) { 11271ba5ad42SEdward Tomasz Napierala PROC_LOCK(td->td_proc); 11281ba5ad42SEdward Tomasz Napierala racct_set(td->td_proc, RACCT_MEMLOCK, 11291ba5ad42SEdward Tomasz Napierala ptoa(pmap_wired_count(vm_map_pmap(&td->td_proc->p_vmspace->vm_map)))); 11301ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc); 11311ba5ad42SEdward Tomasz Napierala } 1132afcc55f3SEdward Tomasz Napierala #endif 1133abd498aaSBruce M Simpson 1134abd498aaSBruce M Simpson return (error); 11354a40e3d4SJohn Dyson } 11364a40e3d4SJohn Dyson 11374a40e3d4SJohn Dyson #ifndef _SYS_SYSPROTO_H_ 1138fa721254SAlfred Perlstein struct munlockall_args { 1139abd498aaSBruce M Simpson register_t dummy; 11404a40e3d4SJohn Dyson }; 11414a40e3d4SJohn Dyson #endif 11424a40e3d4SJohn Dyson 1143d2c60af8SMatthew Dillon /* 1144d2c60af8SMatthew Dillon * MPSAFE 1145d2c60af8SMatthew Dillon */ 11464a40e3d4SJohn Dyson int 11478451d0ddSKip Macy sys_munlockall(td, uap) 1148b40ce416SJulian Elischer struct thread *td; 11494a40e3d4SJohn Dyson struct munlockall_args *uap; 11504a40e3d4SJohn Dyson { 1151abd498aaSBruce M Simpson vm_map_t map; 1152abd498aaSBruce M Simpson int error; 1153abd498aaSBruce M Simpson 1154abd498aaSBruce M Simpson map = &td->td_proc->p_vmspace->vm_map; 1155acd3428bSRobert Watson error = priv_check(td, PRIV_VM_MUNLOCK); 1156abd498aaSBruce M Simpson if (error) 1157abd498aaSBruce M Simpson return (error); 1158abd498aaSBruce M Simpson 1159abd498aaSBruce M Simpson /* Clear the MAP_WIREFUTURE flag from this vm_map. */ 1160abd498aaSBruce M Simpson vm_map_lock(map); 1161abd498aaSBruce M Simpson vm_map_modflags(map, 0, MAP_WIREFUTURE); 1162abd498aaSBruce M Simpson vm_map_unlock(map); 1163abd498aaSBruce M Simpson 1164abd498aaSBruce M Simpson /* Forcibly unwire all pages. */ 1165abd498aaSBruce M Simpson error = vm_map_unwire(map, vm_map_min(map), vm_map_max(map), 1166abd498aaSBruce M Simpson VM_MAP_WIRE_USER|VM_MAP_WIRE_HOLESOK); 1167afcc55f3SEdward Tomasz Napierala #ifdef RACCT 11681ba5ad42SEdward Tomasz Napierala if (error == KERN_SUCCESS) { 11691ba5ad42SEdward Tomasz Napierala PROC_LOCK(td->td_proc); 11701ba5ad42SEdward Tomasz Napierala racct_set(td->td_proc, RACCT_MEMLOCK, 0); 11711ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc); 11721ba5ad42SEdward Tomasz Napierala } 1173afcc55f3SEdward Tomasz Napierala #endif 1174abd498aaSBruce M Simpson 1175abd498aaSBruce M Simpson return (error); 11764a40e3d4SJohn Dyson } 11774a40e3d4SJohn Dyson 11784a40e3d4SJohn Dyson #ifndef _SYS_SYSPROTO_H_ 1179df8bae1dSRodney W. Grimes struct munlock_args { 1180651bb817SAlexander Langer const void *addr; 1181df8bae1dSRodney W. Grimes size_t len; 1182df8bae1dSRodney W. Grimes }; 1183d2d3e875SBruce Evans #endif 1184d2c60af8SMatthew Dillon /* 1185d2c60af8SMatthew Dillon * MPSAFE 1186d2c60af8SMatthew Dillon */ 1187df8bae1dSRodney W. Grimes int 11888451d0ddSKip Macy sys_munlock(td, uap) 1189b40ce416SJulian Elischer struct thread *td; 1190df8bae1dSRodney W. Grimes struct munlock_args *uap; 1191df8bae1dSRodney W. Grimes { 1192bb734798SDon Lewis vm_offset_t addr, end, last, start; 119316929939SDon Lewis vm_size_t size; 1194df8bae1dSRodney W. Grimes int error; 1195df8bae1dSRodney W. Grimes 1196acd3428bSRobert Watson error = priv_check(td, PRIV_VM_MUNLOCK); 119747934cefSDon Lewis if (error) 119847934cefSDon Lewis return (error); 119916929939SDon Lewis addr = (vm_offset_t)uap->addr; 120016929939SDon Lewis size = uap->len; 1201bb734798SDon Lewis last = addr + size; 120216929939SDon Lewis start = trunc_page(addr); 1203bb734798SDon Lewis end = round_page(last); 1204bb734798SDon Lewis if (last < addr || end < addr) 1205df8bae1dSRodney W. Grimes return (EINVAL); 120616929939SDon Lewis error = vm_map_unwire(&td->td_proc->p_vmspace->vm_map, start, end, 120716929939SDon Lewis VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); 1208afcc55f3SEdward Tomasz Napierala #ifdef RACCT 12091ba5ad42SEdward Tomasz Napierala if (error == KERN_SUCCESS) { 12101ba5ad42SEdward Tomasz Napierala PROC_LOCK(td->td_proc); 12111ba5ad42SEdward Tomasz Napierala racct_sub(td->td_proc, RACCT_MEMLOCK, ptoa(end - start)); 12121ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc); 12131ba5ad42SEdward Tomasz Napierala } 1214afcc55f3SEdward Tomasz Napierala #endif 1215df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 1216df8bae1dSRodney W. Grimes } 1217df8bae1dSRodney W. Grimes 1218df8bae1dSRodney W. Grimes /* 1219c8daea13SAlexander Kabaev * vm_mmap_vnode() 1220c8daea13SAlexander Kabaev * 1221c8daea13SAlexander Kabaev * MPSAFE 1222c8daea13SAlexander Kabaev * 1223c8daea13SAlexander Kabaev * Helper function for vm_mmap. Perform sanity check specific for mmap 1224c8daea13SAlexander Kabaev * operations on vnodes. 1225c8daea13SAlexander Kabaev */ 1226c8daea13SAlexander Kabaev int 1227c8daea13SAlexander Kabaev vm_mmap_vnode(struct thread *td, vm_size_t objsize, 1228c8daea13SAlexander Kabaev vm_prot_t prot, vm_prot_t *maxprotp, int *flagsp, 122964345f0bSJohn Baldwin struct vnode *vp, vm_ooffset_t *foffp, vm_object_t *objp) 1230c8daea13SAlexander Kabaev { 1231c8daea13SAlexander Kabaev struct vattr va; 1232c8daea13SAlexander Kabaev vm_object_t obj; 123364345f0bSJohn Baldwin vm_offset_t foff; 1234ae51ff11SJeff Roberson struct mount *mp; 12350359a12eSAttilio Rao struct ucred *cred; 123664345f0bSJohn Baldwin int error, flags; 1237ae51ff11SJeff Roberson int vfslocked; 1238c8daea13SAlexander Kabaev 1239ae51ff11SJeff Roberson mp = vp->v_mount; 12400359a12eSAttilio Rao cred = td->td_ucred; 1241ae51ff11SJeff Roberson vfslocked = VFS_LOCK_GIANT(mp); 1242fa3de770SJohn Baldwin if ((error = vget(vp, LK_SHARED, td)) != 0) { 1243ae51ff11SJeff Roberson VFS_UNLOCK_GIANT(vfslocked); 1244c8daea13SAlexander Kabaev return (error); 1245c8daea13SAlexander Kabaev } 124664345f0bSJohn Baldwin foff = *foffp; 1247c8daea13SAlexander Kabaev flags = *flagsp; 12488516dd18SPoul-Henning Kamp obj = vp->v_object; 1249c8daea13SAlexander Kabaev if (vp->v_type == VREG) { 1250c8daea13SAlexander Kabaev /* 1251c8daea13SAlexander Kabaev * Get the proper underlying object 1252c8daea13SAlexander Kabaev */ 12538516dd18SPoul-Henning Kamp if (obj == NULL) { 1254c8daea13SAlexander Kabaev error = EINVAL; 1255c8daea13SAlexander Kabaev goto done; 1256c8daea13SAlexander Kabaev } 1257c8daea13SAlexander Kabaev if (obj->handle != vp) { 1258c8daea13SAlexander Kabaev vput(vp); 1259c8daea13SAlexander Kabaev vp = (struct vnode*)obj->handle; 1260fa3de770SJohn Baldwin vget(vp, LK_SHARED, td); 1261c8daea13SAlexander Kabaev } 1262c8daea13SAlexander Kabaev } else if (vp->v_type == VCHR) { 126364345f0bSJohn Baldwin error = vm_mmap_cdev(td, objsize, prot, maxprotp, flagsp, 126464345f0bSJohn Baldwin vp->v_rdev, foffp, objp); 126564345f0bSJohn Baldwin if (error == 0) 126664345f0bSJohn Baldwin goto mark_atime; 126791a35e78SKonstantin Belousov goto done; 1268c8daea13SAlexander Kabaev } else { 1269c8daea13SAlexander Kabaev error = EINVAL; 1270c8daea13SAlexander Kabaev goto done; 1271c8daea13SAlexander Kabaev } 12720359a12eSAttilio Rao if ((error = VOP_GETATTR(vp, &va, cred))) 1273c8daea13SAlexander Kabaev goto done; 1274c92163dcSChristian S.J. Peron #ifdef MAC 12750359a12eSAttilio Rao error = mac_vnode_check_mmap(cred, vp, prot, flags); 1276c92163dcSChristian S.J. Peron if (error != 0) 1277c92163dcSChristian S.J. Peron goto done; 1278c92163dcSChristian S.J. Peron #endif 1279c8daea13SAlexander Kabaev if ((flags & MAP_SHARED) != 0) { 1280c8daea13SAlexander Kabaev if ((va.va_flags & (SF_SNAPSHOT|IMMUTABLE|APPEND)) != 0) { 1281c8daea13SAlexander Kabaev if (prot & PROT_WRITE) { 1282c8daea13SAlexander Kabaev error = EPERM; 1283c8daea13SAlexander Kabaev goto done; 1284c8daea13SAlexander Kabaev } 1285c8daea13SAlexander Kabaev *maxprotp &= ~VM_PROT_WRITE; 1286c8daea13SAlexander Kabaev } 1287c8daea13SAlexander Kabaev } 1288c8daea13SAlexander Kabaev /* 1289c8daea13SAlexander Kabaev * If it is a regular file without any references 1290c8daea13SAlexander Kabaev * we do not need to sync it. 1291c8daea13SAlexander Kabaev * Adjust object size to be the size of actual file. 1292c8daea13SAlexander Kabaev */ 1293c8daea13SAlexander Kabaev objsize = round_page(va.va_size); 1294c8daea13SAlexander Kabaev if (va.va_nlink == 0) 1295c8daea13SAlexander Kabaev flags |= MAP_NOSYNC; 12963364c323SKonstantin Belousov obj = vm_pager_allocate(OBJT_VNODE, vp, objsize, prot, foff, td->td_ucred); 1297c8daea13SAlexander Kabaev if (obj == NULL) { 129864345f0bSJohn Baldwin error = ENOMEM; 1299c8daea13SAlexander Kabaev goto done; 1300c8daea13SAlexander Kabaev } 1301c8daea13SAlexander Kabaev *objp = obj; 1302c8daea13SAlexander Kabaev *flagsp = flags; 130364345f0bSJohn Baldwin 130464345f0bSJohn Baldwin mark_atime: 13050359a12eSAttilio Rao vfs_mark_atime(vp, cred); 13061e309003SDiomidis Spinellis 1307c8daea13SAlexander Kabaev done: 1308c8daea13SAlexander Kabaev vput(vp); 1309ae51ff11SJeff Roberson VFS_UNLOCK_GIANT(vfslocked); 1310c8daea13SAlexander Kabaev return (error); 1311c8daea13SAlexander Kabaev } 1312c8daea13SAlexander Kabaev 1313c8daea13SAlexander Kabaev /* 131498df9218SJohn Baldwin * vm_mmap_cdev() 131598df9218SJohn Baldwin * 131698df9218SJohn Baldwin * MPSAFE 131798df9218SJohn Baldwin * 131898df9218SJohn Baldwin * Helper function for vm_mmap. Perform sanity check specific for mmap 131998df9218SJohn Baldwin * operations on cdevs. 132098df9218SJohn Baldwin */ 132198df9218SJohn Baldwin int 132298df9218SJohn Baldwin vm_mmap_cdev(struct thread *td, vm_size_t objsize, 132398df9218SJohn Baldwin vm_prot_t prot, vm_prot_t *maxprotp, int *flagsp, 132464345f0bSJohn Baldwin struct cdev *cdev, vm_ooffset_t *foff, vm_object_t *objp) 132598df9218SJohn Baldwin { 132698df9218SJohn Baldwin vm_object_t obj; 132791a35e78SKonstantin Belousov struct cdevsw *dsw; 13283979450bSKonstantin Belousov int error, flags, ref; 132998df9218SJohn Baldwin 133098df9218SJohn Baldwin flags = *flagsp; 133198df9218SJohn Baldwin 13323979450bSKonstantin Belousov dsw = dev_refthread(cdev, &ref); 133391a35e78SKonstantin Belousov if (dsw == NULL) 133491a35e78SKonstantin Belousov return (ENXIO); 133591a35e78SKonstantin Belousov if (dsw->d_flags & D_MMAP_ANON) { 13363979450bSKonstantin Belousov dev_relthread(cdev, ref); 133798df9218SJohn Baldwin *maxprotp = VM_PROT_ALL; 133898df9218SJohn Baldwin *flagsp |= MAP_ANON; 133998df9218SJohn Baldwin return (0); 134098df9218SJohn Baldwin } 134198df9218SJohn Baldwin /* 134264345f0bSJohn Baldwin * cdevs do not provide private mappings of any kind. 134398df9218SJohn Baldwin */ 134498df9218SJohn Baldwin if ((*maxprotp & VM_PROT_WRITE) == 0 && 134564345f0bSJohn Baldwin (prot & PROT_WRITE) != 0) { 13463979450bSKonstantin Belousov dev_relthread(cdev, ref); 134798df9218SJohn Baldwin return (EACCES); 134864345f0bSJohn Baldwin } 134964345f0bSJohn Baldwin if (flags & (MAP_PRIVATE|MAP_COPY)) { 13503979450bSKonstantin Belousov dev_relthread(cdev, ref); 135198df9218SJohn Baldwin return (EINVAL); 135264345f0bSJohn Baldwin } 135398df9218SJohn Baldwin /* 135498df9218SJohn Baldwin * Force device mappings to be shared. 135598df9218SJohn Baldwin */ 135698df9218SJohn Baldwin flags |= MAP_SHARED; 135798df9218SJohn Baldwin #ifdef MAC_XXX 135864345f0bSJohn Baldwin error = mac_cdev_check_mmap(td->td_ucred, cdev, prot); 135964345f0bSJohn Baldwin if (error != 0) { 13603979450bSKonstantin Belousov dev_relthread(cdev, ref); 136198df9218SJohn Baldwin return (error); 136264345f0bSJohn Baldwin } 136398df9218SJohn Baldwin #endif 136464345f0bSJohn Baldwin /* 136564345f0bSJohn Baldwin * First, try d_mmap_single(). If that is not implemented 136664345f0bSJohn Baldwin * (returns ENODEV), fall back to using the device pager. 136764345f0bSJohn Baldwin * Note that d_mmap_single() must return a reference to the 136864345f0bSJohn Baldwin * object (it needs to bump the reference count of the object 136964345f0bSJohn Baldwin * it returns somehow). 137064345f0bSJohn Baldwin * 137164345f0bSJohn Baldwin * XXX assumes VM_PROT_* == PROT_* 137264345f0bSJohn Baldwin */ 137364345f0bSJohn Baldwin error = dsw->d_mmap_single(cdev, foff, objsize, objp, (int)prot); 13743979450bSKonstantin Belousov dev_relthread(cdev, ref); 137564345f0bSJohn Baldwin if (error != ENODEV) 137664345f0bSJohn Baldwin return (error); 13773364c323SKonstantin Belousov obj = vm_pager_allocate(OBJT_DEVICE, cdev, objsize, prot, *foff, 13783364c323SKonstantin Belousov td->td_ucred); 137998df9218SJohn Baldwin if (obj == NULL) 138098df9218SJohn Baldwin return (EINVAL); 138198df9218SJohn Baldwin *objp = obj; 138298df9218SJohn Baldwin *flagsp = flags; 138398df9218SJohn Baldwin return (0); 138498df9218SJohn Baldwin } 138598df9218SJohn Baldwin 138698df9218SJohn Baldwin /* 13878e38aeffSJohn Baldwin * vm_mmap_shm() 13888e38aeffSJohn Baldwin * 13898e38aeffSJohn Baldwin * MPSAFE 13908e38aeffSJohn Baldwin * 13918e38aeffSJohn Baldwin * Helper function for vm_mmap. Perform sanity check specific for mmap 13928e38aeffSJohn Baldwin * operations on shm file descriptors. 13938e38aeffSJohn Baldwin */ 13948e38aeffSJohn Baldwin int 13958e38aeffSJohn Baldwin vm_mmap_shm(struct thread *td, vm_size_t objsize, 13968e38aeffSJohn Baldwin vm_prot_t prot, vm_prot_t *maxprotp, int *flagsp, 13978e38aeffSJohn Baldwin struct shmfd *shmfd, vm_ooffset_t foff, vm_object_t *objp) 13988e38aeffSJohn Baldwin { 13998e38aeffSJohn Baldwin int error; 14008e38aeffSJohn Baldwin 1401da048309SAlan Cox if ((*flagsp & MAP_SHARED) != 0 && 1402da048309SAlan Cox (*maxprotp & VM_PROT_WRITE) == 0 && 14038e38aeffSJohn Baldwin (prot & PROT_WRITE) != 0) 14048e38aeffSJohn Baldwin return (EACCES); 14058e38aeffSJohn Baldwin #ifdef MAC 14068e38aeffSJohn Baldwin error = mac_posixshm_check_mmap(td->td_ucred, shmfd, prot, *flagsp); 14078e38aeffSJohn Baldwin if (error != 0) 14088e38aeffSJohn Baldwin return (error); 14098e38aeffSJohn Baldwin #endif 14108e38aeffSJohn Baldwin error = shm_mmap(shmfd, objsize, foff, objp); 14118e38aeffSJohn Baldwin if (error) 14128e38aeffSJohn Baldwin return (error); 14138e38aeffSJohn Baldwin return (0); 14148e38aeffSJohn Baldwin } 14158e38aeffSJohn Baldwin 14168e38aeffSJohn Baldwin /* 1417d2c60af8SMatthew Dillon * vm_mmap() 1418d2c60af8SMatthew Dillon * 1419d2c60af8SMatthew Dillon * MPSAFE 1420d2c60af8SMatthew Dillon * 1421d2c60af8SMatthew Dillon * Internal version of mmap. Currently used by mmap, exec, and sys5 1422d2c60af8SMatthew Dillon * shared memory. Handle is either a vnode pointer or NULL for MAP_ANON. 1423df8bae1dSRodney W. Grimes */ 1424df8bae1dSRodney W. Grimes int 1425b9dcd593SBruce Evans vm_mmap(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, 1426b9dcd593SBruce Evans vm_prot_t maxprot, int flags, 142798df9218SJohn Baldwin objtype_t handle_type, void *handle, 1428b9dcd593SBruce Evans vm_ooffset_t foff) 1429df8bae1dSRodney W. Grimes { 1430df8bae1dSRodney W. Grimes boolean_t fitit; 14316bda842dSMatt Jacob vm_object_t object = NULL; 1432df8bae1dSRodney W. Grimes int rv = KERN_SUCCESS; 143320eec4bbSAlan Cox int docow, error; 1434b40ce416SJulian Elischer struct thread *td = curthread; 1435df8bae1dSRodney W. Grimes 1436df8bae1dSRodney W. Grimes if (size == 0) 1437df8bae1dSRodney W. Grimes return (0); 1438df8bae1dSRodney W. Grimes 1439749474f2SPeter Wemm size = round_page(size); 1440df8bae1dSRodney W. Grimes 1441*a6492969SAlan Cox if (map == &td->td_proc->p_vmspace->vm_map) { 144291d5354aSJohn Baldwin PROC_LOCK(td->td_proc); 1443*a6492969SAlan Cox if (map->size + size > lim_cur(td->td_proc, RLIMIT_VMEM)) { 144491d5354aSJohn Baldwin PROC_UNLOCK(td->td_proc); 1445070f64feSMatthew Dillon return (ENOMEM); 1446070f64feSMatthew Dillon } 1447*a6492969SAlan Cox if (racct_set(td->td_proc, RACCT_VMEM, map->size + size)) { 14481ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc); 14491ba5ad42SEdward Tomasz Napierala return (ENOMEM); 14501ba5ad42SEdward Tomasz Napierala } 145191d5354aSJohn Baldwin PROC_UNLOCK(td->td_proc); 1452*a6492969SAlan Cox } 1453070f64feSMatthew Dillon 1454df8bae1dSRodney W. Grimes /* 1455bc9ad247SDavid Greenman * We currently can only deal with page aligned file offsets. 1456bc9ad247SDavid Greenman * The check is here rather than in the syscall because the 1457bc9ad247SDavid Greenman * kernel calls this function internally for other mmaping 1458bc9ad247SDavid Greenman * operations (such as in exec) and non-aligned offsets will 1459bc9ad247SDavid Greenman * cause pmap inconsistencies...so we want to be sure to 1460bc9ad247SDavid Greenman * disallow this in all cases. 1461bc9ad247SDavid Greenman */ 1462bc9ad247SDavid Greenman if (foff & PAGE_MASK) 1463bc9ad247SDavid Greenman return (EINVAL); 1464bc9ad247SDavid Greenman 146506cb7259SDavid Greenman if ((flags & MAP_FIXED) == 0) { 146606cb7259SDavid Greenman fitit = TRUE; 146706cb7259SDavid Greenman *addr = round_page(*addr); 146806cb7259SDavid Greenman } else { 146906cb7259SDavid Greenman if (*addr != trunc_page(*addr)) 147006cb7259SDavid Greenman return (EINVAL); 147106cb7259SDavid Greenman fitit = FALSE; 147206cb7259SDavid Greenman } 1473bc9ad247SDavid Greenman /* 147424a1cce3SDavid Greenman * Lookup/allocate object. 1475df8bae1dSRodney W. Grimes */ 147698df9218SJohn Baldwin switch (handle_type) { 147798df9218SJohn Baldwin case OBJT_DEVICE: 147898df9218SJohn Baldwin error = vm_mmap_cdev(td, size, prot, &maxprot, &flags, 147964345f0bSJohn Baldwin handle, &foff, &object); 148098df9218SJohn Baldwin break; 148198df9218SJohn Baldwin case OBJT_VNODE: 1482c8daea13SAlexander Kabaev error = vm_mmap_vnode(td, size, prot, &maxprot, &flags, 148364345f0bSJohn Baldwin handle, &foff, &object); 148498df9218SJohn Baldwin break; 14858e38aeffSJohn Baldwin case OBJT_SWAP: 14868e38aeffSJohn Baldwin error = vm_mmap_shm(td, size, prot, &maxprot, &flags, 14878e38aeffSJohn Baldwin handle, foff, &object); 14888e38aeffSJohn Baldwin break; 148998df9218SJohn Baldwin case OBJT_DEFAULT: 149098df9218SJohn Baldwin if (handle == NULL) { 149198df9218SJohn Baldwin error = 0; 149298df9218SJohn Baldwin break; 149398df9218SJohn Baldwin } 149498df9218SJohn Baldwin /* FALLTHROUGH */ 149598df9218SJohn Baldwin default: 149698df9218SJohn Baldwin error = EINVAL; 14976bda842dSMatt Jacob break; 149898df9218SJohn Baldwin } 149998df9218SJohn Baldwin if (error) 1500c8daea13SAlexander Kabaev return (error); 15015f55e841SDavid Greenman if (flags & MAP_ANON) { 1502c8daea13SAlexander Kabaev object = NULL; 1503c8daea13SAlexander Kabaev docow = 0; 15045f55e841SDavid Greenman /* 15055f55e841SDavid Greenman * Unnamed anonymous regions always start at 0. 15065f55e841SDavid Greenman */ 150767bf6868SJohn Dyson if (handle == 0) 15085f55e841SDavid Greenman foff = 0; 150974ffb9afSAlan Cox } else if (flags & MAP_PREFAULT_READ) 151074ffb9afSAlan Cox docow = MAP_PREFAULT; 151174ffb9afSAlan Cox else 15124738fa09SAlan Cox docow = MAP_PREFAULT_PARTIAL; 1513df8bae1dSRodney W. Grimes 15144f79d873SMatthew Dillon if ((flags & (MAP_ANON|MAP_SHARED)) == 0) 15154738fa09SAlan Cox docow |= MAP_COPY_ON_WRITE; 15164f79d873SMatthew Dillon if (flags & MAP_NOSYNC) 15174f79d873SMatthew Dillon docow |= MAP_DISABLE_SYNCER; 15189730a5daSPaul Saab if (flags & MAP_NOCORE) 15199730a5daSPaul Saab docow |= MAP_DISABLE_COREDUMP; 15208211bd45SKonstantin Belousov /* Shared memory is also shared with children. */ 15218211bd45SKonstantin Belousov if (flags & MAP_SHARED) 15228211bd45SKonstantin Belousov docow |= MAP_INHERIT_SHARE; 15235850152dSJohn Dyson 15242267af78SJulian Elischer if (flags & MAP_STACK) 1525fd75d710SMarcel Moolenaar rv = vm_map_stack(map, *addr, size, prot, maxprot, 1526fd75d710SMarcel Moolenaar docow | MAP_STACK_GROWS_DOWN); 1527d239bd3cSKonstantin Belousov else if (fitit) 1528d0a83a83SAlan Cox rv = vm_map_find(map, object, foff, addr, size, 1529d0a83a83SAlan Cox object != NULL && object->type == OBJT_DEVICE ? 1530d0a83a83SAlan Cox VMFS_ALIGNED_SPACE : VMFS_ANY_SPACE, prot, maxprot, docow); 15312267af78SJulian Elischer else 1532b8ca4ef2SAlan Cox rv = vm_map_fixed(map, object, foff, *addr, size, 1533bd7e5f99SJohn Dyson prot, maxprot, docow); 1534bd7e5f99SJohn Dyson 1535d2c60af8SMatthew Dillon if (rv != KERN_SUCCESS) { 15367fb0c17eSDavid Greenman /* 153724a1cce3SDavid Greenman * Lose the object reference. Will destroy the 153824a1cce3SDavid Greenman * object if it's an unnamed anonymous mapping 153924a1cce3SDavid Greenman * or named anonymous without other references. 15407fb0c17eSDavid Greenman */ 1541df8bae1dSRodney W. Grimes vm_object_deallocate(object); 1542df8bae1dSRodney W. Grimes } 1543abd498aaSBruce M Simpson 1544abd498aaSBruce M Simpson /* 1545abd498aaSBruce M Simpson * If the process has requested that all future mappings 1546abd498aaSBruce M Simpson * be wired, then heed this. 1547abd498aaSBruce M Simpson */ 1548abd498aaSBruce M Simpson if ((rv == KERN_SUCCESS) && (map->flags & MAP_WIREFUTURE)) 1549abd498aaSBruce M Simpson vm_map_wire(map, *addr, *addr + size, 1550abd498aaSBruce M Simpson VM_MAP_WIRE_USER|VM_MAP_WIRE_NOHOLES); 1551abd498aaSBruce M Simpson 15522e32165cSKonstantin Belousov return (vm_mmap_to_errno(rv)); 15532e32165cSKonstantin Belousov } 15542e32165cSKonstantin Belousov 15552e32165cSKonstantin Belousov int 15562e32165cSKonstantin Belousov vm_mmap_to_errno(int rv) 15572e32165cSKonstantin Belousov { 15582e32165cSKonstantin Belousov 1559df8bae1dSRodney W. Grimes switch (rv) { 1560df8bae1dSRodney W. Grimes case KERN_SUCCESS: 1561df8bae1dSRodney W. Grimes return (0); 1562df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 1563df8bae1dSRodney W. Grimes case KERN_NO_SPACE: 1564df8bae1dSRodney W. Grimes return (ENOMEM); 1565df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 1566df8bae1dSRodney W. Grimes return (EACCES); 1567df8bae1dSRodney W. Grimes default: 1568df8bae1dSRodney W. Grimes return (EINVAL); 1569df8bae1dSRodney W. Grimes } 1570df8bae1dSRodney W. Grimes } 1571