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 2107707ccabSKonstantin Belousov /* 2117707ccabSKonstantin Belousov * Enforce the constraints. 2127707ccabSKonstantin Belousov * Mapping of length 0 is only allowed for old binaries. 2137707ccabSKonstantin Belousov * Anonymous mapping shall specify -1 as filedescriptor and 2147707ccabSKonstantin Belousov * zero position for new code. Be nice to ancient a.out 2157707ccabSKonstantin Belousov * binaries and correct pos for anonymous mapping, since old 2167707ccabSKonstantin Belousov * ld.so sometimes issues anonymous map requests with non-zero 2177707ccabSKonstantin Belousov * pos. 2187707ccabSKonstantin Belousov */ 2197707ccabSKonstantin Belousov if (!SV_CURPROC_FLAG(SV_AOUT)) { 2207707ccabSKonstantin Belousov if ((uap->len == 0 && curproc->p_osrel >= P_OSREL_MAP_ANON) || 2217707ccabSKonstantin Belousov ((flags & MAP_ANON) != 0 && (uap->fd != -1 || pos != 0))) 222df8bae1dSRodney W. Grimes return (EINVAL); 2237707ccabSKonstantin Belousov } else { 2247707ccabSKonstantin Belousov if ((flags & MAP_ANON) != 0) 2257707ccabSKonstantin Belousov pos = 0; 2267707ccabSKonstantin Belousov } 2279154ee6aSPeter Wemm 2282267af78SJulian Elischer if (flags & MAP_STACK) { 2292267af78SJulian Elischer if ((uap->fd != -1) || 2302267af78SJulian Elischer ((prot & (PROT_READ | PROT_WRITE)) != (PROT_READ | PROT_WRITE))) 2312267af78SJulian Elischer return (EINVAL); 2322267af78SJulian Elischer flags |= MAP_ANON; 2332267af78SJulian Elischer pos = 0; 2342907af2aSJulian Elischer } 2352907af2aSJulian Elischer 2369154ee6aSPeter Wemm /* 23754f42e4bSPeter Wemm * Align the file position to a page boundary, 23854f42e4bSPeter Wemm * and save its page offset component. 2399154ee6aSPeter Wemm */ 24054f42e4bSPeter Wemm pageoff = (pos & PAGE_MASK); 24154f42e4bSPeter Wemm pos -= pageoff; 24254f42e4bSPeter Wemm 24354f42e4bSPeter Wemm /* Adjust size for rounding (on both ends). */ 24454f42e4bSPeter Wemm size += pageoff; /* low end... */ 24554f42e4bSPeter Wemm size = (vm_size_t) round_page(size); /* hi end */ 2469154ee6aSPeter Wemm 247df8bae1dSRodney W. Grimes /* 2480d94caffSDavid Greenman * Check for illegal addresses. Watch out for address wrap... Note 2490d94caffSDavid Greenman * that VM_*_ADDRESS are not constants due to casts (argh). 250df8bae1dSRodney W. Grimes */ 251df8bae1dSRodney W. Grimes if (flags & MAP_FIXED) { 25254f42e4bSPeter Wemm /* 25354f42e4bSPeter Wemm * The specified address must have the same remainder 25454f42e4bSPeter Wemm * as the file offset taken modulo PAGE_SIZE, so it 25554f42e4bSPeter Wemm * should be aligned after adjustment by pageoff. 25654f42e4bSPeter Wemm */ 25754f42e4bSPeter Wemm addr -= pageoff; 25854f42e4bSPeter Wemm if (addr & PAGE_MASK) 25954f42e4bSPeter Wemm return (EINVAL); 26027bfa958SSimon L. B. Nielsen 26154f42e4bSPeter Wemm /* Address range must be all in user VM space. */ 26205ba50f5SJake Burkholder if (addr < vm_map_min(&vms->vm_map) || 26305ba50f5SJake Burkholder addr + size > vm_map_max(&vms->vm_map)) 264df8bae1dSRodney W. Grimes return (EINVAL); 265bbc0ec52SDavid Greenman if (addr + size < addr) 266df8bae1dSRodney W. Grimes return (EINVAL); 26791d5354aSJohn Baldwin } else { 268df8bae1dSRodney W. Grimes /* 26954f42e4bSPeter Wemm * XXX for non-fixed mappings where no hint is provided or 27054f42e4bSPeter Wemm * the hint would fall in the potential heap space, 27154f42e4bSPeter Wemm * place it after the end of the largest possible heap. 272df8bae1dSRodney W. Grimes * 27354f42e4bSPeter Wemm * There should really be a pmap call to determine a reasonable 27454f42e4bSPeter Wemm * location. 275df8bae1dSRodney W. Grimes */ 27691d5354aSJohn Baldwin PROC_LOCK(td->td_proc); 27791d5354aSJohn Baldwin if (addr == 0 || 2781f6889a1SMatthew Dillon (addr >= round_page((vm_offset_t)vms->vm_taddr) && 279c460ac3aSPeter Wemm addr < round_page((vm_offset_t)vms->vm_daddr + 28091d5354aSJohn Baldwin lim_max(td->td_proc, RLIMIT_DATA)))) 281c460ac3aSPeter Wemm addr = round_page((vm_offset_t)vms->vm_daddr + 28291d5354aSJohn Baldwin lim_max(td->td_proc, RLIMIT_DATA)); 28391d5354aSJohn Baldwin PROC_UNLOCK(td->td_proc); 28491d5354aSJohn Baldwin } 285df8bae1dSRodney W. Grimes if (flags & MAP_ANON) { 286df8bae1dSRodney W. Grimes /* 287df8bae1dSRodney W. Grimes * Mapping blank space is trivial. 288df8bae1dSRodney W. Grimes */ 289df8bae1dSRodney W. Grimes handle = NULL; 29098df9218SJohn Baldwin handle_type = OBJT_DEFAULT; 291df8bae1dSRodney W. Grimes maxprot = VM_PROT_ALL; 292a9d2f8d8SRobert Watson cap_maxprot = VM_PROT_ALL; 29330d4dd7eSAlexander Kabaev } else { 294df8bae1dSRodney W. Grimes /* 295a9d2f8d8SRobert Watson * Mapping file, get fp for validation and don't let the 296a9d2f8d8SRobert Watson * descriptor disappear on us if we block. Check capability 297a9d2f8d8SRobert Watson * rights, but also return the maximum rights to be combined 298a9d2f8d8SRobert Watson * with maxprot later. 299df8bae1dSRodney W. Grimes */ 300a9d2f8d8SRobert Watson rights = CAP_MMAP; 301a9d2f8d8SRobert Watson if (prot & PROT_READ) 302a9d2f8d8SRobert Watson rights |= CAP_READ; 303a9d2f8d8SRobert Watson if ((flags & MAP_SHARED) != 0) { 304a9d2f8d8SRobert Watson if (prot & PROT_WRITE) 305a9d2f8d8SRobert Watson rights |= CAP_WRITE; 306a9d2f8d8SRobert Watson } 307a9d2f8d8SRobert Watson if (prot & PROT_EXEC) 308a9d2f8d8SRobert Watson rights |= CAP_MAPEXEC; 309a9d2f8d8SRobert Watson if ((error = fget_mmap(td, uap->fd, rights, &cap_maxprot, 310a9d2f8d8SRobert Watson &fp)) != 0) 311426da3bcSAlfred Perlstein goto done; 3128e38aeffSJohn Baldwin if (fp->f_type == DTYPE_SHM) { 3138e38aeffSJohn Baldwin handle = fp->f_data; 3148e38aeffSJohn Baldwin handle_type = OBJT_SWAP; 3158e38aeffSJohn Baldwin maxprot = VM_PROT_NONE; 3168e38aeffSJohn Baldwin 3178e38aeffSJohn Baldwin /* FREAD should always be set. */ 3188e38aeffSJohn Baldwin if (fp->f_flag & FREAD) 3198e38aeffSJohn Baldwin maxprot |= VM_PROT_EXECUTE | VM_PROT_READ; 3208e38aeffSJohn Baldwin if (fp->f_flag & FWRITE) 3218e38aeffSJohn Baldwin maxprot |= VM_PROT_WRITE; 3228e38aeffSJohn Baldwin goto map; 3238e38aeffSJohn Baldwin } 324e4ca250dSJohn Baldwin if (fp->f_type != DTYPE_VNODE) { 32589eae00bSTom Rhodes error = ENODEV; 326426da3bcSAlfred Perlstein goto done; 327e4ca250dSJohn Baldwin } 3288e38aeffSJohn Baldwin #if defined(COMPAT_FREEBSD7) || defined(COMPAT_FREEBSD6) || \ 3298e38aeffSJohn Baldwin defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) 330279d7226SMatthew Dillon /* 331aa543039SGarrett Wollman * POSIX shared-memory objects are defined to have 332aa543039SGarrett Wollman * kernel persistence, and are not defined to support 333aa543039SGarrett Wollman * read(2)/write(2) -- or even open(2). Thus, we can 334aa543039SGarrett Wollman * use MAP_ASYNC to trade on-disk coherence for speed. 335aa543039SGarrett Wollman * The shm_open(3) library routine turns on the FPOSIXSHM 336aa543039SGarrett Wollman * flag to request this behavior. 337aa543039SGarrett Wollman */ 338aa543039SGarrett Wollman if (fp->f_flag & FPOSIXSHM) 339aa543039SGarrett Wollman flags |= MAP_NOSYNC; 3408e38aeffSJohn Baldwin #endif 3413b6d9652SPoul-Henning Kamp vp = fp->f_vnode; 342c8bdd56bSGuido van Rooij /* 343df8bae1dSRodney W. Grimes * Ensure that file and memory protections are 344df8bae1dSRodney W. Grimes * compatible. Note that we only worry about 345df8bae1dSRodney W. Grimes * writability if mapping is shared; in this case, 346df8bae1dSRodney W. Grimes * current and max prot are dictated by the open file. 347df8bae1dSRodney W. Grimes * XXX use the vnode instead? Problem is: what 3480d94caffSDavid Greenman * credentials do we use for determination? What if 3490d94caffSDavid Greenman * proc does a setuid? 350df8bae1dSRodney W. Grimes */ 3518eec77b0STim J. Robbins if (vp->v_mount != NULL && vp->v_mount->mnt_flag & MNT_NOEXEC) 352b483c7f6SGuido van Rooij maxprot = VM_PROT_NONE; 353b483c7f6SGuido van Rooij else 354b483c7f6SGuido van Rooij maxprot = VM_PROT_EXECUTE; 355279d7226SMatthew Dillon if (fp->f_flag & FREAD) { 356df8bae1dSRodney W. Grimes maxprot |= VM_PROT_READ; 357279d7226SMatthew Dillon } else if (prot & PROT_READ) { 358279d7226SMatthew Dillon error = EACCES; 359279d7226SMatthew Dillon goto done; 360279d7226SMatthew Dillon } 361c8bdd56bSGuido van Rooij /* 362c8bdd56bSGuido van Rooij * If we are sharing potential changes (either via 363c8bdd56bSGuido van Rooij * MAP_SHARED or via the implicit sharing of character 364c8bdd56bSGuido van Rooij * device mappings), and we are trying to get write 365c8bdd56bSGuido van Rooij * permission although we opened it without asking 366c8daea13SAlexander Kabaev * for it, bail out. 367c8bdd56bSGuido van Rooij */ 368ce7a036dSAlexander Kabaev if ((flags & MAP_SHARED) != 0) { 36905feb99fSGuido van Rooij if ((fp->f_flag & FWRITE) != 0) { 370df8bae1dSRodney W. Grimes maxprot |= VM_PROT_WRITE; 371279d7226SMatthew Dillon } else if ((prot & PROT_WRITE) != 0) { 372279d7226SMatthew Dillon error = EACCES; 373279d7226SMatthew Dillon goto done; 374279d7226SMatthew Dillon } 375ce7a036dSAlexander Kabaev } else if (vp->v_type != VCHR || (fp->f_flag & FWRITE) != 0) { 37605feb99fSGuido van Rooij maxprot |= VM_PROT_WRITE; 377a9d2f8d8SRobert Watson cap_maxprot |= VM_PROT_WRITE; 378279d7226SMatthew Dillon } 379651bb817SAlexander Langer handle = (void *)vp; 38098df9218SJohn Baldwin handle_type = OBJT_VNODE; 38130d4dd7eSAlexander Kabaev } 3828e38aeffSJohn Baldwin map: 38336b90789SKonstantin Belousov td->td_fpop = fp; 384a9d2f8d8SRobert Watson maxprot &= cap_maxprot; 3851f6889a1SMatthew Dillon error = vm_mmap(&vms->vm_map, &addr, size, prot, maxprot, 38698df9218SJohn Baldwin flags, handle_type, handle, pos); 38736b90789SKonstantin Belousov td->td_fpop = NULL; 38849874f6eSJoseph Koshy #ifdef HWPMC_HOOKS 38949874f6eSJoseph Koshy /* inform hwpmc(4) if an executable is being mapped */ 39049874f6eSJoseph Koshy if (error == 0 && handle_type == OBJT_VNODE && 39149874f6eSJoseph Koshy (prot & PROT_EXEC)) { 39249874f6eSJoseph Koshy pkm.pm_file = handle; 39349874f6eSJoseph Koshy pkm.pm_address = (uintptr_t) addr; 39449874f6eSJoseph Koshy PMC_CALL_HOOK(td, PMC_FN_MMAP, (void *) &pkm); 39549874f6eSJoseph Koshy } 39649874f6eSJoseph Koshy #endif 397df8bae1dSRodney W. Grimes if (error == 0) 398b40ce416SJulian Elischer td->td_retval[0] = (register_t) (addr + pageoff); 399279d7226SMatthew Dillon done: 400279d7226SMatthew Dillon if (fp) 401b40ce416SJulian Elischer fdrop(fp, td); 402f6b5b182SJeff Roberson 403df8bae1dSRodney W. Grimes return (error); 404df8bae1dSRodney W. Grimes } 405df8bae1dSRodney W. Grimes 406c2815ad5SPeter Wemm int 407c2815ad5SPeter Wemm freebsd6_mmap(struct thread *td, struct freebsd6_mmap_args *uap) 408c2815ad5SPeter Wemm { 409c2815ad5SPeter Wemm struct mmap_args oargs; 410c2815ad5SPeter Wemm 411c2815ad5SPeter Wemm oargs.addr = uap->addr; 412c2815ad5SPeter Wemm oargs.len = uap->len; 413c2815ad5SPeter Wemm oargs.prot = uap->prot; 414c2815ad5SPeter Wemm oargs.flags = uap->flags; 415c2815ad5SPeter Wemm oargs.fd = uap->fd; 416c2815ad5SPeter Wemm oargs.pos = uap->pos; 4178451d0ddSKip Macy return (sys_mmap(td, &oargs)); 418c2815ad5SPeter Wemm } 419c2815ad5SPeter Wemm 42005f0fdd2SPoul-Henning Kamp #ifdef COMPAT_43 421d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 42205f0fdd2SPoul-Henning Kamp struct ommap_args { 42305f0fdd2SPoul-Henning Kamp caddr_t addr; 42405f0fdd2SPoul-Henning Kamp int len; 42505f0fdd2SPoul-Henning Kamp int prot; 42605f0fdd2SPoul-Henning Kamp int flags; 42705f0fdd2SPoul-Henning Kamp int fd; 42805f0fdd2SPoul-Henning Kamp long pos; 42905f0fdd2SPoul-Henning Kamp }; 430d2d3e875SBruce Evans #endif 43105f0fdd2SPoul-Henning Kamp int 432b40ce416SJulian Elischer ommap(td, uap) 433b40ce416SJulian Elischer struct thread *td; 43454d92145SMatthew Dillon struct ommap_args *uap; 43505f0fdd2SPoul-Henning Kamp { 43605f0fdd2SPoul-Henning Kamp struct mmap_args nargs; 43705f0fdd2SPoul-Henning Kamp static const char cvtbsdprot[8] = { 43805f0fdd2SPoul-Henning Kamp 0, 43905f0fdd2SPoul-Henning Kamp PROT_EXEC, 44005f0fdd2SPoul-Henning Kamp PROT_WRITE, 44105f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE, 44205f0fdd2SPoul-Henning Kamp PROT_READ, 44305f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_READ, 44405f0fdd2SPoul-Henning Kamp PROT_WRITE | PROT_READ, 44505f0fdd2SPoul-Henning Kamp PROT_EXEC | PROT_WRITE | PROT_READ, 44605f0fdd2SPoul-Henning Kamp }; 4470d94caffSDavid Greenman 44805f0fdd2SPoul-Henning Kamp #define OMAP_ANON 0x0002 44905f0fdd2SPoul-Henning Kamp #define OMAP_COPY 0x0020 45005f0fdd2SPoul-Henning Kamp #define OMAP_SHARED 0x0010 45105f0fdd2SPoul-Henning Kamp #define OMAP_FIXED 0x0100 45205f0fdd2SPoul-Henning Kamp 45305f0fdd2SPoul-Henning Kamp nargs.addr = uap->addr; 45405f0fdd2SPoul-Henning Kamp nargs.len = uap->len; 45505f0fdd2SPoul-Henning Kamp nargs.prot = cvtbsdprot[uap->prot & 0x7]; 456ee4116b8SKonstantin Belousov #ifdef COMPAT_FREEBSD32 457ee4116b8SKonstantin Belousov #if defined(__amd64__) || defined(__ia64__) 458ee4116b8SKonstantin Belousov if (i386_read_exec && SV_PROC_FLAG(td->td_proc, SV_ILP32) && 459ee4116b8SKonstantin Belousov nargs.prot != 0) 460ee4116b8SKonstantin Belousov nargs.prot |= PROT_EXEC; 461ee4116b8SKonstantin Belousov #endif 462ee4116b8SKonstantin Belousov #endif 46305f0fdd2SPoul-Henning Kamp nargs.flags = 0; 46405f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_ANON) 46505f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_ANON; 46605f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_COPY) 46705f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_COPY; 46805f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_SHARED) 46905f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_SHARED; 47005f0fdd2SPoul-Henning Kamp else 47105f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_PRIVATE; 47205f0fdd2SPoul-Henning Kamp if (uap->flags & OMAP_FIXED) 47305f0fdd2SPoul-Henning Kamp nargs.flags |= MAP_FIXED; 47405f0fdd2SPoul-Henning Kamp nargs.fd = uap->fd; 47505f0fdd2SPoul-Henning Kamp nargs.pos = uap->pos; 4768451d0ddSKip Macy return (sys_mmap(td, &nargs)); 47705f0fdd2SPoul-Henning Kamp } 47805f0fdd2SPoul-Henning Kamp #endif /* COMPAT_43 */ 47905f0fdd2SPoul-Henning Kamp 48005f0fdd2SPoul-Henning Kamp 481d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 482df8bae1dSRodney W. Grimes struct msync_args { 483651bb817SAlexander Langer void *addr; 484c899450bSPeter Wemm size_t len; 485e6c6af11SDavid Greenman int flags; 486df8bae1dSRodney W. Grimes }; 487d2d3e875SBruce Evans #endif 488d2c60af8SMatthew Dillon /* 489d2c60af8SMatthew Dillon * MPSAFE 490d2c60af8SMatthew Dillon */ 491df8bae1dSRodney W. Grimes int 4928451d0ddSKip Macy sys_msync(td, uap) 493b40ce416SJulian Elischer struct thread *td; 494df8bae1dSRodney W. Grimes struct msync_args *uap; 495df8bae1dSRodney W. Grimes { 496df8bae1dSRodney W. Grimes vm_offset_t addr; 497dabee6feSPeter Wemm vm_size_t size, pageoff; 498e6c6af11SDavid Greenman int flags; 499df8bae1dSRodney W. Grimes vm_map_t map; 500df8bae1dSRodney W. Grimes int rv; 501df8bae1dSRodney W. Grimes 502df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 5039154ee6aSPeter Wemm size = uap->len; 504e6c6af11SDavid Greenman flags = uap->flags; 505e6c6af11SDavid Greenman 506dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 507dabee6feSPeter Wemm addr -= pageoff; 508dabee6feSPeter Wemm size += pageoff; 509dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 5109154ee6aSPeter Wemm if (addr + size < addr) 511dabee6feSPeter Wemm return (EINVAL); 512dabee6feSPeter Wemm 513dabee6feSPeter Wemm if ((flags & (MS_ASYNC|MS_INVALIDATE)) == (MS_ASYNC|MS_INVALIDATE)) 5141e62bc63SDavid Greenman return (EINVAL); 5151e62bc63SDavid Greenman 516b40ce416SJulian Elischer map = &td->td_proc->p_vmspace->vm_map; 5179154ee6aSPeter Wemm 518df8bae1dSRodney W. Grimes /* 519df8bae1dSRodney W. Grimes * Clean the pages and interpret the return value. 520df8bae1dSRodney W. Grimes */ 521950f8459SAlan Cox rv = vm_map_sync(map, addr, addr + size, (flags & MS_ASYNC) == 0, 522e6c6af11SDavid Greenman (flags & MS_INVALIDATE) != 0); 523df8bae1dSRodney W. Grimes switch (rv) { 524df8bae1dSRodney W. Grimes case KERN_SUCCESS: 525d2c60af8SMatthew Dillon return (0); 526df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 527df8bae1dSRodney W. Grimes return (EINVAL); /* Sun returns ENOMEM? */ 528b7b7cd44SAlan Cox case KERN_INVALID_ARGUMENT: 529b7b7cd44SAlan Cox return (EBUSY); 530126d6082SKonstantin Belousov case KERN_FAILURE: 531126d6082SKonstantin Belousov return (EIO); 532df8bae1dSRodney W. Grimes default: 533df8bae1dSRodney W. Grimes return (EINVAL); 534df8bae1dSRodney W. Grimes } 535df8bae1dSRodney W. Grimes } 536df8bae1dSRodney W. Grimes 537d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 538df8bae1dSRodney W. Grimes struct munmap_args { 539651bb817SAlexander Langer void *addr; 5409154ee6aSPeter Wemm size_t len; 541df8bae1dSRodney W. Grimes }; 542d2d3e875SBruce Evans #endif 543d2c60af8SMatthew Dillon /* 544d2c60af8SMatthew Dillon * MPSAFE 545d2c60af8SMatthew Dillon */ 546df8bae1dSRodney W. Grimes int 5478451d0ddSKip Macy sys_munmap(td, uap) 548b40ce416SJulian Elischer struct thread *td; 54954d92145SMatthew Dillon struct munmap_args *uap; 550df8bae1dSRodney W. Grimes { 55149874f6eSJoseph Koshy #ifdef HWPMC_HOOKS 55249874f6eSJoseph Koshy struct pmckern_map_out pkm; 55349874f6eSJoseph Koshy vm_map_entry_t entry; 55449874f6eSJoseph Koshy #endif 555df8bae1dSRodney W. Grimes vm_offset_t addr; 556dabee6feSPeter Wemm vm_size_t size, pageoff; 557df8bae1dSRodney W. Grimes vm_map_t map; 558df8bae1dSRodney W. Grimes 559df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 5609154ee6aSPeter Wemm size = uap->len; 561d8834602SAlan Cox if (size == 0) 562d8834602SAlan Cox return (EINVAL); 563dabee6feSPeter Wemm 564dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 565dabee6feSPeter Wemm addr -= pageoff; 566dabee6feSPeter Wemm size += pageoff; 567dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 5689154ee6aSPeter Wemm if (addr + size < addr) 569df8bae1dSRodney W. Grimes return (EINVAL); 5709154ee6aSPeter Wemm 571df8bae1dSRodney W. Grimes /* 57205ba50f5SJake Burkholder * Check for illegal addresses. Watch out for address wrap... 573df8bae1dSRodney W. Grimes */ 574b40ce416SJulian Elischer map = &td->td_proc->p_vmspace->vm_map; 57505ba50f5SJake Burkholder if (addr < vm_map_min(map) || addr + size > vm_map_max(map)) 57605ba50f5SJake Burkholder return (EINVAL); 577d8834602SAlan Cox vm_map_lock(map); 57849874f6eSJoseph Koshy #ifdef HWPMC_HOOKS 57949874f6eSJoseph Koshy /* 58049874f6eSJoseph Koshy * Inform hwpmc if the address range being unmapped contains 58149874f6eSJoseph Koshy * an executable region. 58249874f6eSJoseph Koshy */ 5830d419640SRyan Stone pkm.pm_address = (uintptr_t) NULL; 58449874f6eSJoseph Koshy if (vm_map_lookup_entry(map, addr, &entry)) { 58549874f6eSJoseph Koshy for (; 58649874f6eSJoseph Koshy entry != &map->header && entry->start < addr + size; 58749874f6eSJoseph Koshy entry = entry->next) { 58849874f6eSJoseph Koshy if (vm_map_check_protection(map, entry->start, 58949874f6eSJoseph Koshy entry->end, VM_PROT_EXECUTE) == TRUE) { 59049874f6eSJoseph Koshy pkm.pm_address = (uintptr_t) addr; 59149874f6eSJoseph Koshy pkm.pm_size = (size_t) size; 59249874f6eSJoseph Koshy break; 59349874f6eSJoseph Koshy } 59449874f6eSJoseph Koshy } 59549874f6eSJoseph Koshy } 59649874f6eSJoseph Koshy #endif 597655c3490SKonstantin Belousov vm_map_delete(map, addr, addr + size); 5980d419640SRyan Stone 5990d419640SRyan Stone #ifdef HWPMC_HOOKS 6000d419640SRyan Stone /* downgrade the lock to prevent a LOR with the pmc-sx lock */ 6010d419640SRyan Stone vm_map_lock_downgrade(map); 602d473d3a1SRyan Stone if (pkm.pm_address != (uintptr_t) NULL) 6030d419640SRyan Stone PMC_CALL_HOOK(td, PMC_FN_MUNMAP, (void *) &pkm); 6040d419640SRyan Stone vm_map_unlock_read(map); 6050d419640SRyan Stone #else 606d8834602SAlan Cox vm_map_unlock(map); 6070d419640SRyan Stone #endif 6080d419640SRyan Stone /* vm_map_delete returns nothing but KERN_SUCCESS anyway */ 609df8bae1dSRodney W. Grimes return (0); 610df8bae1dSRodney W. Grimes } 611df8bae1dSRodney W. Grimes 612d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 613df8bae1dSRodney W. Grimes struct mprotect_args { 614651bb817SAlexander Langer const void *addr; 6159154ee6aSPeter Wemm size_t len; 616df8bae1dSRodney W. Grimes int prot; 617df8bae1dSRodney W. Grimes }; 618d2d3e875SBruce Evans #endif 619d2c60af8SMatthew Dillon /* 620d2c60af8SMatthew Dillon * MPSAFE 621d2c60af8SMatthew Dillon */ 622df8bae1dSRodney W. Grimes int 6238451d0ddSKip Macy sys_mprotect(td, uap) 624b40ce416SJulian Elischer struct thread *td; 625df8bae1dSRodney W. Grimes struct mprotect_args *uap; 626df8bae1dSRodney W. Grimes { 627df8bae1dSRodney W. Grimes vm_offset_t addr; 628dabee6feSPeter Wemm vm_size_t size, pageoff; 62954d92145SMatthew Dillon vm_prot_t prot; 630df8bae1dSRodney W. Grimes 631df8bae1dSRodney W. Grimes addr = (vm_offset_t) uap->addr; 6329154ee6aSPeter Wemm size = uap->len; 633df8bae1dSRodney W. Grimes prot = uap->prot & VM_PROT_ALL; 634df8bae1dSRodney W. Grimes 635dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 636dabee6feSPeter Wemm addr -= pageoff; 637dabee6feSPeter Wemm size += pageoff; 638dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 6399154ee6aSPeter Wemm if (addr + size < addr) 640dabee6feSPeter Wemm return (EINVAL); 641dabee6feSPeter Wemm 64243285049SAlan Cox switch (vm_map_protect(&td->td_proc->p_vmspace->vm_map, addr, 64343285049SAlan Cox addr + size, prot, FALSE)) { 644df8bae1dSRodney W. Grimes case KERN_SUCCESS: 645df8bae1dSRodney W. Grimes return (0); 646df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 647df8bae1dSRodney W. Grimes return (EACCES); 6483364c323SKonstantin Belousov case KERN_RESOURCE_SHORTAGE: 6493364c323SKonstantin Belousov return (ENOMEM); 650df8bae1dSRodney W. Grimes } 651df8bae1dSRodney W. Grimes return (EINVAL); 652df8bae1dSRodney W. Grimes } 653df8bae1dSRodney W. Grimes 654d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 655dabee6feSPeter Wemm struct minherit_args { 656651bb817SAlexander Langer void *addr; 6579154ee6aSPeter Wemm size_t len; 658dabee6feSPeter Wemm int inherit; 659dabee6feSPeter Wemm }; 660dabee6feSPeter Wemm #endif 661d2c60af8SMatthew Dillon /* 662d2c60af8SMatthew Dillon * MPSAFE 663d2c60af8SMatthew Dillon */ 664dabee6feSPeter Wemm int 6658451d0ddSKip Macy sys_minherit(td, uap) 666b40ce416SJulian Elischer struct thread *td; 667dabee6feSPeter Wemm struct minherit_args *uap; 668dabee6feSPeter Wemm { 669dabee6feSPeter Wemm vm_offset_t addr; 670dabee6feSPeter Wemm vm_size_t size, pageoff; 67154d92145SMatthew Dillon vm_inherit_t inherit; 672dabee6feSPeter Wemm 673dabee6feSPeter Wemm addr = (vm_offset_t)uap->addr; 6749154ee6aSPeter Wemm size = uap->len; 675dabee6feSPeter Wemm inherit = uap->inherit; 676dabee6feSPeter Wemm 677dabee6feSPeter Wemm pageoff = (addr & PAGE_MASK); 678dabee6feSPeter Wemm addr -= pageoff; 679dabee6feSPeter Wemm size += pageoff; 680dabee6feSPeter Wemm size = (vm_size_t) round_page(size); 6819154ee6aSPeter Wemm if (addr + size < addr) 682dabee6feSPeter Wemm return (EINVAL); 683dabee6feSPeter Wemm 684e0be79afSAlan Cox switch (vm_map_inherit(&td->td_proc->p_vmspace->vm_map, addr, 685e0be79afSAlan Cox addr + size, inherit)) { 686dabee6feSPeter Wemm case KERN_SUCCESS: 687dabee6feSPeter Wemm return (0); 688dabee6feSPeter Wemm case KERN_PROTECTION_FAILURE: 689dabee6feSPeter Wemm return (EACCES); 690dabee6feSPeter Wemm } 691dabee6feSPeter Wemm return (EINVAL); 692dabee6feSPeter Wemm } 693dabee6feSPeter Wemm 694dabee6feSPeter Wemm #ifndef _SYS_SYSPROTO_H_ 695df8bae1dSRodney W. Grimes struct madvise_args { 696651bb817SAlexander Langer void *addr; 6979154ee6aSPeter Wemm size_t len; 698df8bae1dSRodney W. Grimes int behav; 699df8bae1dSRodney W. Grimes }; 700d2d3e875SBruce Evans #endif 7010d94caffSDavid Greenman 702d2c60af8SMatthew Dillon /* 703d2c60af8SMatthew Dillon * MPSAFE 704d2c60af8SMatthew Dillon */ 705df8bae1dSRodney W. Grimes int 7068451d0ddSKip Macy sys_madvise(td, uap) 707b40ce416SJulian Elischer struct thread *td; 708df8bae1dSRodney W. Grimes struct madvise_args *uap; 709df8bae1dSRodney W. Grimes { 710f35329acSJohn Dyson vm_offset_t start, end; 71105ba50f5SJake Burkholder vm_map_t map; 712f4cf2141SWes Peters struct proc *p; 713f4cf2141SWes Peters int error; 714b4309055SMatthew Dillon 715b4309055SMatthew Dillon /* 716f4cf2141SWes Peters * Check for our special case, advising the swap pager we are 717f4cf2141SWes Peters * "immortal." 718f4cf2141SWes Peters */ 719f4cf2141SWes Peters if (uap->behav == MADV_PROTECT) { 720acd3428bSRobert Watson error = priv_check(td, PRIV_VM_MADV_PROTECT); 72169297bf8SJohn Baldwin if (error == 0) { 722f4cf2141SWes Peters p = td->td_proc; 723f4cf2141SWes Peters PROC_LOCK(p); 724f4cf2141SWes Peters p->p_flag |= P_PROTECTED; 725f4cf2141SWes Peters PROC_UNLOCK(p); 72669297bf8SJohn Baldwin } 727f4cf2141SWes Peters return (error); 728f4cf2141SWes Peters } 729f4cf2141SWes Peters /* 730b4309055SMatthew Dillon * Check for illegal behavior 731b4309055SMatthew Dillon */ 7329730a5daSPaul Saab if (uap->behav < 0 || uap->behav > MADV_CORE) 733b4309055SMatthew Dillon return (EINVAL); 734867a482dSJohn Dyson /* 735867a482dSJohn Dyson * Check for illegal addresses. Watch out for address wrap... Note 736867a482dSJohn Dyson * that VM_*_ADDRESS are not constants due to casts (argh). 737867a482dSJohn Dyson */ 73805ba50f5SJake Burkholder map = &td->td_proc->p_vmspace->vm_map; 73905ba50f5SJake Burkholder if ((vm_offset_t)uap->addr < vm_map_min(map) || 74005ba50f5SJake Burkholder (vm_offset_t)uap->addr + uap->len > vm_map_max(map)) 741867a482dSJohn Dyson return (EINVAL); 742867a482dSJohn Dyson if (((vm_offset_t) uap->addr + uap->len) < (vm_offset_t) uap->addr) 743867a482dSJohn Dyson return (EINVAL); 744867a482dSJohn Dyson 745867a482dSJohn Dyson /* 746867a482dSJohn Dyson * Since this routine is only advisory, we default to conservative 747867a482dSJohn Dyson * behavior. 748867a482dSJohn Dyson */ 749cd6eea25SDavid Greenman start = trunc_page((vm_offset_t) uap->addr); 750cd6eea25SDavid Greenman end = round_page((vm_offset_t) uap->addr + uap->len); 751867a482dSJohn Dyson 75205ba50f5SJake Burkholder if (vm_map_madvise(map, start, end, uap->behav)) 753094f6d26SAlan Cox return (EINVAL); 754094f6d26SAlan Cox return (0); 755df8bae1dSRodney W. Grimes } 756df8bae1dSRodney W. Grimes 757d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 758df8bae1dSRodney W. Grimes struct mincore_args { 759651bb817SAlexander Langer const void *addr; 7609154ee6aSPeter Wemm size_t len; 761df8bae1dSRodney W. Grimes char *vec; 762df8bae1dSRodney W. Grimes }; 763d2d3e875SBruce Evans #endif 7640d94caffSDavid Greenman 765d2c60af8SMatthew Dillon /* 766d2c60af8SMatthew Dillon * MPSAFE 767d2c60af8SMatthew Dillon */ 768df8bae1dSRodney W. Grimes int 7698451d0ddSKip Macy sys_mincore(td, uap) 770b40ce416SJulian Elischer struct thread *td; 771df8bae1dSRodney W. Grimes struct mincore_args *uap; 772df8bae1dSRodney W. Grimes { 773867a482dSJohn Dyson vm_offset_t addr, first_addr; 774867a482dSJohn Dyson vm_offset_t end, cend; 775867a482dSJohn Dyson pmap_t pmap; 776867a482dSJohn Dyson vm_map_t map; 77702c04a2fSJohn Dyson char *vec; 778d2c60af8SMatthew Dillon int error = 0; 779867a482dSJohn Dyson int vecindex, lastvecindex; 78054d92145SMatthew Dillon vm_map_entry_t current; 781867a482dSJohn Dyson vm_map_entry_t entry; 782567e51e1SAlan Cox vm_object_t object; 783567e51e1SAlan Cox vm_paddr_t locked_pa; 784567e51e1SAlan Cox vm_page_t m; 785567e51e1SAlan Cox vm_pindex_t pindex; 786867a482dSJohn Dyson int mincoreinfo; 787dd2622a8SAlan Cox unsigned int timestamp; 788567e51e1SAlan Cox boolean_t locked; 789df8bae1dSRodney W. Grimes 790867a482dSJohn Dyson /* 791867a482dSJohn Dyson * Make sure that the addresses presented are valid for user 792867a482dSJohn Dyson * mode. 793867a482dSJohn Dyson */ 794867a482dSJohn Dyson first_addr = addr = trunc_page((vm_offset_t) uap->addr); 7959154ee6aSPeter Wemm end = addr + (vm_size_t)round_page(uap->len); 79605ba50f5SJake Burkholder map = &td->td_proc->p_vmspace->vm_map; 79705ba50f5SJake Burkholder if (end > vm_map_max(map) || end < addr) 798455dd7d4SKonstantin Belousov return (ENOMEM); 79902c04a2fSJohn Dyson 800867a482dSJohn Dyson /* 801867a482dSJohn Dyson * Address of byte vector 802867a482dSJohn Dyson */ 80302c04a2fSJohn Dyson vec = uap->vec; 804867a482dSJohn Dyson 805b40ce416SJulian Elischer pmap = vmspace_pmap(td->td_proc->p_vmspace); 806867a482dSJohn Dyson 807eff50fcdSAlan Cox vm_map_lock_read(map); 808dd2622a8SAlan Cox RestartScan: 809dd2622a8SAlan Cox timestamp = map->timestamp; 810867a482dSJohn Dyson 811455dd7d4SKonstantin Belousov if (!vm_map_lookup_entry(map, addr, &entry)) { 812455dd7d4SKonstantin Belousov vm_map_unlock_read(map); 813455dd7d4SKonstantin Belousov return (ENOMEM); 814455dd7d4SKonstantin Belousov } 815867a482dSJohn Dyson 816867a482dSJohn Dyson /* 817867a482dSJohn Dyson * Do this on a map entry basis so that if the pages are not 818867a482dSJohn Dyson * in the current processes address space, we can easily look 819867a482dSJohn Dyson * up the pages elsewhere. 820867a482dSJohn Dyson */ 821867a482dSJohn Dyson lastvecindex = -1; 822867a482dSJohn Dyson for (current = entry; 823867a482dSJohn Dyson (current != &map->header) && (current->start < end); 824867a482dSJohn Dyson current = current->next) { 825867a482dSJohn Dyson 826867a482dSJohn Dyson /* 827455dd7d4SKonstantin Belousov * check for contiguity 828455dd7d4SKonstantin Belousov */ 829455dd7d4SKonstantin Belousov if (current->end < end && 830455dd7d4SKonstantin Belousov (entry->next == &map->header || 831455dd7d4SKonstantin Belousov current->next->start > current->end)) { 832455dd7d4SKonstantin Belousov vm_map_unlock_read(map); 833455dd7d4SKonstantin Belousov return (ENOMEM); 834455dd7d4SKonstantin Belousov } 835455dd7d4SKonstantin Belousov 836455dd7d4SKonstantin Belousov /* 837867a482dSJohn Dyson * ignore submaps (for now) or null objects 838867a482dSJohn Dyson */ 8399fdfe602SMatthew Dillon if ((current->eflags & MAP_ENTRY_IS_SUB_MAP) || 840867a482dSJohn Dyson current->object.vm_object == NULL) 841867a482dSJohn Dyson continue; 842867a482dSJohn Dyson 843867a482dSJohn Dyson /* 844867a482dSJohn Dyson * limit this scan to the current map entry and the 845867a482dSJohn Dyson * limits for the mincore call 846867a482dSJohn Dyson */ 847867a482dSJohn Dyson if (addr < current->start) 848867a482dSJohn Dyson addr = current->start; 849867a482dSJohn Dyson cend = current->end; 850867a482dSJohn Dyson if (cend > end) 851867a482dSJohn Dyson cend = end; 852867a482dSJohn Dyson 853867a482dSJohn Dyson /* 854867a482dSJohn Dyson * scan this entry one page at a time 855867a482dSJohn Dyson */ 856867a482dSJohn Dyson while (addr < cend) { 857867a482dSJohn Dyson /* 858867a482dSJohn Dyson * Check pmap first, it is likely faster, also 859867a482dSJohn Dyson * it can provide info as to whether we are the 860867a482dSJohn Dyson * one referencing or modifying the page. 861867a482dSJohn Dyson */ 862567e51e1SAlan Cox object = NULL; 863567e51e1SAlan Cox locked_pa = 0; 864567e51e1SAlan Cox retry: 865567e51e1SAlan Cox m = NULL; 866567e51e1SAlan Cox mincoreinfo = pmap_mincore(pmap, addr, &locked_pa); 867567e51e1SAlan Cox if (locked_pa != 0) { 868867a482dSJohn Dyson /* 869567e51e1SAlan Cox * The page is mapped by this process but not 870567e51e1SAlan Cox * both accessed and modified. It is also 871567e51e1SAlan Cox * managed. Acquire the object lock so that 872567e51e1SAlan Cox * other mappings might be examined. 873867a482dSJohn Dyson */ 874567e51e1SAlan Cox m = PHYS_TO_VM_PAGE(locked_pa); 875567e51e1SAlan Cox if (m->object != object) { 876567e51e1SAlan Cox if (object != NULL) 877567e51e1SAlan Cox VM_OBJECT_UNLOCK(object); 878567e51e1SAlan Cox object = m->object; 879567e51e1SAlan Cox locked = VM_OBJECT_TRYLOCK(object); 880567e51e1SAlan Cox vm_page_unlock(m); 881567e51e1SAlan Cox if (!locked) { 882567e51e1SAlan Cox VM_OBJECT_LOCK(object); 8832965a453SKip Macy vm_page_lock(m); 884567e51e1SAlan Cox goto retry; 885567e51e1SAlan Cox } 886567e51e1SAlan Cox } else 887567e51e1SAlan Cox vm_page_unlock(m); 888567e51e1SAlan Cox KASSERT(m->valid == VM_PAGE_BITS_ALL, 889567e51e1SAlan Cox ("mincore: page %p is mapped but invalid", 890567e51e1SAlan Cox m)); 891567e51e1SAlan Cox } else if (mincoreinfo == 0) { 892567e51e1SAlan Cox /* 893567e51e1SAlan Cox * The page is not mapped by this process. If 894567e51e1SAlan Cox * the object implements managed pages, then 895567e51e1SAlan Cox * determine if the page is resident so that 896567e51e1SAlan Cox * the mappings might be examined. 897567e51e1SAlan Cox */ 898567e51e1SAlan Cox if (current->object.vm_object != object) { 899567e51e1SAlan Cox if (object != NULL) 900567e51e1SAlan Cox VM_OBJECT_UNLOCK(object); 901567e51e1SAlan Cox object = current->object.vm_object; 902567e51e1SAlan Cox VM_OBJECT_LOCK(object); 903567e51e1SAlan Cox } 904567e51e1SAlan Cox if (object->type == OBJT_DEFAULT || 905567e51e1SAlan Cox object->type == OBJT_SWAP || 906567e51e1SAlan Cox object->type == OBJT_VNODE) { 907567e51e1SAlan Cox pindex = OFF_TO_IDX(current->offset + 908567e51e1SAlan Cox (addr - current->start)); 909567e51e1SAlan Cox m = vm_page_lookup(object, pindex); 9101c8279e4SAlan Cox if (m == NULL && 9111c8279e4SAlan Cox vm_page_is_cached(object, pindex)) 9121c8279e4SAlan Cox mincoreinfo = MINCORE_INCORE; 913567e51e1SAlan Cox if (m != NULL && m->valid == 0) 914567e51e1SAlan Cox m = NULL; 915567e51e1SAlan Cox if (m != NULL) 916567e51e1SAlan Cox mincoreinfo = MINCORE_INCORE; 917567e51e1SAlan Cox } 918567e51e1SAlan Cox } 919567e51e1SAlan Cox if (m != NULL) { 920567e51e1SAlan Cox /* Examine other mappings to the page. */ 921567e51e1SAlan Cox if (m->dirty == 0 && pmap_is_modified(m)) 922567e51e1SAlan Cox vm_page_dirty(m); 923567e51e1SAlan Cox if (m->dirty != 0) 924867a482dSJohn Dyson mincoreinfo |= MINCORE_MODIFIED_OTHER; 925c46b90e9SAlan Cox /* 9263407fefeSKonstantin Belousov * The first test for PGA_REFERENCED is an 927c46b90e9SAlan Cox * optimization. The second test is 928c46b90e9SAlan Cox * required because a concurrent pmap 929c46b90e9SAlan Cox * operation could clear the last reference 9303407fefeSKonstantin Belousov * and set PGA_REFERENCED before the call to 931c46b90e9SAlan Cox * pmap_is_referenced(). 932c46b90e9SAlan Cox */ 9333407fefeSKonstantin Belousov if ((m->aflags & PGA_REFERENCED) != 0 || 934c46b90e9SAlan Cox pmap_is_referenced(m) || 9353407fefeSKonstantin Belousov (m->aflags & PGA_REFERENCED) != 0) 936867a482dSJohn Dyson mincoreinfo |= MINCORE_REFERENCED_OTHER; 9379b5a5d81SJohn Dyson } 938567e51e1SAlan Cox if (object != NULL) 939567e51e1SAlan Cox VM_OBJECT_UNLOCK(object); 940867a482dSJohn Dyson 941867a482dSJohn Dyson /* 942dd2622a8SAlan Cox * subyte may page fault. In case it needs to modify 943dd2622a8SAlan Cox * the map, we release the lock. 944dd2622a8SAlan Cox */ 945dd2622a8SAlan Cox vm_map_unlock_read(map); 946dd2622a8SAlan Cox 947dd2622a8SAlan Cox /* 948867a482dSJohn Dyson * calculate index into user supplied byte vector 949867a482dSJohn Dyson */ 950867a482dSJohn Dyson vecindex = OFF_TO_IDX(addr - first_addr); 951867a482dSJohn Dyson 952867a482dSJohn Dyson /* 953867a482dSJohn Dyson * If we have skipped map entries, we need to make sure that 954867a482dSJohn Dyson * the byte vector is zeroed for those skipped entries. 955867a482dSJohn Dyson */ 956867a482dSJohn Dyson while ((lastvecindex + 1) < vecindex) { 957867a482dSJohn Dyson error = subyte(vec + lastvecindex, 0); 958867a482dSJohn Dyson if (error) { 959d2c60af8SMatthew Dillon error = EFAULT; 960d2c60af8SMatthew Dillon goto done2; 961867a482dSJohn Dyson } 962867a482dSJohn Dyson ++lastvecindex; 963867a482dSJohn Dyson } 964867a482dSJohn Dyson 965867a482dSJohn Dyson /* 966867a482dSJohn Dyson * Pass the page information to the user 967867a482dSJohn Dyson */ 968867a482dSJohn Dyson error = subyte(vec + vecindex, mincoreinfo); 969867a482dSJohn Dyson if (error) { 970d2c60af8SMatthew Dillon error = EFAULT; 971d2c60af8SMatthew Dillon goto done2; 972867a482dSJohn Dyson } 973dd2622a8SAlan Cox 974dd2622a8SAlan Cox /* 975dd2622a8SAlan Cox * If the map has changed, due to the subyte, the previous 976dd2622a8SAlan Cox * output may be invalid. 977dd2622a8SAlan Cox */ 978dd2622a8SAlan Cox vm_map_lock_read(map); 979dd2622a8SAlan Cox if (timestamp != map->timestamp) 980dd2622a8SAlan Cox goto RestartScan; 981dd2622a8SAlan Cox 982867a482dSJohn Dyson lastvecindex = vecindex; 98302c04a2fSJohn Dyson addr += PAGE_SIZE; 98402c04a2fSJohn Dyson } 985867a482dSJohn Dyson } 986867a482dSJohn Dyson 987867a482dSJohn Dyson /* 988dd2622a8SAlan Cox * subyte may page fault. In case it needs to modify 989dd2622a8SAlan Cox * the map, we release the lock. 990dd2622a8SAlan Cox */ 991dd2622a8SAlan Cox vm_map_unlock_read(map); 992dd2622a8SAlan Cox 993dd2622a8SAlan Cox /* 994867a482dSJohn Dyson * Zero the last entries in the byte vector. 995867a482dSJohn Dyson */ 996867a482dSJohn Dyson vecindex = OFF_TO_IDX(end - first_addr); 997867a482dSJohn Dyson while ((lastvecindex + 1) < vecindex) { 998867a482dSJohn Dyson error = subyte(vec + lastvecindex, 0); 999867a482dSJohn Dyson if (error) { 1000d2c60af8SMatthew Dillon error = EFAULT; 1001d2c60af8SMatthew Dillon goto done2; 1002867a482dSJohn Dyson } 1003867a482dSJohn Dyson ++lastvecindex; 1004867a482dSJohn Dyson } 1005867a482dSJohn Dyson 1006dd2622a8SAlan Cox /* 1007dd2622a8SAlan Cox * If the map has changed, due to the subyte, the previous 1008dd2622a8SAlan Cox * output may be invalid. 1009dd2622a8SAlan Cox */ 1010dd2622a8SAlan Cox vm_map_lock_read(map); 1011dd2622a8SAlan Cox if (timestamp != map->timestamp) 1012dd2622a8SAlan Cox goto RestartScan; 1013eff50fcdSAlan Cox vm_map_unlock_read(map); 1014d2c60af8SMatthew Dillon done2: 1015d2c60af8SMatthew Dillon return (error); 1016df8bae1dSRodney W. Grimes } 1017df8bae1dSRodney W. Grimes 1018d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1019df8bae1dSRodney W. Grimes struct mlock_args { 1020651bb817SAlexander Langer const void *addr; 1021df8bae1dSRodney W. Grimes size_t len; 1022df8bae1dSRodney W. Grimes }; 1023d2d3e875SBruce Evans #endif 1024d2c60af8SMatthew Dillon /* 1025d2c60af8SMatthew Dillon * MPSAFE 1026d2c60af8SMatthew Dillon */ 1027df8bae1dSRodney W. Grimes int 10288451d0ddSKip Macy sys_mlock(td, uap) 1029b40ce416SJulian Elischer struct thread *td; 1030df8bae1dSRodney W. Grimes struct mlock_args *uap; 1031df8bae1dSRodney W. Grimes { 1032f0ea4612SDon Lewis struct proc *proc; 1033bb734798SDon Lewis vm_offset_t addr, end, last, start; 1034bb734798SDon Lewis vm_size_t npages, size; 10351ba5ad42SEdward Tomasz Napierala unsigned long nsize; 1036bb734798SDon Lewis int error; 1037df8bae1dSRodney W. Grimes 1038acd3428bSRobert Watson error = priv_check(td, PRIV_VM_MLOCK); 103947934cefSDon Lewis if (error) 104047934cefSDon Lewis return (error); 104116929939SDon Lewis addr = (vm_offset_t)uap->addr; 104216929939SDon Lewis size = uap->len; 1043bb734798SDon Lewis last = addr + size; 104416929939SDon Lewis start = trunc_page(addr); 1045bb734798SDon Lewis end = round_page(last); 1046bb734798SDon Lewis if (last < addr || end < addr) 1047df8bae1dSRodney W. Grimes return (EINVAL); 104816929939SDon Lewis npages = atop(end - start); 104916929939SDon Lewis if (npages > vm_page_max_wired) 105016929939SDon Lewis return (ENOMEM); 1051f0ea4612SDon Lewis proc = td->td_proc; 105247934cefSDon Lewis PROC_LOCK(proc); 1053c4e357e8SAndrey Zonov nsize = ptoa(npages + vmspace_wired_count(proc->p_vmspace)); 10541ba5ad42SEdward Tomasz Napierala if (nsize > lim_cur(proc, RLIMIT_MEMLOCK)) { 105547934cefSDon Lewis PROC_UNLOCK(proc); 10564a40e3d4SJohn Dyson return (ENOMEM); 105791d5354aSJohn Baldwin } 105847934cefSDon Lewis PROC_UNLOCK(proc); 10592feb50bfSAttilio Rao if (npages + cnt.v_wire_count > vm_page_max_wired) 106016929939SDon Lewis return (EAGAIN); 1061afcc55f3SEdward Tomasz Napierala #ifdef RACCT 10621ba5ad42SEdward Tomasz Napierala PROC_LOCK(proc); 10631ba5ad42SEdward Tomasz Napierala error = racct_set(proc, RACCT_MEMLOCK, nsize); 10641ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(proc); 10651ba5ad42SEdward Tomasz Napierala if (error != 0) 10661ba5ad42SEdward Tomasz Napierala return (ENOMEM); 1067afcc55f3SEdward Tomasz Napierala #endif 106816929939SDon Lewis error = vm_map_wire(&proc->p_vmspace->vm_map, start, end, 106916929939SDon Lewis VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); 1070afcc55f3SEdward Tomasz Napierala #ifdef RACCT 10711ba5ad42SEdward Tomasz Napierala if (error != KERN_SUCCESS) { 10721ba5ad42SEdward Tomasz Napierala PROC_LOCK(proc); 10731ba5ad42SEdward Tomasz Napierala racct_set(proc, RACCT_MEMLOCK, 1074c4e357e8SAndrey Zonov ptoa(vmspace_wired_count(proc->p_vmspace))); 10751ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(proc); 10761ba5ad42SEdward Tomasz Napierala } 1077afcc55f3SEdward Tomasz Napierala #endif 1078df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 1079df8bae1dSRodney W. Grimes } 1080df8bae1dSRodney W. Grimes 1081d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 10824a40e3d4SJohn Dyson struct mlockall_args { 10834a40e3d4SJohn Dyson int how; 10844a40e3d4SJohn Dyson }; 10854a40e3d4SJohn Dyson #endif 10864a40e3d4SJohn Dyson 1087d2c60af8SMatthew Dillon /* 1088d2c60af8SMatthew Dillon * MPSAFE 1089d2c60af8SMatthew Dillon */ 10904a40e3d4SJohn Dyson int 10918451d0ddSKip Macy sys_mlockall(td, uap) 1092b40ce416SJulian Elischer struct thread *td; 10934a40e3d4SJohn Dyson struct mlockall_args *uap; 10944a40e3d4SJohn Dyson { 1095abd498aaSBruce M Simpson vm_map_t map; 1096abd498aaSBruce M Simpson int error; 1097abd498aaSBruce M Simpson 1098abd498aaSBruce M Simpson map = &td->td_proc->p_vmspace->vm_map; 1099abd498aaSBruce M Simpson error = 0; 1100abd498aaSBruce M Simpson 1101abd498aaSBruce M Simpson if ((uap->how == 0) || ((uap->how & ~(MCL_CURRENT|MCL_FUTURE)) != 0)) 1102abd498aaSBruce M Simpson return (EINVAL); 1103abd498aaSBruce M Simpson 110411f7ddc5SBruce M Simpson #if 0 1105abd498aaSBruce M Simpson /* 1106abd498aaSBruce M Simpson * If wiring all pages in the process would cause it to exceed 1107abd498aaSBruce M Simpson * a hard resource limit, return ENOMEM. 1108abd498aaSBruce M Simpson */ 110991d5354aSJohn Baldwin PROC_LOCK(td->td_proc); 1110fd6f4ffbSEdward Tomasz Napierala if (map->size > lim_cur(td->td_proc, RLIMIT_MEMLOCK)) { 111191d5354aSJohn Baldwin PROC_UNLOCK(td->td_proc); 1112abd498aaSBruce M Simpson return (ENOMEM); 111391d5354aSJohn Baldwin } 111491d5354aSJohn Baldwin PROC_UNLOCK(td->td_proc); 1115abd498aaSBruce M Simpson #else 1116acd3428bSRobert Watson error = priv_check(td, PRIV_VM_MLOCK); 1117abd498aaSBruce M Simpson if (error) 1118abd498aaSBruce M Simpson return (error); 1119abd498aaSBruce M Simpson #endif 1120afcc55f3SEdward Tomasz Napierala #ifdef RACCT 11211ba5ad42SEdward Tomasz Napierala PROC_LOCK(td->td_proc); 11221ba5ad42SEdward Tomasz Napierala error = racct_set(td->td_proc, RACCT_MEMLOCK, map->size); 11231ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc); 11241ba5ad42SEdward Tomasz Napierala if (error != 0) 11251ba5ad42SEdward Tomasz Napierala return (ENOMEM); 1126afcc55f3SEdward Tomasz Napierala #endif 1127abd498aaSBruce M Simpson 1128abd498aaSBruce M Simpson if (uap->how & MCL_FUTURE) { 1129abd498aaSBruce M Simpson vm_map_lock(map); 1130abd498aaSBruce M Simpson vm_map_modflags(map, MAP_WIREFUTURE, 0); 1131abd498aaSBruce M Simpson vm_map_unlock(map); 1132abd498aaSBruce M Simpson error = 0; 1133abd498aaSBruce M Simpson } 1134abd498aaSBruce M Simpson 1135abd498aaSBruce M Simpson if (uap->how & MCL_CURRENT) { 1136abd498aaSBruce M Simpson /* 1137abd498aaSBruce M Simpson * P1003.1-2001 mandates that all currently mapped pages 1138abd498aaSBruce M Simpson * will be memory resident and locked (wired) upon return 1139abd498aaSBruce M Simpson * from mlockall(). vm_map_wire() will wire pages, by 1140abd498aaSBruce M Simpson * calling vm_fault_wire() for each page in the region. 1141abd498aaSBruce M Simpson */ 1142abd498aaSBruce M Simpson error = vm_map_wire(map, vm_map_min(map), vm_map_max(map), 1143abd498aaSBruce M Simpson VM_MAP_WIRE_USER|VM_MAP_WIRE_HOLESOK); 1144abd498aaSBruce M Simpson error = (error == KERN_SUCCESS ? 0 : EAGAIN); 1145abd498aaSBruce M Simpson } 1146afcc55f3SEdward Tomasz Napierala #ifdef RACCT 11471ba5ad42SEdward Tomasz Napierala if (error != KERN_SUCCESS) { 11481ba5ad42SEdward Tomasz Napierala PROC_LOCK(td->td_proc); 11491ba5ad42SEdward Tomasz Napierala racct_set(td->td_proc, RACCT_MEMLOCK, 1150c4e357e8SAndrey Zonov ptoa(vmspace_wired_count(td->td_proc->p_vmspace))); 11511ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc); 11521ba5ad42SEdward Tomasz Napierala } 1153afcc55f3SEdward Tomasz Napierala #endif 1154abd498aaSBruce M Simpson 1155abd498aaSBruce M Simpson return (error); 11564a40e3d4SJohn Dyson } 11574a40e3d4SJohn Dyson 11584a40e3d4SJohn Dyson #ifndef _SYS_SYSPROTO_H_ 1159fa721254SAlfred Perlstein struct munlockall_args { 1160abd498aaSBruce M Simpson register_t dummy; 11614a40e3d4SJohn Dyson }; 11624a40e3d4SJohn Dyson #endif 11634a40e3d4SJohn Dyson 1164d2c60af8SMatthew Dillon /* 1165d2c60af8SMatthew Dillon * MPSAFE 1166d2c60af8SMatthew Dillon */ 11674a40e3d4SJohn Dyson int 11688451d0ddSKip Macy sys_munlockall(td, uap) 1169b40ce416SJulian Elischer struct thread *td; 11704a40e3d4SJohn Dyson struct munlockall_args *uap; 11714a40e3d4SJohn Dyson { 1172abd498aaSBruce M Simpson vm_map_t map; 1173abd498aaSBruce M Simpson int error; 1174abd498aaSBruce M Simpson 1175abd498aaSBruce M Simpson map = &td->td_proc->p_vmspace->vm_map; 1176acd3428bSRobert Watson error = priv_check(td, PRIV_VM_MUNLOCK); 1177abd498aaSBruce M Simpson if (error) 1178abd498aaSBruce M Simpson return (error); 1179abd498aaSBruce M Simpson 1180abd498aaSBruce M Simpson /* Clear the MAP_WIREFUTURE flag from this vm_map. */ 1181abd498aaSBruce M Simpson vm_map_lock(map); 1182abd498aaSBruce M Simpson vm_map_modflags(map, 0, MAP_WIREFUTURE); 1183abd498aaSBruce M Simpson vm_map_unlock(map); 1184abd498aaSBruce M Simpson 1185abd498aaSBruce M Simpson /* Forcibly unwire all pages. */ 1186abd498aaSBruce M Simpson error = vm_map_unwire(map, vm_map_min(map), vm_map_max(map), 1187abd498aaSBruce M Simpson VM_MAP_WIRE_USER|VM_MAP_WIRE_HOLESOK); 1188afcc55f3SEdward Tomasz Napierala #ifdef RACCT 11891ba5ad42SEdward Tomasz Napierala if (error == KERN_SUCCESS) { 11901ba5ad42SEdward Tomasz Napierala PROC_LOCK(td->td_proc); 11911ba5ad42SEdward Tomasz Napierala racct_set(td->td_proc, RACCT_MEMLOCK, 0); 11921ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc); 11931ba5ad42SEdward Tomasz Napierala } 1194afcc55f3SEdward Tomasz Napierala #endif 1195abd498aaSBruce M Simpson 1196abd498aaSBruce M Simpson return (error); 11974a40e3d4SJohn Dyson } 11984a40e3d4SJohn Dyson 11994a40e3d4SJohn Dyson #ifndef _SYS_SYSPROTO_H_ 1200df8bae1dSRodney W. Grimes struct munlock_args { 1201651bb817SAlexander Langer const void *addr; 1202df8bae1dSRodney W. Grimes size_t len; 1203df8bae1dSRodney W. Grimes }; 1204d2d3e875SBruce Evans #endif 1205d2c60af8SMatthew Dillon /* 1206d2c60af8SMatthew Dillon * MPSAFE 1207d2c60af8SMatthew Dillon */ 1208df8bae1dSRodney W. Grimes int 12098451d0ddSKip Macy sys_munlock(td, uap) 1210b40ce416SJulian Elischer struct thread *td; 1211df8bae1dSRodney W. Grimes struct munlock_args *uap; 1212df8bae1dSRodney W. Grimes { 1213bb734798SDon Lewis vm_offset_t addr, end, last, start; 121416929939SDon Lewis vm_size_t size; 1215df8bae1dSRodney W. Grimes int error; 1216df8bae1dSRodney W. Grimes 1217acd3428bSRobert Watson error = priv_check(td, PRIV_VM_MUNLOCK); 121847934cefSDon Lewis if (error) 121947934cefSDon Lewis return (error); 122016929939SDon Lewis addr = (vm_offset_t)uap->addr; 122116929939SDon Lewis size = uap->len; 1222bb734798SDon Lewis last = addr + size; 122316929939SDon Lewis start = trunc_page(addr); 1224bb734798SDon Lewis end = round_page(last); 1225bb734798SDon Lewis if (last < addr || end < addr) 1226df8bae1dSRodney W. Grimes return (EINVAL); 122716929939SDon Lewis error = vm_map_unwire(&td->td_proc->p_vmspace->vm_map, start, end, 122816929939SDon Lewis VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); 1229afcc55f3SEdward Tomasz Napierala #ifdef RACCT 12301ba5ad42SEdward Tomasz Napierala if (error == KERN_SUCCESS) { 12311ba5ad42SEdward Tomasz Napierala PROC_LOCK(td->td_proc); 12321ba5ad42SEdward Tomasz Napierala racct_sub(td->td_proc, RACCT_MEMLOCK, ptoa(end - start)); 12331ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc); 12341ba5ad42SEdward Tomasz Napierala } 1235afcc55f3SEdward Tomasz Napierala #endif 1236df8bae1dSRodney W. Grimes return (error == KERN_SUCCESS ? 0 : ENOMEM); 1237df8bae1dSRodney W. Grimes } 1238df8bae1dSRodney W. Grimes 1239df8bae1dSRodney W. Grimes /* 1240c8daea13SAlexander Kabaev * vm_mmap_vnode() 1241c8daea13SAlexander Kabaev * 1242c8daea13SAlexander Kabaev * Helper function for vm_mmap. Perform sanity check specific for mmap 1243c8daea13SAlexander Kabaev * operations on vnodes. 124484110e7eSKonstantin Belousov * 124584110e7eSKonstantin Belousov * For VCHR vnodes, the vnode lock is held over the call to 124684110e7eSKonstantin Belousov * vm_mmap_cdev() to keep vp->v_rdev valid. 1247c8daea13SAlexander Kabaev */ 1248c8daea13SAlexander Kabaev int 1249c8daea13SAlexander Kabaev vm_mmap_vnode(struct thread *td, vm_size_t objsize, 1250c8daea13SAlexander Kabaev vm_prot_t prot, vm_prot_t *maxprotp, int *flagsp, 125184110e7eSKonstantin Belousov struct vnode *vp, vm_ooffset_t *foffp, vm_object_t *objp, 125284110e7eSKonstantin Belousov boolean_t *writecounted) 1253c8daea13SAlexander Kabaev { 1254c8daea13SAlexander Kabaev struct vattr va; 1255c8daea13SAlexander Kabaev vm_object_t obj; 125664345f0bSJohn Baldwin vm_offset_t foff; 1257ae51ff11SJeff Roberson struct mount *mp; 12580359a12eSAttilio Rao struct ucred *cred; 1259*5050aa86SKonstantin Belousov int error, flags, locktype; 1260c8daea13SAlexander Kabaev 1261ae51ff11SJeff Roberson mp = vp->v_mount; 12620359a12eSAttilio Rao cred = td->td_ucred; 126384110e7eSKonstantin Belousov if ((*maxprotp & VM_PROT_WRITE) && (*flagsp & MAP_SHARED)) 126484110e7eSKonstantin Belousov locktype = LK_EXCLUSIVE; 126584110e7eSKonstantin Belousov else 126684110e7eSKonstantin Belousov locktype = LK_SHARED; 1267*5050aa86SKonstantin Belousov if ((error = vget(vp, locktype, td)) != 0) 1268c8daea13SAlexander Kabaev return (error); 126964345f0bSJohn Baldwin foff = *foffp; 1270c8daea13SAlexander Kabaev flags = *flagsp; 12718516dd18SPoul-Henning Kamp obj = vp->v_object; 1272c8daea13SAlexander Kabaev if (vp->v_type == VREG) { 1273c8daea13SAlexander Kabaev /* 1274c8daea13SAlexander Kabaev * Get the proper underlying object 1275c8daea13SAlexander Kabaev */ 12768516dd18SPoul-Henning Kamp if (obj == NULL) { 1277c8daea13SAlexander Kabaev error = EINVAL; 1278c8daea13SAlexander Kabaev goto done; 1279c8daea13SAlexander Kabaev } 1280c8daea13SAlexander Kabaev if (obj->handle != vp) { 1281c8daea13SAlexander Kabaev vput(vp); 1282c8daea13SAlexander Kabaev vp = (struct vnode *)obj->handle; 128384110e7eSKonstantin Belousov /* 128484110e7eSKonstantin Belousov * Bypass filesystems obey the mpsafety of the 128584110e7eSKonstantin Belousov * underlying fs. 128684110e7eSKonstantin Belousov */ 128784110e7eSKonstantin Belousov error = vget(vp, locktype, td); 1288*5050aa86SKonstantin Belousov if (error != 0) 128984110e7eSKonstantin Belousov return (error); 129084110e7eSKonstantin Belousov } 129184110e7eSKonstantin Belousov if (locktype == LK_EXCLUSIVE) { 129284110e7eSKonstantin Belousov *writecounted = TRUE; 129384110e7eSKonstantin Belousov vnode_pager_update_writecount(obj, 0, objsize); 129484110e7eSKonstantin Belousov } 1295c8daea13SAlexander Kabaev } else if (vp->v_type == VCHR) { 129664345f0bSJohn Baldwin error = vm_mmap_cdev(td, objsize, prot, maxprotp, flagsp, 129764345f0bSJohn Baldwin vp->v_rdev, foffp, objp); 129864345f0bSJohn Baldwin if (error == 0) 129964345f0bSJohn Baldwin goto mark_atime; 130091a35e78SKonstantin Belousov goto done; 1301c8daea13SAlexander Kabaev } else { 1302c8daea13SAlexander Kabaev error = EINVAL; 1303c8daea13SAlexander Kabaev goto done; 1304c8daea13SAlexander Kabaev } 13050359a12eSAttilio Rao if ((error = VOP_GETATTR(vp, &va, cred))) 1306c8daea13SAlexander Kabaev goto done; 1307c92163dcSChristian S.J. Peron #ifdef MAC 13080359a12eSAttilio Rao error = mac_vnode_check_mmap(cred, vp, prot, flags); 1309c92163dcSChristian S.J. Peron if (error != 0) 1310c92163dcSChristian S.J. Peron goto done; 1311c92163dcSChristian S.J. Peron #endif 1312c8daea13SAlexander Kabaev if ((flags & MAP_SHARED) != 0) { 1313c8daea13SAlexander Kabaev if ((va.va_flags & (SF_SNAPSHOT|IMMUTABLE|APPEND)) != 0) { 1314c8daea13SAlexander Kabaev if (prot & PROT_WRITE) { 1315c8daea13SAlexander Kabaev error = EPERM; 1316c8daea13SAlexander Kabaev goto done; 1317c8daea13SAlexander Kabaev } 1318c8daea13SAlexander Kabaev *maxprotp &= ~VM_PROT_WRITE; 1319c8daea13SAlexander Kabaev } 1320c8daea13SAlexander Kabaev } 1321c8daea13SAlexander Kabaev /* 1322c8daea13SAlexander Kabaev * If it is a regular file without any references 1323c8daea13SAlexander Kabaev * we do not need to sync it. 1324c8daea13SAlexander Kabaev * Adjust object size to be the size of actual file. 1325c8daea13SAlexander Kabaev */ 1326c8daea13SAlexander Kabaev objsize = round_page(va.va_size); 1327c8daea13SAlexander Kabaev if (va.va_nlink == 0) 1328c8daea13SAlexander Kabaev flags |= MAP_NOSYNC; 132984110e7eSKonstantin Belousov obj = vm_pager_allocate(OBJT_VNODE, vp, objsize, prot, foff, cred); 1330c8daea13SAlexander Kabaev if (obj == NULL) { 133164345f0bSJohn Baldwin error = ENOMEM; 1332c8daea13SAlexander Kabaev goto done; 1333c8daea13SAlexander Kabaev } 1334c8daea13SAlexander Kabaev *objp = obj; 1335c8daea13SAlexander Kabaev *flagsp = flags; 133664345f0bSJohn Baldwin 133764345f0bSJohn Baldwin mark_atime: 13380359a12eSAttilio Rao vfs_mark_atime(vp, cred); 13391e309003SDiomidis Spinellis 1340c8daea13SAlexander Kabaev done: 1341c8daea13SAlexander Kabaev vput(vp); 1342c8daea13SAlexander Kabaev return (error); 1343c8daea13SAlexander Kabaev } 1344c8daea13SAlexander Kabaev 1345c8daea13SAlexander Kabaev /* 134698df9218SJohn Baldwin * vm_mmap_cdev() 134798df9218SJohn Baldwin * 134898df9218SJohn Baldwin * MPSAFE 134998df9218SJohn Baldwin * 135098df9218SJohn Baldwin * Helper function for vm_mmap. Perform sanity check specific for mmap 135198df9218SJohn Baldwin * operations on cdevs. 135298df9218SJohn Baldwin */ 135398df9218SJohn Baldwin int 135498df9218SJohn Baldwin vm_mmap_cdev(struct thread *td, vm_size_t objsize, 135598df9218SJohn Baldwin vm_prot_t prot, vm_prot_t *maxprotp, int *flagsp, 135664345f0bSJohn Baldwin struct cdev *cdev, vm_ooffset_t *foff, vm_object_t *objp) 135798df9218SJohn Baldwin { 135898df9218SJohn Baldwin vm_object_t obj; 135991a35e78SKonstantin Belousov struct cdevsw *dsw; 13603979450bSKonstantin Belousov int error, flags, ref; 136198df9218SJohn Baldwin 136298df9218SJohn Baldwin flags = *flagsp; 136398df9218SJohn Baldwin 13643979450bSKonstantin Belousov dsw = dev_refthread(cdev, &ref); 136591a35e78SKonstantin Belousov if (dsw == NULL) 136691a35e78SKonstantin Belousov return (ENXIO); 136791a35e78SKonstantin Belousov if (dsw->d_flags & D_MMAP_ANON) { 13683979450bSKonstantin Belousov dev_relthread(cdev, ref); 136998df9218SJohn Baldwin *maxprotp = VM_PROT_ALL; 137098df9218SJohn Baldwin *flagsp |= MAP_ANON; 137198df9218SJohn Baldwin return (0); 137298df9218SJohn Baldwin } 137398df9218SJohn Baldwin /* 137464345f0bSJohn Baldwin * cdevs do not provide private mappings of any kind. 137598df9218SJohn Baldwin */ 137698df9218SJohn Baldwin if ((*maxprotp & VM_PROT_WRITE) == 0 && 137764345f0bSJohn Baldwin (prot & PROT_WRITE) != 0) { 13783979450bSKonstantin Belousov dev_relthread(cdev, ref); 137998df9218SJohn Baldwin return (EACCES); 138064345f0bSJohn Baldwin } 138164345f0bSJohn Baldwin if (flags & (MAP_PRIVATE|MAP_COPY)) { 13823979450bSKonstantin Belousov dev_relthread(cdev, ref); 138398df9218SJohn Baldwin return (EINVAL); 138464345f0bSJohn Baldwin } 138598df9218SJohn Baldwin /* 138698df9218SJohn Baldwin * Force device mappings to be shared. 138798df9218SJohn Baldwin */ 138898df9218SJohn Baldwin flags |= MAP_SHARED; 138998df9218SJohn Baldwin #ifdef MAC_XXX 139064345f0bSJohn Baldwin error = mac_cdev_check_mmap(td->td_ucred, cdev, prot); 139164345f0bSJohn Baldwin if (error != 0) { 13923979450bSKonstantin Belousov dev_relthread(cdev, ref); 139398df9218SJohn Baldwin return (error); 139464345f0bSJohn Baldwin } 139598df9218SJohn Baldwin #endif 139664345f0bSJohn Baldwin /* 139764345f0bSJohn Baldwin * First, try d_mmap_single(). If that is not implemented 139864345f0bSJohn Baldwin * (returns ENODEV), fall back to using the device pager. 139964345f0bSJohn Baldwin * Note that d_mmap_single() must return a reference to the 140064345f0bSJohn Baldwin * object (it needs to bump the reference count of the object 140164345f0bSJohn Baldwin * it returns somehow). 140264345f0bSJohn Baldwin * 140364345f0bSJohn Baldwin * XXX assumes VM_PROT_* == PROT_* 140464345f0bSJohn Baldwin */ 140564345f0bSJohn Baldwin error = dsw->d_mmap_single(cdev, foff, objsize, objp, (int)prot); 14063979450bSKonstantin Belousov dev_relthread(cdev, ref); 140764345f0bSJohn Baldwin if (error != ENODEV) 140864345f0bSJohn Baldwin return (error); 14093364c323SKonstantin Belousov obj = vm_pager_allocate(OBJT_DEVICE, cdev, objsize, prot, *foff, 14103364c323SKonstantin Belousov td->td_ucred); 141198df9218SJohn Baldwin if (obj == NULL) 141298df9218SJohn Baldwin return (EINVAL); 141398df9218SJohn Baldwin *objp = obj; 141498df9218SJohn Baldwin *flagsp = flags; 141598df9218SJohn Baldwin return (0); 141698df9218SJohn Baldwin } 141798df9218SJohn Baldwin 141898df9218SJohn Baldwin /* 14198e38aeffSJohn Baldwin * vm_mmap_shm() 14208e38aeffSJohn Baldwin * 14218e38aeffSJohn Baldwin * MPSAFE 14228e38aeffSJohn Baldwin * 14238e38aeffSJohn Baldwin * Helper function for vm_mmap. Perform sanity check specific for mmap 14248e38aeffSJohn Baldwin * operations on shm file descriptors. 14258e38aeffSJohn Baldwin */ 14268e38aeffSJohn Baldwin int 14278e38aeffSJohn Baldwin vm_mmap_shm(struct thread *td, vm_size_t objsize, 14288e38aeffSJohn Baldwin vm_prot_t prot, vm_prot_t *maxprotp, int *flagsp, 14298e38aeffSJohn Baldwin struct shmfd *shmfd, vm_ooffset_t foff, vm_object_t *objp) 14308e38aeffSJohn Baldwin { 14318e38aeffSJohn Baldwin int error; 14328e38aeffSJohn Baldwin 1433da048309SAlan Cox if ((*flagsp & MAP_SHARED) != 0 && 1434da048309SAlan Cox (*maxprotp & VM_PROT_WRITE) == 0 && 14358e38aeffSJohn Baldwin (prot & PROT_WRITE) != 0) 14368e38aeffSJohn Baldwin return (EACCES); 14378e38aeffSJohn Baldwin #ifdef MAC 14388e38aeffSJohn Baldwin error = mac_posixshm_check_mmap(td->td_ucred, shmfd, prot, *flagsp); 14398e38aeffSJohn Baldwin if (error != 0) 14408e38aeffSJohn Baldwin return (error); 14418e38aeffSJohn Baldwin #endif 14428e38aeffSJohn Baldwin error = shm_mmap(shmfd, objsize, foff, objp); 14438e38aeffSJohn Baldwin if (error) 14448e38aeffSJohn Baldwin return (error); 14458e38aeffSJohn Baldwin return (0); 14468e38aeffSJohn Baldwin } 14478e38aeffSJohn Baldwin 14488e38aeffSJohn Baldwin /* 1449d2c60af8SMatthew Dillon * vm_mmap() 1450d2c60af8SMatthew Dillon * 1451d2c60af8SMatthew Dillon * MPSAFE 1452d2c60af8SMatthew Dillon * 1453d2c60af8SMatthew Dillon * Internal version of mmap. Currently used by mmap, exec, and sys5 1454d2c60af8SMatthew Dillon * shared memory. Handle is either a vnode pointer or NULL for MAP_ANON. 1455df8bae1dSRodney W. Grimes */ 1456df8bae1dSRodney W. Grimes int 1457b9dcd593SBruce Evans vm_mmap(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, 1458b9dcd593SBruce Evans vm_prot_t maxprot, int flags, 145998df9218SJohn Baldwin objtype_t handle_type, void *handle, 1460b9dcd593SBruce Evans vm_ooffset_t foff) 1461df8bae1dSRodney W. Grimes { 1462df8bae1dSRodney W. Grimes boolean_t fitit; 14636bda842dSMatt Jacob vm_object_t object = NULL; 1464b40ce416SJulian Elischer struct thread *td = curthread; 1465f9230ad6SAlan Cox int docow, error, rv; 146684110e7eSKonstantin Belousov boolean_t writecounted; 1467df8bae1dSRodney W. Grimes 1468df8bae1dSRodney W. Grimes if (size == 0) 1469df8bae1dSRodney W. Grimes return (0); 1470df8bae1dSRodney W. Grimes 1471749474f2SPeter Wemm size = round_page(size); 1472df8bae1dSRodney W. Grimes 1473a6492969SAlan Cox if (map == &td->td_proc->p_vmspace->vm_map) { 147491d5354aSJohn Baldwin PROC_LOCK(td->td_proc); 1475a6492969SAlan Cox if (map->size + size > lim_cur(td->td_proc, RLIMIT_VMEM)) { 147691d5354aSJohn Baldwin PROC_UNLOCK(td->td_proc); 1477070f64feSMatthew Dillon return (ENOMEM); 1478070f64feSMatthew Dillon } 1479a6492969SAlan Cox if (racct_set(td->td_proc, RACCT_VMEM, map->size + size)) { 14801ba5ad42SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc); 14811ba5ad42SEdward Tomasz Napierala return (ENOMEM); 14821ba5ad42SEdward Tomasz Napierala } 148391d5354aSJohn Baldwin PROC_UNLOCK(td->td_proc); 1484a6492969SAlan Cox } 1485070f64feSMatthew Dillon 1486df8bae1dSRodney W. Grimes /* 1487bc9ad247SDavid Greenman * We currently can only deal with page aligned file offsets. 1488bc9ad247SDavid Greenman * The check is here rather than in the syscall because the 1489bc9ad247SDavid Greenman * kernel calls this function internally for other mmaping 1490bc9ad247SDavid Greenman * operations (such as in exec) and non-aligned offsets will 1491bc9ad247SDavid Greenman * cause pmap inconsistencies...so we want to be sure to 1492bc9ad247SDavid Greenman * disallow this in all cases. 1493bc9ad247SDavid Greenman */ 1494bc9ad247SDavid Greenman if (foff & PAGE_MASK) 1495bc9ad247SDavid Greenman return (EINVAL); 1496bc9ad247SDavid Greenman 149706cb7259SDavid Greenman if ((flags & MAP_FIXED) == 0) { 149806cb7259SDavid Greenman fitit = TRUE; 149906cb7259SDavid Greenman *addr = round_page(*addr); 150006cb7259SDavid Greenman } else { 150106cb7259SDavid Greenman if (*addr != trunc_page(*addr)) 150206cb7259SDavid Greenman return (EINVAL); 150306cb7259SDavid Greenman fitit = FALSE; 150406cb7259SDavid Greenman } 150584110e7eSKonstantin Belousov writecounted = FALSE; 150684110e7eSKonstantin Belousov 1507bc9ad247SDavid Greenman /* 150824a1cce3SDavid Greenman * Lookup/allocate object. 1509df8bae1dSRodney W. Grimes */ 151098df9218SJohn Baldwin switch (handle_type) { 151198df9218SJohn Baldwin case OBJT_DEVICE: 151298df9218SJohn Baldwin error = vm_mmap_cdev(td, size, prot, &maxprot, &flags, 151364345f0bSJohn Baldwin handle, &foff, &object); 151498df9218SJohn Baldwin break; 151598df9218SJohn Baldwin case OBJT_VNODE: 1516c8daea13SAlexander Kabaev error = vm_mmap_vnode(td, size, prot, &maxprot, &flags, 151784110e7eSKonstantin Belousov handle, &foff, &object, &writecounted); 151898df9218SJohn Baldwin break; 15198e38aeffSJohn Baldwin case OBJT_SWAP: 15208e38aeffSJohn Baldwin error = vm_mmap_shm(td, size, prot, &maxprot, &flags, 15218e38aeffSJohn Baldwin handle, foff, &object); 15228e38aeffSJohn Baldwin break; 152398df9218SJohn Baldwin case OBJT_DEFAULT: 152498df9218SJohn Baldwin if (handle == NULL) { 152598df9218SJohn Baldwin error = 0; 152698df9218SJohn Baldwin break; 152798df9218SJohn Baldwin } 152898df9218SJohn Baldwin /* FALLTHROUGH */ 152998df9218SJohn Baldwin default: 153098df9218SJohn Baldwin error = EINVAL; 15316bda842dSMatt Jacob break; 153298df9218SJohn Baldwin } 153398df9218SJohn Baldwin if (error) 1534c8daea13SAlexander Kabaev return (error); 15355f55e841SDavid Greenman if (flags & MAP_ANON) { 1536c8daea13SAlexander Kabaev object = NULL; 1537c8daea13SAlexander Kabaev docow = 0; 15385f55e841SDavid Greenman /* 15395f55e841SDavid Greenman * Unnamed anonymous regions always start at 0. 15405f55e841SDavid Greenman */ 154167bf6868SJohn Dyson if (handle == 0) 15425f55e841SDavid Greenman foff = 0; 154374ffb9afSAlan Cox } else if (flags & MAP_PREFAULT_READ) 154474ffb9afSAlan Cox docow = MAP_PREFAULT; 154574ffb9afSAlan Cox else 15464738fa09SAlan Cox docow = MAP_PREFAULT_PARTIAL; 1547df8bae1dSRodney W. Grimes 15484f79d873SMatthew Dillon if ((flags & (MAP_ANON|MAP_SHARED)) == 0) 15494738fa09SAlan Cox docow |= MAP_COPY_ON_WRITE; 15504f79d873SMatthew Dillon if (flags & MAP_NOSYNC) 15514f79d873SMatthew Dillon docow |= MAP_DISABLE_SYNCER; 15529730a5daSPaul Saab if (flags & MAP_NOCORE) 15539730a5daSPaul Saab docow |= MAP_DISABLE_COREDUMP; 15548211bd45SKonstantin Belousov /* Shared memory is also shared with children. */ 15558211bd45SKonstantin Belousov if (flags & MAP_SHARED) 15568211bd45SKonstantin Belousov docow |= MAP_INHERIT_SHARE; 155784110e7eSKonstantin Belousov if (writecounted) 155884110e7eSKonstantin Belousov docow |= MAP_VN_WRITECOUNT; 15595850152dSJohn Dyson 15602267af78SJulian Elischer if (flags & MAP_STACK) 1561fd75d710SMarcel Moolenaar rv = vm_map_stack(map, *addr, size, prot, maxprot, 1562fd75d710SMarcel Moolenaar docow | MAP_STACK_GROWS_DOWN); 1563d239bd3cSKonstantin Belousov else if (fitit) 1564d0a83a83SAlan Cox rv = vm_map_find(map, object, foff, addr, size, 1565d0a83a83SAlan Cox object != NULL && object->type == OBJT_DEVICE ? 1566d0a83a83SAlan Cox VMFS_ALIGNED_SPACE : VMFS_ANY_SPACE, prot, maxprot, docow); 15672267af78SJulian Elischer else 1568b8ca4ef2SAlan Cox rv = vm_map_fixed(map, object, foff, *addr, size, 1569bd7e5f99SJohn Dyson prot, maxprot, docow); 1570bd7e5f99SJohn Dyson 1571f9230ad6SAlan Cox if (rv == KERN_SUCCESS) { 15727fb0c17eSDavid Greenman /* 1573f9230ad6SAlan Cox * If the process has requested that all future mappings 1574f9230ad6SAlan Cox * be wired, then heed this. 1575f9230ad6SAlan Cox */ 15761472f4f4SKonstantin Belousov if (map->flags & MAP_WIREFUTURE) { 1577f9230ad6SAlan Cox vm_map_wire(map, *addr, *addr + size, 15781472f4f4SKonstantin Belousov VM_MAP_WIRE_USER | ((flags & MAP_STACK) ? 15791472f4f4SKonstantin Belousov VM_MAP_WIRE_HOLESOK : VM_MAP_WIRE_NOHOLES)); 15801472f4f4SKonstantin Belousov } 1581f9230ad6SAlan Cox } else { 1582f9230ad6SAlan Cox /* 158384110e7eSKonstantin Belousov * If this mapping was accounted for in the vnode's 158484110e7eSKonstantin Belousov * writecount, then undo that now. 15857fb0c17eSDavid Greenman */ 158684110e7eSKonstantin Belousov if (writecounted) 158784110e7eSKonstantin Belousov vnode_pager_release_writecount(object, 0, size); 1588f9230ad6SAlan Cox /* 1589f9230ad6SAlan Cox * Lose the object reference. Will destroy the 1590f9230ad6SAlan Cox * object if it's an unnamed anonymous mapping 1591f9230ad6SAlan Cox * or named anonymous without other references. 1592f9230ad6SAlan Cox */ 1593df8bae1dSRodney W. Grimes vm_object_deallocate(object); 1594df8bae1dSRodney W. Grimes } 15952e32165cSKonstantin Belousov return (vm_mmap_to_errno(rv)); 15962e32165cSKonstantin Belousov } 15972e32165cSKonstantin Belousov 1598f9230ad6SAlan Cox /* 1599f9230ad6SAlan Cox * Translate a Mach VM return code to zero on success or the appropriate errno 1600f9230ad6SAlan Cox * on failure. 1601f9230ad6SAlan Cox */ 16022e32165cSKonstantin Belousov int 16032e32165cSKonstantin Belousov vm_mmap_to_errno(int rv) 16042e32165cSKonstantin Belousov { 16052e32165cSKonstantin Belousov 1606df8bae1dSRodney W. Grimes switch (rv) { 1607df8bae1dSRodney W. Grimes case KERN_SUCCESS: 1608df8bae1dSRodney W. Grimes return (0); 1609df8bae1dSRodney W. Grimes case KERN_INVALID_ADDRESS: 1610df8bae1dSRodney W. Grimes case KERN_NO_SPACE: 1611df8bae1dSRodney W. Grimes return (ENOMEM); 1612df8bae1dSRodney W. Grimes case KERN_PROTECTION_FAILURE: 1613df8bae1dSRodney W. Grimes return (EACCES); 1614df8bae1dSRodney W. Grimes default: 1615df8bae1dSRodney W. Grimes return (EINVAL); 1616df8bae1dSRodney W. Grimes } 1617df8bae1dSRodney W. Grimes } 1618