1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1991, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * the Systems Programming Group of the University of Utah Computer 10 * Science Department. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: Utah $Hdr: vm_unix.c 1.1 89/11/07$ 37 * 38 * @(#)vm_unix.c 8.1 (Berkeley) 6/11/93 39 */ 40 41 /* 42 * Traditional sbrk/grow interface to VM 43 */ 44 45 #include <sys/cdefs.h> 46 __FBSDID("$FreeBSD$"); 47 48 #include <sys/param.h> 49 #include <sys/lock.h> 50 #include <sys/mutex.h> 51 #include <sys/proc.h> 52 #include <sys/racct.h> 53 #include <sys/resourcevar.h> 54 #include <sys/syscallsubr.h> 55 #include <sys/sysent.h> 56 #include <sys/sysproto.h> 57 #include <sys/systm.h> 58 59 #include <vm/vm.h> 60 #include <vm/vm_param.h> 61 #include <vm/pmap.h> 62 #include <vm/vm_map.h> 63 64 #ifndef _SYS_SYSPROTO_H_ 65 struct break_args { 66 char *nsize; 67 }; 68 #endif 69 int 70 sys_break(struct thread *td, struct break_args *uap) 71 { 72 #if !defined(__aarch64__) && !defined(__riscv) 73 uintptr_t addr; 74 int error; 75 76 addr = (uintptr_t)uap->nsize; 77 error = kern_break(td, &addr); 78 if (error == 0) 79 td->td_retval[0] = addr; 80 return (error); 81 #else /* defined(__aarch64__) || defined(__riscv) */ 82 return (ENOSYS); 83 #endif /* defined(__aarch64__) || defined(__riscv) */ 84 } 85 86 int 87 kern_break(struct thread *td, uintptr_t *addr) 88 { 89 struct vmspace *vm = td->td_proc->p_vmspace; 90 vm_map_t map = &vm->vm_map; 91 vm_offset_t new, old, base; 92 rlim_t datalim, lmemlim, vmemlim; 93 int prot, rv; 94 int error = 0; 95 boolean_t do_map_wirefuture; 96 97 datalim = lim_cur(td, RLIMIT_DATA); 98 lmemlim = lim_cur(td, RLIMIT_MEMLOCK); 99 vmemlim = lim_cur(td, RLIMIT_VMEM); 100 101 do_map_wirefuture = FALSE; 102 new = round_page(*addr); 103 vm_map_lock(map); 104 105 base = round_page((vm_offset_t) vm->vm_daddr); 106 old = base + ctob(vm->vm_dsize); 107 if (new > base) { 108 /* 109 * Check the resource limit, but allow a process to reduce 110 * its usage, even if it remains over the limit. 111 */ 112 if (new - base > datalim && new > old) { 113 error = ENOMEM; 114 goto done; 115 } 116 if (new > vm_map_max(map)) { 117 error = ENOMEM; 118 goto done; 119 } 120 } else if (new < base) { 121 /* 122 * Simply return the current break address without 123 * modifying any state. This is an ad-hoc interface 124 * used by libc to determine the initial break address, 125 * avoiding a dependency on magic features in the system 126 * linker. 127 */ 128 new = old; 129 goto done; 130 } 131 132 if (new > old) { 133 if (!old_mlock && map->flags & MAP_WIREFUTURE) { 134 if (ptoa(pmap_wired_count(map->pmap)) + 135 (new - old) > lmemlim) { 136 error = ENOMEM; 137 goto done; 138 } 139 } 140 if (map->size + (new - old) > vmemlim) { 141 error = ENOMEM; 142 goto done; 143 } 144 #ifdef RACCT 145 if (racct_enable) { 146 PROC_LOCK(td->td_proc); 147 error = racct_set(td->td_proc, RACCT_DATA, new - base); 148 if (error != 0) { 149 PROC_UNLOCK(td->td_proc); 150 error = ENOMEM; 151 goto done; 152 } 153 error = racct_set(td->td_proc, RACCT_VMEM, 154 map->size + (new - old)); 155 if (error != 0) { 156 racct_set_force(td->td_proc, RACCT_DATA, 157 old - base); 158 PROC_UNLOCK(td->td_proc); 159 error = ENOMEM; 160 goto done; 161 } 162 if (!old_mlock && map->flags & MAP_WIREFUTURE) { 163 error = racct_set(td->td_proc, RACCT_MEMLOCK, 164 ptoa(pmap_wired_count(map->pmap)) + 165 (new - old)); 166 if (error != 0) { 167 racct_set_force(td->td_proc, RACCT_DATA, 168 old - base); 169 racct_set_force(td->td_proc, RACCT_VMEM, 170 map->size); 171 PROC_UNLOCK(td->td_proc); 172 error = ENOMEM; 173 goto done; 174 } 175 } 176 PROC_UNLOCK(td->td_proc); 177 } 178 #endif 179 prot = VM_PROT_RW; 180 #ifdef COMPAT_FREEBSD32 181 #if defined(__amd64__) 182 if (i386_read_exec && SV_PROC_FLAG(td->td_proc, SV_ILP32)) 183 prot |= VM_PROT_EXECUTE; 184 #endif 185 #endif 186 rv = vm_map_insert(map, NULL, 0, old, new, prot, VM_PROT_ALL, 0); 187 if (rv != KERN_SUCCESS) { 188 #ifdef RACCT 189 if (racct_enable) { 190 PROC_LOCK(td->td_proc); 191 racct_set_force(td->td_proc, 192 RACCT_DATA, old - base); 193 racct_set_force(td->td_proc, 194 RACCT_VMEM, map->size); 195 if (!old_mlock && map->flags & MAP_WIREFUTURE) { 196 racct_set_force(td->td_proc, 197 RACCT_MEMLOCK, 198 ptoa(pmap_wired_count(map->pmap))); 199 } 200 PROC_UNLOCK(td->td_proc); 201 } 202 #endif 203 error = ENOMEM; 204 goto done; 205 } 206 vm->vm_dsize += btoc(new - old); 207 /* 208 * Handle the MAP_WIREFUTURE case for legacy applications, 209 * by marking the newly mapped range of pages as wired. 210 * We are not required to perform a corresponding 211 * vm_map_unwire() before vm_map_delete() below, as 212 * it will forcibly unwire the pages in the range. 213 * 214 * XXX If the pages cannot be wired, no error is returned. 215 */ 216 if ((map->flags & MAP_WIREFUTURE) == MAP_WIREFUTURE) 217 do_map_wirefuture = TRUE; 218 } else if (new < old) { 219 rv = vm_map_delete(map, new, old); 220 if (rv != KERN_SUCCESS) { 221 error = ENOMEM; 222 goto done; 223 } 224 vm->vm_dsize -= btoc(old - new); 225 #ifdef RACCT 226 if (racct_enable) { 227 PROC_LOCK(td->td_proc); 228 racct_set_force(td->td_proc, RACCT_DATA, new - base); 229 racct_set_force(td->td_proc, RACCT_VMEM, map->size); 230 if (!old_mlock && map->flags & MAP_WIREFUTURE) { 231 racct_set_force(td->td_proc, RACCT_MEMLOCK, 232 ptoa(pmap_wired_count(map->pmap))); 233 } 234 PROC_UNLOCK(td->td_proc); 235 } 236 #endif 237 } 238 done: 239 vm_map_unlock(map); 240 241 if (do_map_wirefuture) 242 (void) vm_map_wire(map, old, new, 243 VM_MAP_WIRE_USER|VM_MAP_WIRE_NOHOLES); 244 245 if (error == 0) 246 *addr = new; 247 248 return (error); 249 } 250 251 #ifdef COMPAT_FREEBSD11 252 int 253 freebsd11_vadvise(struct thread *td, struct freebsd11_vadvise_args *uap) 254 { 255 256 return (EINVAL); 257 } 258 #endif 259