1/* $NetBSD: trap_subr.S,v 1.30 2022/09/12 08:02:44 rin Exp $ */ 2 3/* 4 * Copyright 2001 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38/* 39 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 40 * Copyright (C) 1995, 1996 TooLs GmbH. 41 * All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by TooLs GmbH. 54 * 4. The name of TooLs GmbH may not be used to endorse or promote products 55 * derived from this software without specific prior written permission. 56 * 57 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 58 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 59 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 60 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 61 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 62 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 63 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 64 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 65 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 66 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 67 */ 68 69/* 70 * NOTICE: This is not a standalone file. to use it, #include it in 71 * your port's locore.S, like so: 72 * 73 * #include <powerpc/ibm4xx/trap_subr.S> 74 */ 75 76#ifdef _KERNEL_OPT 77#include "opt_ddb.h" 78#include "opt_kgdb.h" 79#endif 80 81/* 82 * XXX Interrupt and spill stacks need to be per-CPU. 83 */ 84 85#define GET_PCB(rX) \ 86 GET_CPUINFO(rX); \ 87 lwz rX,CI_CURPCB(rX) 88 89#define STANDARD_PROLOG(savearea) \ 90 mtsprg1 %r1; /* save SP */ \ 91 GET_CPUINFO(%r1); \ 92 stmw %r28,(savearea+CPUSAVE_R28)(%r1); /* free r28-r31 */ \ 93 mflr %r28; /* save LR */ \ 94 mfcr %r29; /* save CR */ \ 95 mfsrr0 %r30; \ 96 mfsrr1 %r31; /* Test whether we already had PR set */ \ 97 stmw %r30,(savearea+CPUSAVE_SRR0)(%r1); /* save srr0/srr1 */ \ 98 mfsprg1 %r1; /* restore SP */ \ 99 mtcr %r31; \ 100 bf MSR_PR,1f; /* branch if MSR[PR] is clear */ \ 101 GET_PCB(%r1); \ 102 addi %r1,%r1,USPACE-CALLFRAMELEN; /* stack is top of user struct */ \ 1031: 104 105#define ACCESS_PROLOG(savearea) \ 106 mtsprg1 %r1; /* save SP temporalily */ \ 107 GET_CPUINFO(%r1); \ 108 stmw %r28,(savearea+CPUSAVE_R28)(%r1); /* free r28-r31 */ \ 109 mflr %r28; /* save LR */ \ 110 mfcr %r29; /* save CR */ \ 111 mfdear %r30; \ 112 mfesr %r31; \ 113 stmw %r30,(savearea+CPUSAVE_DEAR)(%r1); /* save esr/dear */ \ 114 mfsrr0 %r30; \ 115 mfsrr1 %r31; /* Test whether we already had PR set */ \ 116 stmw %r30,(savearea+CPUSAVE_SRR0)(%r1); /* save srr0/srr1 */ \ 117 mfsprg1 %r1; /* restore SP */ \ 118 mtcr %r31; \ 119 bf MSR_PR,1f; /* branch if MSR[PR] is clear */ \ 120 GET_PCB(%r1); \ 121 addi %r1,%r1,USPACE-CALLFRAMELEN; /* stack is top of user struct */ \ 1221: 123 124#define CRITICAL_PROLOG(savearea) \ 125 mtsprg1 %r1; /* save SP */ \ 126 GET_CPUINFO(%r1); \ 127 stmw %r28,(savearea+CPUSAVE_R28)(%r1); /* free r28-r31 */ \ 128 mflr %r28; /* save LR */ \ 129 mfcr %r29; /* save CR */ \ 130 mfsrr2 %r30; /* Fake a standard trap */ \ 131 mfsrr3 %r31; /* Test whether we already had PR set */ \ 132 stmw %r30,(savearea+CPUSAVE_SRR0)(%r1); /* save srr0/srr1 */ \ 133 mfsprg1 %r1; /* restore SP */ \ 134 mtcr %r31; \ 135 bf MSR_PR,1f; /* branch if MSR[PR] is clear */ \ 136 GET_PCB(%r1); \ 137 addi %r1,%r1,USPACE-CALLFRAMELEN; /* stack is top of user struct */ \ 1381: 139 140 141/* Standard handler saves r1,r28-31,LR,CR, sets up the stack and calls s_trap */ 142#define STANDARD_EXC_HANDLER(name)\ 143 .globl _C_LABEL(name ## trap),_C_LABEL(name ## size) ; \ 144_C_LABEL(name ## trap): \ 145 STANDARD_PROLOG(CI_TEMPSAVE); \ 146 bla s_trap; \ 147_C_LABEL(name ## size) = .-_C_LABEL(name ## trap) 148 149/* Access exceptions also need DEAR and ESR saved */ 150#define ACCESS_EXC_HANDLER(name)\ 151 .globl _C_LABEL(name ## trap),_C_LABEL(name ## size) ; \ 152_C_LABEL(name ## trap): \ 153 ACCESS_PROLOG(CI_TEMPSAVE); \ 154 bla s_trap; \ 155_C_LABEL(name ## size) = .-_C_LABEL(name ## trap) 156 157/* Maybe this should call ddb.... */ 158#define CRITICAL_EXC_HANDLER(name)\ 159 .globl _C_LABEL(name ## trap),_C_LABEL(name ## size) ; \ 160_C_LABEL(name ## trap): \ 161 CRITICAL_PROLOG(CI_TEMPSAVE); \ 162 bla s_trap; \ 163_C_LABEL(name ## size) = .-_C_LABEL(name ## trap) 164 165#define INTR_PROLOG(tempsave) \ 166 mtsprg1 %r1; /* save SP */ \ 167 GET_CPUINFO(%r1); \ 168 stmw %r28,(tempsave+CPUSAVE_R28)(%r1); /* free r28-r31 */ \ 169 mflr %r28; /* save LR */ \ 170 mfcr %r29; /* save CR */ \ 171 mfxer %r30; /* save XER */ \ 172 mfsrr1 %r31; \ 173 mtcr %r31; \ 174 mfsprg1 %r1; /* restore SP */ \ 175 bf MSR_PR,1f; /* branch if PSL_PR is false */ \ 176 GET_PCB(%r1); \ 177 addi %r1,%r1,USPACE-CALLFRAMELEN; /* stack is top of user struct */ \ 1781: 179 180 .text 181 STANDARD_EXC_HANDLER(default) 182 ACCESS_EXC_HANDLER(access) 183 CRITICAL_EXC_HANDLER(critical) 184 185/* 186 * This one for the external interrupt handler. 187 */ 188 .globl _C_LABEL(extint),_C_LABEL(extsize) 189_C_LABEL(extint): 190 INTR_PROLOG(CI_TEMPSAVE) 191 ba extintr 192_C_LABEL(extsize) = .-_C_LABEL(extint) 193 194 195#if defined(DDB) || defined(KGDB) 196/* 197 * In case of DDB we want a separate trap catcher for it 198 */ 199 .globl _C_LABEL(ddblow),_C_LABEL(ddbsize) 200_C_LABEL(ddblow): 201 ACCESS_PROLOG(CI_DDBSAVE) 202 bla ddbtrap 203_C_LABEL(ddbsize) = .-_C_LABEL(ddblow) 204#endif /* DDB || KGDB */ 205 206#ifdef DEBUG 207#define TRAP_IF_ZERO(r) tweqi r,0 208#else 209#define TRAP_IF_ZERO(r) 210#endif 211 212#define ENABLE_TRANSLATION(pidreg,tmpreg) \ 213 mfspr pidreg,SPR_PID; \ 214 li tmpreg,KERNEL_PID; \ 215 mtspr SPR_PID,tmpreg; \ 216 mfmsr tmpreg; \ 217 ori tmpreg,tmpreg,(PSL_DR|PSL_IR)@l; \ 218 mtmsr tmpreg; \ 219 isync 220 221/* 222 * FRAME_SETUP assumes: 223 * SPRG1 SP (r1) 224 * savearea r28-r31,DEAR,ESR,SRR0,SRR1 225 * (DEAR & ESR only for access traps) 226 * %r28 LR 227 * %r29 CR 228 * %r1 kernel stack 229 * LR trap type 230 */ 231#define FRAME_SETUP(savearea) \ 232/* Have to enable translation to allow access of kernel stack: */ \ 233 ENABLE_TRANSLATION(%r30,%r31); \ 234 mfsprg1 %r31; \ 235 stwu %r31,-FRAMELEN(%r1); \ 236 stw %r30,FRAME_PID(%r1); \ 237 stw %r0,FRAME_R0(%r1); \ 238 stw %r31,FRAME_R1(%r1); \ 239 stw %r2,FRAME_R2(%r1); \ 240 GET_CPUINFO(%r2); \ 241 stw %r28,FRAME_LR(%r1); \ 242 stw %r29,FRAME_CR(%r1); \ 243 lmw %r28,(savearea+CPUSAVE_R28)(%r2); \ 244 stmw %r3,FRAME_R3(%r1); \ 245 lmw %r28,(savearea+CPUSAVE_DEAR)(%r2); \ 246 lwz %r13,CI_CURLWP(%r2); \ 247 mfxer %r3; \ 248 mfctr %r4; \ 249 mflr %r5; \ 250 andi. %r5,%r5,0xff00; \ 251 stw %r3,FRAME_XER(%r1); \ 252 stw %r4,FRAME_CTR(%r1); \ 253 stw %r5,FRAME_EXC(%r1); \ 254 stw %r28,FRAME_DEAR(%r1); \ 255 stw %r29,FRAME_ESR(%r1); \ 256 stw %r30,FRAME_SRR0(%r1); \ 257 stw %r31,FRAME_SRR1(%r1) 258 259#define FRAME_SAVE_CALLEE \ 260 stmw %r14,FRAME_R14(%r1) 261 262#define FRAME_RESTORE \ 263 lwz %r6,FRAME_LR(%r1); \ 264 lwz %r7,FRAME_CR(%r1); \ 265 lwz %r8,FRAME_XER(%r1); \ 266 lwz %r9,FRAME_CTR(%r1); \ 267 lwz %r10,FRAME_SRR0(%r1); \ 268 lwz %r11,FRAME_SRR1(%r1); \ 269 mtlr %r6; \ 270 mtcr %r7; \ 271 mtxer %r8; \ 272 mtctr %r9; \ 273 mtsrr0 %r10; \ 274 mtsrr1 %r11; \ 275 lwz %r13,FRAME_R13(%r1); \ 276 lwz %r12,FRAME_R12(%r1); \ 277 lwz %r11,FRAME_R11(%r1); \ 278 lwz %r10,FRAME_R10(%r1); \ 279 lwz %r9,FRAME_R9(%r1); \ 280 lwz %r8,FRAME_R8(%r1); \ 281 lwz %r7,FRAME_R7(%r1); \ 282 lwz %r6,FRAME_R6(%r1); \ 283 lwz %r5,FRAME_R5(%r1); \ 284 lwz %r4,FRAME_R4(%r1); \ 285 lwz %r3,FRAME_R3(%r1); \ 286 lwz %r2,FRAME_R2(%r1); \ 287 lwz %r0,FRAME_R1(%r1); \ 288 mtsprg1 %r0; \ 289 lwz %r0,FRAME_R0(%r1) 290 291/* 292 * Now the common trap catching code. 293 */ 294s_trap: 295 FRAME_SETUP(CI_TEMPSAVE) 296 /* R31 = SRR1 */ 297/* Now we can recover interrupts again: */ 298trapagain: 299 wrtee %r31 /* reenable interrupts */ 300/* Call C trap code: */ 301 addi %r3,%r1,FRAME_TF 302 bl _C_LABEL(trap) 303 .globl _C_LABEL(trapexit) 304_C_LABEL(trapexit): 305 /* Disable interrupts: */ 306 wrteei 0 307 308 /* Test AST pending: */ 309 mtcr %r31 310 bf MSR_PR,trapleave_to_kernel /* branch if MSR[PR] is false */ 311 312 lwz %r4,L_MD_ASTPENDING(%r13) 313 andi. %r4,%r4,1 314 beq trapleave_to_user 315 316 li %r6,EXC_AST 317 stw %r6,FRAME_EXC(%r1) 318 b trapagain 319 320trapleave_to_kernel: 321 lmw %r14, FRAME_R14(%r1) /* restore callee registers */ 322 323intrleave_to_kernel: 324 FRAME_RESTORE /* old SP is now in sprg1 */ 325 326 mtsprg2 %r30 327 mtsprg3 %r31 328 mfmsr %r30 329 li %r31,(PSL_DR|PSL_IR)@l 330 andc %r30,%r30,%r31 331 lwz %r31,FRAME_PID(%r1) 332 TRAP_IF_ZERO(%r31) 333 /* 334 * Now that we are done with the trapframe, we can load the original SP 335 */ 336 mfsprg1 %r1 337 mtmsr %r30 /* disable translation */ 338 isync 339 mtspr SPR_PID,%r31 340 mfsprg3 %r31 341 mfsprg2 %r30 342 IBM405_ERRATA77_SYNC 343 rfi 344 ba . /* Protect against prefetch */ 345 346trapleave_to_user: 347 lmw %r14, FRAME_R14(%r1) /* restore callee registers */ 348 349intrleave_to_user: 350/* Now restore regs: */ 351 lwz %r3,FRAME_PID(%r1) 352 lwz %r4,FRAME_SRR1(%r1) 353 bl _C_LABEL(ctx_setup) 354 TRAP_IF_ZERO(%r3) 355 stw %r3,FRAME_PID(%r1) 356 357 FRAME_RESTORE /* old SP is now in sprg1 */ 358 359 /* 360 * We are returning to userspace so we need to switch PIDs. 361 * Since the kernel executes out of what would be userspace, 362 * we need to turn off translation before we set the PID. 363 * 364 * Alterantively, we could map a kernel page at 0xfffff000 365 * that had the mtpid code in it and branch to it and avoid 366 * all this. (ba foo; foo: mtpid %r31; mfsprg3 %r31; rfi;) 367 */ 368 mtsprg2 %r30 369 mtsprg3 %r31 370 mfmsr %r30 371 li %r31,(PSL_DR|PSL_IR)@l 372 andc %r30,%r30,%r31 373 lwz %r31,FRAME_PID(%r1) 374 TRAP_IF_ZERO(%r31) 375 /* 376 * Now that we are done with the trapframe, we can load the original SP 377 */ 378 mfsprg1 %r1 379 mtmsr %r30 /* disable translation */ 380 isync 381 mtspr SPR_PID,%r31 382 mfsprg3 %r31 383 mfsprg2 %r30 384 IBM405_ERRATA77_SYNC 385 rfi 386 ba . /* Protect against prefetch */ 387 388 389 .globl _C_LABEL(sctrap),_C_LABEL(scsize),_C_LABEL(sctrapexit) 390_C_LABEL(sctrap): 391 STANDARD_PROLOG(CI_TEMPSAVE) 392 bla s_sctrap 393_C_LABEL(scsize) = .-_C_LABEL(sctrap) 394 395s_sctrap: 396 FRAME_SETUP(CI_TEMPSAVE) 397/* Now we can recover interrupts again: */ 398 wrteei 1 /* Enable interrupts */ 399/* Call the appropriate syscall handler: */ 400 addi %r3,%r1,FRAME_TF 401 lwz %r4,L_PROC(%r13) 402 lwz %r4,P_MD_SYSCALL(%r4) 403 mtctr %r4 404 bctrl 405_C_LABEL(sctrapexit): 406 b trapexit 407 408/* 409 * External interrupt second level handler 410 */ 411 412#define INTR_SAVE(tempsave) \ 413/* Save non-volatile registers: */ \ 414 stwu %r1,-FRAMELEN(%r1); /* temporarily */ \ 415 stw %r0,FRAME_R0(%r1); \ 416 mfsprg1 %r0; /* get original SP */ \ 417 stw %r0,FRAME_R1(%r1); /* and store it */ \ 418 stw %r2,FRAME_R2(%r1); \ 419 stw %r3,FRAME_R3(%r1); \ 420 stw %r4,FRAME_R4(%r1); \ 421 stw %r5,FRAME_R5(%r1); \ 422 stw %r6,FRAME_R6(%r1); \ 423 stw %r7,FRAME_R7(%r1); \ 424 stw %r8,FRAME_R8(%r1); \ 425 stw %r9,FRAME_R9(%r1); \ 426 stw %r10,FRAME_R10(%r1); \ 427 stw %r11,FRAME_R11(%r1); \ 428 stw %r12,FRAME_R12(%r1); \ 429 stw %r13,FRAME_R13(%r1); \ 430 mfctr %r31; \ 431 stmw %r28,FRAME_LR(%r1); /* save LR, CR, XER, CTR */ \ 432 GET_CPUINFO(%r5); \ 433 lmw %r28,(tempsave+CPUSAVE_R28)(%r5); /* restore r28-r31 */ \ 434 lwz %r13,CI_CURLWP(%r5); \ 435 lwz %r5,CI_IDEPTH(%r5); \ 436 mfsrr0 %r4; \ 437 mfsrr1 %r3; \ 438 stw %r5,FRAME_IDEPTH(%r1); \ 439 stw %r4,FRAME_SRR0(%r1); \ 440 stw %r3,FRAME_SRR1(%r1); \ 441/* interrupts are recoverable here, and enable translation */ \ 442 ENABLE_TRANSLATION(%r0,%r5); \ 443 stw %r0,FRAME_PID(%r1); 444 445 .globl _C_LABEL(extint_call) 446extintr: 447 INTR_SAVE(CI_TEMPSAVE) 448_C_LABEL(extint_call): 449 bl _C_LABEL(extint_call) /* to be filled in later */ 450 451intr_exit: 452/* Disable interrupts */ 453 wrteei 0 454 isync 455 456 lwz %r4,FRAME_SRR1(%r1) 457/* Returning to user mode? */ 458 mtcr %r4 /* saved SRR1 */ 459 bf MSR_PR,intrleave_to_kernel /* branch if MSR[PR] is false */ 460 461 lwz %r4,L_MD_ASTPENDING(%r13)/* Test AST pending */ 462 andi. %r4,%r4,1 463 beq intrleave_to_user 464 465 FRAME_SAVE_CALLEE /* save rest of callee registers */ 466 li %r6,EXC_AST 467 stw %r6,FRAME_EXC(%r1) 468 lwz %r31,FRAME_SRR1(%r1) /* move SRR1 to R31 */ 469 b trapagain 470 471/* 472 * PIT interrupt handler. 473 */ 474 .align 5 475_C_LABEL(pitint): 476 INTR_PROLOG(CI_TEMPSAVE) 477 INTR_SAVE(CI_TEMPSAVE) 478 addi %r3,%r1,FRAME_CF /* clock frame */ 479 bl _C_LABEL(decr_intr) 480 b intr_exit 481 482/* 483 * FIT interrupt handler. 484 */ 485 .align 5 486_C_LABEL(fitint): 487 INTR_PROLOG(CI_TEMPSAVE) 488 INTR_SAVE(CI_TEMPSAVE) 489 addi %r3,%r1,FRAME_CF /* clock frame */ 490 bl _C_LABEL(stat_intr) 491 b intr_exit 492 493#if defined(DDB) || defined(KGDB) 494/* 495 * Deliberate entry to ddbtrap 496 */ 497 .globl _C_LABEL(ddb_trap) 498_C_LABEL(ddb_trap): 499 mtsprg1 %r1 500 GET_CPUINFO(%r4) 501 mfmsr %r3 502 stw %r3,(CI_DDBSAVE+CPUSAVE_SRR1)(%r4) 503 wrteei 0 /* disable interrupts */ 504 isync 505 stmw %r28,CI_DDBSAVE(%r4) 506 mflr %r28 507 stw %r28,(CI_DDBSAVE+CPUSAVE_SRR0)(%r4) 508 li %r29,EXC_BPT 509 mtlr %r29 510 mfcr %r29 511 512/* 513 * Now the ddb/kgdb trap catching code. 514 */ 515ddbtrap: 516 FRAME_SETUP(CI_DDBSAVE) 517/* Call C trap code: */ 518 addi %r3,%r1,FRAME_TF 519 bl _C_LABEL(ddb_trap_glue) 520 or. %r3,%r3,%r3 521 beq trapagain 522 b trapexit 523#endif /* DDB || KGDB */ 524