1/* $NetBSD: trap_subr.S,v 1.21 2002/05/02 16:47:49 kleink Exp $ */ 2 3/* 4 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 5 * Copyright (C) 1995, 1996 TooLs GmbH. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by TooLs GmbH. 19 * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34/* 35 * NOTICE: This is not a standalone file. to use it, #include it in 36 * your port's locore.S, like so: 37 * 38 * #include <powerpc/powerpc/trap_subr.S> 39 */ 40 41/* 42 * Data used during primary/secondary traps/interrupts 43 */ 44#define tempsave EXC_MCHK+0xe0 /* primary save area for trap handling */ 45#define disisave EXC_DSI+0xe0 /* primary save area for dsi/isi traps */ 46 47/* 48 * XXX Interrupt and spill stacks need to be per-CPU. 49 */ 50 .data 51 .align 4 52intstk: 53 .space INTSTK /* interrupt stack */ 54 55GLOBAL(intr_depth) 56 .long -1 /* in-use marker */ 57 58 .comm spillstk,SPILLSTK,8 59 60/* 61 * This code gets copied to all the trap vectors 62 * (except ISI/DSI, ALI, the interrupts, and possibly the debugging 63 * traps when using IPKDB). 64 */ 65 .text 66 .globl _C_LABEL(trapcode),_C_LABEL(trapsize) 67_C_LABEL(trapcode): 68 mtsprg 1,1 /* save SP */ 69 stmw 28,tempsave(0) /* free r28-r31 */ 70 mflr 28 /* save LR */ 71 mfcr 29 /* save CR */ 72/* Test whether we already had PR set */ 73 mfsrr1 31 74 mtcr 31 75 bc 4,17,1f /* branch if PSL_PR is clear */ 76 lis 1,_C_LABEL(curpcb)@ha 77 lwz 1,_C_LABEL(curpcb)@l(1) 78 addi 1,1,USPACE /* stack is top of user struct */ 791: 80 bla s_trap 81_C_LABEL(trapsize) = .-_C_LABEL(trapcode) 82 83/* 84 * For ALI: has to save DSISR and DAR 85 */ 86 .globl _C_LABEL(alitrap),_C_LABEL(alisize) 87_C_LABEL(alitrap): 88 mtsprg 1,1 /* save SP */ 89 stmw 28,tempsave(0) /* free r28-r31 */ 90 mfdar 30 91 mfdsisr 31 92 stmw 30,tempsave+16(0) 93 mflr 28 /* save LR */ 94 mfcr 29 /* save CR */ 95/* Test whether we already had PR set */ 96 mfsrr1 31 97 mtcr 31 98 bc 4,17,1f /* branch if PSL_PR is clear */ 99 lis 1,_C_LABEL(curpcb)@ha 100 lwz 1,_C_LABEL(curpcb)@l(1) 101 addi 1,1,USPACE /* stack is top of user struct */ 1021: 103 bla s_trap 104_C_LABEL(alisize) = .-_C_LABEL(alitrap) 105 106/* 107 * Similar to the above for DSI 108 * Has to handle BAT spills 109 * and standard pagetable spills 110 */ 111 .globl _C_LABEL(dsitrap),_C_LABEL(dsisize) 112_C_LABEL(dsitrap): 113 stmw 28,disisave(0) /* free r28-r31 */ 114 mfcr 29 /* save CR */ 115 mfxer 30 /* save XER */ 116 mtsprg 2,30 /* in SPRG2 */ 117 mfsrr1 31 /* test kernel mode */ 118 mtcr 31 119 bc 12,17,1f /* branch if PSL_PR is set */ 120 mfdar 31 /* get fault address */ 121 rlwinm 31,31,7,25,28 /* get segment * 8 */ 122 123 /* get batu */ 124 addis 31,31,_C_LABEL(battable)@ha 125 lwz 30,_C_LABEL(battable)@l(31) 126 mtcr 30 127 bc 4,30,1f /* branch if supervisor valid is 128 false */ 129 /* get batl */ 130 lwz 31,_C_LABEL(battable)+4@l(31) 131/* We randomly use the highest two bat registers here */ 132 mftb 28 133 andi. 28,28,1 134 bne 2f 135 mtdbatu 2,30 136 mtdbatl 2,31 137 b 3f 1382: 139 mtdbatu 3,30 140 mtdbatl 3,31 1413: 142 mfsprg 30,2 /* restore XER */ 143 mtxer 30 144 mtcr 29 /* restore CR */ 145 lmw 28,disisave(0) /* restore r28-r31 */ 146 rfi /* return to trapped code */ 1471: 148 mflr 28 /* save LR */ 149 bla s_dsitrap 150_C_LABEL(dsisize) = .-_C_LABEL(dsitrap) 151 152/* 153 * Dedicated MPC601 version of the above. 154 * Considers different BAT format and combined implementation 155 * (being addressed as I-BAT). 156 */ 157 .globl _C_LABEL(dsitrap601),_C_LABEL(dsi601size) 158_C_LABEL(dsitrap601): 159 stmw 28,disisave(0) /* free r28-r31 */ 160 mfcr 29 /* save CR */ 161 mfxer 30 /* save XER */ 162 mtsprg 2,30 /* in SPRG2 */ 163 mfsrr1 31 /* test kernel mode */ 164 mtcr 31 165 bc 12,17,1f /* branch if PSL_PR is set */ 166 mfdar 31 /* get fault address */ 167 rlwinm 31,31,12,20,28 /* get "segment" battable offset */ 168 169 /* get batl */ 170 addis 31,31,_C_LABEL(battable)@ha 171 lwz 30,_C_LABEL(battable)+4@l(31) 172 mtcr 30 173 bc 4,25,1f /* branch if Valid is is false, 174 presently assumes supervisor only */ 175 176 /* get batu */ 177 lwz 31,_C_LABEL(battable)@l(31) 178/* We randomly use the highest two bat registers here */ 179 mfspr 28,SPR_RTCL_R 180 andi. 28,28,128 181 bne 2f 182 mtibatu 2,31 183 mtibatl 2,30 184 b 3f 1852: 186 mtibatu 3,31 187 mtibatl 3,30 1883: 189 mfsprg 30,2 /* restore XER */ 190 mtxer 30 191 mtcr 29 /* restore CR */ 192 lmw 28,disisave(0) /* restore r28-r31 */ 193 rfi /* return to trapped code */ 1941: 195 mflr 28 /* save LR */ 196 bla s_dsitrap 197_C_LABEL(dsi601size) = .-_C_LABEL(dsitrap601) 198 199/* 200 * Similar to the above for ISI 201 */ 202 .globl _C_LABEL(isitrap),_C_LABEL(isisize) 203_C_LABEL(isitrap): 204 stmw 28,disisave(0) /* free r28-r31 */ 205 mflr 28 /* save LR */ 206 mfcr 29 /* save CR */ 207 mfsrr1 31 /* test kernel mode */ 208 mtcr 31 209 bc 12,17,1f /* branch if PSL_PR is set */ 210 mfsrr0 31 /* get fault address */ 211 rlwinm 31,31,7,25,28 /* get segment * 8 */ 212 213 /* get batu */ 214 addis 31,31,_C_LABEL(battable)@ha 215 lwz 30,_C_LABEL(battable)@l(31) 216 mtcr 30 217 bc 4,30,1f /* branch if supervisor valid is 218 false */ 219 mtibatu 3,30 220 221 /* get batl */ 222 lwz 30,_C_LABEL(battable)+4@l(31) 223 mtibatl 3,30 224 225 mtcr 29 /* restore CR */ 226 lmw 28,disisave(0) /* restore r28-r31 */ 227 rfi /* return to trapped code */ 2281: 229 bla s_isitrap 230_C_LABEL(isisize)= .-_C_LABEL(isitrap) 231 232/* 233 * Dedicated MPC601 version of the above. 234 * Considers different BAT format. 235 */ 236 .globl _C_LABEL(isitrap601),_C_LABEL(isi601size) 237_C_LABEL(isitrap601): 238 stmw 28,disisave(0) /* free r28-r31 */ 239 mflr 28 /* save LR */ 240 mfcr 29 /* save CR */ 241 mfsrr1 31 /* test kernel mode */ 242 mtcr 31 243 bc 12,17,1f /* branch if PSL_PR is set */ 244 mfsrr0 31 /* get fault address */ 245 rlwinm 31,31,12,20,28 /* get "segment" battable offset */ 246 247 /* get batl */ 248 addis 31,31,_C_LABEL(battable)@ha 249 lwz 30,_C_LABEL(battable)+4@l(31) 250 mtcr 30 251 bc 4,25,1f /* branch if Valid is is false, 252 presently assumes supervisor only */ 253 /* get batu */ 254 lwz 31,_C_LABEL(battable)@l(31) 255 256 mtibatu 3,31 257 mtibatl 3,30 258 259 mtcr 29 /* restore CR */ 260 lmw 28,disisave(0) /* restore r28-r31 */ 261 rfi /* return to trapped code */ 2621: 263 bla s_isitrap 264_C_LABEL(isi601size)= .-_C_LABEL(isitrap601) 265 266/* 267 * This one for the external interrupt handler. 268 */ 269 .globl _C_LABEL(extint),_C_LABEL(extsize) 270_C_LABEL(extint): 271 mtsprg 1,1 /* save SP */ 272 stmw 28,tempsave(0) /* free r28-r31 */ 273 mflr 28 /* save LR */ 274 mfcr 29 /* save CR */ 275 mfxer 30 /* save XER */ 276 lis 1,intstk+INTSTK@ha /* get interrupt stack */ 277 addi 1,1,intstk+INTSTK@l /* this is really intr_depth! */ 278 lwz 31,0(1) /* were we already running on intstk? */ 279 addic. 31,31,1 280 stw 31,0(1) 281 beq 1f 282 mfsprg 1,1 /* yes, get old SP */ 2831: 284 ba extintr 285_C_LABEL(extsize) = .-_C_LABEL(extint) 286 287/* 288 * And this one for the decrementer interrupt handler. 289 */ 290 .globl _C_LABEL(decrint),_C_LABEL(decrsize) 291_C_LABEL(decrint): 292 mtsprg 1,1 /* save SP */ 293 stmw 28,tempsave(0) /* free r28-r31 */ 294 mflr 28 /* save LR */ 295 mfcr 29 /* save CR */ 296 mfxer 30 /* save XER */ 297 lis 1,intstk+INTSTK@ha /* get interrupt stack */ 298 addi 1,1,intstk+INTSTK@l 299 lwz 31,0(1) /* were we already running on intstk? */ 300 addic. 31,31,1 301 stw 31,0(1) 302 beq 1f 303 mfsprg 1,1 /* yes, get old SP */ 3041: 305 ba decrintr 306_C_LABEL(decrsize) = .-_C_LABEL(decrint) 307 308/* 309 * Now the tlb software load for 603 processors: 310 * (Code essentially from the 603e User Manual, Chapter 5, but 311 * corrected a lot.) 312 */ 313 314 .globl _C_LABEL(tlbimiss),_C_LABEL(tlbimsize) 315_C_LABEL(tlbimiss): 316#ifdef PMAPDEBUG 317 mfspr 2,SPR_IMISS /* exception address */ 318 li 1,24 /* get rid of the lower */ 319 srw 2,2,1 /* 24 bits */ 320 li 1,1 /* Load 1 */ 321 cmpl 2,1,1 /* is it > 16MB */ 322 blt 99f /* nope, skip saving these SPRs */ 323 li 1,0xc0 /* arbitrary */ 324 mfspr 2,SPR_HASH1 325 stw 2,0(1) 326 mfspr 2,SPR_HASH2 327 stw 2,4(1) 328 mfspr 2,SPR_IMISS 329 stw 2,8(1) 330 mfspr 2,SPR_ICMP 331 stw 2,12(1) 33299: 333#endif /* PMAPDEBUG */ 334 mfspr 2,SPR_HASH1 /* get first pointer */ 335 li 1,8 336 mfctr 0 /* save counter */ 337 mfspr 3,SPR_ICMP /* get first compare value */ 338 addi 2,2,-8 /* predec pointer */ 3391: 340 mtctr 1 /* load counter */ 3412: 342 lwzu 1,8(2) /* get next pte */ 343 cmpl 0,1,3 /* see if found pte */ 344 bdneq 2b /* loop if not eq */ 345 bne 3f /* not found */ 346 lwz 1,4(2) /* load tlb entry lower word */ 347 andi. 3,1,8 /* check G-bit */ 348 bne 4f /* if guarded, take ISI */ 349 mtctr 0 /* restore counter */ 350 mfspr 0,SPR_IMISS /* get the miss address for the tlbli */ 351 mfsrr1 3 /* get the saved cr0 bits */ 352 mtcrf 0x80,3 /* and restore */ 353 ori 1,1,0x100 /* set the reference bit */ 354 mtspr SPR_RPA,1 /* set the pte */ 355 srwi 1,1,8 /* get byte 7 of pte */ 356 tlbli 0 /* load the itlb */ 357 stb 1,6(2) /* update page table */ 358 rfi 359 3603: /* not found in pteg */ 361 andi. 1,3,0x40 /* have we already done second hash? */ 362 bne 5f 363 mfspr 2,SPR_HASH2 /* get the second pointer */ 364 ori 3,3,0x40 /* change the compare value */ 365 li 1,8 366 addi 2,2,-8 /* predec pointer */ 367 b 1b 3684: /* guarded */ 369 mfsrr1 3 370 andi. 2,3,0xffff /* clean upper srr1 */ 371 oris 2,2,0x8000000@h /* set srr<4> to flag prot violation */ 372 b 6f 3735: /* not found anywhere */ 374 mfsrr1 3 375 andi. 2,3,0xffff /* clean upper srr1 */ 376 oris 2,2,0x40000000@h /* set srr1<1> to flag pte not found */ 3776: 378 mtctr 0 /* restore counter */ 379 mtsrr1 2 380 mfmsr 0 381 xoris 0,0,0x20000@h /* flip the msr<tgpr> bit */ 382 mtcrf 0x80,3 /* restore cr0 */ 383 mtmsr 0 /* now with native gprs */ 384 isync 385 ba EXC_ISI 386_C_LABEL(tlbimsize) = .-_C_LABEL(tlbimiss) 387 388 .globl _C_LABEL(tlbdlmiss),_C_LABEL(tlbdlmsize) 389_C_LABEL(tlbdlmiss): 390 mfspr 2,SPR_HASH1 /* get first pointer */ 391 li 1,8 392 mfctr 0 /* save counter */ 393 mfspr 3,SPR_DCMP /* get first compare value */ 394 addi 2,2,-8 /* predec pointer */ 3951: 396 mtctr 1 /* load counter */ 3972: 398 lwzu 1,8(2) /* get next pte */ 399 cmpl 0,1,3 /* see if found pte */ 400 bdneq 2b /* loop if not eq */ 401 bne 3f /* not found */ 402 lwz 1,4(2) /* load tlb entry lower word */ 403 mtctr 0 /* restore counter */ 404 mfspr 0,SPR_DMISS /* get the miss address for the tlbld */ 405 mfsrr1 3 /* get the saved cr0 bits */ 406 mtcrf 0x80,3 /* and restore */ 407 ori 1,1,0x100 /* set the reference bit */ 408 mtspr SPR_RPA,1 /* set the pte */ 409 srwi 1,1,8 /* get byte 7 of pte */ 410 tlbld 0 /* load the dtlb */ 411 stb 1,6(2) /* update page table */ 412 rfi 413 4143: /* not found in pteg */ 415 andi. 1,3,0x40 /* have we already done second hash? */ 416 bne 5f 417 mfspr 2,SPR_HASH2 /* get the second pointer */ 418 ori 3,3,0x40 /* change the compare value */ 419 li 1,8 420 addi 2,2,-8 /* predec pointer */ 421 b 1b 4225: /* not found anywhere */ 423 mfsrr1 3 424 lis 1,0x40000000@h /* set dsisr<1> to flag pte not found */ 425 mtctr 0 /* restore counter */ 426 andi. 2,3,0xffff /* clean upper srr1 */ 427 mtsrr1 2 428 mtdsisr 1 /* load the dsisr */ 429 mfspr 1,SPR_DMISS /* get the miss address */ 430 mtdar 1 /* put in dar */ 431 mfmsr 0 432 xoris 0,0,0x20000@h /* flip the msr<tgpr> bit */ 433 mtcrf 0x80,3 /* restore cr0 */ 434 mtmsr 0 /* now with native gprs */ 435 isync 436 ba EXC_DSI 437_C_LABEL(tlbdlmsize) = .-_C_LABEL(tlbdlmiss) 438 439 .globl _C_LABEL(tlbdsmiss),_C_LABEL(tlbdsmsize) 440_C_LABEL(tlbdsmiss): 441 mfspr 2,SPR_HASH1 /* get first pointer */ 442 li 1,8 443 mfctr 0 /* save counter */ 444 mfspr 3,SPR_DCMP /* get first compare value */ 445 addi 2,2,-8 /* predec pointer */ 4461: 447 mtctr 1 /* load counter */ 4482: 449 lwzu 1,8(2) /* get next pte */ 450 cmpl 0,1,3 /* see if found pte */ 451 bdneq 2b /* loop if not eq */ 452 bne 3f /* not found */ 453 lwz 1,4(2) /* load tlb entry lower word */ 454 andi. 3,1,0x80 /* check the C-bit */ 455 beq 4f 4565: 457 mtctr 0 /* restore counter */ 458 mfspr 0,SPR_DMISS /* get the miss address for the tlbld */ 459 mfsrr1 3 /* get the saved cr0 bits */ 460 mtcrf 0x80,3 /* and restore */ 461 mtspr SPR_RPA,1 /* set the pte */ 462 tlbld 0 /* load the dtlb */ 463 rfi 464 4653: /* not found in pteg */ 466 andi. 1,3,0x40 /* have we already done second hash? */ 467 bne 5f 468 mfspr 2,SPR_HASH2 /* get the second pointer */ 469 ori 3,3,0x40 /* change the compare value */ 470 li 1,8 471 addi 2,2,-8 /* predec pointer */ 472 b 1b 4734: /* found, but C-bit = 0 */ 474 rlwinm. 3,1,30,0,1 /* test PP */ 475 bge- 7f 476 andi. 3,1,1 477 beq+ 8f 4789: /* found, but protection violation (PP==00)*/ 479 mfsrr1 3 480 lis 1,0xa000000@h /* indicate protection violation 481 on store */ 482 b 1f 4837: /* found, PP=1x */ 484 mfspr 3,SPR_DMISS /* get the miss address */ 485 mfsrin 1,3 /* get the segment register */ 486 mfsrr1 3 487 rlwinm 3,3,18,31,31 /* get PR-bit */ 488 rlwnm. 2,2,3,1,1 /* get the key */ 489 bne- 9b /* protection violation */ 4908: /* found, set reference/change bits */ 491 lwz 1,4(2) /* reload tlb entry */ 492 ori 1,1,0x180 493 sth 1,6(2) 494 b 5b 4955: /* not found anywhere */ 496 mfsrr1 3 497 lis 1,0x42000000@h /* set dsisr<1> to flag pte not found */ 498 /* dsisr<6> to flag store */ 4991: 500 mtctr 0 /* restore counter */ 501 andi. 2,3,0xffff /* clean upper srr1 */ 502 mtsrr1 2 503 mtdsisr 1 /* load the dsisr */ 504 mfspr 1,SPR_DMISS /* get the miss address */ 505 mtdar 1 /* put in dar */ 506 mfmsr 0 507 xoris 0,0,0x20000@h /* flip the msr<tgpr> bit */ 508 mtcrf 0x80,3 /* restore cr0 */ 509 mtmsr 0 /* now with native gprs */ 510 isync 511 ba EXC_DSI 512_C_LABEL(tlbdsmsize) = .-_C_LABEL(tlbdsmiss) 513 514#if defined(DDB) || defined(KGDB) 515#define ddbsave 0xde0 /* primary save area for DDB */ 516/* 517 * In case of DDB we want a separate trap catcher for it 518 */ 519 .local ddbstk 520 .comm ddbstk,INTSTK,8 /* ddb stack */ 521 522 .globl _C_LABEL(ddblow),_C_LABEL(ddbsize) 523_C_LABEL(ddblow): 524 mtsprg 1,1 /* save SP */ 525 stmw 28,ddbsave(0) /* free r28-r31 */ 526 mflr 28 /* save LR */ 527 mfcr 29 /* save CR */ 528 lis 1,ddbstk+INTSTK@ha /* get new SP */ 529 addi 1,1,ddbstk+INTSTK@l 530 bla ddbtrap 531_C_LABEL(ddbsize) = .-_C_LABEL(ddblow) 532#endif /* DDB | KGDB */ 533 534#ifdef IPKDB 535#define ipkdbsave 0xde0 /* primary save area for IPKDB */ 536/* 537 * In case of IPKDB we want a separate trap catcher for it 538 */ 539 540 .local ipkdbstk 541 .comm ipkdbstk,INTSTK,8 /* ipkdb stack */ 542 543 .globl _C_LABEL(ipkdblow),_C_LABEL(ipkdbsize) 544_C_LABEL(ipkdblow): 545 mtsprg 1,1 /* save SP */ 546 stmw 28,ipkdbsave(0) /* free r28-r31 */ 547 mflr 28 /* save LR */ 548 mfcr 29 /* save CR */ 549 lis 1,ipkdbstk+INTSTK@ha /* get new SP */ 550 addi 1,1,ipkdbstk+INTSTK@l 551 bla ipkdbtrap 552_C_LABEL(ipkdbsize) = .-_C_LABEL(ipkdblow) 553#endif /* IPKDB */ 554 555#ifdef CPU601_KERN_ENTRY_HOOK 556#define CPU601_KERN_ENTRY(_s1_,_s2_) \ 557 mfpvr _s1_; \ 558 srwi _s1_,_s1_,16; \ 559 cmpi 0,_s1_,MPC601; \ 560 bne 98f; /* skip if not 601 */ \ 561 CPU601_KERN_ENTRY_HOOK(_s1_,_s2_); \ 56298: 563#else 564#define CPU601_KERN_ENTRY(_s1_,_s2_) /* nothing */ 565#endif 566 567#ifdef CPU601_KERN_LEAVE_HOOK 568#define CPU601_KERN_LEAVE(_pmap_,_s1_) \ 569 mfpvr _s1_; \ 570 srwi _s1_,_s1_,16; \ 571 cmpi 0,_s1_,MPC601; \ 572 bne 99f; /* skip if not 601 */ \ 573 CPU601_KERN_LEAVE_HOOK(_pmap_,_s1_); \ 574 xor _s1_,_s1_,_s1_; \ 575 mtibatl 0,_s1_; /* obliterate BATs */ \ 576 mtibatl 1,_s1_; \ 577 mtibatl 2,_s1_; \ 578 mtibatl 3,_s1_; \ 57999: 580#else 581#define CPU601_KERN_LEAVE(_pmap_,_s1_) /* nothing */ 582#endif 583 584/* 585 * FRAME_SETUP assumes: 586 * SPRG1 SP (1) 587 * savearea r28-r31,DAR,DSISR (DAR & DSISR only for DSI traps) 588 * 28 LR 589 * 29 CR 590 * 1 kernel stack 591 * LR trap type 592 * SRR0/1 as at start of trap 593 */ 594#define FRAME_SETUP(savearea) \ 595/* Have to enable translation to allow access of kernel stack: */ \ 596 mfsrr0 30; \ 597 mfsrr1 31; \ 598 stmw 30,savearea+24(0); \ 599 mfmsr 30; \ 600 ori 30,30,(PSL_DR|PSL_IR); \ 601 mtmsr 30; \ 602 isync; \ 603 mfsprg 31,1; \ 604 stwu 31,-FRAMELEN(1); \ 605 stw 0,FRAME_0+8(1); \ 606 stw 31,FRAME_1+8(1); \ 607 stw 28,FRAME_LR+8(1); \ 608 stw 29,FRAME_CR+8(1); \ 609 lmw 28,savearea(0); \ 610 stmw 2,FRAME_2+8(1); \ 611 lmw 28,savearea+16(0); \ 612 mfxer 3; \ 613 mfctr 4; \ 614 mflr 5; \ 615 andi. 5,5,0xff00; \ 616 stw 3,FRAME_XER+8(1); \ 617 stw 4,FRAME_CTR+8(1); \ 618 stw 5,FRAME_EXC+8(1); \ 619 stw 28,FRAME_DAR+8(1); \ 620 stw 29,FRAME_DSISR+8(1); \ 621 stw 30,FRAME_SRR0+8(1); \ 622 stw 31,FRAME_SRR1+8(1) 623 624#define FRAME_LEAVE(savearea) \ 625/* Now restore regs: */ \ 626 lwz 2,FRAME_SRR0+8(1); \ 627 lwz 3,FRAME_SRR1+8(1); \ 628 lwz 4,FRAME_CTR+8(1); \ 629 lwz 5,FRAME_XER+8(1); \ 630 lwz 6,FRAME_LR+8(1); \ 631 lwz 7,FRAME_CR+8(1); \ 632 stw 2,savearea(0); \ 633 stw 3,savearea+4(0); \ 634 mtctr 4; \ 635 mtxer 5; \ 636 mtlr 6; \ 637 mtsprg 1,7; /* save cr */ \ 638 lmw 2,FRAME_2+8(1); \ 639 lwz 0,FRAME_0+8(1); \ 640 lwz 1,FRAME_1+8(1); \ 641 mtsprg 2,2; /* save r2 & r3 */ \ 642 mtsprg 3,3; \ 643/* Disable translation, machine check and recoverability: */ \ 644 mfmsr 2; \ 645 andi. 2,2,~(PSL_DR|PSL_IR|PSL_ME|PSL_RI)@l; \ 646 mtmsr 2; \ 647 isync; \ 648/* Decide whether we return to user mode: */ \ 649 lwz 3,savearea+4(0); \ 650 mtcr 3; \ 651 bc 4,17,1f; /* branch if PSL_PR is false */ \ 652/* Restore user & kernel access SR: */ \ 653 lis 2,_C_LABEL(curpm)@ha; /* get real address of pmap */ \ 654 lwz 2,_C_LABEL(curpm)@l(2); \ 655 lwz 3,PM_SR+0(2); \ 656 mtsr 0,3; /* restore SR0 */ \ 657 lwz 3,PM_SR+4(2); \ 658 mtsr 1,3; /* restore SR1 */ \ 659 lwz 3,PM_SR+8(2); \ 660 mtsr 2,3; /* restore SR2 */ \ 661 lwz 3,PM_SR+12(2); \ 662 mtsr 3,3; /* restore SR3 */ \ 663 lwz 3,PM_SR+16(2); \ 664 mtsr 4,3; /* restore SR4 */ \ 665 lwz 3,PM_SR+20(2); \ 666 mtsr 5,3; /* restore SR5 */ \ 667 lwz 3,PM_SR+24(2); \ 668 mtsr 6,3; /* restore SR6 */ \ 669 lwz 3,PM_SR+28(2); \ 670 mtsr 7,3; /* restore SR7 */ \ 671 lwz 3,PM_USRSR(2); \ 672 mtsr USER_SR,3; \ 673 lwz 3,PM_KERNELSR(2); \ 674 mtsr KERNEL_SR,3; \ 675 CPU601_KERN_LEAVE(2,3); \ 6761: mfsprg 2,1; /* restore cr */ \ 677 mtcr 2; \ 678 lwz 2,savearea(0); \ 679 lwz 3,savearea+4(0); \ 680 mtsrr0 2; \ 681 mtsrr1 3; \ 682 mfsprg 2,2; /* restore r2 & r3 */ \ 683 mfsprg 3,3 684 685/* 686 * Preamble code for DSI/ISI traps 687 */ 688disitrap: 689 lmw 30,disisave(0) 690 stmw 30,tempsave(0) 691 lmw 30,disisave+8(0) 692 stmw 30,tempsave+8(0) 693 mfdar 30 694 mfdsisr 31 695 stmw 30,tempsave+16(0) 696realtrap: 697/* Test whether we already had PR set */ 698 mfsrr1 1 699 mtcr 1 700 mfsprg 1,1 /* restore SP (might have been 701 overwritten) */ 702 bc 4,17,s_trap /* branch if PSL_PR is false */ 703 lis 1,_C_LABEL(curpcb)@ha 704 lwz 1,_C_LABEL(curpcb)@l(1) 705 addi 1,1,USPACE /* stack is top of user struct */ 706 707/* 708 * Now the common trap catching code. 709 */ 710s_trap: 711/* First have to enable KERNEL mapping */ 712 lis 31,KERNEL_SEGMENT@h 713 ori 31,31,KERNEL_SEGMENT@l 714 mtsr KERNEL_SR,31 715 CPU601_KERN_ENTRY(30,31) 716/* Obliterate SRs so BAT spills work correctly */ 717 lis 31,EMPTY_SEGMENT@h 718 ori 31,31,EMPTY_SEGMENT@l 719 mtsr 0,31 720 mtsr 1,31 721 mtsr 2,31 722 mtsr 3,31 723 mtsr 4,31 724 mtsr 5,31 725 mtsr 6,31 726 mtsr 7,31 727 FRAME_SETUP(tempsave) 728/* Now we can recover interrupts again: */ 729 mfmsr 7 730 ori 7,7,(PSL_EE|PSL_ME|PSL_RI)@l 731 mtmsr 7 732 isync 733/* Call C trap code: */ 734trapagain: 735 addi 3,1,8 736 bl _C_LABEL(trap) 737 .globl _C_LABEL(trapexit) 738_C_LABEL(trapexit): 739/* Disable interrupts: */ 740 mfmsr 3 741 andi. 3,3,~PSL_EE@l 742 mtmsr 3 743/* Test AST pending: */ 744 lwz 5,FRAME_SRR1+8(1) 745 mtcr 5 746 bc 4,17,1f /* branch if PSL_PR is false */ 747 lis 3,_C_LABEL(astpending)@ha 748 lwz 4,_C_LABEL(astpending)@l(3) 749 andi. 4,4,1 750 beq 1f 751 li 6,EXC_AST 752 stw 6,FRAME_EXC+8(1) 753 b trapagain 7541: 755 FRAME_LEAVE(tempsave) 756 rfi 757 758/* 759 * DSI second stage fault handler 760 */ 761s_dsitrap: 762 mfdsisr 31 /* test whether this may be a 763 spill fault */ 764 mtcr 31 765 mtsprg 1,1 /* save SP */ 766 bc 4,1,disitrap /* branch if table miss is false */ 767 lis 1,spillstk+SPILLSTK@ha 768 addi 1,1,spillstk+SPILLSTK@l /* get spill stack */ 769 stwu 1,-SPFRAMELEN(1) 770 stw 0,SPFRAME_R0(1) /* save non-volatile registers */ 771 stw 3,SPFRAME_R3(1) 772 stw 4,SPFRAME_R4(1) 773 stw 5,SPFRAME_R5(1) 774 stw 6,SPFRAME_R6(1) 775 stw 7,SPFRAME_R7(1) 776 stw 8,SPFRAME_R8(1) 777 stw 9,SPFRAME_R9(1) 778 stw 10,SPFRAME_R10(1) 779 stw 11,SPFRAME_R11(1) 780 stw 12,SPFRAME_R12(1) 781 mflr 30 /* save trap type */ 782 mfctr 31 /* & CTR */ 783 mfdar 3 784s_pte_spill: 785 bl _C_LABEL(pmap_pte_spill) /* try a spill */ 786 or. 3,3,3 787 mtctr 31 /* restore CTR */ 788 mtlr 30 /* and trap type */ 789 mfsprg 31,2 /* get saved XER */ 790 mtxer 31 /* restore XER */ 791 lwz 12,SPFRAME_R12(1) /* restore non-volatile registers */ 792 lwz 11,SPFRAME_R11(1) 793 lwz 10,SPFRAME_R10(1) 794 lwz 9,SPFRAME_R9(1) 795 lwz 8,SPFRAME_R8(1) 796 lwz 7,SPFRAME_R7(1) 797 lwz 6,SPFRAME_R6(1) 798 lwz 5,SPFRAME_R5(1) 799 lwz 4,SPFRAME_R4(1) 800 lwz 3,SPFRAME_R3(1) 801 lwz 0,SPFRAME_R0(1) 802 beq disitrap 803 mfsprg 1,1 /* restore SP */ 804 mtcr 29 /* restore CR */ 805 mtlr 28 /* restore LR */ 806 lmw 28,disisave(0) /* restore r28-r31 */ 807 rfi /* return to trapped code */ 808 809/* 810 * ISI second stage fault handler 811 */ 812s_isitrap: 813 mfsrr1 31 /* test whether this may be a 814 spill fault */ 815 mtcr 31 816 mtsprg 1,1 /* save SP */ 817 bc 4,1,disitrap /* branch if table miss is false */ 818 lis 1,spillstk+SPILLSTK@ha 819 addi 1,1,spillstk+SPILLSTK@l /* get spill stack */ 820 stwu 1,-SPFRAMELEN(1) 821 stw 0,SPFRAME_R0(1) /* save non-volatile registers */ 822 stw 3,SPFRAME_R3(1) 823 stw 4,SPFRAME_R4(1) 824 stw 5,SPFRAME_R5(1) 825 stw 6,SPFRAME_R6(1) 826 stw 7,SPFRAME_R7(1) 827 stw 8,SPFRAME_R8(1) 828 stw 9,SPFRAME_R9(1) 829 stw 10,SPFRAME_R10(1) 830 stw 11,SPFRAME_R11(1) 831 stw 12,SPFRAME_R12(1) 832 mfxer 30 /* save XER */ 833 mtsprg 2,30 834 mflr 30 /* save trap type */ 835 mfctr 31 /* & ctr */ 836 mfsrr0 3 837 b s_pte_spill /* above */ 838 839/* 840 * External interrupt second level handler 841 */ 842#define INTRENTER \ 843/* Save non-volatile registers: */ \ 844 stwu 1,-IFRAMELEN(1); /* temporarily */ \ 845 stw 0,IFRAME_R0(1); \ 846 mfsprg 0,1; /* get original SP */ \ 847 stw 0,IFRAME_R1(1); /* and store it */ \ 848 stw 3,IFRAME_R3(1); \ 849 stw 4,IFRAME_R4(1); \ 850 stw 5,IFRAME_R5(1); \ 851 stw 6,IFRAME_R6(1); \ 852 stw 7,IFRAME_R7(1); \ 853 stw 8,IFRAME_R8(1); \ 854 stw 9,IFRAME_R9(1); \ 855 stw 10,IFRAME_R10(1); \ 856 stw 11,IFRAME_R11(1); \ 857 stw 12,IFRAME_R12(1); \ 858 stw 28,IFRAME_LR(1); /* saved LR */ \ 859 stw 29,IFRAME_CR(1); /* saved CR */ \ 860 stw 30,IFRAME_XER(1); /* saved XER */ \ 861 lmw 28,tempsave(0); /* restore r28-r31 */ \ 862 mfctr 6; \ 863 lis 5,_C_LABEL(intr_depth)@ha; \ 864 lwz 5,_C_LABEL(intr_depth)@l(5); \ 865 mfsrr0 4; \ 866 mfsrr1 3; \ 867 stw 6,IFRAME_CTR(1); \ 868 stw 5,IFRAME_INTR_DEPTH(1); \ 869 stw 4,IFRAME_SRR0(1); \ 870 stw 3,IFRAME_SRR1(1); \ 871 mtcr 3; \ 872 bc 4,17,99f; /* branch if PSL_PR is false */ \ 873 lis 3,EMPTY_SEGMENT@h; \ 874 ori 3,3,EMPTY_SEGMENT@l; \ 875 mtsr 0,3; /* reset SRs so BAT spills work */ \ 876 mtsr 1,3; \ 877 mtsr 2,3; \ 878 mtsr 3,3; \ 879 mtsr 4,3; \ 880 mtsr 5,3; \ 881 mtsr 6,3; \ 882 mtsr 7,3; \ 883 CPU601_KERN_ENTRY(3,4); \ 884/* interrupts are recoverable here, and enable translation */ \ 885 lis 3,(KERNEL_SEGMENT|SR_SUKEY|SR_PRKEY)@h; \ 886 ori 3,3,(KERNEL_SEGMENT|SR_SUKEY|SR_PRKEY)@l; \ 887 mtsr KERNEL_SR,3; \ 88899: mfmsr 5; \ 889 ori 5,5,(PSL_IR|PSL_DR|PSL_RI); \ 890 mtmsr 5; \ 891 isync 892 893 .globl _C_LABEL(extint_call) 894extintr: 895 INTRENTER 896_C_LABEL(extint_call): 897 bl _C_LABEL(extint_call) /* to be filled in later */ 898 899intr_exit: 900/* Disable interrupts (should already be disabled) and MMU here: */ 901 mfmsr 3 902 andi. 3,3,~(PSL_EE|PSL_ME|PSL_RI|PSL_DR|PSL_IR)@l 903 mtmsr 3 904 isync 905/* restore possibly overwritten registers: */ 906 lwz 12,IFRAME_R12(1) 907 lwz 11,IFRAME_R11(1) 908 lwz 10,IFRAME_R10(1) 909 lwz 9,IFRAME_R9(1) 910 lwz 8,IFRAME_R8(1) 911 lwz 7,IFRAME_R7(1) 912 lwz 6,IFRAME_SRR1(1) 913 lwz 5,IFRAME_SRR0(1) 914 lwz 4,IFRAME_CTR(1) 915 lwz 3,IFRAME_XER(1) 916 mtsrr1 6 917 mtsrr0 5 918 mtctr 4 919 mtxer 3 920/* Returning to user mode? */ 921 mtcr 6 /* saved SRR1 */ 922 bc 4,17,1f /* branch if PSL_PR is false */ 923 lis 3,_C_LABEL(curpm)@ha /* get current pmap real address */ 924 lwz 3,_C_LABEL(curpm)@l(3) 925 lwz 4,PM_SR+0(3) 926 mtsr 0,4 /* Restore SR0 */ 927 lwz 4,PM_SR+4(3) 928 mtsr 1,4 /* Restore SR1 */ 929 lwz 4,PM_SR+8(3) 930 mtsr 2,4 /* Restore SR2 */ 931 lwz 4,PM_SR+12(3) 932 mtsr 3,4 /* Restore SR3 */ 933 lwz 4,PM_SR+16(3) 934 mtsr 4,4 /* Restore SR4 */ 935 lwz 4,PM_SR+20(3) 936 mtsr 5,4 /* Restore SR5 */ 937 lwz 4,PM_SR+24(3) 938 mtsr 6,4 /* Restore SR6 */ 939 lwz 4,PM_SR+28(3) 940 mtsr 7,4 /* Restore SR7 */ 941 lwz 4,PM_KERNELSR(3) 942 mtsr KERNEL_SR,4 /* Restore kernel SR */ 943 CPU601_KERN_LEAVE(3,4) 944 lis 3,_C_LABEL(astpending)@ha /* Test AST pending */ 945 lwz 4,_C_LABEL(astpending)@l(3) 946 andi. 4,4,1 947 beq 1f 948/* Setup for entry to realtrap: */ 949 lwz 3,IFRAME_R1(1) /* get saved SP */ 950 mtsprg 1,3 951 li 6,EXC_AST 952 stmw 28,tempsave(0) /* establish tempsave again */ 953 mtlr 6 954 lwz 28,IFRAME_LR(1) /* saved LR */ 955 lwz 29,IFRAME_CR(1) /* saved CR */ 956 lwz 6,IFRAME_R6(1) 957 lwz 5,IFRAME_R5(1) 958 lwz 4,IFRAME_R4(1) 959 lwz 3,IFRAME_R3(1) 960 lwz 0,IFRAME_R0(1) 961 lis 30,_C_LABEL(intr_depth)@ha /* adjust reentrancy count */ 962 lwz 31,_C_LABEL(intr_depth)@l(30) 963 addi 31,31,-1 964 stw 31,_C_LABEL(intr_depth)@l(30) 965 b realtrap 9661: 967/* Here is the normal exit of extintr: */ 968 lwz 5,IFRAME_CR(1) 969 lwz 6,IFRAME_LR(1) 970 mtcr 5 971 mtlr 6 972 lwz 6,IFRAME_R6(1) 973 lwz 5,IFRAME_R5(1) 974 lis 3,_C_LABEL(intr_depth)@ha /* adjust reentrancy count */ 975 lwz 4,_C_LABEL(intr_depth)@l(3) 976 addi 4,4,-1 977 stw 4,_C_LABEL(intr_depth)@l(3) 978 lwz 4,IFRAME_R4(1) 979 lwz 3,IFRAME_R3(1) 980 lwz 0,IFRAME_R0(1) 981 lwz 1,IFRAME_R1(1) 982 rfi 983 984/* 985 * Decrementer interrupt second level handler 986 */ 987decrintr: 988 INTRENTER 989 addi 3,1,8 /* intr frame -> clock frame */ 990 bl _C_LABEL(decr_intr) 991 b intr_exit 992 993#if defined(DDB) 994/* 995 * Deliberate entry to ddbtrap 996 */ 997 .globl _C_LABEL(ddb_trap) 998_C_LABEL(ddb_trap): 999 mtsprg 1,1 1000 mfmsr 3 1001 mtsrr1 3 1002 andi. 3,3,~(PSL_EE|PSL_ME)@l 1003 mtmsr 3 /* disable interrupts */ 1004 isync 1005 stmw 28,ddbsave(0) 1006 mflr 28 1007 li 29,EXC_BPT 1008 mtlr 29 1009 mfcr 29 1010 mtsrr0 28 1011#endif /* DDB */ 1012 1013#if defined(DDB) || defined(KGDB) 1014/* 1015 * Now the ddb trap catching code. 1016 */ 1017ddbtrap: 1018 FRAME_SETUP(ddbsave) 1019/* Call C trap code: */ 1020 addi 3,1,8 1021 bl _C_LABEL(ddb_trap_glue) 1022 or. 3,3,3 1023 bne ddbleave 1024/* This wasn't for DDB, so switch to real trap: */ 1025 lwz 3,FRAME_EXC+8(1) /* save exception */ 1026 stw 3,ddbsave+8(0) 1027 FRAME_LEAVE(ddbsave) 1028 mtsprg 1,1 /* prepare for entrance to realtrap */ 1029 stmw 28,tempsave(0) 1030 mflr 28 1031 mfcr 29 1032 lwz 31,ddbsave+8(0) 1033 mtlr 31 1034 b realtrap 1035ddbleave: 1036 FRAME_LEAVE(ddbsave) 1037 rfi 1038#endif /* DDB || KGDB */ 1039 1040#ifdef IPKDB 1041/* 1042 * Deliberate entry to ipkdbtrap 1043 */ 1044 .globl _C_LABEL(ipkdb_trap) 1045_C_LABEL(ipkdb_trap): 1046 mtsprg 1,1 1047 mfmsr 3 1048 mtsrr1 3 1049 andi. 3,3,~(PSL_EE|PSL_ME)@l 1050 mtmsr 3 /* disable interrupts */ 1051 isync 1052 stmw 28,ipkdbsave(0) 1053 mflr 28 1054 li 29,EXC_BPT 1055 mtlr 29 1056 mfcr 29 1057 mtsrr0 28 1058 1059/* 1060 * Now the ipkdb trap catching code. 1061 */ 1062ipkdbtrap: 1063 FRAME_SETUP(ipkdbsave) 1064/* Call C trap code: */ 1065 addi 3,1,8 1066 bl _C_LABEL(ipkdb_trap_glue) 1067 or. 3,3,3 1068 bne ipkdbleave 1069/* This wasn't for IPKDB, so switch to real trap: */ 1070 lwz 3,FRAME_EXC+8(1) /* save exception */ 1071 stw 3,ipkdbsave+8(0) 1072 FRAME_LEAVE(ipkdbsave) 1073 mtsprg 1,1 /* prepare for entrance to realtrap */ 1074 stmw 28,tempsave(0) 1075 mflr 28 1076 mfcr 29 1077 lwz 31,ipkdbsave+8(0) 1078 mtlr 31 1079 b realtrap 1080ipkdbleave: 1081 FRAME_LEAVE(ipkdbsave) 1082 rfi 1083 1084ipkdbfault: 1085 ba _ipkdbfault 1086_ipkdbfault: 1087 mfsrr0 3 1088 addi 3,3,4 1089 mtsrr0 3 1090 li 3,-1 1091 rfi 1092 1093/* 1094 * int ipkdbfbyte(unsigned char *p) 1095 */ 1096 .globl _C_LABEL(ipkdbfbyte) 1097_C_LABEL(ipkdbfbyte): 1098 li 9,EXC_DSI /* establish new fault routine */ 1099 lwz 5,0(9) 1100 lis 6,ipkdbfault@ha 1101 lwz 6,ipkdbfault@l(6) 1102 stw 6,0(9) 1103#ifdef IPKDBUSERHACK 1104 lis 8,_C_LABEL(ipkdbsr)@ha 1105 lwz 8,_C_LABEL(ipkdbsr)@l(8) 1106 mtsr USER_SR,8 1107 isync 1108#endif 1109 dcbst 0,9 /* flush data... */ 1110 sync 1111 icbi 0,9 /* and instruction caches */ 1112 lbz 3,0(3) /* fetch data */ 1113 stw 5,0(9) /* restore previous fault handler */ 1114 dcbst 0,9 /* and flush data... */ 1115 sync 1116 icbi 0,9 /* and instruction caches */ 1117 blr 1118 1119/* 1120 * int ipkdbsbyte(unsigned char *p, int c) 1121 */ 1122 .globl _C_LABEL(ipkdbsbyte) 1123_C_LABEL(ipkdbsbyte): 1124 li 9,EXC_DSI /* establish new fault routine */ 1125 lwz 5,0(9) 1126 lis 6,ipkdbfault@ha 1127 lwz 6,ipkdbfault@l(6) 1128 stw 6,0(9) 1129#ifdef IPKDBUSERHACK 1130 lis 8,_C_LABEL(ipkdbsr)@ha 1131 lwz 8,_C_LABEL(ipkdbsr)@l(8) 1132 mtsr USER_SR,8 1133 isync 1134#endif 1135 dcbst 0,9 /* flush data... */ 1136 sync 1137 icbi 0,9 /* and instruction caches */ 1138 mr 6,3 1139 xor 3,3,3 1140 stb 4,0(6) 1141 dcbst 0,6 /* Now do appropriate flushes 1142 to data... */ 1143 sync 1144 icbi 0,6 /* and instruction caches */ 1145 stw 5,0(9) /* restore previous fault handler */ 1146 dcbst 0,9 /* and flush data... */ 1147 sync 1148 icbi 0,9 /* and instruction caches */ 1149 blr 1150#endif /* IPKDB */ 1151