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 #include <sys/param.h> 47 #include <sys/lock.h> 48 #include <sys/mutex.h> 49 #include <sys/proc.h> 50 #include <sys/racct.h> 51 #include <sys/resourcevar.h> 52 #include <sys/syscallsubr.h> 53 #include <sys/sysent.h> 54 #include <sys/sysproto.h> 55 #include <sys/systm.h> 56 #if defined(__amd64__) || defined(__i386__) /* for i386_read_exec */ 57 #include <machine/md_var.h> 58 #endif 59 60 #include <vm/vm.h> 61 #include <vm/vm_param.h> 62 #include <vm/pmap.h> 63 #include <vm/vm_map.h> 64 65 #ifndef _SYS_SYSPROTO_H_ 66 struct break_args { 67 char *nsize; 68 }; 69 #endif 70 int 71 sys_break(struct thread *td, struct break_args *uap) 72 { 73 #if !defined(__aarch64__) && !defined(__riscv) 74 uintptr_t addr; 75 int error; 76 77 addr = (uintptr_t)uap->nsize; 78 error = kern_break(td, &addr); 79 if (error == 0) 80 td->td_retval[0] = addr; 81 return (error); 82 #else /* defined(__aarch64__) || defined(__riscv) */ 83 return (ENOSYS); 84 #endif /* defined(__aarch64__) || defined(__riscv) */ 85 } 86 87 int 88 kern_break(struct thread *td, uintptr_t *addr) 89 { 90 struct vmspace *vm = td->td_proc->p_vmspace; 91 vm_map_t map = &vm->vm_map; 92 vm_offset_t new, old, base; 93 rlim_t datalim, lmemlim, vmemlim; 94 int prot, rv; 95 int error = 0; 96 97 datalim = lim_cur(td, RLIMIT_DATA); 98 lmemlim = lim_cur(td, RLIMIT_MEMLOCK); 99 vmemlim = lim_cur(td, RLIMIT_VMEM); 100 101 new = round_page(*addr); 102 vm_map_lock(map); 103 104 base = round_page((vm_offset_t) vm->vm_daddr); 105 old = base + ctob(vm->vm_dsize); 106 if (new > base) { 107 /* 108 * Check the resource limit, but allow a process to reduce 109 * its usage, even if it remains over the limit. 110 */ 111 if (new - base > datalim && new > old) { 112 error = ENOMEM; 113 goto done; 114 } 115 if (new > vm_map_max(map)) { 116 error = ENOMEM; 117 goto done; 118 } 119 } else if (new < base) { 120 /* 121 * Simply return the current break address without 122 * modifying any state. This is an ad-hoc interface 123 * used by libc to determine the initial break address, 124 * avoiding a dependency on magic features in the system 125 * linker. 126 */ 127 new = old; 128 goto done; 129 } 130 131 if (new > old) { 132 if (!old_mlock && map->flags & MAP_WIREFUTURE) { 133 if (ptoa(pmap_wired_count(map->pmap)) + 134 (new - old) > lmemlim) { 135 error = ENOMEM; 136 goto done; 137 } 138 } 139 if (map->size + (new - old) > vmemlim) { 140 error = ENOMEM; 141 goto done; 142 } 143 #ifdef RACCT 144 if (racct_enable) { 145 PROC_LOCK(td->td_proc); 146 error = racct_set(td->td_proc, RACCT_DATA, new - base); 147 if (error != 0) { 148 PROC_UNLOCK(td->td_proc); 149 error = ENOMEM; 150 goto done; 151 } 152 error = racct_set(td->td_proc, RACCT_VMEM, 153 map->size + (new - old)); 154 if (error != 0) { 155 racct_set_force(td->td_proc, RACCT_DATA, 156 old - base); 157 PROC_UNLOCK(td->td_proc); 158 error = ENOMEM; 159 goto done; 160 } 161 if (!old_mlock && map->flags & MAP_WIREFUTURE) { 162 error = racct_set(td->td_proc, RACCT_MEMLOCK, 163 ptoa(pmap_wired_count(map->pmap)) + 164 (new - old)); 165 if (error != 0) { 166 racct_set_force(td->td_proc, RACCT_DATA, 167 old - base); 168 racct_set_force(td->td_proc, RACCT_VMEM, 169 map->size); 170 PROC_UNLOCK(td->td_proc); 171 error = ENOMEM; 172 goto done; 173 } 174 } 175 PROC_UNLOCK(td->td_proc); 176 } 177 #endif 178 prot = VM_PROT_RW; 179 #if (defined(COMPAT_FREEBSD32) && defined(__amd64__)) || defined(__i386__) 180 if (i386_read_exec && SV_PROC_FLAG(td->td_proc, SV_ILP32)) 181 prot |= VM_PROT_EXECUTE; 182 #endif 183 rv = vm_map_insert(map, NULL, 0, old, new, prot, VM_PROT_ALL, 184 0); 185 if (rv == KERN_SUCCESS && (map->flags & MAP_WIREFUTURE) != 0) { 186 rv = vm_map_wire_locked(map, old, new, 187 VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); 188 if (rv != KERN_SUCCESS) 189 (void)vm_map_delete(map, old, new); 190 } 191 if (rv != KERN_SUCCESS) { 192 #ifdef RACCT 193 if (racct_enable) { 194 PROC_LOCK(td->td_proc); 195 racct_set_force(td->td_proc, 196 RACCT_DATA, old - base); 197 racct_set_force(td->td_proc, 198 RACCT_VMEM, map->size); 199 if (!old_mlock && map->flags & MAP_WIREFUTURE) { 200 racct_set_force(td->td_proc, 201 RACCT_MEMLOCK, 202 ptoa(pmap_wired_count(map->pmap))); 203 } 204 PROC_UNLOCK(td->td_proc); 205 } 206 #endif 207 error = ENOMEM; 208 goto done; 209 } 210 vm->vm_dsize += btoc(new - old); 211 } else if (new < old) { 212 rv = vm_map_delete(map, new, old); 213 if (rv != KERN_SUCCESS) { 214 error = ENOMEM; 215 goto done; 216 } 217 vm->vm_dsize -= btoc(old - new); 218 #ifdef RACCT 219 if (racct_enable) { 220 PROC_LOCK(td->td_proc); 221 racct_set_force(td->td_proc, RACCT_DATA, new - base); 222 racct_set_force(td->td_proc, RACCT_VMEM, map->size); 223 if (!old_mlock && map->flags & MAP_WIREFUTURE) { 224 racct_set_force(td->td_proc, RACCT_MEMLOCK, 225 ptoa(pmap_wired_count(map->pmap))); 226 } 227 PROC_UNLOCK(td->td_proc); 228 } 229 #endif 230 } 231 done: 232 vm_map_unlock(map); 233 234 if (error == 0) 235 *addr = new; 236 237 return (error); 238 } 239 240 #ifdef COMPAT_FREEBSD11 241 int 242 freebsd11_vadvise(struct thread *td, struct freebsd11_vadvise_args *uap) 243 { 244 245 return (EINVAL); 246 } 247 #endif 248