1 1.19 riastrad /* $NetBSD: subr_copy.c,v 1.19 2023/05/22 14:07:24 riastradh Exp $ */ 2 1.1 pooka 3 1.1 pooka /*- 4 1.9 thorpej * Copyright (c) 1997, 1998, 1999, 2002, 2007, 2008, 2019 5 1.9 thorpej * The NetBSD Foundation, Inc. 6 1.1 pooka * All rights reserved. 7 1.1 pooka * 8 1.1 pooka * This code is derived from software contributed to The NetBSD Foundation 9 1.1 pooka * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 10 1.1 pooka * NASA Ames Research Center. 11 1.1 pooka * 12 1.1 pooka * Redistribution and use in source and binary forms, with or without 13 1.1 pooka * modification, are permitted provided that the following conditions 14 1.1 pooka * are met: 15 1.1 pooka * 1. Redistributions of source code must retain the above copyright 16 1.1 pooka * notice, this list of conditions and the following disclaimer. 17 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 18 1.1 pooka * notice, this list of conditions and the following disclaimer in the 19 1.1 pooka * documentation and/or other materials provided with the distribution. 20 1.1 pooka * 21 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 1.1 pooka * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 1.1 pooka * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 1.1 pooka * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 1.1 pooka * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 1.1 pooka * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 1.1 pooka * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 1.1 pooka * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 1.1 pooka * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 1.1 pooka * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 1.1 pooka * POSSIBILITY OF SUCH DAMAGE. 32 1.1 pooka */ 33 1.1 pooka 34 1.1 pooka /* 35 1.1 pooka * Copyright (c) 1982, 1986, 1991, 1993 36 1.1 pooka * The Regents of the University of California. All rights reserved. 37 1.1 pooka * (c) UNIX System Laboratories, Inc. 38 1.1 pooka * All or some portions of this file are derived from material licensed 39 1.1 pooka * to the University of California by American Telephone and Telegraph 40 1.1 pooka * Co. or Unix System Laboratories, Inc. and are reproduced herein with 41 1.1 pooka * the permission of UNIX System Laboratories, Inc. 42 1.1 pooka * 43 1.1 pooka * Copyright (c) 1992, 1993 44 1.1 pooka * The Regents of the University of California. All rights reserved. 45 1.1 pooka * 46 1.1 pooka * This software was developed by the Computer Systems Engineering group 47 1.1 pooka * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 48 1.1 pooka * contributed to Berkeley. 49 1.1 pooka * 50 1.1 pooka * All advertising materials mentioning features or use of this software 51 1.1 pooka * must display the following acknowledgement: 52 1.1 pooka * This product includes software developed by the University of 53 1.1 pooka * California, Lawrence Berkeley Laboratory. 54 1.1 pooka * 55 1.1 pooka * Redistribution and use in source and binary forms, with or without 56 1.1 pooka * modification, are permitted provided that the following conditions 57 1.1 pooka * are met: 58 1.1 pooka * 1. Redistributions of source code must retain the above copyright 59 1.1 pooka * notice, this list of conditions and the following disclaimer. 60 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 61 1.1 pooka * notice, this list of conditions and the following disclaimer in the 62 1.1 pooka * documentation and/or other materials provided with the distribution. 63 1.1 pooka * 3. Neither the name of the University nor the names of its contributors 64 1.1 pooka * may be used to endorse or promote products derived from this software 65 1.1 pooka * without specific prior written permission. 66 1.1 pooka * 67 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 68 1.1 pooka * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 69 1.1 pooka * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 70 1.1 pooka * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 71 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 72 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 73 1.1 pooka * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 74 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 75 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 76 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 77 1.1 pooka * SUCH DAMAGE. 78 1.1 pooka * 79 1.1 pooka * @(#)kern_subr.c 8.4 (Berkeley) 2/14/95 80 1.1 pooka */ 81 1.1 pooka 82 1.1 pooka #include <sys/cdefs.h> 83 1.19 riastrad __KERNEL_RCSID(0, "$NetBSD: subr_copy.c,v 1.19 2023/05/22 14:07:24 riastradh Exp $"); 84 1.9 thorpej 85 1.9 thorpej #define __UFETCHSTORE_PRIVATE 86 1.9 thorpej #define __UCAS_PRIVATE 87 1.1 pooka 88 1.1 pooka #include <sys/param.h> 89 1.1 pooka #include <sys/fcntl.h> 90 1.1 pooka #include <sys/proc.h> 91 1.1 pooka #include <sys/systm.h> 92 1.1 pooka 93 1.1 pooka #include <uvm/uvm_extern.h> 94 1.1 pooka 95 1.1 pooka void 96 1.1 pooka uio_setup_sysspace(struct uio *uio) 97 1.1 pooka { 98 1.1 pooka 99 1.1 pooka uio->uio_vmspace = vmspace_kernel(); 100 1.1 pooka } 101 1.1 pooka 102 1.1 pooka int 103 1.1 pooka uiomove(void *buf, size_t n, struct uio *uio) 104 1.1 pooka { 105 1.1 pooka struct vmspace *vm = uio->uio_vmspace; 106 1.1 pooka struct iovec *iov; 107 1.1 pooka size_t cnt; 108 1.1 pooka int error = 0; 109 1.1 pooka char *cp = buf; 110 1.1 pooka 111 1.1 pooka ASSERT_SLEEPABLE(); 112 1.1 pooka 113 1.6 riastrad KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE); 114 1.1 pooka while (n > 0 && uio->uio_resid) { 115 1.18 riastrad KASSERT(uio->uio_iovcnt > 0); 116 1.1 pooka iov = uio->uio_iov; 117 1.1 pooka cnt = iov->iov_len; 118 1.1 pooka if (cnt == 0) { 119 1.18 riastrad KASSERT(uio->uio_iovcnt > 1); 120 1.1 pooka uio->uio_iov++; 121 1.1 pooka uio->uio_iovcnt--; 122 1.1 pooka continue; 123 1.1 pooka } 124 1.1 pooka if (cnt > n) 125 1.1 pooka cnt = n; 126 1.1 pooka if (!VMSPACE_IS_KERNEL_P(vm)) { 127 1.13 ad preempt_point(); 128 1.1 pooka } 129 1.1 pooka 130 1.1 pooka if (uio->uio_rw == UIO_READ) { 131 1.1 pooka error = copyout_vmspace(vm, cp, iov->iov_base, 132 1.1 pooka cnt); 133 1.1 pooka } else { 134 1.1 pooka error = copyin_vmspace(vm, iov->iov_base, cp, 135 1.1 pooka cnt); 136 1.1 pooka } 137 1.1 pooka if (error) { 138 1.1 pooka break; 139 1.1 pooka } 140 1.1 pooka iov->iov_base = (char *)iov->iov_base + cnt; 141 1.1 pooka iov->iov_len -= cnt; 142 1.1 pooka uio->uio_resid -= cnt; 143 1.1 pooka uio->uio_offset += cnt; 144 1.1 pooka cp += cnt; 145 1.1 pooka KDASSERT(cnt <= n); 146 1.1 pooka n -= cnt; 147 1.1 pooka } 148 1.1 pooka 149 1.1 pooka return (error); 150 1.1 pooka } 151 1.1 pooka 152 1.1 pooka /* 153 1.1 pooka * Wrapper for uiomove() that validates the arguments against a known-good 154 1.1 pooka * kernel buffer. 155 1.1 pooka */ 156 1.1 pooka int 157 1.1 pooka uiomove_frombuf(void *buf, size_t buflen, struct uio *uio) 158 1.1 pooka { 159 1.1 pooka size_t offset; 160 1.1 pooka 161 1.1 pooka if (uio->uio_offset < 0 || /* uio->uio_resid < 0 || */ 162 1.1 pooka (offset = uio->uio_offset) != uio->uio_offset) 163 1.1 pooka return (EINVAL); 164 1.1 pooka if (offset >= buflen) 165 1.1 pooka return (0); 166 1.1 pooka return (uiomove((char *)buf + offset, buflen - offset, uio)); 167 1.1 pooka } 168 1.1 pooka 169 1.19 riastrad int 170 1.19 riastrad uiopeek(void *buf, size_t n, struct uio *uio) 171 1.19 riastrad { 172 1.19 riastrad struct vmspace *vm = uio->uio_vmspace; 173 1.19 riastrad struct iovec *iov; 174 1.19 riastrad size_t cnt; 175 1.19 riastrad int error = 0; 176 1.19 riastrad char *cp = buf; 177 1.19 riastrad size_t resid = uio->uio_resid; 178 1.19 riastrad int iovcnt = uio->uio_iovcnt; 179 1.19 riastrad char *base; 180 1.19 riastrad size_t len; 181 1.19 riastrad 182 1.19 riastrad KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE); 183 1.19 riastrad 184 1.19 riastrad if (n == 0 || resid == 0) 185 1.19 riastrad return 0; 186 1.19 riastrad iov = uio->uio_iov; 187 1.19 riastrad base = iov->iov_base; 188 1.19 riastrad len = iov->iov_len; 189 1.19 riastrad 190 1.19 riastrad while (n > 0 && resid > 0) { 191 1.19 riastrad KASSERT(iovcnt > 0); 192 1.19 riastrad cnt = len; 193 1.19 riastrad if (cnt == 0) { 194 1.19 riastrad KASSERT(iovcnt > 1); 195 1.19 riastrad iov++; 196 1.19 riastrad iovcnt--; 197 1.19 riastrad base = iov->iov_base; 198 1.19 riastrad len = iov->iov_len; 199 1.19 riastrad continue; 200 1.19 riastrad } 201 1.19 riastrad if (cnt > n) 202 1.19 riastrad cnt = n; 203 1.19 riastrad if (!VMSPACE_IS_KERNEL_P(vm)) { 204 1.19 riastrad preempt_point(); 205 1.19 riastrad } 206 1.19 riastrad 207 1.19 riastrad if (uio->uio_rw == UIO_READ) { 208 1.19 riastrad error = copyout_vmspace(vm, cp, base, cnt); 209 1.19 riastrad } else { 210 1.19 riastrad error = copyin_vmspace(vm, base, cp, cnt); 211 1.19 riastrad } 212 1.19 riastrad if (error) { 213 1.19 riastrad break; 214 1.19 riastrad } 215 1.19 riastrad base += cnt; 216 1.19 riastrad len -= cnt; 217 1.19 riastrad resid -= cnt; 218 1.19 riastrad cp += cnt; 219 1.19 riastrad KDASSERT(cnt <= n); 220 1.19 riastrad n -= cnt; 221 1.19 riastrad } 222 1.19 riastrad 223 1.19 riastrad return error; 224 1.19 riastrad } 225 1.19 riastrad 226 1.19 riastrad void 227 1.19 riastrad uioskip(size_t n, struct uio *uio) 228 1.19 riastrad { 229 1.19 riastrad struct iovec *iov; 230 1.19 riastrad size_t cnt; 231 1.19 riastrad 232 1.19 riastrad KASSERTMSG(n <= uio->uio_resid, "n=%zu resid=%zu", n, uio->uio_resid); 233 1.19 riastrad 234 1.19 riastrad KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE); 235 1.19 riastrad while (n > 0 && uio->uio_resid) { 236 1.19 riastrad KASSERT(uio->uio_iovcnt > 0); 237 1.19 riastrad iov = uio->uio_iov; 238 1.19 riastrad cnt = iov->iov_len; 239 1.19 riastrad if (cnt == 0) { 240 1.19 riastrad KASSERT(uio->uio_iovcnt > 1); 241 1.19 riastrad uio->uio_iov++; 242 1.19 riastrad uio->uio_iovcnt--; 243 1.19 riastrad continue; 244 1.19 riastrad } 245 1.19 riastrad if (cnt > n) 246 1.19 riastrad cnt = n; 247 1.19 riastrad iov->iov_base = (char *)iov->iov_base + cnt; 248 1.19 riastrad iov->iov_len -= cnt; 249 1.19 riastrad uio->uio_resid -= cnt; 250 1.19 riastrad uio->uio_offset += cnt; 251 1.19 riastrad KDASSERT(cnt <= n); 252 1.19 riastrad n -= cnt; 253 1.19 riastrad } 254 1.19 riastrad } 255 1.19 riastrad 256 1.1 pooka /* 257 1.1 pooka * Give next character to user as result of read. 258 1.1 pooka */ 259 1.1 pooka int 260 1.1 pooka ureadc(int c, struct uio *uio) 261 1.1 pooka { 262 1.1 pooka struct iovec *iov; 263 1.1 pooka 264 1.1 pooka if (uio->uio_resid <= 0) 265 1.1 pooka panic("ureadc: non-positive resid"); 266 1.1 pooka again: 267 1.1 pooka if (uio->uio_iovcnt <= 0) 268 1.1 pooka panic("ureadc: non-positive iovcnt"); 269 1.1 pooka iov = uio->uio_iov; 270 1.1 pooka if (iov->iov_len <= 0) { 271 1.1 pooka uio->uio_iovcnt--; 272 1.1 pooka uio->uio_iov++; 273 1.1 pooka goto again; 274 1.1 pooka } 275 1.1 pooka if (!VMSPACE_IS_KERNEL_P(uio->uio_vmspace)) { 276 1.9 thorpej int error; 277 1.9 thorpej if ((error = ustore_char(iov->iov_base, c)) != 0) 278 1.9 thorpej return (error); 279 1.1 pooka } else { 280 1.1 pooka *(char *)iov->iov_base = c; 281 1.1 pooka } 282 1.1 pooka iov->iov_base = (char *)iov->iov_base + 1; 283 1.1 pooka iov->iov_len--; 284 1.1 pooka uio->uio_resid--; 285 1.1 pooka uio->uio_offset++; 286 1.1 pooka return (0); 287 1.1 pooka } 288 1.1 pooka 289 1.1 pooka /* 290 1.1 pooka * Like copyin(), but operates on an arbitrary vmspace. 291 1.1 pooka */ 292 1.1 pooka int 293 1.1 pooka copyin_vmspace(struct vmspace *vm, const void *uaddr, void *kaddr, size_t len) 294 1.1 pooka { 295 1.1 pooka struct iovec iov; 296 1.1 pooka struct uio uio; 297 1.1 pooka int error; 298 1.1 pooka 299 1.1 pooka if (len == 0) 300 1.1 pooka return (0); 301 1.1 pooka 302 1.3 riastrad if (VMSPACE_IS_KERNEL_P(vm)) { 303 1.3 riastrad return kcopy(uaddr, kaddr, len); 304 1.3 riastrad } 305 1.2 riastrad if (__predict_true(vm == curproc->p_vmspace)) { 306 1.2 riastrad return copyin(uaddr, kaddr, len); 307 1.2 riastrad } 308 1.1 pooka 309 1.1 pooka iov.iov_base = kaddr; 310 1.1 pooka iov.iov_len = len; 311 1.1 pooka uio.uio_iov = &iov; 312 1.1 pooka uio.uio_iovcnt = 1; 313 1.1 pooka uio.uio_offset = (off_t)(uintptr_t)uaddr; 314 1.1 pooka uio.uio_resid = len; 315 1.1 pooka uio.uio_rw = UIO_READ; 316 1.1 pooka UIO_SETUP_SYSSPACE(&uio); 317 1.7 christos error = uvm_io(&vm->vm_map, &uio, 0); 318 1.1 pooka 319 1.1 pooka return (error); 320 1.1 pooka } 321 1.1 pooka 322 1.1 pooka /* 323 1.1 pooka * Like copyout(), but operates on an arbitrary vmspace. 324 1.1 pooka */ 325 1.1 pooka int 326 1.1 pooka copyout_vmspace(struct vmspace *vm, const void *kaddr, void *uaddr, size_t len) 327 1.1 pooka { 328 1.1 pooka struct iovec iov; 329 1.1 pooka struct uio uio; 330 1.1 pooka int error; 331 1.1 pooka 332 1.1 pooka if (len == 0) 333 1.1 pooka return (0); 334 1.1 pooka 335 1.3 riastrad if (VMSPACE_IS_KERNEL_P(vm)) { 336 1.3 riastrad return kcopy(kaddr, uaddr, len); 337 1.3 riastrad } 338 1.2 riastrad if (__predict_true(vm == curproc->p_vmspace)) { 339 1.2 riastrad return copyout(kaddr, uaddr, len); 340 1.2 riastrad } 341 1.1 pooka 342 1.1 pooka iov.iov_base = __UNCONST(kaddr); /* XXXUNCONST cast away const */ 343 1.1 pooka iov.iov_len = len; 344 1.1 pooka uio.uio_iov = &iov; 345 1.1 pooka uio.uio_iovcnt = 1; 346 1.1 pooka uio.uio_offset = (off_t)(uintptr_t)uaddr; 347 1.1 pooka uio.uio_resid = len; 348 1.1 pooka uio.uio_rw = UIO_WRITE; 349 1.1 pooka UIO_SETUP_SYSSPACE(&uio); 350 1.7 christos error = uvm_io(&vm->vm_map, &uio, 0); 351 1.1 pooka 352 1.1 pooka return (error); 353 1.1 pooka } 354 1.1 pooka 355 1.1 pooka /* 356 1.1 pooka * Like copyin(), but operates on an arbitrary process. 357 1.1 pooka */ 358 1.1 pooka int 359 1.1 pooka copyin_proc(struct proc *p, const void *uaddr, void *kaddr, size_t len) 360 1.1 pooka { 361 1.1 pooka struct vmspace *vm; 362 1.1 pooka int error; 363 1.1 pooka 364 1.1 pooka error = proc_vmspace_getref(p, &vm); 365 1.1 pooka if (error) { 366 1.1 pooka return error; 367 1.1 pooka } 368 1.1 pooka error = copyin_vmspace(vm, uaddr, kaddr, len); 369 1.1 pooka uvmspace_free(vm); 370 1.1 pooka 371 1.1 pooka return error; 372 1.1 pooka } 373 1.1 pooka 374 1.1 pooka /* 375 1.1 pooka * Like copyout(), but operates on an arbitrary process. 376 1.1 pooka */ 377 1.1 pooka int 378 1.1 pooka copyout_proc(struct proc *p, const void *kaddr, void *uaddr, size_t len) 379 1.1 pooka { 380 1.1 pooka struct vmspace *vm; 381 1.1 pooka int error; 382 1.1 pooka 383 1.1 pooka error = proc_vmspace_getref(p, &vm); 384 1.1 pooka if (error) { 385 1.1 pooka return error; 386 1.1 pooka } 387 1.1 pooka error = copyout_vmspace(vm, kaddr, uaddr, len); 388 1.1 pooka uvmspace_free(vm); 389 1.1 pooka 390 1.1 pooka return error; 391 1.1 pooka } 392 1.1 pooka 393 1.1 pooka /* 394 1.8 chs * Like copyin(), but operates on an arbitrary pid. 395 1.8 chs */ 396 1.8 chs int 397 1.8 chs copyin_pid(pid_t pid, const void *uaddr, void *kaddr, size_t len) 398 1.8 chs { 399 1.8 chs struct proc *p; 400 1.8 chs struct vmspace *vm; 401 1.8 chs int error; 402 1.8 chs 403 1.14 ad mutex_enter(&proc_lock); 404 1.8 chs p = proc_find(pid); 405 1.8 chs if (p == NULL) { 406 1.14 ad mutex_exit(&proc_lock); 407 1.8 chs return ESRCH; 408 1.8 chs } 409 1.8 chs mutex_enter(p->p_lock); 410 1.12 chs error = proc_vmspace_getref(p, &vm); 411 1.8 chs mutex_exit(p->p_lock); 412 1.14 ad mutex_exit(&proc_lock); 413 1.8 chs 414 1.12 chs if (error == 0) { 415 1.12 chs error = copyin_vmspace(vm, uaddr, kaddr, len); 416 1.12 chs uvmspace_free(vm); 417 1.12 chs } 418 1.8 chs return error; 419 1.8 chs } 420 1.8 chs 421 1.8 chs /* 422 1.1 pooka * Like copyin(), except it operates on kernel addresses when the FKIOCTL 423 1.1 pooka * flag is passed in `ioctlflags' from the ioctl call. 424 1.1 pooka */ 425 1.1 pooka int 426 1.1 pooka ioctl_copyin(int ioctlflags, const void *src, void *dst, size_t len) 427 1.1 pooka { 428 1.1 pooka if (ioctlflags & FKIOCTL) 429 1.1 pooka return kcopy(src, dst, len); 430 1.1 pooka return copyin(src, dst, len); 431 1.1 pooka } 432 1.1 pooka 433 1.1 pooka /* 434 1.1 pooka * Like copyout(), except it operates on kernel addresses when the FKIOCTL 435 1.1 pooka * flag is passed in `ioctlflags' from the ioctl call. 436 1.1 pooka */ 437 1.1 pooka int 438 1.1 pooka ioctl_copyout(int ioctlflags, const void *src, void *dst, size_t len) 439 1.1 pooka { 440 1.1 pooka if (ioctlflags & FKIOCTL) 441 1.1 pooka return kcopy(src, dst, len); 442 1.1 pooka return copyout(src, dst, len); 443 1.1 pooka } 444 1.9 thorpej 445 1.9 thorpej /* 446 1.9 thorpej * User-space CAS / fetch / store 447 1.9 thorpej */ 448 1.9 thorpej 449 1.9 thorpej #ifdef __NO_STRICT_ALIGNMENT 450 1.9 thorpej #define CHECK_ALIGNMENT(x) __nothing 451 1.9 thorpej #else /* ! __NO_STRICT_ALIGNMENT */ 452 1.9 thorpej static bool 453 1.9 thorpej ufetchstore_aligned(uintptr_t uaddr, size_t size) 454 1.9 thorpej { 455 1.9 thorpej return (uaddr & (size - 1)) == 0; 456 1.9 thorpej } 457 1.9 thorpej 458 1.9 thorpej #define CHECK_ALIGNMENT() \ 459 1.9 thorpej do { \ 460 1.9 thorpej if (!ufetchstore_aligned((uintptr_t)uaddr, sizeof(*uaddr))) \ 461 1.9 thorpej return EFAULT; \ 462 1.9 thorpej } while (/*CONSTCOND*/0) 463 1.9 thorpej #endif /* __NO_STRICT_ALIGNMENT */ 464 1.9 thorpej 465 1.10 thorpej /* 466 1.10 thorpej * __HAVE_UCAS_FULL platforms provide _ucas_32() and _ucas_64() themselves. 467 1.10 thorpej * _RUMPKERNEL also provides it's own _ucas_32() and _ucas_64(). 468 1.10 thorpej * 469 1.10 thorpej * In all other cases, we provide generic implementations that work on 470 1.10 thorpej * all platforms. 471 1.10 thorpej */ 472 1.10 thorpej 473 1.10 thorpej #if !defined(__HAVE_UCAS_FULL) && !defined(_RUMPKERNEL) 474 1.9 thorpej #if !defined(__HAVE_UCAS_MP) && defined(MULTIPROCESSOR) 475 1.9 thorpej #include <sys/atomic.h> 476 1.9 thorpej #include <sys/cpu.h> 477 1.9 thorpej #include <sys/once.h> 478 1.9 thorpej #include <sys/mutex.h> 479 1.9 thorpej #include <sys/ipi.h> 480 1.9 thorpej 481 1.9 thorpej static int ucas_critical_splcookie; 482 1.9 thorpej static volatile u_int ucas_critical_pausing_cpus; 483 1.9 thorpej static u_int ucas_critical_ipi; 484 1.9 thorpej static ONCE_DECL(ucas_critical_init_once) 485 1.9 thorpej 486 1.9 thorpej static void 487 1.9 thorpej ucas_critical_cpu_gate(void *arg __unused) 488 1.9 thorpej { 489 1.9 thorpej int count = SPINLOCK_BACKOFF_MIN; 490 1.9 thorpej 491 1.15 riastrad KASSERT(atomic_load_relaxed(&ucas_critical_pausing_cpus) > 0); 492 1.15 riastrad 493 1.15 riastrad /* 494 1.15 riastrad * Notify ucas_critical_wait that we have stopped. Using 495 1.15 riastrad * store-release ensures all our memory operations up to the 496 1.15 riastrad * IPI happen before the ucas -- no buffered stores on our end 497 1.15 riastrad * can clobber it later on, for instance. 498 1.15 riastrad * 499 1.15 riastrad * Matches atomic_load_acquire in ucas_critical_wait -- turns 500 1.15 riastrad * the following atomic_dec_uint into a store-release. 501 1.15 riastrad */ 502 1.16 riastrad membar_release(); 503 1.9 thorpej atomic_dec_uint(&ucas_critical_pausing_cpus); 504 1.15 riastrad 505 1.15 riastrad /* 506 1.15 riastrad * Wait for ucas_critical_exit to reopen the gate and let us 507 1.15 riastrad * proceed. Using a load-acquire ensures the ucas happens 508 1.15 riastrad * before any of our memory operations when we return from the 509 1.15 riastrad * IPI and proceed -- we won't observe any stale cached value 510 1.15 riastrad * that the ucas overwrote, for instance. 511 1.15 riastrad * 512 1.15 riastrad * Matches atomic_store_release in ucas_critical_exit. 513 1.15 riastrad */ 514 1.15 riastrad while (atomic_load_acquire(&ucas_critical_pausing_cpus) != (u_int)-1) { 515 1.9 thorpej SPINLOCK_BACKOFF(count); 516 1.9 thorpej } 517 1.9 thorpej } 518 1.9 thorpej 519 1.9 thorpej static int 520 1.9 thorpej ucas_critical_init(void) 521 1.9 thorpej { 522 1.15 riastrad 523 1.9 thorpej ucas_critical_ipi = ipi_register(ucas_critical_cpu_gate, NULL); 524 1.9 thorpej return 0; 525 1.9 thorpej } 526 1.9 thorpej 527 1.9 thorpej static void 528 1.9 thorpej ucas_critical_wait(void) 529 1.9 thorpej { 530 1.9 thorpej int count = SPINLOCK_BACKOFF_MIN; 531 1.9 thorpej 532 1.15 riastrad /* 533 1.15 riastrad * Wait for all CPUs to stop at the gate. Using a load-acquire 534 1.15 riastrad * ensures all memory operations before they stop at the gate 535 1.15 riastrad * happen before the ucas -- no buffered stores in other CPUs 536 1.15 riastrad * can clobber it later on, for instance. 537 1.15 riastrad * 538 1.16 riastrad * Matches membar_release/atomic_dec_uint (store-release) in 539 1.15 riastrad * ucas_critical_cpu_gate. 540 1.15 riastrad */ 541 1.15 riastrad while (atomic_load_acquire(&ucas_critical_pausing_cpus) > 0) { 542 1.9 thorpej SPINLOCK_BACKOFF(count); 543 1.9 thorpej } 544 1.9 thorpej } 545 1.9 thorpej #endif /* ! __HAVE_UCAS_MP && MULTIPROCESSOR */ 546 1.9 thorpej 547 1.9 thorpej static inline void 548 1.9 thorpej ucas_critical_enter(lwp_t * const l) 549 1.9 thorpej { 550 1.9 thorpej 551 1.9 thorpej #if !defined(__HAVE_UCAS_MP) && defined(MULTIPROCESSOR) 552 1.9 thorpej if (ncpu > 1) { 553 1.9 thorpej RUN_ONCE(&ucas_critical_init_once, ucas_critical_init); 554 1.9 thorpej 555 1.9 thorpej /* 556 1.9 thorpej * Acquire the mutex first, then go to splhigh() and 557 1.9 thorpej * broadcast the IPI to lock all of the other CPUs 558 1.9 thorpej * behind the gate. 559 1.9 thorpej * 560 1.9 thorpej * N.B. Going to splhigh() implicitly disables preemption, 561 1.9 thorpej * so there's no need to do it explicitly. 562 1.9 thorpej */ 563 1.9 thorpej mutex_enter(&cpu_lock); 564 1.9 thorpej ucas_critical_splcookie = splhigh(); 565 1.9 thorpej ucas_critical_pausing_cpus = ncpu - 1; 566 1.9 thorpej ipi_trigger_broadcast(ucas_critical_ipi, true); 567 1.9 thorpej ucas_critical_wait(); 568 1.9 thorpej return; 569 1.9 thorpej } 570 1.9 thorpej #endif /* ! __HAVE_UCAS_MP && MULTIPROCESSOR */ 571 1.9 thorpej 572 1.9 thorpej KPREEMPT_DISABLE(l); 573 1.9 thorpej } 574 1.9 thorpej 575 1.9 thorpej static inline void 576 1.9 thorpej ucas_critical_exit(lwp_t * const l) 577 1.9 thorpej { 578 1.9 thorpej 579 1.9 thorpej #if !defined(__HAVE_UCAS_MP) && defined(MULTIPROCESSOR) 580 1.9 thorpej if (ncpu > 1) { 581 1.15 riastrad /* 582 1.15 riastrad * Open the gate and notify all CPUs in 583 1.15 riastrad * ucas_critical_cpu_gate that they can now proceed. 584 1.15 riastrad * Using a store-release ensures the ucas happens 585 1.15 riastrad * before any memory operations they issue after the 586 1.15 riastrad * IPI -- they won't observe any stale cache of the 587 1.15 riastrad * target word, for instance. 588 1.15 riastrad * 589 1.15 riastrad * Matches atomic_load_acquire in ucas_critical_cpu_gate. 590 1.15 riastrad */ 591 1.15 riastrad atomic_store_release(&ucas_critical_pausing_cpus, (u_int)-1); 592 1.9 thorpej splx(ucas_critical_splcookie); 593 1.9 thorpej mutex_exit(&cpu_lock); 594 1.9 thorpej return; 595 1.9 thorpej } 596 1.9 thorpej #endif /* ! __HAVE_UCAS_MP && MULTIPROCESSOR */ 597 1.9 thorpej 598 1.9 thorpej KPREEMPT_ENABLE(l); 599 1.9 thorpej } 600 1.9 thorpej 601 1.9 thorpej int 602 1.9 thorpej _ucas_32(volatile uint32_t *uaddr, uint32_t old, uint32_t new, uint32_t *ret) 603 1.9 thorpej { 604 1.9 thorpej lwp_t * const l = curlwp; 605 1.9 thorpej uint32_t *uva = ((void *)(uintptr_t)uaddr); 606 1.9 thorpej int error; 607 1.9 thorpej 608 1.9 thorpej /* 609 1.9 thorpej * Wire the user address down to avoid taking a page fault during 610 1.9 thorpej * the critical section. 611 1.9 thorpej */ 612 1.9 thorpej error = uvm_vslock(l->l_proc->p_vmspace, uva, sizeof(*uaddr), 613 1.9 thorpej VM_PROT_READ | VM_PROT_WRITE); 614 1.9 thorpej if (error) 615 1.9 thorpej return error; 616 1.9 thorpej 617 1.9 thorpej ucas_critical_enter(l); 618 1.9 thorpej error = _ufetch_32(uva, ret); 619 1.9 thorpej if (error == 0 && *ret == old) { 620 1.9 thorpej error = _ustore_32(uva, new); 621 1.9 thorpej } 622 1.9 thorpej ucas_critical_exit(l); 623 1.9 thorpej 624 1.9 thorpej uvm_vsunlock(l->l_proc->p_vmspace, uva, sizeof(*uaddr)); 625 1.9 thorpej 626 1.9 thorpej return error; 627 1.9 thorpej } 628 1.9 thorpej 629 1.9 thorpej #ifdef _LP64 630 1.9 thorpej int 631 1.9 thorpej _ucas_64(volatile uint64_t *uaddr, uint64_t old, uint64_t new, uint64_t *ret) 632 1.9 thorpej { 633 1.9 thorpej lwp_t * const l = curlwp; 634 1.9 thorpej uint64_t *uva = ((void *)(uintptr_t)uaddr); 635 1.9 thorpej int error; 636 1.9 thorpej 637 1.9 thorpej /* 638 1.9 thorpej * Wire the user address down to avoid taking a page fault during 639 1.9 thorpej * the critical section. 640 1.9 thorpej */ 641 1.9 thorpej error = uvm_vslock(l->l_proc->p_vmspace, uva, sizeof(*uaddr), 642 1.9 thorpej VM_PROT_READ | VM_PROT_WRITE); 643 1.9 thorpej if (error) 644 1.9 thorpej return error; 645 1.9 thorpej 646 1.9 thorpej ucas_critical_enter(l); 647 1.9 thorpej error = _ufetch_64(uva, ret); 648 1.9 thorpej if (error == 0 && *ret == old) { 649 1.9 thorpej error = _ustore_64(uva, new); 650 1.9 thorpej } 651 1.9 thorpej ucas_critical_exit(l); 652 1.9 thorpej 653 1.9 thorpej uvm_vsunlock(l->l_proc->p_vmspace, uva, sizeof(*uaddr)); 654 1.9 thorpej 655 1.9 thorpej return error; 656 1.9 thorpej } 657 1.9 thorpej #endif /* _LP64 */ 658 1.10 thorpej #endif /* ! __HAVE_UCAS_FULL && ! _RUMPKERNEL */ 659 1.9 thorpej 660 1.9 thorpej int 661 1.9 thorpej ucas_32(volatile uint32_t *uaddr, uint32_t old, uint32_t new, uint32_t *ret) 662 1.9 thorpej { 663 1.9 thorpej 664 1.9 thorpej ASSERT_SLEEPABLE(); 665 1.9 thorpej CHECK_ALIGNMENT(); 666 1.11 thorpej #if (defined(__HAVE_UCAS_MP) && defined(MULTIPROCESSOR)) && \ 667 1.11 thorpej !defined(_RUMPKERNEL) 668 1.9 thorpej if (ncpu > 1) { 669 1.9 thorpej return _ucas_32_mp(uaddr, old, new, ret); 670 1.9 thorpej } 671 1.9 thorpej #endif /* __HAVE_UCAS_MP && MULTIPROCESSOR */ 672 1.9 thorpej return _ucas_32(uaddr, old, new, ret); 673 1.9 thorpej } 674 1.9 thorpej 675 1.9 thorpej #ifdef _LP64 676 1.9 thorpej int 677 1.9 thorpej ucas_64(volatile uint64_t *uaddr, uint64_t old, uint64_t new, uint64_t *ret) 678 1.9 thorpej { 679 1.9 thorpej 680 1.9 thorpej ASSERT_SLEEPABLE(); 681 1.9 thorpej CHECK_ALIGNMENT(); 682 1.11 thorpej #if (defined(__HAVE_UCAS_MP) && defined(MULTIPROCESSOR)) && \ 683 1.11 thorpej !defined(_RUMPKERNEL) 684 1.9 thorpej if (ncpu > 1) { 685 1.9 thorpej return _ucas_64_mp(uaddr, old, new, ret); 686 1.9 thorpej } 687 1.9 thorpej #endif /* __HAVE_UCAS_MP && MULTIPROCESSOR */ 688 1.9 thorpej return _ucas_64(uaddr, old, new, ret); 689 1.9 thorpej } 690 1.9 thorpej #endif /* _LP64 */ 691 1.9 thorpej 692 1.9 thorpej __strong_alias(ucas_int,ucas_32); 693 1.9 thorpej #ifdef _LP64 694 1.9 thorpej __strong_alias(ucas_ptr,ucas_64); 695 1.9 thorpej #else 696 1.9 thorpej __strong_alias(ucas_ptr,ucas_32); 697 1.9 thorpej #endif /* _LP64 */ 698 1.9 thorpej 699 1.9 thorpej int 700 1.9 thorpej ufetch_8(const uint8_t *uaddr, uint8_t *valp) 701 1.9 thorpej { 702 1.9 thorpej 703 1.9 thorpej ASSERT_SLEEPABLE(); 704 1.9 thorpej CHECK_ALIGNMENT(); 705 1.9 thorpej return _ufetch_8(uaddr, valp); 706 1.9 thorpej } 707 1.9 thorpej 708 1.9 thorpej int 709 1.9 thorpej ufetch_16(const uint16_t *uaddr, uint16_t *valp) 710 1.9 thorpej { 711 1.9 thorpej 712 1.9 thorpej ASSERT_SLEEPABLE(); 713 1.9 thorpej CHECK_ALIGNMENT(); 714 1.9 thorpej return _ufetch_16(uaddr, valp); 715 1.9 thorpej } 716 1.9 thorpej 717 1.9 thorpej int 718 1.9 thorpej ufetch_32(const uint32_t *uaddr, uint32_t *valp) 719 1.9 thorpej { 720 1.9 thorpej 721 1.9 thorpej ASSERT_SLEEPABLE(); 722 1.9 thorpej CHECK_ALIGNMENT(); 723 1.9 thorpej return _ufetch_32(uaddr, valp); 724 1.9 thorpej } 725 1.9 thorpej 726 1.9 thorpej #ifdef _LP64 727 1.9 thorpej int 728 1.9 thorpej ufetch_64(const uint64_t *uaddr, uint64_t *valp) 729 1.9 thorpej { 730 1.9 thorpej 731 1.9 thorpej ASSERT_SLEEPABLE(); 732 1.9 thorpej CHECK_ALIGNMENT(); 733 1.9 thorpej return _ufetch_64(uaddr, valp); 734 1.9 thorpej } 735 1.9 thorpej #endif /* _LP64 */ 736 1.9 thorpej 737 1.9 thorpej __strong_alias(ufetch_char,ufetch_8); 738 1.9 thorpej __strong_alias(ufetch_short,ufetch_16); 739 1.9 thorpej __strong_alias(ufetch_int,ufetch_32); 740 1.9 thorpej #ifdef _LP64 741 1.9 thorpej __strong_alias(ufetch_long,ufetch_64); 742 1.9 thorpej __strong_alias(ufetch_ptr,ufetch_64); 743 1.9 thorpej #else 744 1.9 thorpej __strong_alias(ufetch_long,ufetch_32); 745 1.9 thorpej __strong_alias(ufetch_ptr,ufetch_32); 746 1.9 thorpej #endif /* _LP64 */ 747 1.9 thorpej 748 1.9 thorpej int 749 1.9 thorpej ustore_8(uint8_t *uaddr, uint8_t val) 750 1.9 thorpej { 751 1.9 thorpej 752 1.9 thorpej ASSERT_SLEEPABLE(); 753 1.9 thorpej CHECK_ALIGNMENT(); 754 1.9 thorpej return _ustore_8(uaddr, val); 755 1.9 thorpej } 756 1.9 thorpej 757 1.9 thorpej int 758 1.9 thorpej ustore_16(uint16_t *uaddr, uint16_t val) 759 1.9 thorpej { 760 1.9 thorpej 761 1.9 thorpej ASSERT_SLEEPABLE(); 762 1.9 thorpej CHECK_ALIGNMENT(); 763 1.9 thorpej return _ustore_16(uaddr, val); 764 1.9 thorpej } 765 1.9 thorpej 766 1.9 thorpej int 767 1.9 thorpej ustore_32(uint32_t *uaddr, uint32_t val) 768 1.9 thorpej { 769 1.9 thorpej 770 1.9 thorpej ASSERT_SLEEPABLE(); 771 1.9 thorpej CHECK_ALIGNMENT(); 772 1.9 thorpej return _ustore_32(uaddr, val); 773 1.9 thorpej } 774 1.9 thorpej 775 1.9 thorpej #ifdef _LP64 776 1.9 thorpej int 777 1.9 thorpej ustore_64(uint64_t *uaddr, uint64_t val) 778 1.9 thorpej { 779 1.9 thorpej 780 1.9 thorpej ASSERT_SLEEPABLE(); 781 1.9 thorpej CHECK_ALIGNMENT(); 782 1.9 thorpej return _ustore_64(uaddr, val); 783 1.9 thorpej } 784 1.9 thorpej #endif /* _LP64 */ 785 1.9 thorpej 786 1.9 thorpej __strong_alias(ustore_char,ustore_8); 787 1.9 thorpej __strong_alias(ustore_short,ustore_16); 788 1.9 thorpej __strong_alias(ustore_int,ustore_32); 789 1.9 thorpej #ifdef _LP64 790 1.9 thorpej __strong_alias(ustore_long,ustore_64); 791 1.9 thorpej __strong_alias(ustore_ptr,ustore_64); 792 1.9 thorpej #else 793 1.9 thorpej __strong_alias(ustore_long,ustore_32); 794 1.9 thorpej __strong_alias(ustore_ptr,ustore_32); 795 1.9 thorpej #endif /* _LP64 */ 796