1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-4-Clause 3 * 4 * Copyright (C) 2002 Benno Rice 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 /*- 28 * Copyright (C) 1993 Wolfgang Solfrank. 29 * Copyright (C) 1993 TooLs GmbH. 30 * All rights reserved. 31 * 32 * Redistribution and use in source and binary forms, with or without 33 * modification, are permitted provided that the following conditions 34 * are met: 35 * 1. Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * 2. Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditions and the following disclaimer in the 39 * documentation and/or other materials provided with the distribution. 40 * 3. All advertising materials mentioning features or use of this software 41 * must display the following acknowledgement: 42 * This product includes software developed by TooLs GmbH. 43 * 4. The name of TooLs GmbH may not be used to endorse or promote products 44 * derived from this software without specific prior written permission. 45 * 46 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 49 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 52 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 53 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 54 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 55 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 */ 57 58 #include <sys/cdefs.h> 59 __FBSDID("$FreeBSD$"); 60 61 #include <sys/param.h> 62 #include <sys/lock.h> 63 #include <sys/mutex.h> 64 #include <sys/systm.h> 65 #include <sys/proc.h> 66 67 #include <vm/vm.h> 68 #include <vm/pmap.h> 69 #include <vm/vm_map.h> 70 71 #include <machine/pcb.h> 72 #include <machine/vmparam.h> 73 74 int 75 copyout(const void *kaddr, void *udaddr, size_t len) 76 { 77 struct thread *td; 78 pmap_t pm; 79 jmp_buf env; 80 const char *kp; 81 char *up, *p; 82 size_t l; 83 84 td = curthread; 85 pm = &td->td_proc->p_vmspace->vm_pmap; 86 87 td->td_pcb->pcb_onfault = &env; 88 if (setjmp(env)) { 89 td->td_pcb->pcb_onfault = NULL; 90 return (EFAULT); 91 } 92 93 kp = kaddr; 94 up = udaddr; 95 96 while (len > 0) { 97 if (pmap_map_user_ptr(pm, up, (void **)&p, len, &l)) { 98 td->td_pcb->pcb_onfault = NULL; 99 return (EFAULT); 100 } 101 102 bcopy(kp, p, l); 103 104 up += l; 105 kp += l; 106 len -= l; 107 } 108 109 td->td_pcb->pcb_onfault = NULL; 110 return (0); 111 } 112 113 int 114 copyin(const void *udaddr, void *kaddr, size_t len) 115 { 116 struct thread *td; 117 pmap_t pm; 118 jmp_buf env; 119 const char *up; 120 char *kp, *p; 121 size_t l; 122 123 td = curthread; 124 pm = &td->td_proc->p_vmspace->vm_pmap; 125 126 td->td_pcb->pcb_onfault = &env; 127 if (setjmp(env)) { 128 td->td_pcb->pcb_onfault = NULL; 129 return (EFAULT); 130 } 131 132 kp = kaddr; 133 up = udaddr; 134 135 while (len > 0) { 136 if (pmap_map_user_ptr(pm, up, (void **)&p, len, &l)) { 137 td->td_pcb->pcb_onfault = NULL; 138 return (EFAULT); 139 } 140 141 bcopy(p, kp, l); 142 143 up += l; 144 kp += l; 145 len -= l; 146 } 147 148 td->td_pcb->pcb_onfault = NULL; 149 return (0); 150 } 151 152 int 153 copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done) 154 { 155 const char *up; 156 char *kp; 157 size_t l; 158 int rv, c; 159 160 kp = kaddr; 161 up = udaddr; 162 163 rv = ENAMETOOLONG; 164 165 for (l = 0; len-- > 0; l++) { 166 if ((c = fubyte(up++)) < 0) { 167 rv = EFAULT; 168 break; 169 } 170 171 if (!(*kp++ = c)) { 172 l++; 173 rv = 0; 174 break; 175 } 176 } 177 178 if (done != NULL) { 179 *done = l; 180 } 181 182 return (rv); 183 } 184 185 int 186 subyte(volatile void *addr, int byte) 187 { 188 struct thread *td; 189 pmap_t pm; 190 jmp_buf env; 191 char *p; 192 193 td = curthread; 194 pm = &td->td_proc->p_vmspace->vm_pmap; 195 196 td->td_pcb->pcb_onfault = &env; 197 if (setjmp(env)) { 198 td->td_pcb->pcb_onfault = NULL; 199 return (-1); 200 } 201 202 if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) { 203 td->td_pcb->pcb_onfault = NULL; 204 return (-1); 205 } 206 207 *p = (char)byte; 208 209 td->td_pcb->pcb_onfault = NULL; 210 return (0); 211 } 212 213 #ifdef __powerpc64__ 214 int 215 suword32(volatile void *addr, int word) 216 { 217 struct thread *td; 218 pmap_t pm; 219 jmp_buf env; 220 int *p; 221 222 td = curthread; 223 pm = &td->td_proc->p_vmspace->vm_pmap; 224 225 td->td_pcb->pcb_onfault = &env; 226 if (setjmp(env)) { 227 td->td_pcb->pcb_onfault = NULL; 228 return (-1); 229 } 230 231 if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) { 232 td->td_pcb->pcb_onfault = NULL; 233 return (-1); 234 } 235 236 *p = word; 237 238 td->td_pcb->pcb_onfault = NULL; 239 return (0); 240 } 241 #endif 242 243 int 244 suword(volatile void *addr, long word) 245 { 246 struct thread *td; 247 pmap_t pm; 248 jmp_buf env; 249 long *p; 250 251 td = curthread; 252 pm = &td->td_proc->p_vmspace->vm_pmap; 253 254 td->td_pcb->pcb_onfault = &env; 255 if (setjmp(env)) { 256 td->td_pcb->pcb_onfault = NULL; 257 return (-1); 258 } 259 260 if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) { 261 td->td_pcb->pcb_onfault = NULL; 262 return (-1); 263 } 264 265 *p = word; 266 267 td->td_pcb->pcb_onfault = NULL; 268 return (0); 269 } 270 271 #ifdef __powerpc64__ 272 int 273 suword64(volatile void *addr, int64_t word) 274 { 275 return (suword(addr, (long)word)); 276 } 277 #else 278 int 279 suword32(volatile void *addr, int32_t word) 280 { 281 return (suword(addr, (long)word)); 282 } 283 #endif 284 285 int 286 fubyte(volatile const void *addr) 287 { 288 struct thread *td; 289 pmap_t pm; 290 jmp_buf env; 291 u_char *p; 292 int val; 293 294 td = curthread; 295 pm = &td->td_proc->p_vmspace->vm_pmap; 296 297 td->td_pcb->pcb_onfault = &env; 298 if (setjmp(env)) { 299 td->td_pcb->pcb_onfault = NULL; 300 return (-1); 301 } 302 303 if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) { 304 td->td_pcb->pcb_onfault = NULL; 305 return (-1); 306 } 307 308 val = *p; 309 310 td->td_pcb->pcb_onfault = NULL; 311 return (val); 312 } 313 314 int 315 fuword16(volatile const void *addr) 316 { 317 struct thread *td; 318 pmap_t pm; 319 jmp_buf env; 320 uint16_t *p, val; 321 322 td = curthread; 323 pm = &td->td_proc->p_vmspace->vm_pmap; 324 325 td->td_pcb->pcb_onfault = &env; 326 if (setjmp(env)) { 327 td->td_pcb->pcb_onfault = NULL; 328 return (-1); 329 } 330 331 if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) { 332 td->td_pcb->pcb_onfault = NULL; 333 return (-1); 334 } 335 336 val = *p; 337 338 td->td_pcb->pcb_onfault = NULL; 339 return (val); 340 } 341 342 int 343 fueword32(volatile const void *addr, int32_t *val) 344 { 345 struct thread *td; 346 pmap_t pm; 347 jmp_buf env; 348 int32_t *p; 349 350 td = curthread; 351 pm = &td->td_proc->p_vmspace->vm_pmap; 352 353 td->td_pcb->pcb_onfault = &env; 354 if (setjmp(env)) { 355 td->td_pcb->pcb_onfault = NULL; 356 return (-1); 357 } 358 359 if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) { 360 td->td_pcb->pcb_onfault = NULL; 361 return (-1); 362 } 363 364 *val = *p; 365 366 td->td_pcb->pcb_onfault = NULL; 367 return (0); 368 } 369 370 #ifdef __powerpc64__ 371 int 372 fueword64(volatile const void *addr, int64_t *val) 373 { 374 struct thread *td; 375 pmap_t pm; 376 jmp_buf env; 377 int64_t *p; 378 379 td = curthread; 380 pm = &td->td_proc->p_vmspace->vm_pmap; 381 382 td->td_pcb->pcb_onfault = &env; 383 if (setjmp(env)) { 384 td->td_pcb->pcb_onfault = NULL; 385 return (-1); 386 } 387 388 if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) { 389 td->td_pcb->pcb_onfault = NULL; 390 return (-1); 391 } 392 393 *val = *p; 394 395 td->td_pcb->pcb_onfault = NULL; 396 return (0); 397 } 398 #endif 399 400 int 401 fueword(volatile const void *addr, long *val) 402 { 403 struct thread *td; 404 pmap_t pm; 405 jmp_buf env; 406 long *p; 407 408 td = curthread; 409 pm = &td->td_proc->p_vmspace->vm_pmap; 410 411 td->td_pcb->pcb_onfault = &env; 412 if (setjmp(env)) { 413 td->td_pcb->pcb_onfault = NULL; 414 return (-1); 415 } 416 417 if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) { 418 td->td_pcb->pcb_onfault = NULL; 419 return (-1); 420 } 421 422 *val = *p; 423 424 td->td_pcb->pcb_onfault = NULL; 425 return (0); 426 } 427 428 int 429 casueword32(volatile uint32_t *addr, uint32_t old, uint32_t *oldvalp, 430 uint32_t new) 431 { 432 struct thread *td; 433 pmap_t pm; 434 jmp_buf env; 435 uint32_t *p, val; 436 437 td = curthread; 438 pm = &td->td_proc->p_vmspace->vm_pmap; 439 440 td->td_pcb->pcb_onfault = &env; 441 if (setjmp(env)) { 442 td->td_pcb->pcb_onfault = NULL; 443 return (-1); 444 } 445 446 if (pmap_map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p, 447 sizeof(*p), NULL)) { 448 td->td_pcb->pcb_onfault = NULL; 449 return (-1); 450 } 451 452 __asm __volatile ( 453 "1:\tlwarx %0, 0, %2\n\t" /* load old value */ 454 "cmplw %3, %0\n\t" /* compare */ 455 "bne 2f\n\t" /* exit if not equal */ 456 "stwcx. %4, 0, %2\n\t" /* attempt to store */ 457 "bne- 1b\n\t" /* spin if failed */ 458 "b 3f\n\t" /* we've succeeded */ 459 "2:\n\t" 460 "stwcx. %0, 0, %2\n\t" /* clear reservation (74xx) */ 461 "3:\n\t" 462 : "=&r" (val), "=m" (*p) 463 : "r" (p), "r" (old), "r" (new), "m" (*p) 464 : "cr0", "memory"); 465 466 td->td_pcb->pcb_onfault = NULL; 467 468 *oldvalp = val; 469 return (0); 470 } 471 472 #ifndef __powerpc64__ 473 int 474 casueword(volatile u_long *addr, u_long old, u_long *oldvalp, u_long new) 475 { 476 477 return (casueword32((volatile uint32_t *)addr, old, 478 (uint32_t *)oldvalp, new)); 479 } 480 #else 481 int 482 casueword(volatile u_long *addr, u_long old, u_long *oldvalp, u_long new) 483 { 484 struct thread *td; 485 pmap_t pm; 486 jmp_buf env; 487 u_long *p, val; 488 489 td = curthread; 490 pm = &td->td_proc->p_vmspace->vm_pmap; 491 492 td->td_pcb->pcb_onfault = &env; 493 if (setjmp(env)) { 494 td->td_pcb->pcb_onfault = NULL; 495 return (-1); 496 } 497 498 if (pmap_map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p, 499 sizeof(*p), NULL)) { 500 td->td_pcb->pcb_onfault = NULL; 501 return (-1); 502 } 503 504 __asm __volatile ( 505 "1:\tldarx %0, 0, %2\n\t" /* load old value */ 506 "cmpld %3, %0\n\t" /* compare */ 507 "bne 2f\n\t" /* exit if not equal */ 508 "stdcx. %4, 0, %2\n\t" /* attempt to store */ 509 "bne- 1b\n\t" /* spin if failed */ 510 "b 3f\n\t" /* we've succeeded */ 511 "2:\n\t" 512 "stdcx. %0, 0, %2\n\t" /* clear reservation (74xx) */ 513 "3:\n\t" 514 : "=&r" (val), "=m" (*p) 515 : "r" (p), "r" (old), "r" (new), "m" (*p) 516 : "cr0", "memory"); 517 518 td->td_pcb->pcb_onfault = NULL; 519 520 *oldvalp = val; 521 return (0); 522 } 523 #endif 524