1/*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2018, Matthew Macy <mmacy@freebsd.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30/* 31 * Assembly variants of various functions, for those that don't need generic C 32 * implementations. Currently this includes: 33 * 34 * - Direct-access versions of copyin/copyout methods. 35 * - These are used by Radix AIM pmap (ISA 3.0), and Book-E, to avoid 36 * unnecessary pmap_map_usr_ptr() calls. 37 */ 38 39#include "assym.inc" 40#include "opt_sched.h" 41 42#include <sys/syscall.h> 43#include <sys/errno.h> 44 45#include <machine/param.h> 46#include <machine/asm.h> 47#include <machine/spr.h> 48#include <machine/trap.h> 49#include <machine/vmparam.h> 50 51#ifdef _CALL_ELF 52.abiversion _CALL_ELF 53#endif 54 55#ifdef __powerpc64__ 56#define LOAD ld 57#define STORE std 58#define WORD 8 59#define CMPI cmpdi 60#define CMPLI cmpldi 61/* log_2(8 * WORD) */ 62#define LOOP_LOG 6 63#define LOG_WORD 3 64#define CURTHREAD %r13 65#else 66#define LOAD lwz 67#define STORE stw 68#define WORD 4 69#define CMPI cmpwi 70#define CMPLI cmplwi 71/* log_2(8 * WORD) */ 72#define LOOP_LOG 5 73#define LOG_WORD 2 74#define CURTHREAD %r2 75#endif 76 77#ifdef AIM 78#define ENTRY_DIRECT(x) ENTRY(x ## _direct) 79#define END_DIRECT(x) END(x ## _direct) 80#else 81#define ENTRY_DIRECT(x) ENTRY(x) 82#define END_DIRECT(x) END(x) 83#endif 84 85#ifdef __powerpc64__ 86#define PROLOGUE ;\ 87 mflr %r0 ;\ 88 std %r0, 16(%r1) ;\ 89 90#define EPILOGUE ;\ 91 ld %r0, 16(%r1) ;\ 92 mtlr %r0 ;\ 93 blr ;\ 94 nop 95 96#define VALIDATE_TRUNCATE_ADDR_COPY VALIDATE_ADDR_COPY 97#define VALIDATE_ADDR_COPY(raddr, len) \ 98 srdi %r0, raddr, 52 ;\ 99 cmpwi %r0, 1 ;\ 100 bge- copy_fault ;\ 101 nop 102 103#define VALIDATE_ADDR_FUSU(raddr) ;\ 104 srdi %r0, raddr, 52 ;\ 105 cmpwi %r0, 1 ;\ 106 bge- fusufault ;\ 107 nop 108 109#else 110#define PROLOGUE ;\ 111 mflr %r0 ;\ 112 stw %r0, 4(%r1) ;\ 113 114#define EPILOGUE ;\ 115 lwz %r0, 4(%r1) ;\ 116 mtlr %r0 ;\ 117 blr ;\ 118 nop 119 120/* %r0 is temporary */ 121/* 122 * Validate address and length are valid. 123 * For VALIDATE_ADDR_COPY() have to account for wraparound. 124 */ 125#define VALIDATE_ADDR_COPY(raddr, len) \ 126 lis %r0, VM_MAXUSER_ADDRESS@h ;\ 127 ori %r0, %r0, VM_MAXUSER_ADDRESS@l ;\ 128 cmplw %r0, raddr ;\ 129 blt- copy_fault ;\ 130 add %r0, raddr, len ;\ 131 cmplw 7, %r0, raddr ;\ 132 blt- 7, copy_fault ;\ 133 mtcrf 0x80, %r0 ;\ 134 bt- 0, copy_fault ;\ 135 nop 136 137#define VALIDATE_TRUNCATE_ADDR_COPY(raddr, len) \ 138 lis %r0, VM_MAXUSER_ADDRESS@h ;\ 139 ori %r0, %r0, VM_MAXUSER_ADDRESS@l ;\ 140 cmplw %r0, raddr ;\ 141 blt- copy_fault ;\ 142 sub %r0, %r0, raddr ;\ 143 cmplw len, %r0 ;\ 144 isel len, len, %r0, 0 ;\ 145 146#define VALIDATE_ADDR_FUSU(raddr) \ 147 lis %r0, VM_MAXUSER_ADDRESS@h ;\ 148 ori %r0, %r0, VM_MAXUSER_ADDRESS@l ;\ 149 cmplw %r0, raddr ;\ 150 ble- fusufault 151 152#endif 153 154#define SET_COPYFAULT(raddr, rpcb, len) \ 155 VALIDATE_ADDR_COPY(raddr, len) ;\ 156 li %r0, COPYFAULT ;\ 157 LOAD rpcb, TD_PCB(CURTHREAD) ;\ 158 STORE %r0, PCB_ONFAULT(rpcb) ;\ 159 160#define SET_COPYFAULT_TRUNCATE(raddr, rpcb, len)\ 161 VALIDATE_TRUNCATE_ADDR_COPY(raddr, len) ;\ 162 li %r0, COPYFAULT ;\ 163 LOAD rpcb, TD_PCB(CURTHREAD) ;\ 164 STORE %r0, PCB_ONFAULT(rpcb) 165 166#define SET_FUSUFAULT(raddr, rpcb) \ 167 VALIDATE_ADDR_FUSU(raddr) ;\ 168 li %r0, FUSUFAULT ;\ 169 LOAD rpcb, TD_PCB(CURTHREAD) ;\ 170 STORE %r0, PCB_ONFAULT(rpcb) 171 172#define CLEAR_FAULT_NO_CLOBBER(rpcb) \ 173 LOAD rpcb, TD_PCB(CURTHREAD) ;\ 174 li %r0, 0 ;\ 175 STORE %r0, PCB_ONFAULT(rpcb) 176 177#define CLEAR_FAULT(rpcb) \ 178 CLEAR_FAULT_NO_CLOBBER(rpcb) ;\ 179 li %r3, 0 180 181/* 182 * bcopy(src, dst, len) 183 * %r3 %r4 %r5 184 * 185 * %r7 is the pcb pointer 186 * 187 * %r0 and %r8-%r10 are volatile 188 * %r11 and %r12 are generally volatile, used in linking and exception 189 * handling. Can be clobbered here. 190 * 191 * Does not allocate or use stack space, but clobbers all volatile registers. 192 */ 193 194#define rs %r3 195#define rd %r4 196#define rl %r5 197 198#define t1 %r6 199#define t2 %r7 200#define t3 %r8 201#define t4 %r9 202#define t5 %r10 203#define t6 %r11 204#define t7 %r12 205#define t8 %r0 206 207#define Thresh WORD * 8 208#define W4 3 209#define W2 2 210#define W1 1 211#define WORDS(n) (32 - LOG_WORD - W##n) 212.text 213ENTRY(bcopy_generic) 214 CMPLI 0, %r5, 0 215 beq .Lend 216 dcbtst 0, rd 217 dcbt 0, rs 218 CMPLI rl, Thresh 219 blt .Lsmall 220 b .Llarge 221/* memcpy */ 222/* ... */ 223.Lsmall: /* < 8 words remaining */ 224 mtcrf 0x3, rl 225.Lsmall_start: 226 bf WORDS(4), 0f 227 LOAD t1, 0(rs) 228 LOAD t2, WORD*1(rs) 229 LOAD t3, WORD*2(rs) 230 LOAD t4, WORD*3(rs) 231 addi rs, rs, WORD*4 232 STORE t1, 0(rd) 233 STORE t2, WORD*1(rd) 234 STORE t3, WORD*2(rd) 235 STORE t4, WORD*3(rd) 236 addi rd, rd, WORD*4 2370: /* < 4 words remaining */ 238 bf WORDS(2), 1f 239 LOAD t1, 0(rs) 240 LOAD t2, WORD*1(rs) 241 addi rs, rs, WORD*2 242 STORE t1, 0(rd) 243 STORE t2, WORD*1(rd) 244 addi rd, rd, WORD*2 2451: /* < 2 words remaining */ 246 bf WORDS(1), 2f 247 LOAD t1, 0(rs) 248 addi rs, rs, WORD 249 STORE t1, 0(rd) 250 addi rd, rd, WORD 2512: /* < 1 word remaining */ 252#ifdef __powerpc64__ 253 bf 29, 3f 254 lwz t1, 0(rs) 255 addi rs, rs, 4 256 stw t1, 0(rd) 257 addi rd, rd, 4 2583: /* < 4 bytes remaining */ 259#endif 260 bf 30, 4f 261 lhz t1, 0(rs) 262 addi rs, rs, 2 263 sth t1, 0(rd) 264 addi rd, rd, 2 2654: /* < 2 bytes remaining */ 266 bf 31, .Lout 267 lbz t1, 0(rs) 268 addi rs, rs, 1 269 stb t1, 0(rd) 270 addi rd, rd, 1 271 b .Lout 272 273 .align 4 274.Llarge: 275 neg t3, rd 276 andi. t6, t3, WORD-1 /* Align rd to word size */ 277 mtctr t6 278 sub rl, rl, t6 279 beq+ .Llargealigned 2801: 281 lbz t1, 0(rs) 282 addi rs, rs, 1 283 stb t1, 0(rd) 284 addi rd, rd, 1 285 bdnz 1b 286 287.Llargealigned: 288 srwi. t2, rl, LOOP_LOG /* length >> log_2(loop_size) => 8W iterations */ 289 mtcrf 0x3, rl 290 beq .Lsmall_start 291 mtctr t2 292 b 1f 293 294 .align 5 2951: 296 LOAD t1, 0(rs) 297 LOAD t2, WORD(rs) 298 LOAD t3, WORD*2(rs) 299 LOAD t4, WORD*3(rs) 300 LOAD t5, WORD*4(rs) 301 LOAD t6, WORD*5(rs) 302 LOAD t7, WORD*6(rs) 303 LOAD t8, WORD*7(rs) 304 addi rs, rs, WORD*8 305 STORE t1, 0(rd) 306 STORE t2, WORD*1(rd) 307 STORE t3, WORD*2(rd) 308 STORE t4, WORD*3(rd) 309 STORE t5, WORD*4(rd) 310 STORE t6, WORD*5(rd) 311 STORE t7, WORD*6(rd) 312 STORE t8, WORD*7(rd) 313 addi rd, rd, WORD*8 314 bdnz 1b 315 316 b .Lsmall_start 317.Lout: 318/* done */ 319.Lend: 320 blr 321END(bcopy_generic) 322 323/* 324 * copyout(from_kernel, to_user, len) 325 * %r3, %r4, %r5 326 */ 327ENTRY_DIRECT(copyout) 328 PROLOGUE 329 SET_COPYFAULT(%r4, %r7, %r5) 330 bl bcopy_generic 331 nop 332 CLEAR_FAULT(%r7) 333 EPILOGUE 334END_DIRECT(copyout) 335 336/* 337 * copyin(from_user, to_kernel, len) 338 * %r3, %r4, %r5 339 */ 340ENTRY_DIRECT(copyin) 341 PROLOGUE 342 SET_COPYFAULT(%r3, %r7, %r5) 343 bl bcopy_generic 344 nop 345 CLEAR_FAULT(%r7) 346 EPILOGUE 347END_DIRECT(copyin) 348 349/* 350 * copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done) 351 * %r3 %r4 %r5 %r6 352 */ 353 354ENTRY_DIRECT(copyinstr) 355 PROLOGUE 356 SET_COPYFAULT_TRUNCATE(%r3, %r7, %r5) 357 addi %r9, %r5, 1 358 mtctr %r9 359 mr %r8, %r3 360 addi %r8, %r8, -1 361 addi %r4, %r4, -1 362 li %r3, ENAMETOOLONG 3630: 364 bdz- 2f 365 lbzu %r0, 1(%r8) 366 stbu %r0, 1(%r4) 367 368 // NULL byte reached ? 369 CMPI %r0, 0 370 beq- 1f 371 b 0b 3721: 373 li %r3, 0 3742: 375 /* skip storing length if done is NULL */ 376 CMPI %r6, 0 377 beq- 3f 378 mfctr %r0 379 sub %r0, %r9, %r0 380 STORE %r0, 0(%r6) 3813: 382 CLEAR_FAULT_NO_CLOBBER(%r7) 383 EPILOGUE 384END_DIRECT(copyinstr) 385 386ENTRY_DIRECT(subyte) 387 PROLOGUE 388 SET_FUSUFAULT(%r3, %r7) 389 stb %r4, 0(%r3) 390 CLEAR_FAULT(%r7) 391 EPILOGUE 392END_DIRECT(subyte) 393 394#ifndef __powerpc64__ 395ENTRY_DIRECT(suword) 396 PROLOGUE 397 SET_FUSUFAULT(%r3, %r7) 398 stw %r4, 0(%r3) 399 CLEAR_FAULT(%r7) 400 EPILOGUE 401END_DIRECT(suword) 402#endif 403 404ENTRY_DIRECT(suword16) 405 PROLOGUE 406 SET_FUSUFAULT(%r3, %r7) 407 sth %r4, 0(%r3) 408 CLEAR_FAULT(%r7) 409 EPILOGUE 410END_DIRECT(suword16) 411 412ENTRY_DIRECT(suword32) 413 PROLOGUE 414 SET_FUSUFAULT(%r3, %r7) 415 stw %r4, 0(%r3) 416 CLEAR_FAULT(%r7) 417 EPILOGUE 418END_DIRECT(suword32) 419 420#ifdef __powerpc64__ 421ENTRY_DIRECT(suword64) 422 PROLOGUE 423 SET_FUSUFAULT(%r3, %r7) 424 std %r4, 0(%r3) 425 CLEAR_FAULT(%r7) 426 EPILOGUE 427END_DIRECT(suword64) 428 429ENTRY_DIRECT(suword) 430 PROLOGUE 431 SET_FUSUFAULT(%r3, %r7) 432 std %r4, 0(%r3) 433 CLEAR_FAULT(%r7) 434 EPILOGUE 435END_DIRECT(suword) 436#endif 437 438ENTRY_DIRECT(fubyte) 439 PROLOGUE 440 SET_FUSUFAULT(%r3, %r7) 441 lbz %r3, 0(%r3) 442 CLEAR_FAULT_NO_CLOBBER(%r7) 443 EPILOGUE 444END_DIRECT(fubyte) 445 446ENTRY_DIRECT(fuword16) 447 PROLOGUE 448 SET_FUSUFAULT(%r3, %r7) 449 lhz %r3, 0(%r3) 450 CLEAR_FAULT_NO_CLOBBER(%r7) 451 EPILOGUE 452END_DIRECT(fuword16) 453 454#ifndef __powerpc64__ 455ENTRY_DIRECT(fueword) 456 PROLOGUE 457 SET_FUSUFAULT(%r3, %r7) 458 lwz %r0, 0(%r3) 459 stw %r0, 0(%r4) 460 CLEAR_FAULT(%r7) 461 EPILOGUE 462END_DIRECT(fueword) 463#endif 464ENTRY_DIRECT(fueword32) 465 PROLOGUE 466 SET_FUSUFAULT(%r3, %r7) 467 lwz %r0, 0(%r3) 468 stw %r0, 0(%r4) 469 CLEAR_FAULT(%r7) 470 EPILOGUE 471END_DIRECT(fueword32) 472 473#ifdef __powerpc64__ 474ENTRY_DIRECT(fueword) 475 PROLOGUE 476 SET_FUSUFAULT(%r3, %r7) 477 ld %r0, 0(%r3) 478 std %r0, 0(%r4) 479 CLEAR_FAULT(%r7) 480 EPILOGUE 481END_DIRECT(fueword) 482 483ENTRY_DIRECT(fueword64) 484 PROLOGUE 485 SET_FUSUFAULT(%r3, %r7) 486 ld %r0, 0(%r3) 487 std %r0, 0(%r4) 488 CLEAR_FAULT(%r7) 489 EPILOGUE 490END_DIRECT(fueword64) 491#endif 492 493/* 494 * casueword(volatile u_long *base, u_long old, u_long *oldp, u_long new) 495 * %r3 %r4 %r5 %r6 496 */ 497 498#define CASUEWORD32(raddr, rpcb) ;\ 499 PROLOGUE ;\ 500 SET_FUSUFAULT(raddr, rpcb) ;\ 501 li %r8, 0 ;\ 5021: ;\ 503 lwarx %r0, 0, %r3 ;\ 504 cmplw %r4, %r0 ;\ 505 bne 2f ;\ 506 stwcx. %r6, 0, %r3 ;\ 507 bne- 3f ;\ 508 b 4f ;\ 5092: ;\ 510 stwcx. %r0, 0, %r3 /* clear reservation (74xx) */ ;\ 5113: ;\ 512 li %r8, 1 ;\ 5134: ;\ 514 stw %r0, 0(%r5) ;\ 515 CLEAR_FAULT_NO_CLOBBER(rpcb) ;\ 516 mr %r3, %r8 ;\ 517 EPILOGUE 518 519ENTRY_DIRECT(casueword32) 520 CASUEWORD32(%r3, %r7) 521END_DIRECT(casueword32) 522 523#ifdef __powerpc64__ 524#define CASUEWORD64(raddr, rpcb) ;\ 525 PROLOGUE ;\ 526 SET_FUSUFAULT(raddr, rpcb) ;\ 527 li %r8, 0 ;\ 5281: ;\ 529 ldarx %r0, 0, %r3 ;\ 530 cmpld %r4, %r0 ;\ 531 bne 2f ;\ 532 stdcx. %r6, 0, %r3 ;\ 533 bne- 3f ;\ 534 b 4f ;\ 5352: ;\ 536 stdcx. %r0, 0, %r3 /* clear reservation (74xx) */ ;\ 5373: ;\ 538 li %r8, 1 ;\ 5394: ;\ 540 std %r0, 0(%r5) ;\ 541 CLEAR_FAULT_NO_CLOBBER(rpcb) ;\ 542 mr %r3, %r8 ;\ 543 EPILOGUE 544 545ENTRY_DIRECT(casueword) 546 CASUEWORD64(%r3, %r7) 547END_DIRECT(casueword) 548 549ENTRY_DIRECT(casueword64) 550 CASUEWORD64(%r3, %r7) 551END_DIRECT(casueword64) 552#else 553ENTRY_DIRECT(casueword) 554 CASUEWORD32(%r3, %r7) 555END_DIRECT(casueword) 556#endif 557 558_NAKED_ENTRY(fusufault) 559 CLEAR_FAULT_NO_CLOBBER(%r7) 560 li %r3, -1 561 EPILOGUE 562_END(fusufault) 563 564_NAKED_ENTRY(copy_fault) 565 CLEAR_FAULT_NO_CLOBBER(%r7) 566 li %r3, EFAULT 567 EPILOGUE 568_END(copy_fault) 569