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> 8484110e7eSKonstantin Belousov #include <vm/vnode_pager.h> 85df8bae1dSRodney W. Grimes 8649874f6eSJoseph Koshy #ifdef HWPMC_HOOKS 8749874f6eSJoseph Koshy #include <sys/pmckern.h> 8849874f6eSJoseph Koshy #endif 8949874f6eSJoseph Koshy 90d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 91df8bae1dSRodney W. Grimes struct sbrk_args { 92df8bae1dSRodney W. Grimes int incr; 93df8bae1dSRodney W. Grimes }; 94d2d3e875SBruce Evans #endif 950d94caffSDavid Greenman 96c8daea13SAlexander Kabaev static int vm_mmap_vnode(struct thread *, vm_size_t, vm_prot_t, vm_prot_t *, 9784110e7eSKonstantin Belousov int *, struct vnode *, vm_ooffset_t *, vm_object_t *, boolean_t *); 9898df9218SJohn Baldwin static int vm_mmap_cdev(struct thread *, vm_size_t, vm_prot_t, vm_prot_t *, 9964345f0bSJohn Baldwin int *, struct cdev *, vm_ooffset_t *, vm_object_t *); 1008e38aeffSJohn Baldwin static int vm_mmap_shm(struct thread *, vm_size_t, vm_prot_t, vm_prot_t *, 1018e38aeffSJohn Baldwin int *, struct shmfd *, vm_ooffset_t, vm_object_t *); 102c8daea13SAlexander Kabaev 103d2c60af8SMatthew Dillon /* 104d2c60af8SMatthew Dillon * MPSAFE 105d2c60af8SMatthew Dillon */ 106df8bae1dSRodney W. Grimes /* ARGSUSED */ 107df8bae1dSRodney W. Grimes int 1088451d0ddSKip Macy sys_sbrk(td, uap) 109b40ce416SJulian Elischer struct thread *td; 110df8bae1dSRodney W. Grimes struct sbrk_args *uap; 111df8bae1dSRodney W. Grimes { 112df8bae1dSRodney W. Grimes /* Not yet implemented */ 113df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 114df8bae1dSRodney W. Grimes } 115df8bae1dSRodney W. Grimes 116d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 117df8bae1dSRodney W. Grimes struct sstk_args { 118df8bae1dSRodney W. Grimes int incr; 119df8bae1dSRodney W. Grimes }; 120d2d3e875SBruce Evans #endif 1210d94caffSDavid Greenman 122d2c60af8SMatthew Dillon /* 123d2c60af8SMatthew Dillon * MPSAFE 124d2c60af8SMatthew Dillon */ 125df8bae1dSRodney W. Grimes /* ARGSUSED */ 126df8bae1dSRodney W. Grimes int 1278451d0ddSKip Macy sys_sstk(td, uap) 128b40ce416SJulian Elischer struct thread *td; 129df8bae1dSRodney W. Grimes struct sstk_args *uap; 130df8bae1dSRodney W. Grimes { 131df8bae1dSRodney W. Grimes /* Not yet implemented */ 132df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 133df8bae1dSRodney W. Grimes } 134df8bae1dSRodney W. Grimes 1351930e303SPoul-Henning Kamp #if defined(COMPAT_43) 136d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 137df8bae1dSRodney W. Grimes struct getpagesize_args { 138df8bae1dSRodney W. Grimes int dummy; 139df8bae1dSRodney W. Grimes }; 140d2d3e875SBruce Evans #endif 1410d94caffSDavid Greenman 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); 511126d6082SKonstantin Belousov case KERN_FAILURE: 512126d6082SKonstantin Belousov return (EIO); 513df8bae1dSRodney W. Grimes default: 514df8bae1dSRodney W. Grimes return (EINVAL); 515df8bae1dSRodney W. Grimes } 516df8bae1dSRodney W. Grimes } 517df8bae1dSRodney W. Grimes 518d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 519df8bae1dSRodney W. Grimes struct munmap_args { 520651bb817SAlexander Langer void *addr; 5219154ee6aSPeter Wemm size_t len; 522df8bae1dSRodney W. Grimes }; 523d2d3e875SBruce Evans #endif 524d2c60af8SMatthew Dillon /* 525d2c60af8SMatthew Dillon * MPSAFE 526d2c60af8SMatthew Dillon */ 527df8bae1dSRodney W. Grimes int 5288451d0ddSKip Macy sys_munmap(td, uap) 529b40ce416SJulian Elischer struct thread *td; 53054d92145SMatthew Dillon struct munmap_args *uap; 531df8bae1dSRodney W. Grimes { 53249874f6eSJoseph Koshy #ifdef HWPMC_HOOKS 53349874f6eSJoseph Koshy struct pmckern_map_out pkm; 53449874f6eSJoseph Koshy vm_map_entry_t entry; 53549874f6eSJoseph Koshy #endif 536df8bae1dSRodney W. Grimes vm_offset_t addr; 537dabee6feSPeter Wemm vm_size_t size, pageoff; 538df8bae1dSRodney W. Grimes vm_map_t map; 539df8bae1dSRodney W. Grimes 540df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 5419154ee6aSPeter Wemm size = uap->len; 542d8834602SAlan Cox if (size == 0) 543d8834602SAlan Cox return (EINVAL); 544dabee6feSPeter Wemm 545dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 546dabee6feSPeter Wemm addr -= pageoff; 547dabee6feSPeter Wemm size += pageoff; 548dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 5499154ee6aSPeter Wemm if (addr + size < addr) 550df8bae1dSRodney W. Grimes return (EINVAL); 5519154ee6aSPeter Wemm 552df8bae1dSRodney W. Grimes /* 55305ba50f5SJake Burkholder * Check for illegal addresses. Watch out for address wrap... 554df8bae1dSRodney W. Grimes */ 555b40ce416SJulian Elischer map = &td->td_proc->p_vmspace->vm_map; 55605ba50f5SJake Burkholder if (addr < vm_map_min(map) || addr + size > vm_map_max(map)) 55705ba50f5SJake Burkholder return (EINVAL); 558d8834602SAlan Cox vm_map_lock(map); 55949874f6eSJoseph Koshy #ifdef HWPMC_HOOKS 56049874f6eSJoseph Koshy /* 56149874f6eSJoseph Koshy * Inform hwpmc if the address range being unmapped contains 56249874f6eSJoseph Koshy * an executable region. 56349874f6eSJoseph Koshy */ 5640d419640SRyan Stone pkm.pm_address = (uintptr_t) NULL; 56549874f6eSJoseph Koshy if (vm_map_lookup_entry(map, addr, &entry)) { 56649874f6eSJoseph Koshy for (; 56749874f6eSJoseph Koshy entry != &map->header && entry->start < addr + size; 56849874f6eSJoseph Koshy entry = entry->next) { 56949874f6eSJoseph Koshy if (vm_map_check_protection(map, entry->start, 57049874f6eSJoseph Koshy entry->end, VM_PROT_EXECUTE) == TRUE) { 57149874f6eSJoseph Koshy pkm.pm_address = (uintptr_t) addr; 57249874f6eSJoseph Koshy pkm.pm_size = (size_t) size; 57349874f6eSJoseph Koshy break; 57449874f6eSJoseph Koshy } 57549874f6eSJoseph Koshy } 57649874f6eSJoseph Koshy } 57749874f6eSJoseph Koshy #endif 578655c3490SKonstantin Belousov vm_map_delete(map, addr, addr + size); 5790d419640SRyan Stone 5800d419640SRyan Stone #ifdef HWPMC_HOOKS 5810d419640SRyan Stone /* downgrade the lock to prevent a LOR with the pmc-sx lock */ 5820d419640SRyan Stone vm_map_lock_downgrade(map); 583d473d3a1SRyan Stone if (pkm.pm_address != (uintptr_t) NULL) 5840d419640SRyan Stone PMC_CALL_HOOK(td, PMC_FN_MUNMAP, (void *) &pkm); 5850d419640SRyan Stone vm_map_unlock_read(map); 5860d419640SRyan Stone #else 587d8834602SAlan Cox vm_map_unlock(map); 5880d419640SRyan Stone #endif 5890d419640SRyan Stone /* vm_map_delete returns nothing but KERN_SUCCESS anyway */ 590df8bae1dSRodney W. Grimes return (0); 591df8bae1dSRodney W. Grimes } 592df8bae1dSRodney W. Grimes 593d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 594df8bae1dSRodney W. Grimes struct mprotect_args { 595651bb817SAlexander Langer const void *addr; 5969154ee6aSPeter Wemm size_t len; 597df8bae1dSRodney W. Grimes int prot; 598df8bae1dSRodney W. Grimes }; 599d2d3e875SBruce Evans #endif 600d2c60af8SMatthew Dillon /* 601d2c60af8SMatthew Dillon * MPSAFE 602d2c60af8SMatthew Dillon */ 603df8bae1dSRodney W. Grimes int 6048451d0ddSKip Macy sys_mprotect(td, uap) 605b40ce416SJulian Elischer struct thread *td; 606df8bae1dSRodney W. Grimes struct mprotect_args *uap; 607df8bae1dSRodney W. Grimes { 608df8bae1dSRodney W. Grimes vm_offset_t addr; 609dabee6feSPeter Wemm vm_size_t size, pageoff; 61054d92145SMatthew Dillon vm_prot_t prot; 611df8bae1dSRodney W. Grimes 612df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 6139154ee6aSPeter Wemm size = uap->len; 614df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 615df8bae1dSRodney W. Grimes 616dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 617dabee6feSPeter Wemm addr -= pageoff; 618dabee6feSPeter Wemm size += pageoff; 619dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 6209154ee6aSPeter Wemm if (addr + size < addr) 621dabee6feSPeter Wemm return (EINVAL); 622dabee6feSPeter Wemm 62343285049SAlan Cox switch (vm_map_protect(&td->td_proc->p_vmspace->vm_map, addr, 62443285049SAlan Cox addr + size, prot, FALSE)) { 625df8bae1dSRodney W. Grimes case KERN_SUCCESS: 626df8bae1dSRodney W. Grimes return (0); 627df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 628df8bae1dSRodney W. Grimes return (EACCES); 6293364c323SKonstantin Belousov case KERN_RESOURCE_SHORTAGE: 6303364c323SKonstantin Belousov return (ENOMEM); 631df8bae1dSRodney W. Grimes } 632df8bae1dSRodney W. Grimes return (EINVAL); 633df8bae1dSRodney W. Grimes } 634df8bae1dSRodney W. Grimes 635d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 636dabee6feSPeter Wemm struct minherit_args { 637651bb817SAlexander Langer void *addr; 6389154ee6aSPeter Wemm size_t len; 639dabee6feSPeter Wemm int inherit; 640dabee6feSPeter Wemm }; 641dabee6feSPeter Wemm #endif 642d2c60af8SMatthew Dillon /* 643d2c60af8SMatthew Dillon * MPSAFE 644d2c60af8SMatthew Dillon */ 645dabee6feSPeter Wemm int 6468451d0ddSKip Macy sys_minherit(td, uap) 647b40ce416SJulian Elischer struct thread *td; 648dabee6feSPeter Wemm struct minherit_args *uap; 649dabee6feSPeter Wemm { 650dabee6feSPeter Wemm vm_offset_t addr; 651dabee6feSPeter Wemm vm_size_t size, pageoff; 65254d92145SMatthew Dillon vm_inherit_t inherit; 653dabee6feSPeter Wemm 654dabee6feSPeter Wemm addr = (vm_offset_t)uap->addr; 6559154ee6aSPeter Wemm size = uap->len; 656dabee6feSPeter Wemm inherit = uap->inherit; 657dabee6feSPeter Wemm 658dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 659dabee6feSPeter Wemm addr -= pageoff; 660dabee6feSPeter Wemm size += pageoff; 661dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 6629154ee6aSPeter Wemm if (addr + size < addr) 663dabee6feSPeter Wemm return (EINVAL); 664dabee6feSPeter Wemm 665e0be79afSAlan Cox switch (vm_map_inherit(&td->td_proc->p_vmspace->vm_map, addr, 666e0be79afSAlan Cox addr + size, inherit)) { 667dabee6feSPeter Wemm case KERN_SUCCESS: 668dabee6feSPeter Wemm return (0); 669dabee6feSPeter Wemm case KERN_PROTECTION_FAILURE: 670dabee6feSPeter Wemm return (EACCES); 671dabee6feSPeter Wemm } 672dabee6feSPeter Wemm return (EINVAL); 673dabee6feSPeter Wemm } 674dabee6feSPeter Wemm 675dabee6feSPeter Wemm #ifndef _SYS_SYSPROTO_H_ 676df8bae1dSRodney W. Grimes struct madvise_args { 677651bb817SAlexander Langer void *addr; 6789154ee6aSPeter Wemm size_t len; 679df8bae1dSRodney W. Grimes int behav; 680df8bae1dSRodney W. Grimes }; 681d2d3e875SBruce Evans #endif 6820d94caffSDavid Greenman 683d2c60af8SMatthew Dillon /* 684d2c60af8SMatthew Dillon * MPSAFE 685d2c60af8SMatthew Dillon */ 686df8bae1dSRodney W. Grimes int 6878451d0ddSKip Macy sys_madvise(td, uap) 688b40ce416SJulian Elischer struct thread *td; 689df8bae1dSRodney W. Grimes struct madvise_args *uap; 690df8bae1dSRodney W. Grimes { 691f35329acSJohn Dyson vm_offset_t start, end; 69205ba50f5SJake Burkholder vm_map_t map; 693f4cf2141SWes Peters struct proc *p; 694f4cf2141SWes Peters int error; 695b4309055SMatthew Dillon 696b4309055SMatthew Dillon /* 697f4cf2141SWes Peters * Check for our special case, advising the swap pager we are 698f4cf2141SWes Peters * "immortal." 699f4cf2141SWes Peters */ 700f4cf2141SWes Peters if (uap->behav == MADV_PROTECT) { 701acd3428bSRobert Watson error = priv_check(td, PRIV_VM_MADV_PROTECT); 70269297bf8SJohn Baldwin if (error == 0) { 703f4cf2141SWes Peters p = td->td_proc; 704f4cf2141SWes Peters PROC_LOCK(p); 705f4cf2141SWes Peters p->p_flag |= P_PROTECTED; 706f4cf2141SWes Peters PROC_UNLOCK(p); 70769297bf8SJohn Baldwin } 708f4cf2141SWes Peters return (error); 709f4cf2141SWes Peters } 710f4cf2141SWes Peters /* 711b4309055SMatthew Dillon * Check for illegal behavior 712b4309055SMatthew Dillon */ 7139730a5daSPaul Saab if (uap->behav < 0 || uap->behav > MADV_CORE) 714b4309055SMatthew Dillon return (EINVAL); 715867a482dSJohn Dyson /* 716867a482dSJohn Dyson * Check for illegal addresses. Watch out for address wrap... Note 717867a482dSJohn Dyson * that VM_*_ADDRESS are not constants due to casts (argh). 718867a482dSJohn Dyson */ 71905ba50f5SJake Burkholder map = &td->td_proc->p_vmspace->vm_map; 72005ba50f5SJake Burkholder if ((vm_offset_t)uap->addr < vm_map_min(map) || 72105ba50f5SJake Burkholder (vm_offset_t)uap->addr + uap->len > vm_map_max(map)) 722867a482dSJohn Dyson return (EINVAL); 723867a482dSJohn Dyson if (((vm_offset_t) uap->addr + uap->len) < (vm_offset_t) uap->addr) 724867a482dSJohn Dyson return (EINVAL); 725867a482dSJohn Dyson 726867a482dSJohn Dyson /* 727867a482dSJohn Dyson * Since this routine is only advisory, we default to conservative 728867a482dSJohn Dyson * behavior. 729867a482dSJohn Dyson */ 730cd6eea25SDavid Greenman start = trunc_page((vm_offset_t) uap->addr); 731cd6eea25SDavid Greenman end = round_page((vm_offset_t) uap->addr + uap->len); 732867a482dSJohn Dyson 73305ba50f5SJake Burkholder if (vm_map_madvise(map, start, end, uap->behav)) 734094f6d26SAlan Cox return (EINVAL); 735094f6d26SAlan Cox return (0); 736df8bae1dSRodney W. Grimes } 737df8bae1dSRodney W. Grimes 738d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 739df8bae1dSRodney W. Grimes struct mincore_args { 740651bb817SAlexander Langer const void *addr; 7419154ee6aSPeter Wemm size_t len; 742df8bae1dSRodney W. Grimes char *vec; 743df8bae1dSRodney W. Grimes }; 744d2d3e875SBruce Evans #endif 7450d94caffSDavid Greenman 746d2c60af8SMatthew Dillon /* 747d2c60af8SMatthew Dillon * MPSAFE 748d2c60af8SMatthew Dillon */ 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); 891*1c8279e4SAlan Cox if (m == NULL && 892*1c8279e4SAlan Cox vm_page_is_cached(object, pindex)) 893*1c8279e4SAlan Cox mincoreinfo = MINCORE_INCORE; 894567e51e1SAlan Cox if (m != NULL && m->valid == 0) 895567e51e1SAlan Cox m = NULL; 896567e51e1SAlan Cox if (m != NULL) 897567e51e1SAlan Cox mincoreinfo = MINCORE_INCORE; 898567e51e1SAlan Cox } 899567e51e1SAlan Cox } 900567e51e1SAlan Cox if (m != NULL) { 901567e51e1SAlan Cox /* Examine other mappings to the page. */ 902567e51e1SAlan Cox if (m->dirty == 0 && pmap_is_modified(m)) 903567e51e1SAlan Cox vm_page_dirty(m); 904567e51e1SAlan Cox if (m->dirty != 0) 905867a482dSJohn Dyson mincoreinfo |= MINCORE_MODIFIED_OTHER; 906c46b90e9SAlan Cox /* 9073407fefeSKonstantin Belousov * The first test for PGA_REFERENCED is an 908c46b90e9SAlan Cox * optimization. The second test is 909c46b90e9SAlan Cox * required because a concurrent pmap 910c46b90e9SAlan Cox * operation could clear the last reference 9113407fefeSKonstantin Belousov * and set PGA_REFERENCED before the call to 912c46b90e9SAlan Cox * pmap_is_referenced(). 913c46b90e9SAlan Cox */ 9143407fefeSKonstantin Belousov if ((m->aflags & PGA_REFERENCED) != 0 || 915c46b90e9SAlan Cox pmap_is_referenced(m) || 9163407fefeSKonstantin Belousov (m->aflags & PGA_REFERENCED) != 0) 917867a482dSJohn Dyson mincoreinfo |= MINCORE_REFERENCED_OTHER; 9189b5a5d81SJohn Dyson } 919567e51e1SAlan Cox if (object != NULL) 920567e51e1SAlan Cox VM_OBJECT_UNLOCK(object); 921867a482dSJohn Dyson 922867a482dSJohn Dyson /* 923dd2622a8SAlan Cox * subyte may page fault. In case it needs to modify 924dd2622a8SAlan Cox * the map, we release the lock. 925dd2622a8SAlan Cox */ 926dd2622a8SAlan Cox vm_map_unlock_read(map); 927dd2622a8SAlan Cox 928dd2622a8SAlan Cox /* 929867a482dSJohn Dyson * calculate index into user supplied byte vector 930867a482dSJohn Dyson */ 931867a482dSJohn Dyson vecindex = OFF_TO_IDX(addr - first_addr); 932867a482dSJohn Dyson 933867a482dSJohn Dyson /* 934867a482dSJohn Dyson * If we have skipped map entries, we need to make sure that 935867a482dSJohn Dyson * the byte vector is zeroed for those skipped entries. 936867a482dSJohn Dyson */ 937867a482dSJohn Dyson while ((lastvecindex + 1) < vecindex) { 938867a482dSJohn Dyson error = subyte(vec + lastvecindex, 0); 939867a482dSJohn Dyson if (error) { 940d2c60af8SMatthew Dillon error = EFAULT; 941d2c60af8SMatthew Dillon goto done2; 942867a482dSJohn Dyson } 943867a482dSJohn Dyson ++lastvecindex; 944867a482dSJohn Dyson } 945867a482dSJohn Dyson 946867a482dSJohn Dyson /* 947867a482dSJohn Dyson * Pass the page information to the user 948867a482dSJohn Dyson */ 949867a482dSJohn Dyson error = subyte(vec + vecindex, mincoreinfo); 950867a482dSJohn Dyson if (error) { 951d2c60af8SMatthew Dillon error = EFAULT; 952d2c60af8SMatthew Dillon goto done2; 953867a482dSJohn Dyson } 954dd2622a8SAlan Cox 955dd2622a8SAlan Cox /* 956dd2622a8SAlan Cox * If the map has changed, due to the subyte, the previous 957dd2622a8SAlan Cox * output may be invalid. 958dd2622a8SAlan Cox */ 959dd2622a8SAlan Cox vm_map_lock_read(map); 960dd2622a8SAlan Cox if (timestamp != map->timestamp) 961dd2622a8SAlan Cox goto RestartScan; 962dd2622a8SAlan Cox 963867a482dSJohn Dyson lastvecindex = vecindex; 96402c04a2fSJohn Dyson addr += PAGE_SIZE; 96502c04a2fSJohn Dyson } 966867a482dSJohn Dyson } 967867a482dSJohn Dyson 968867a482dSJohn Dyson /* 969dd2622a8SAlan Cox * subyte may page fault. In case it needs to modify 970dd2622a8SAlan Cox * the map, we release the lock. 971dd2622a8SAlan Cox */ 972dd2622a8SAlan Cox vm_map_unlock_read(map); 973dd2622a8SAlan Cox 974dd2622a8SAlan Cox /* 975867a482dSJohn Dyson * Zero the last entries in the byte vector. 976867a482dSJohn Dyson */ 977867a482dSJohn Dyson vecindex = OFF_TO_IDX(end - first_addr); 978867a482dSJohn Dyson while ((lastvecindex + 1) < vecindex) { 979867a482dSJohn Dyson error = subyte(vec + lastvecindex, 0); 980867a482dSJohn Dyson if (error) { 981d2c60af8SMatthew Dillon error = EFAULT; 982d2c60af8SMatthew Dillon goto done2; 983867a482dSJohn Dyson } 984867a482dSJohn Dyson ++lastvecindex; 985867a482dSJohn Dyson } 986867a482dSJohn Dyson 987dd2622a8SAlan Cox /* 988dd2622a8SAlan Cox * If the map has changed, due to the subyte, the previous 989dd2622a8SAlan Cox * output may be invalid. 990dd2622a8SAlan Cox */ 991dd2622a8SAlan Cox vm_map_lock_read(map); 992dd2622a8SAlan Cox if (timestamp != map->timestamp) 993dd2622a8SAlan Cox goto RestartScan; 994eff50fcdSAlan Cox vm_map_unlock_read(map); 995d2c60af8SMatthew Dillon done2: 996d2c60af8SMatthew Dillon return (error); 997df8bae1dSRodney W. Grimes } 998df8bae1dSRodney W. Grimes 999d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1000df8bae1dSRodney W. Grimes struct mlock_args { 1001651bb817SAlexander Langer const void *addr; 1002df8bae1dSRodney W. Grimes size_t len; 1003df8bae1dSRodney W. Grimes }; 1004d2d3e875SBruce Evans #endif 1005d2c60af8SMatthew Dillon /* 1006d2c60af8SMatthew Dillon * MPSAFE 1007d2c60af8SMatthew Dillon */ 1008df8bae1dSRodney W. Grimes int 10098451d0ddSKip Macy sys_mlock(td, uap) 1010b40ce416SJulian Elischer struct thread *td; 1011df8bae1dSRodney W. Grimes struct mlock_args *uap; 1012df8bae1dSRodney W. Grimes { 1013f0ea4612SDon Lewis struct proc *proc; 1014bb734798SDon Lewis vm_offset_t addr, end, last, start; 1015bb734798SDon Lewis vm_size_t npages, size; 10161ba5ad42SEdward Tomasz Napierala unsigned long nsize; 1017bb734798SDon Lewis int error; 1018df8bae1dSRodney W. Grimes 1019acd3428bSRobert Watson error = priv_check(td, PRIV_VM_MLOCK); 102047934cefSDon Lewis if (error) 102147934cefSDon Lewis return (error); 102216929939SDon Lewis addr = (vm_offset_t)uap->addr; 102316929939SDon Lewis size = uap->len; 1024bb734798SDon Lewis last = addr + size; 102516929939SDon Lewis start = trunc_page(addr); 1026bb734798SDon Lewis end = round_page(last); 1027bb734798SDon Lewis if (last < addr || end < addr) 1028df8bae1dSRodney W. Grimes return (EINVAL); 102916929939SDon Lewis npages = atop(end - start); 103016929939SDon Lewis if (npages > vm_page_max_wired) 103116929939SDon Lewis return (ENOMEM); 1032f0ea4612SDon Lewis proc = td->td_proc; 103347934cefSDon Lewis PROC_LOCK(proc); 10341ba5ad42SEdward Tomasz Napierala nsize = ptoa(npages + 10351ba5ad42SEdward Tomasz Napierala pmap_wired_count(vm_map_pmap(&proc->p_vmspace->vm_map))); 10361ba5ad42SEdward Tomasz Napierala if (nsize > lim_cur(proc, RLIMIT_MEMLOCK)) { 103747934cefSDon Lewis PROC_UNLOCK(proc); 10384a40e3d4SJohn Dyson return (ENOMEM); 103991d5354aSJohn Baldwin } 104047934cefSDon Lewis PROC_UNLOCK(proc); 10412feb50bfSAttilio Rao if (npages + cnt.v_wire_count > vm_page_max_wired) 104216929939SDon Lewis return (EAGAIN); 1043afcc55f3SEdward Tomasz Napierala #ifdef RACCT 10441ba5ad42SEdward Tomasz Napierala PROC_LOCK(proc); 10451ba5ad42SEdward Tomasz Napierala error = racct_set(proc, RACCT_MEMLOCK, nsize); 10461ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(proc); 10471ba5ad42SEdward Tomasz Napierala if (error != 0) 10481ba5ad42SEdward Tomasz Napierala return (ENOMEM); 1049afcc55f3SEdward Tomasz Napierala #endif 105016929939SDon Lewis error = vm_map_wire(&proc->p_vmspace->vm_map, start, end, 105116929939SDon Lewis VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); 1052afcc55f3SEdward Tomasz Napierala #ifdef RACCT 10531ba5ad42SEdward Tomasz Napierala if (error != KERN_SUCCESS) { 10541ba5ad42SEdward Tomasz Napierala PROC_LOCK(proc); 10551ba5ad42SEdward Tomasz Napierala racct_set(proc, RACCT_MEMLOCK, 10561ba5ad42SEdward Tomasz Napierala ptoa(pmap_wired_count(vm_map_pmap(&proc->p_vmspace->vm_map)))); 10571ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(proc); 10581ba5ad42SEdward Tomasz Napierala } 1059afcc55f3SEdward Tomasz Napierala #endif 1060df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 1061df8bae1dSRodney W. Grimes } 1062df8bae1dSRodney W. Grimes 1063d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 10644a40e3d4SJohn Dyson struct mlockall_args { 10654a40e3d4SJohn Dyson int how; 10664a40e3d4SJohn Dyson }; 10674a40e3d4SJohn Dyson #endif 10684a40e3d4SJohn Dyson 1069d2c60af8SMatthew Dillon /* 1070d2c60af8SMatthew Dillon * MPSAFE 1071d2c60af8SMatthew Dillon */ 10724a40e3d4SJohn Dyson int 10738451d0ddSKip Macy sys_mlockall(td, uap) 1074b40ce416SJulian Elischer struct thread *td; 10754a40e3d4SJohn Dyson struct mlockall_args *uap; 10764a40e3d4SJohn Dyson { 1077abd498aaSBruce M Simpson vm_map_t map; 1078abd498aaSBruce M Simpson int error; 1079abd498aaSBruce M Simpson 1080abd498aaSBruce M Simpson map = &td->td_proc->p_vmspace->vm_map; 1081abd498aaSBruce M Simpson error = 0; 1082abd498aaSBruce M Simpson 1083abd498aaSBruce M Simpson if ((uap->how == 0) || ((uap->how & ~(MCL_CURRENT|MCL_FUTURE)) != 0)) 1084abd498aaSBruce M Simpson return (EINVAL); 1085abd498aaSBruce M Simpson 108611f7ddc5SBruce M Simpson #if 0 1087abd498aaSBruce M Simpson /* 1088abd498aaSBruce M Simpson * If wiring all pages in the process would cause it to exceed 1089abd498aaSBruce M Simpson * a hard resource limit, return ENOMEM. 1090abd498aaSBruce M Simpson */ 109191d5354aSJohn Baldwin PROC_LOCK(td->td_proc); 1092fd6f4ffbSEdward Tomasz Napierala if (map->size > lim_cur(td->td_proc, RLIMIT_MEMLOCK)) { 109391d5354aSJohn Baldwin PROC_UNLOCK(td->td_proc); 1094abd498aaSBruce M Simpson return (ENOMEM); 109591d5354aSJohn Baldwin } 109691d5354aSJohn Baldwin PROC_UNLOCK(td->td_proc); 1097abd498aaSBruce M Simpson #else 1098acd3428bSRobert Watson error = priv_check(td, PRIV_VM_MLOCK); 1099abd498aaSBruce M Simpson if (error) 1100abd498aaSBruce M Simpson return (error); 1101abd498aaSBruce M Simpson #endif 1102afcc55f3SEdward Tomasz Napierala #ifdef RACCT 11031ba5ad42SEdward Tomasz Napierala PROC_LOCK(td->td_proc); 11041ba5ad42SEdward Tomasz Napierala error = racct_set(td->td_proc, RACCT_MEMLOCK, map->size); 11051ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc); 11061ba5ad42SEdward Tomasz Napierala if (error != 0) 11071ba5ad42SEdward Tomasz Napierala return (ENOMEM); 1108afcc55f3SEdward Tomasz Napierala #endif 1109abd498aaSBruce M Simpson 1110abd498aaSBruce M Simpson if (uap->how & MCL_FUTURE) { 1111abd498aaSBruce M Simpson vm_map_lock(map); 1112abd498aaSBruce M Simpson vm_map_modflags(map, MAP_WIREFUTURE, 0); 1113abd498aaSBruce M Simpson vm_map_unlock(map); 1114abd498aaSBruce M Simpson error = 0; 1115abd498aaSBruce M Simpson } 1116abd498aaSBruce M Simpson 1117abd498aaSBruce M Simpson if (uap->how & MCL_CURRENT) { 1118abd498aaSBruce M Simpson /* 1119abd498aaSBruce M Simpson * P1003.1-2001 mandates that all currently mapped pages 1120abd498aaSBruce M Simpson * will be memory resident and locked (wired) upon return 1121abd498aaSBruce M Simpson * from mlockall(). vm_map_wire() will wire pages, by 1122abd498aaSBruce M Simpson * calling vm_fault_wire() for each page in the region. 1123abd498aaSBruce M Simpson */ 1124abd498aaSBruce M Simpson error = vm_map_wire(map, vm_map_min(map), vm_map_max(map), 1125abd498aaSBruce M Simpson VM_MAP_WIRE_USER|VM_MAP_WIRE_HOLESOK); 1126abd498aaSBruce M Simpson error = (error == KERN_SUCCESS ? 0 : EAGAIN); 1127abd498aaSBruce M Simpson } 1128afcc55f3SEdward Tomasz Napierala #ifdef RACCT 11291ba5ad42SEdward Tomasz Napierala if (error != KERN_SUCCESS) { 11301ba5ad42SEdward Tomasz Napierala PROC_LOCK(td->td_proc); 11311ba5ad42SEdward Tomasz Napierala racct_set(td->td_proc, RACCT_MEMLOCK, 11321ba5ad42SEdward Tomasz Napierala ptoa(pmap_wired_count(vm_map_pmap(&td->td_proc->p_vmspace->vm_map)))); 11331ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc); 11341ba5ad42SEdward Tomasz Napierala } 1135afcc55f3SEdward Tomasz Napierala #endif 1136abd498aaSBruce M Simpson 1137abd498aaSBruce M Simpson return (error); 11384a40e3d4SJohn Dyson } 11394a40e3d4SJohn Dyson 11404a40e3d4SJohn Dyson #ifndef _SYS_SYSPROTO_H_ 1141fa721254SAlfred Perlstein struct munlockall_args { 1142abd498aaSBruce M Simpson register_t dummy; 11434a40e3d4SJohn Dyson }; 11444a40e3d4SJohn Dyson #endif 11454a40e3d4SJohn Dyson 1146d2c60af8SMatthew Dillon /* 1147d2c60af8SMatthew Dillon * MPSAFE 1148d2c60af8SMatthew Dillon */ 11494a40e3d4SJohn Dyson int 11508451d0ddSKip Macy sys_munlockall(td, uap) 1151b40ce416SJulian Elischer struct thread *td; 11524a40e3d4SJohn Dyson struct munlockall_args *uap; 11534a40e3d4SJohn Dyson { 1154abd498aaSBruce M Simpson vm_map_t map; 1155abd498aaSBruce M Simpson int error; 1156abd498aaSBruce M Simpson 1157abd498aaSBruce M Simpson map = &td->td_proc->p_vmspace->vm_map; 1158acd3428bSRobert Watson error = priv_check(td, PRIV_VM_MUNLOCK); 1159abd498aaSBruce M Simpson if (error) 1160abd498aaSBruce M Simpson return (error); 1161abd498aaSBruce M Simpson 1162abd498aaSBruce M Simpson /* Clear the MAP_WIREFUTURE flag from this vm_map. */ 1163abd498aaSBruce M Simpson vm_map_lock(map); 1164abd498aaSBruce M Simpson vm_map_modflags(map, 0, MAP_WIREFUTURE); 1165abd498aaSBruce M Simpson vm_map_unlock(map); 1166abd498aaSBruce M Simpson 1167abd498aaSBruce M Simpson /* Forcibly unwire all pages. */ 1168abd498aaSBruce M Simpson error = vm_map_unwire(map, vm_map_min(map), vm_map_max(map), 1169abd498aaSBruce M Simpson VM_MAP_WIRE_USER|VM_MAP_WIRE_HOLESOK); 1170afcc55f3SEdward Tomasz Napierala #ifdef RACCT 11711ba5ad42SEdward Tomasz Napierala if (error == KERN_SUCCESS) { 11721ba5ad42SEdward Tomasz Napierala PROC_LOCK(td->td_proc); 11731ba5ad42SEdward Tomasz Napierala racct_set(td->td_proc, RACCT_MEMLOCK, 0); 11741ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc); 11751ba5ad42SEdward Tomasz Napierala } 1176afcc55f3SEdward Tomasz Napierala #endif 1177abd498aaSBruce M Simpson 1178abd498aaSBruce M Simpson return (error); 11794a40e3d4SJohn Dyson } 11804a40e3d4SJohn Dyson 11814a40e3d4SJohn Dyson #ifndef _SYS_SYSPROTO_H_ 1182df8bae1dSRodney W. Grimes struct munlock_args { 1183651bb817SAlexander Langer const void *addr; 1184df8bae1dSRodney W. Grimes size_t len; 1185df8bae1dSRodney W. Grimes }; 1186d2d3e875SBruce Evans #endif 1187d2c60af8SMatthew Dillon /* 1188d2c60af8SMatthew Dillon * MPSAFE 1189d2c60af8SMatthew Dillon */ 1190df8bae1dSRodney W. Grimes int 11918451d0ddSKip Macy sys_munlock(td, uap) 1192b40ce416SJulian Elischer struct thread *td; 1193df8bae1dSRodney W. Grimes struct munlock_args *uap; 1194df8bae1dSRodney W. Grimes { 1195bb734798SDon Lewis vm_offset_t addr, end, last, start; 119616929939SDon Lewis vm_size_t size; 1197df8bae1dSRodney W. Grimes int error; 1198df8bae1dSRodney W. Grimes 1199acd3428bSRobert Watson error = priv_check(td, PRIV_VM_MUNLOCK); 120047934cefSDon Lewis if (error) 120147934cefSDon Lewis return (error); 120216929939SDon Lewis addr = (vm_offset_t)uap->addr; 120316929939SDon Lewis size = uap->len; 1204bb734798SDon Lewis last = addr + size; 120516929939SDon Lewis start = trunc_page(addr); 1206bb734798SDon Lewis end = round_page(last); 1207bb734798SDon Lewis if (last < addr || end < addr) 1208df8bae1dSRodney W. Grimes return (EINVAL); 120916929939SDon Lewis error = vm_map_unwire(&td->td_proc->p_vmspace->vm_map, start, end, 121016929939SDon Lewis VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); 1211afcc55f3SEdward Tomasz Napierala #ifdef RACCT 12121ba5ad42SEdward Tomasz Napierala if (error == KERN_SUCCESS) { 12131ba5ad42SEdward Tomasz Napierala PROC_LOCK(td->td_proc); 12141ba5ad42SEdward Tomasz Napierala racct_sub(td->td_proc, RACCT_MEMLOCK, ptoa(end - start)); 12151ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc); 12161ba5ad42SEdward Tomasz Napierala } 1217afcc55f3SEdward Tomasz Napierala #endif 1218df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 1219df8bae1dSRodney W. Grimes } 1220df8bae1dSRodney W. Grimes 1221df8bae1dSRodney W. Grimes /* 1222c8daea13SAlexander Kabaev * vm_mmap_vnode() 1223c8daea13SAlexander Kabaev * 1224c8daea13SAlexander Kabaev * Helper function for vm_mmap. Perform sanity check specific for mmap 1225c8daea13SAlexander Kabaev * operations on vnodes. 122684110e7eSKonstantin Belousov * 122784110e7eSKonstantin Belousov * For VCHR vnodes, the vnode lock is held over the call to 122884110e7eSKonstantin Belousov * vm_mmap_cdev() to keep vp->v_rdev valid. 1229c8daea13SAlexander Kabaev */ 1230c8daea13SAlexander Kabaev int 1231c8daea13SAlexander Kabaev vm_mmap_vnode(struct thread *td, vm_size_t objsize, 1232c8daea13SAlexander Kabaev vm_prot_t prot, vm_prot_t *maxprotp, int *flagsp, 123384110e7eSKonstantin Belousov struct vnode *vp, vm_ooffset_t *foffp, vm_object_t *objp, 123484110e7eSKonstantin Belousov boolean_t *writecounted) 1235c8daea13SAlexander Kabaev { 1236c8daea13SAlexander Kabaev struct vattr va; 1237c8daea13SAlexander Kabaev vm_object_t obj; 123864345f0bSJohn Baldwin vm_offset_t foff; 1239ae51ff11SJeff Roberson struct mount *mp; 12400359a12eSAttilio Rao struct ucred *cred; 124184110e7eSKonstantin Belousov int error, flags, locktype, vfslocked; 1242c8daea13SAlexander Kabaev 1243ae51ff11SJeff Roberson mp = vp->v_mount; 12440359a12eSAttilio Rao cred = td->td_ucred; 124584110e7eSKonstantin Belousov if ((*maxprotp & VM_PROT_WRITE) && (*flagsp & MAP_SHARED)) 124684110e7eSKonstantin Belousov locktype = LK_EXCLUSIVE; 124784110e7eSKonstantin Belousov else 124884110e7eSKonstantin Belousov locktype = LK_SHARED; 1249ae51ff11SJeff Roberson vfslocked = VFS_LOCK_GIANT(mp); 125084110e7eSKonstantin Belousov if ((error = vget(vp, locktype, td)) != 0) { 1251ae51ff11SJeff Roberson VFS_UNLOCK_GIANT(vfslocked); 1252c8daea13SAlexander Kabaev return (error); 1253c8daea13SAlexander Kabaev } 125464345f0bSJohn Baldwin foff = *foffp; 1255c8daea13SAlexander Kabaev flags = *flagsp; 12568516dd18SPoul-Henning Kamp obj = vp->v_object; 1257c8daea13SAlexander Kabaev if (vp->v_type == VREG) { 1258c8daea13SAlexander Kabaev /* 1259c8daea13SAlexander Kabaev * Get the proper underlying object 1260c8daea13SAlexander Kabaev */ 12618516dd18SPoul-Henning Kamp if (obj == NULL) { 1262c8daea13SAlexander Kabaev error = EINVAL; 1263c8daea13SAlexander Kabaev goto done; 1264c8daea13SAlexander Kabaev } 1265c8daea13SAlexander Kabaev if (obj->handle != vp) { 1266c8daea13SAlexander Kabaev vput(vp); 1267c8daea13SAlexander Kabaev vp = (struct vnode *)obj->handle; 126884110e7eSKonstantin Belousov /* 126984110e7eSKonstantin Belousov * Bypass filesystems obey the mpsafety of the 127084110e7eSKonstantin Belousov * underlying fs. 127184110e7eSKonstantin Belousov */ 127284110e7eSKonstantin Belousov error = vget(vp, locktype, td); 127384110e7eSKonstantin Belousov if (error != 0) { 127484110e7eSKonstantin Belousov VFS_UNLOCK_GIANT(vfslocked); 127584110e7eSKonstantin Belousov return (error); 127684110e7eSKonstantin Belousov } 12779d22083dSKonstantin Belousov } 127884110e7eSKonstantin Belousov if (locktype == LK_EXCLUSIVE) { 127984110e7eSKonstantin Belousov *writecounted = TRUE; 128084110e7eSKonstantin Belousov vnode_pager_update_writecount(obj, 0, objsize); 128184110e7eSKonstantin Belousov } 1282c8daea13SAlexander Kabaev } else if (vp->v_type == VCHR) { 128364345f0bSJohn Baldwin error = vm_mmap_cdev(td, objsize, prot, maxprotp, flagsp, 128464345f0bSJohn Baldwin vp->v_rdev, foffp, objp); 128564345f0bSJohn Baldwin if (error == 0) 128664345f0bSJohn Baldwin goto mark_atime; 128791a35e78SKonstantin Belousov goto done; 1288c8daea13SAlexander Kabaev } else { 1289c8daea13SAlexander Kabaev error = EINVAL; 1290c8daea13SAlexander Kabaev goto done; 1291c8daea13SAlexander Kabaev } 12920359a12eSAttilio Rao if ((error = VOP_GETATTR(vp, &va, cred))) 1293c8daea13SAlexander Kabaev goto done; 1294c92163dcSChristian S.J. Peron #ifdef MAC 12950359a12eSAttilio Rao error = mac_vnode_check_mmap(cred, vp, prot, flags); 1296c92163dcSChristian S.J. Peron if (error != 0) 1297c92163dcSChristian S.J. Peron goto done; 1298c92163dcSChristian S.J. Peron #endif 1299c8daea13SAlexander Kabaev if ((flags & MAP_SHARED) != 0) { 1300c8daea13SAlexander Kabaev if ((va.va_flags & (SF_SNAPSHOT|IMMUTABLE|APPEND)) != 0) { 1301c8daea13SAlexander Kabaev if (prot & PROT_WRITE) { 1302c8daea13SAlexander Kabaev error = EPERM; 1303c8daea13SAlexander Kabaev goto done; 1304c8daea13SAlexander Kabaev } 1305c8daea13SAlexander Kabaev *maxprotp &= ~VM_PROT_WRITE; 1306c8daea13SAlexander Kabaev } 1307c8daea13SAlexander Kabaev } 1308c8daea13SAlexander Kabaev /* 1309c8daea13SAlexander Kabaev * If it is a regular file without any references 1310c8daea13SAlexander Kabaev * we do not need to sync it. 1311c8daea13SAlexander Kabaev * Adjust object size to be the size of actual file. 1312c8daea13SAlexander Kabaev */ 1313c8daea13SAlexander Kabaev objsize = round_page(va.va_size); 1314c8daea13SAlexander Kabaev if (va.va_nlink == 0) 1315c8daea13SAlexander Kabaev flags |= MAP_NOSYNC; 131684110e7eSKonstantin Belousov obj = vm_pager_allocate(OBJT_VNODE, vp, objsize, prot, foff, cred); 1317c8daea13SAlexander Kabaev if (obj == NULL) { 131864345f0bSJohn Baldwin error = ENOMEM; 1319c8daea13SAlexander Kabaev goto done; 1320c8daea13SAlexander Kabaev } 1321c8daea13SAlexander Kabaev *objp = obj; 1322c8daea13SAlexander Kabaev *flagsp = flags; 132364345f0bSJohn Baldwin 132464345f0bSJohn Baldwin mark_atime: 13250359a12eSAttilio Rao vfs_mark_atime(vp, cred); 13261e309003SDiomidis Spinellis 1327c8daea13SAlexander Kabaev done: 1328c8daea13SAlexander Kabaev vput(vp); 1329ae51ff11SJeff Roberson VFS_UNLOCK_GIANT(vfslocked); 1330c8daea13SAlexander Kabaev return (error); 1331c8daea13SAlexander Kabaev } 1332c8daea13SAlexander Kabaev 1333c8daea13SAlexander Kabaev /* 133498df9218SJohn Baldwin * vm_mmap_cdev() 133598df9218SJohn Baldwin * 133698df9218SJohn Baldwin * MPSAFE 133798df9218SJohn Baldwin * 133898df9218SJohn Baldwin * Helper function for vm_mmap. Perform sanity check specific for mmap 133998df9218SJohn Baldwin * operations on cdevs. 134098df9218SJohn Baldwin */ 134198df9218SJohn Baldwin int 134298df9218SJohn Baldwin vm_mmap_cdev(struct thread *td, vm_size_t objsize, 134398df9218SJohn Baldwin vm_prot_t prot, vm_prot_t *maxprotp, int *flagsp, 134464345f0bSJohn Baldwin struct cdev *cdev, vm_ooffset_t *foff, vm_object_t *objp) 134598df9218SJohn Baldwin { 134698df9218SJohn Baldwin vm_object_t obj; 134791a35e78SKonstantin Belousov struct cdevsw *dsw; 13483979450bSKonstantin Belousov int error, flags, ref; 134998df9218SJohn Baldwin 135098df9218SJohn Baldwin flags = *flagsp; 135198df9218SJohn Baldwin 13523979450bSKonstantin Belousov dsw = dev_refthread(cdev, &ref); 135391a35e78SKonstantin Belousov if (dsw == NULL) 135491a35e78SKonstantin Belousov return (ENXIO); 135591a35e78SKonstantin Belousov if (dsw->d_flags & D_MMAP_ANON) { 13563979450bSKonstantin Belousov dev_relthread(cdev, ref); 135798df9218SJohn Baldwin *maxprotp = VM_PROT_ALL; 135898df9218SJohn Baldwin *flagsp |= MAP_ANON; 135998df9218SJohn Baldwin return (0); 136098df9218SJohn Baldwin } 136198df9218SJohn Baldwin /* 136264345f0bSJohn Baldwin * cdevs do not provide private mappings of any kind. 136398df9218SJohn Baldwin */ 136498df9218SJohn Baldwin if ((*maxprotp & VM_PROT_WRITE) == 0 && 136564345f0bSJohn Baldwin (prot & PROT_WRITE) != 0) { 13663979450bSKonstantin Belousov dev_relthread(cdev, ref); 136798df9218SJohn Baldwin return (EACCES); 136864345f0bSJohn Baldwin } 136964345f0bSJohn Baldwin if (flags & (MAP_PRIVATE|MAP_COPY)) { 13703979450bSKonstantin Belousov dev_relthread(cdev, ref); 137198df9218SJohn Baldwin return (EINVAL); 137264345f0bSJohn Baldwin } 137398df9218SJohn Baldwin /* 137498df9218SJohn Baldwin * Force device mappings to be shared. 137598df9218SJohn Baldwin */ 137698df9218SJohn Baldwin flags |= MAP_SHARED; 137798df9218SJohn Baldwin #ifdef MAC_XXX 137864345f0bSJohn Baldwin error = mac_cdev_check_mmap(td->td_ucred, cdev, prot); 137964345f0bSJohn Baldwin if (error != 0) { 13803979450bSKonstantin Belousov dev_relthread(cdev, ref); 138198df9218SJohn Baldwin return (error); 138264345f0bSJohn Baldwin } 138398df9218SJohn Baldwin #endif 138464345f0bSJohn Baldwin /* 138564345f0bSJohn Baldwin * First, try d_mmap_single(). If that is not implemented 138664345f0bSJohn Baldwin * (returns ENODEV), fall back to using the device pager. 138764345f0bSJohn Baldwin * Note that d_mmap_single() must return a reference to the 138864345f0bSJohn Baldwin * object (it needs to bump the reference count of the object 138964345f0bSJohn Baldwin * it returns somehow). 139064345f0bSJohn Baldwin * 139164345f0bSJohn Baldwin * XXX assumes VM_PROT_* == PROT_* 139264345f0bSJohn Baldwin */ 139364345f0bSJohn Baldwin error = dsw->d_mmap_single(cdev, foff, objsize, objp, (int)prot); 13943979450bSKonstantin Belousov dev_relthread(cdev, ref); 139564345f0bSJohn Baldwin if (error != ENODEV) 139664345f0bSJohn Baldwin return (error); 13973364c323SKonstantin Belousov obj = vm_pager_allocate(OBJT_DEVICE, cdev, objsize, prot, *foff, 13983364c323SKonstantin Belousov td->td_ucred); 139998df9218SJohn Baldwin if (obj == NULL) 140098df9218SJohn Baldwin return (EINVAL); 140198df9218SJohn Baldwin *objp = obj; 140298df9218SJohn Baldwin *flagsp = flags; 140398df9218SJohn Baldwin return (0); 140498df9218SJohn Baldwin } 140598df9218SJohn Baldwin 140698df9218SJohn Baldwin /* 14078e38aeffSJohn Baldwin * vm_mmap_shm() 14088e38aeffSJohn Baldwin * 14098e38aeffSJohn Baldwin * MPSAFE 14108e38aeffSJohn Baldwin * 14118e38aeffSJohn Baldwin * Helper function for vm_mmap. Perform sanity check specific for mmap 14128e38aeffSJohn Baldwin * operations on shm file descriptors. 14138e38aeffSJohn Baldwin */ 14148e38aeffSJohn Baldwin int 14158e38aeffSJohn Baldwin vm_mmap_shm(struct thread *td, vm_size_t objsize, 14168e38aeffSJohn Baldwin vm_prot_t prot, vm_prot_t *maxprotp, int *flagsp, 14178e38aeffSJohn Baldwin struct shmfd *shmfd, vm_ooffset_t foff, vm_object_t *objp) 14188e38aeffSJohn Baldwin { 14198e38aeffSJohn Baldwin int error; 14208e38aeffSJohn Baldwin 1421da048309SAlan Cox if ((*flagsp & MAP_SHARED) != 0 && 1422da048309SAlan Cox (*maxprotp & VM_PROT_WRITE) == 0 && 14238e38aeffSJohn Baldwin (prot & PROT_WRITE) != 0) 14248e38aeffSJohn Baldwin return (EACCES); 14258e38aeffSJohn Baldwin #ifdef MAC 14268e38aeffSJohn Baldwin error = mac_posixshm_check_mmap(td->td_ucred, shmfd, prot, *flagsp); 14278e38aeffSJohn Baldwin if (error != 0) 14288e38aeffSJohn Baldwin return (error); 14298e38aeffSJohn Baldwin #endif 14308e38aeffSJohn Baldwin error = shm_mmap(shmfd, objsize, foff, objp); 14318e38aeffSJohn Baldwin if (error) 14328e38aeffSJohn Baldwin return (error); 14338e38aeffSJohn Baldwin return (0); 14348e38aeffSJohn Baldwin } 14358e38aeffSJohn Baldwin 14368e38aeffSJohn Baldwin /* 1437d2c60af8SMatthew Dillon * vm_mmap() 1438d2c60af8SMatthew Dillon * 1439d2c60af8SMatthew Dillon * MPSAFE 1440d2c60af8SMatthew Dillon * 1441d2c60af8SMatthew Dillon * Internal version of mmap. Currently used by mmap, exec, and sys5 1442d2c60af8SMatthew Dillon * shared memory. Handle is either a vnode pointer or NULL for MAP_ANON. 1443df8bae1dSRodney W. Grimes */ 1444df8bae1dSRodney W. Grimes int 1445b9dcd593SBruce Evans vm_mmap(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, 1446b9dcd593SBruce Evans vm_prot_t maxprot, int flags, 144798df9218SJohn Baldwin objtype_t handle_type, void *handle, 1448b9dcd593SBruce Evans vm_ooffset_t foff) 1449df8bae1dSRodney W. Grimes { 1450df8bae1dSRodney W. Grimes boolean_t fitit; 14516bda842dSMatt Jacob vm_object_t object = NULL; 1452b40ce416SJulian Elischer struct thread *td = curthread; 1453f9230ad6SAlan Cox int docow, error, rv; 145484110e7eSKonstantin Belousov boolean_t writecounted; 1455df8bae1dSRodney W. Grimes 1456df8bae1dSRodney W. Grimes if (size == 0) 1457df8bae1dSRodney W. Grimes return (0); 1458df8bae1dSRodney W. Grimes 1459749474f2SPeter Wemm size = round_page(size); 1460df8bae1dSRodney W. Grimes 1461a6492969SAlan Cox if (map == &td->td_proc->p_vmspace->vm_map) { 146291d5354aSJohn Baldwin PROC_LOCK(td->td_proc); 1463a6492969SAlan Cox if (map->size + size > lim_cur(td->td_proc, RLIMIT_VMEM)) { 146491d5354aSJohn Baldwin PROC_UNLOCK(td->td_proc); 1465070f64feSMatthew Dillon return (ENOMEM); 1466070f64feSMatthew Dillon } 1467a6492969SAlan Cox if (racct_set(td->td_proc, RACCT_VMEM, map->size + size)) { 14681ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc); 14691ba5ad42SEdward Tomasz Napierala return (ENOMEM); 14701ba5ad42SEdward Tomasz Napierala } 147191d5354aSJohn Baldwin PROC_UNLOCK(td->td_proc); 1472a6492969SAlan Cox } 1473070f64feSMatthew Dillon 1474df8bae1dSRodney W. Grimes /* 1475bc9ad247SDavid Greenman * We currently can only deal with page aligned file offsets. 1476bc9ad247SDavid Greenman * The check is here rather than in the syscall because the 1477bc9ad247SDavid Greenman * kernel calls this function internally for other mmaping 1478bc9ad247SDavid Greenman * operations (such as in exec) and non-aligned offsets will 1479bc9ad247SDavid Greenman * cause pmap inconsistencies...so we want to be sure to 1480bc9ad247SDavid Greenman * disallow this in all cases. 1481bc9ad247SDavid Greenman */ 1482bc9ad247SDavid Greenman if (foff & PAGE_MASK) 1483bc9ad247SDavid Greenman return (EINVAL); 1484bc9ad247SDavid Greenman 148506cb7259SDavid Greenman if ((flags & MAP_FIXED) == 0) { 148606cb7259SDavid Greenman fitit = TRUE; 148706cb7259SDavid Greenman *addr = round_page(*addr); 148806cb7259SDavid Greenman } else { 148906cb7259SDavid Greenman if (*addr != trunc_page(*addr)) 149006cb7259SDavid Greenman return (EINVAL); 149106cb7259SDavid Greenman fitit = FALSE; 149206cb7259SDavid Greenman } 149384110e7eSKonstantin Belousov writecounted = FALSE; 149484110e7eSKonstantin Belousov 1495bc9ad247SDavid Greenman /* 149624a1cce3SDavid Greenman * Lookup/allocate object. 1497df8bae1dSRodney W. Grimes */ 149898df9218SJohn Baldwin switch (handle_type) { 149998df9218SJohn Baldwin case OBJT_DEVICE: 150098df9218SJohn Baldwin error = vm_mmap_cdev(td, size, prot, &maxprot, &flags, 150164345f0bSJohn Baldwin handle, &foff, &object); 150298df9218SJohn Baldwin break; 150398df9218SJohn Baldwin case OBJT_VNODE: 1504c8daea13SAlexander Kabaev error = vm_mmap_vnode(td, size, prot, &maxprot, &flags, 150584110e7eSKonstantin Belousov handle, &foff, &object, &writecounted); 150698df9218SJohn Baldwin break; 15078e38aeffSJohn Baldwin case OBJT_SWAP: 15088e38aeffSJohn Baldwin error = vm_mmap_shm(td, size, prot, &maxprot, &flags, 15098e38aeffSJohn Baldwin handle, foff, &object); 15108e38aeffSJohn Baldwin break; 151198df9218SJohn Baldwin case OBJT_DEFAULT: 151298df9218SJohn Baldwin if (handle == NULL) { 151398df9218SJohn Baldwin error = 0; 151498df9218SJohn Baldwin break; 151598df9218SJohn Baldwin } 151698df9218SJohn Baldwin /* FALLTHROUGH */ 151798df9218SJohn Baldwin default: 151898df9218SJohn Baldwin error = EINVAL; 15196bda842dSMatt Jacob break; 152098df9218SJohn Baldwin } 152198df9218SJohn Baldwin if (error) 1522c8daea13SAlexander Kabaev return (error); 15235f55e841SDavid Greenman if (flags & MAP_ANON) { 1524c8daea13SAlexander Kabaev object = NULL; 1525c8daea13SAlexander Kabaev docow = 0; 15265f55e841SDavid Greenman /* 15275f55e841SDavid Greenman * Unnamed anonymous regions always start at 0. 15285f55e841SDavid Greenman */ 152967bf6868SJohn Dyson if (handle == 0) 15305f55e841SDavid Greenman foff = 0; 153174ffb9afSAlan Cox } else if (flags & MAP_PREFAULT_READ) 153274ffb9afSAlan Cox docow = MAP_PREFAULT; 153374ffb9afSAlan Cox else 15344738fa09SAlan Cox docow = MAP_PREFAULT_PARTIAL; 1535df8bae1dSRodney W. Grimes 15364f79d873SMatthew Dillon if ((flags & (MAP_ANON|MAP_SHARED)) == 0) 15374738fa09SAlan Cox docow |= MAP_COPY_ON_WRITE; 15384f79d873SMatthew Dillon if (flags & MAP_NOSYNC) 15394f79d873SMatthew Dillon docow |= MAP_DISABLE_SYNCER; 15409730a5daSPaul Saab if (flags & MAP_NOCORE) 15419730a5daSPaul Saab docow |= MAP_DISABLE_COREDUMP; 15428211bd45SKonstantin Belousov /* Shared memory is also shared with children. */ 15438211bd45SKonstantin Belousov if (flags & MAP_SHARED) 15448211bd45SKonstantin Belousov docow |= MAP_INHERIT_SHARE; 154584110e7eSKonstantin Belousov if (writecounted) 154684110e7eSKonstantin Belousov docow |= MAP_VN_WRITECOUNT; 15475850152dSJohn Dyson 15482267af78SJulian Elischer if (flags & MAP_STACK) 1549fd75d710SMarcel Moolenaar rv = vm_map_stack(map, *addr, size, prot, maxprot, 1550fd75d710SMarcel Moolenaar docow | MAP_STACK_GROWS_DOWN); 1551d239bd3cSKonstantin Belousov else if (fitit) 1552d0a83a83SAlan Cox rv = vm_map_find(map, object, foff, addr, size, 1553d0a83a83SAlan Cox object != NULL && object->type == OBJT_DEVICE ? 1554d0a83a83SAlan Cox VMFS_ALIGNED_SPACE : VMFS_ANY_SPACE, prot, maxprot, docow); 15552267af78SJulian Elischer else 1556b8ca4ef2SAlan Cox rv = vm_map_fixed(map, object, foff, *addr, size, 1557bd7e5f99SJohn Dyson prot, maxprot, docow); 1558bd7e5f99SJohn Dyson 1559f9230ad6SAlan Cox if (rv == KERN_SUCCESS) { 15607fb0c17eSDavid Greenman /* 1561f9230ad6SAlan Cox * If the process has requested that all future mappings 1562f9230ad6SAlan Cox * be wired, then heed this. 1563f9230ad6SAlan Cox */ 1564f9230ad6SAlan Cox if (map->flags & MAP_WIREFUTURE) 1565f9230ad6SAlan Cox vm_map_wire(map, *addr, *addr + size, 1566f9230ad6SAlan Cox VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); 1567f9230ad6SAlan Cox } else { 1568f9230ad6SAlan Cox /* 156984110e7eSKonstantin Belousov * If this mapping was accounted for in the vnode's 157084110e7eSKonstantin Belousov * writecount, then undo that now. 15717fb0c17eSDavid Greenman */ 157284110e7eSKonstantin Belousov if (writecounted) 157384110e7eSKonstantin Belousov vnode_pager_release_writecount(object, 0, size); 1574f9230ad6SAlan Cox /* 1575f9230ad6SAlan Cox * Lose the object reference. Will destroy the 1576f9230ad6SAlan Cox * object if it's an unnamed anonymous mapping 1577f9230ad6SAlan Cox * or named anonymous without other references. 1578f9230ad6SAlan Cox */ 1579df8bae1dSRodney W. Grimes vm_object_deallocate(object); 1580df8bae1dSRodney W. Grimes } 15812e32165cSKonstantin Belousov return (vm_mmap_to_errno(rv)); 15822e32165cSKonstantin Belousov } 15832e32165cSKonstantin Belousov 1584f9230ad6SAlan Cox /* 1585f9230ad6SAlan Cox * Translate a Mach VM return code to zero on success or the appropriate errno 1586f9230ad6SAlan Cox * on failure. 1587f9230ad6SAlan Cox */ 15882e32165cSKonstantin Belousov int 15892e32165cSKonstantin Belousov vm_mmap_to_errno(int rv) 15902e32165cSKonstantin Belousov { 15912e32165cSKonstantin Belousov 1592df8bae1dSRodney W. Grimes switch (rv) { 1593df8bae1dSRodney W. Grimes case KERN_SUCCESS: 1594df8bae1dSRodney W. Grimes return (0); 1595df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 1596df8bae1dSRodney W. Grimes case KERN_NO_SPACE: 1597df8bae1dSRodney W. Grimes return (ENOMEM); 1598df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 1599df8bae1dSRodney W. Grimes return (EACCES); 1600df8bae1dSRodney W. Grimes default: 1601df8bae1dSRodney W. Grimes return (EINVAL); 1602df8bae1dSRodney W. Grimes } 1603df8bae1dSRodney W. Grimes } 1604