1/* $NetBSD: trap_subr.S,v 1.29 2002/10/10 22:37:52 matt 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#include "opt_altivec.h" 41 42#ifdef ALTIVEC 43#define SAVE_VRSAVE(tf,b) \ 44 mfspr b,SPR_VRSAVE; \ 45 stw b,FRAME_VRSAVE+8(tf); 46 47#define RESTORE_VRSAVE(tf,b) \ 48 lwz b,FRAME_VRSAVE+8(tf); \ 49 mtspr SPR_VRSAVE,b; 50#else 51#define SAVE_VRSAVE(tf,b) 52#define RESTORE_VRSAVE(tf,b) 53#endif 54#define RESTORE_SRS(pmap,sr) mtsr 0,sr; \ 55 lwz sr,4(pmap); mtsr 1,sr; \ 56 lwz sr,8(pmap); mtsr 2,sr; \ 57 lwz sr,12(pmap); mtsr 3,sr; \ 58 lwz sr,16(pmap); mtsr 4,sr; \ 59 lwz sr,20(pmap); mtsr 5,sr; \ 60 lwz sr,24(pmap); mtsr 6,sr; \ 61 lwz sr,28(pmap); mtsr 7,sr; \ 62 lwz sr,32(pmap); mtsr 8,sr; \ 63 lwz sr,36(pmap); mtsr 9,sr; \ 64 lwz sr,40(pmap); mtsr 10,sr; \ 65 lwz sr,44(pmap); mtsr 11,sr; \ 66 lwz sr,48(pmap); mtsr 12,sr; \ 67 lwz sr,52(pmap); mtsr 13,sr; \ 68 lwz sr,56(pmap); mtsr 14,sr; \ 69 lwz sr,60(pmap); mtsr 15,sr; 70 71/* 72 * User SRs are loaded through a pointer to the current pmap. 73 */ 74#define RESTORE_USER_SRS(pmap,sr) \ 75 lis pmap,_C_LABEL(curpm)@ha; \ 76 lwz pmap,_C_LABEL(curpm)@l(pmap); \ 77 lwzu sr,PM_SR(pmap); \ 78 RESTORE_SRS(pmap,sr) 79 80/* 81 * Kernel SRs are loaded directly from kernel_pmap_ 82 */ 83#define RESTORE_KERN_SRS(pmap,sr) \ 84 lis pmap,_C_LABEL(kernel_pmap_)@ha; \ 85 lwzu sr,_C_LABEL(kernel_pmap_)+PM_SR@l(pmap); \ 86 RESTORE_SRS(pmap,sr) 87 88/* 89 * Data used during primary/secondary traps/interrupts 90 */ 91#define tempsave EXC_MCHK+0xe0 /* primary save area for trap handling */ 92#define disisave EXC_DSI+0xe0 /* primary save area for dsi/isi traps */ 93 94/* 95 * XXX Interrupt and spill stacks need to be per-CPU. 96 */ 97 .data 98 .align 4 99intstk: 100 .space INTSTK /* interrupt stack */ 101 102GLOBAL(intr_depth) 103 .long -1 /* in-use marker */ 104 105 .comm spillstk,SPILLSTK,8 106 107/* 108 * This code gets copied to all the trap vectors (except ISI/DSI, ALI, the 109 * interrupts, and possibly the debugging traps when using IPKDB). 110 * Note that it is 7 instructions long and can fit in the smallest vector. 111 */ 112 .text 113 .globl _C_LABEL(trapcode),_C_LABEL(trapsize) 114_C_LABEL(trapcode): 115 mtsprg 1,1 /* save SP */ 116 stmw 28,tempsave(0) /* free r28-r31 */ 117 mflr 28 /* save LR */ 118 mfcr 29 /* save CR */ 119/* Test whether we already had PR set */ 120 mfsrr1 31 121 mtcr 31 122 bla s_trap 123_C_LABEL(trapsize) = .-_C_LABEL(trapcode) 124 125/* 126 * For ALI: has to save DSISR and DAR 127 */ 128 .globl _C_LABEL(alitrap),_C_LABEL(alisize) 129_C_LABEL(alitrap): 130 mtsprg 1,1 /* save SP */ 131 stmw 28,tempsave(0) /* free r28-r31 */ 132 mfdar 30 133 mfdsisr 31 134 stmw 30,tempsave+16(0) 135 mflr 28 /* save LR */ 136 mfcr 29 /* save CR */ 137/* Test whether we already had PR set */ 138 mfsrr1 31 139 mtcr 31 140 bla s_trap 141_C_LABEL(alisize) = .-_C_LABEL(alitrap) 142 143/* 144 * Similar to the above for DSI 145 * Has to handle BAT spills 146 * and standard pagetable spills 147 */ 148 .globl _C_LABEL(dsitrap),_C_LABEL(dsisize) 149_C_LABEL(dsitrap): 150 stmw 28,disisave(0) /* free r28-r31 */ 151 mfcr 29 /* save CR */ 152 mfxer 30 /* save XER */ 153 mtsprg 2,30 /* in SPRG2 */ 154 mfsrr1 31 /* test kernel mode */ 155 mtcr 31 156 bc 12,17,1f /* branch if PSL_PR is set */ 157 mfdar 31 /* get fault address */ 158 rlwinm 31,31,7,25,28 /* get segment * 8 */ 159 160 /* get batu */ 161 addis 31,31,_C_LABEL(battable)@ha 162 lwz 30,_C_LABEL(battable)@l(31) 163 mtcr 30 164 bc 4,30,1f /* branch if supervisor valid is 165 false */ 166 /* get batl */ 167 lwz 31,_C_LABEL(battable)+4@l(31) 168/* We randomly use the highest two bat registers here */ 169 mftb 28 170 andi. 28,28,1 171 bne 2f 172 mtdbatu 2,30 173 mtdbatl 2,31 174 b 3f 1752: 176 mtdbatu 3,30 177 mtdbatl 3,31 1783: 179 mfsprg 30,2 /* restore XER */ 180 mtxer 30 181 mtcr 29 /* restore CR */ 182 lmw 28,disisave(0) /* restore r28-r31 */ 183 rfi /* return to trapped code */ 1841: 185 mflr 28 /* save LR */ 186 mtsprg 1,1 /* save SP */ 187 bla disitrap 188_C_LABEL(dsisize) = .-_C_LABEL(dsitrap) 189 190/* 191 * Dedicated MPC601 version of the above. 192 * Considers different BAT format and combined implementation 193 * (being addressed as I-BAT). 194 */ 195 .globl _C_LABEL(dsitrap601),_C_LABEL(dsi601size) 196_C_LABEL(dsitrap601): 197 stmw 28,disisave(0) /* free r28-r31 */ 198 mfcr 29 /* save CR */ 199 mfxer 30 /* save XER */ 200 mtsprg 2,30 /* in SPRG2 */ 201 mfsrr1 31 /* test kernel mode */ 202 mtcr 31 203 bc 12,17,1f /* branch if PSL_PR is set */ 204 mfdar 31 /* get fault address */ 205 rlwinm 31,31,12,20,28 /* get "segment" battable offset */ 206 207 /* get batl */ 208 addis 31,31,_C_LABEL(battable)@ha 209 lwz 30,_C_LABEL(battable)+4@l(31) 210 mtcr 30 211 bc 4,25,1f /* branch if Valid is is false, 212 presently assumes supervisor only */ 213 214 /* get batu */ 215 lwz 31,_C_LABEL(battable)@l(31) 216/* We randomly use the highest two bat registers here */ 217 mfspr 28,SPR_RTCL_R 218 andi. 28,28,128 219 bne 2f 220 mtibatu 2,31 221 mtibatl 2,30 222 b 3f 2232: 224 mtibatu 3,31 225 mtibatl 3,30 2263: 227 mfsprg 30,2 /* restore XER */ 228 mtxer 30 229 mtcr 29 /* restore CR */ 230 lmw 28,disisave(0) /* restore r28-r31 */ 231 rfi /* return to trapped code */ 2321: 233 mflr 28 /* save LR */ 234 mtsprg 1,1 235 bla disitrap 236_C_LABEL(dsi601size) = .-_C_LABEL(dsitrap601) 237 238/* 239 * This one for the external interrupt handler. 240 */ 241 .globl _C_LABEL(extint),_C_LABEL(extsize) 242_C_LABEL(extint): 243 mtsprg 1,1 /* save SP */ 244 stmw 28,tempsave(0) /* free r28-r31 */ 245 mflr 28 /* save LR */ 246 mfcr 29 /* save CR */ 247 mfxer 30 /* save XER */ 248 lis 1,intstk+INTSTK@ha /* get interrupt stack */ 249 addi 1,1,intstk+INTSTK@l /* this is really intr_depth! */ 250 lwz 31,0(1) /* were we already running on intstk? */ 251 addic. 31,31,1 252 stw 31,0(1) 253 beq 1f 254 mfsprg 1,1 /* yes, get old SP */ 2551: 256 ba extintr 257_C_LABEL(extsize) = .-_C_LABEL(extint) 258 259/* 260 * And this one for the decrementer interrupt handler. 261 */ 262 .globl _C_LABEL(decrint),_C_LABEL(decrsize) 263_C_LABEL(decrint): 264 mtsprg 1,1 /* save SP */ 265 stmw 28,tempsave(0) /* free r28-r31 */ 266 mflr 28 /* save LR */ 267 mfcr 29 /* save CR */ 268 mfxer 30 /* save XER */ 269 lis 1,intstk+INTSTK@ha /* get interrupt stack */ 270 addi 1,1,intstk+INTSTK@l 271 lwz 31,0(1) /* were we already running on intstk? */ 272 addic. 31,31,1 273 stw 31,0(1) 274 beq 1f 275 mfsprg 1,1 /* yes, get old SP */ 2761: 277 ba decrintr 278_C_LABEL(decrsize) = .-_C_LABEL(decrint) 279 280/* 281 * Now the tlb software load for 603 processors: 282 * (Code essentially from the 603e User Manual, Chapter 5, but 283 * corrected a lot.) 284 */ 285 .globl _C_LABEL(tlbimiss),_C_LABEL(tlbimsize) 286_C_LABEL(tlbimiss): 287#ifdef PMAPDEBUG 288 mfspr 2,SPR_IMISS /* exception address */ 289 li 1,24 /* get rid of the lower */ 290 srw 2,2,1 /* 24 bits */ 291 li 1,1 /* Load 1 */ 292 cmpl 2,1,1 /* is it > 16MB */ 293 blt 99f /* nope, skip saving these SPRs */ 294 li 1,0xc0 /* arbitrary */ 295 mfspr 2,SPR_HASH1 296 stw 2,0(1) 297 mfspr 2,SPR_HASH2 298 stw 2,4(1) 299 mfspr 2,SPR_IMISS 300 stw 2,8(1) 301 mfspr 2,SPR_ICMP 302 stw 2,12(1) 30399: 304#endif /* PMAPDEBUG */ 305 mfspr 2,SPR_HASH1 /* get first pointer */ 306 li 1,8 307 mfctr 0 /* save counter */ 308 mfspr 3,SPR_ICMP /* get first compare value */ 309 addi 2,2,-8 /* predec pointer */ 3101: 311 mtctr 1 /* load counter */ 3122: 313 lwzu 1,8(2) /* get next pte */ 314 cmpl 0,1,3 /* see if found pte */ 315 bdneq 2b /* loop if not eq */ 316 bne 3f /* not found */ 317 lwz 1,4(2) /* load tlb entry lower word */ 318 andi. 3,1,8 /* check G-bit */ 319 bne 4f /* if guarded, take ISI */ 320 mtctr 0 /* restore counter */ 321 mfspr 0,SPR_IMISS /* get the miss address for the tlbli */ 322 mfsrr1 3 /* get the saved cr0 bits */ 323 mtcrf 0x80,3 /* and restore */ 324 ori 1,1,0x100 /* set the reference bit */ 325 mtspr SPR_RPA,1 /* set the pte */ 326 srwi 1,1,8 /* get byte 7 of pte */ 327 tlbli 0 /* load the itlb */ 328 stb 1,6(2) /* update page table */ 329 rfi 330 3313: /* not found in pteg */ 332 andi. 1,3,0x40 /* have we already done second hash? */ 333 bne 5f 334 mfspr 2,SPR_HASH2 /* get the second pointer */ 335 ori 3,3,0x40 /* change the compare value */ 336 li 1,8 337 addi 2,2,-8 /* predec pointer */ 338 b 1b 3394: /* guarded */ 340 mfsrr1 3 341 andi. 2,3,0xffff /* clean upper srr1 */ 342 oris 2,2,0x8000000@h /* set srr<4> to flag prot violation */ 343 b 6f 3445: /* not found anywhere */ 345 mfsrr1 3 346 andi. 2,3,0xffff /* clean upper srr1 */ 347 oris 2,2,0x40000000@h /* set srr1<1> to flag pte not found */ 3486: 349 mtctr 0 /* restore counter */ 350 mtsrr1 2 351 mfmsr 0 352 xoris 0,0,0x20000@h /* flip the msr<tgpr> bit */ 353 mtcrf 0x80,3 /* restore cr0 */ 354 mtmsr 0 /* now with native gprs */ 355 isync 356 ba EXC_ISI 357_C_LABEL(tlbimsize) = .-_C_LABEL(tlbimiss) 358 359 .globl _C_LABEL(tlbdlmiss),_C_LABEL(tlbdlmsize) 360_C_LABEL(tlbdlmiss): 361 mfspr 2,SPR_HASH1 /* get first pointer */ 362 li 1,8 363 mfctr 0 /* save counter */ 364 mfspr 3,SPR_DCMP /* get first compare value */ 365 addi 2,2,-8 /* predec pointer */ 3661: 367 mtctr 1 /* load counter */ 3682: 369 lwzu 1,8(2) /* get next pte */ 370 cmpl 0,1,3 /* see if found pte */ 371 bdneq 2b /* loop if not eq */ 372 bne 3f /* not found */ 373 lwz 1,4(2) /* load tlb entry lower word */ 374 mtctr 0 /* restore counter */ 375 mfspr 0,SPR_DMISS /* get the miss address for the tlbld */ 376 mfsrr1 3 /* get the saved cr0 bits */ 377 mtcrf 0x80,3 /* and restore */ 378 ori 1,1,0x100 /* set the reference bit */ 379 mtspr SPR_RPA,1 /* set the pte */ 380 srwi 1,1,8 /* get byte 7 of pte */ 381 tlbld 0 /* load the dtlb */ 382 stb 1,6(2) /* update page table */ 383 rfi 384 3853: /* not found in pteg */ 386 andi. 1,3,0x40 /* have we already done second hash? */ 387 bne 5f 388 mfspr 2,SPR_HASH2 /* get the second pointer */ 389 ori 3,3,0x40 /* change the compare value */ 390 li 1,8 391 addi 2,2,-8 /* predec pointer */ 392 b 1b 3935: /* not found anywhere */ 394 mfsrr1 3 395 lis 1,0x40000000@h /* set dsisr<1> to flag pte not found */ 396 mtctr 0 /* restore counter */ 397 andi. 2,3,0xffff /* clean upper srr1 */ 398 mtsrr1 2 399 mtdsisr 1 /* load the dsisr */ 400 mfspr 1,SPR_DMISS /* get the miss address */ 401 mtdar 1 /* put in dar */ 402 mfmsr 0 403 xoris 0,0,0x20000@h /* flip the msr<tgpr> bit */ 404 mtcrf 0x80,3 /* restore cr0 */ 405 mtmsr 0 /* now with native gprs */ 406 isync 407 ba EXC_DSI 408_C_LABEL(tlbdlmsize) = .-_C_LABEL(tlbdlmiss) 409 410 .globl _C_LABEL(tlbdsmiss),_C_LABEL(tlbdsmsize) 411_C_LABEL(tlbdsmiss): 412 mfspr 2,SPR_HASH1 /* get first pointer */ 413 li 1,8 414 mfctr 0 /* save counter */ 415 mfspr 3,SPR_DCMP /* get first compare value */ 416 addi 2,2,-8 /* predec pointer */ 4171: 418 mtctr 1 /* load counter */ 4192: 420 lwzu 1,8(2) /* get next pte */ 421 cmpl 0,1,3 /* see if found pte */ 422 bdneq 2b /* loop if not eq */ 423 bne 3f /* not found */ 424 lwz 1,4(2) /* load tlb entry lower word */ 425 andi. 3,1,0x80 /* check the C-bit */ 426 beq 4f 4275: 428 mtctr 0 /* restore counter */ 429 mfspr 0,SPR_DMISS /* get the miss address for the tlbld */ 430 mfsrr1 3 /* get the saved cr0 bits */ 431 mtcrf 0x80,3 /* and restore */ 432 mtspr SPR_RPA,1 /* set the pte */ 433 tlbld 0 /* load the dtlb */ 434 rfi 435 4363: /* not found in pteg */ 437 andi. 1,3,0x40 /* have we already done second hash? */ 438 bne 5f 439 mfspr 2,SPR_HASH2 /* get the second pointer */ 440 ori 3,3,0x40 /* change the compare value */ 441 li 1,8 442 addi 2,2,-8 /* predec pointer */ 443 b 1b 4444: /* found, but C-bit = 0 */ 445 rlwinm. 3,1,30,0,1 /* test PP */ 446 bge- 7f 447 andi. 3,1,1 448 beq+ 8f 4499: /* found, but protection violation (PP==00)*/ 450 mfsrr1 3 451 lis 1,0xa000000@h /* indicate protection violation 452 on store */ 453 b 1f 4547: /* found, PP=1x */ 455 mfspr 3,SPR_DMISS /* get the miss address */ 456 mfsrin 1,3 /* get the segment register */ 457 mfsrr1 3 458 rlwinm 3,3,18,31,31 /* get PR-bit */ 459 rlwnm. 2,2,3,1,1 /* get the key */ 460 bne- 9b /* protection violation */ 4618: /* found, set reference/change bits */ 462 lwz 1,4(2) /* reload tlb entry */ 463 ori 1,1,0x180 464 sth 1,6(2) 465 b 5b 4665: /* not found anywhere */ 467 mfsrr1 3 468 lis 1,0x42000000@h /* set dsisr<1> to flag pte not found */ 469 /* dsisr<6> to flag store */ 4701: 471 mtctr 0 /* restore counter */ 472 andi. 2,3,0xffff /* clean upper srr1 */ 473 mtsrr1 2 474 mtdsisr 1 /* load the dsisr */ 475 mfspr 1,SPR_DMISS /* get the miss address */ 476 mtdar 1 /* put in dar */ 477 mfmsr 0 478 xoris 0,0,0x20000@h /* flip the msr<tgpr> bit */ 479 mtcrf 0x80,3 /* restore cr0 */ 480 mtmsr 0 /* now with native gprs */ 481 isync 482 ba EXC_DSI 483_C_LABEL(tlbdsmsize) = .-_C_LABEL(tlbdsmiss) 484 485#if defined(DDB) || defined(KGDB) 486#define ddbsave 0xde0 /* primary save area for DDB */ 487/* 488 * In case of DDB we want a separate trap catcher for it 489 */ 490 .local ddbstk 491 .comm ddbstk,INTSTK,8 /* ddb stack */ 492 493 .globl _C_LABEL(ddblow),_C_LABEL(ddbsize) 494_C_LABEL(ddblow): 495 mtsprg 1,1 /* save SP */ 496 stmw 28,ddbsave(0) /* free r28-r31 */ 497 mflr 28 /* save LR */ 498 mfcr 29 /* save CR */ 499 lis 1,ddbstk+INTSTK@ha /* get new SP */ 500 addi 1,1,ddbstk+INTSTK@l 501 bla ddbtrap 502_C_LABEL(ddbsize) = .-_C_LABEL(ddblow) 503#endif /* DDB || KGDB */ 504 505#ifdef IPKDB 506#define ipkdbsave 0xde0 /* primary save area for IPKDB */ 507/* 508 * In case of IPKDB we want a separate trap catcher for it 509 */ 510 511 .local ipkdbstk 512 .comm ipkdbstk,INTSTK,8 /* ipkdb stack */ 513 514 .globl _C_LABEL(ipkdblow),_C_LABEL(ipkdbsize) 515_C_LABEL(ipkdblow): 516 mtsprg 1,1 /* save SP */ 517 stmw 28,ipkdbsave(0) /* free r28-r31 */ 518 mflr 28 /* save LR */ 519 mfcr 29 /* save CR */ 520 lis 1,ipkdbstk+INTSTK@ha /* get new SP */ 521 addi 1,1,ipkdbstk+INTSTK@l 522 bla ipkdbtrap 523_C_LABEL(ipkdbsize) = .-_C_LABEL(ipkdblow) 524#endif /* IPKDB */ 525 526#ifdef CPU601_KERN_ENTRY_HOOK 527#define CPU601_KERN_ENTRY(_s1_,_s2_) \ 528 mfpvr _s1_; \ 529 srwi _s1_,_s1_,16; \ 530 cmpi 0,_s1_,MPC601; \ 531 bne 98f; /* skip if not 601 */ \ 532 CPU601_KERN_ENTRY_HOOK(_s1_,_s2_); \ 53398: 534#else 535#define CPU601_KERN_ENTRY(_s1_,_s2_) /* nothing */ 536#endif 537 538#ifdef CPU601_KERN_LEAVE_HOOK 539#define CPU601_KERN_LEAVE(_pmap_,_s1_) \ 540 mfpvr _s1_; \ 541 srwi _s1_,_s1_,16; \ 542 cmpi 0,_s1_,MPC601; \ 543 bne 99f; /* skip if not 601 */ \ 544 CPU601_KERN_LEAVE_HOOK(_pmap_,_s1_); \ 545 xor _s1_,_s1_,_s1_; \ 546 mtibatl 0,_s1_; /* obliterate BATs */ \ 547 mtibatl 1,_s1_; \ 548 mtibatl 2,_s1_; \ 549 mtibatl 3,_s1_; \ 55099: 551#else 552#define CPU601_KERN_LEAVE(_pmap_,_s1_) /* nothing */ 553#endif 554 555/* 556 * FRAME_SETUP assumes: 557 * SPRG1 SP (1) 558 * savearea r28-r31,DAR,DSISR (DAR & DSISR only for DSI traps) 559 * 28 LR 560 * 29 CR 561 * 1 kernel stack 562 * LR trap type 563 * SRR0/1 as at start of trap 564 */ 565#define FRAME_SETUP(savearea) \ 566/* Have to enable translation to allow access of kernel stack: */ \ 567 mfsrr0 30; \ 568 mfsrr1 31; \ 569 stmw 30,savearea+24(0); \ 570 mfmsr 30; \ 571 ori 30,30,(PSL_DR|PSL_IR); \ 572 mtmsr 30; \ 573 isync; \ 574 mfsprg 31,1; \ 575 stwu 31,-FRAMELEN(1); \ 576 stw 0,FRAME_0+8(1); \ 577 stw 31,FRAME_1+8(1); \ 578 stw 28,FRAME_LR+8(1); \ 579 stw 29,FRAME_CR+8(1); \ 580 lmw 28,savearea(0); \ 581 stmw 2,FRAME_2+8(1); /* after this, r2-r31 can be used */ \ 582 lmw 28,savearea+16(0); \ 583 mfxer 3; \ 584 mfctr 4; \ 585 mflr 5; \ 586 andi. 5,5,0xff00; \ 587 stw 3,FRAME_XER+8(1); \ 588 stw 4,FRAME_CTR+8(1); \ 589 stw 5,FRAME_EXC+8(1); \ 590 SAVE_VRSAVE(1,6); \ 591 stw 28,FRAME_DAR+8(1); \ 592 stw 29,FRAME_DSISR+8(1); \ 593 stw 30,FRAME_SRR0+8(1); \ 594 stw 31,FRAME_SRR1+8(1) 595 596#define FRAME_LEAVE(savearea) \ 597/* Now restore regs: */ \ 598 lwz 2,FRAME_SRR0+8(1); \ 599 lwz 3,FRAME_SRR1+8(1); \ 600 lwz 4,FRAME_CTR+8(1); \ 601 lwz 5,FRAME_XER+8(1); \ 602 lwz 6,FRAME_LR+8(1); \ 603 lwz 7,FRAME_CR+8(1); \ 604 RESTORE_VRSAVE(1,8); \ 605 stw 2,savearea(0); \ 606 stw 3,savearea+4(0); \ 607 mtctr 4; \ 608 mtxer 5; \ 609 mtlr 6; \ 610 mtsprg 1,7; /* save cr */ \ 611 lmw 2,FRAME_2+8(1); \ 612 lwz 0,FRAME_0+8(1); /* restore r0 */ \ 613 lwz 1,FRAME_1+8(1); /* restore old sp in r1 */ \ 614 mtsprg 2,2; /* save r2 & r3 */ \ 615 mtsprg 3,3; \ 616/* Disable translation, machine check and recoverability: */ \ 617 mfmsr 2; \ 618 andi. 2,2,~(PSL_DR|PSL_IR|PSL_ME|PSL_RI)@l; \ 619 mtmsr 2; \ 620 isync; \ 621/* Decide whether we return to user mode: */ \ 622 lwz 3,savearea+4(0); \ 623 mtcr 3; \ 624 bc 4,17,1f; /* branch if PSL_PR is false */ \ 625/* Restore user SRs */ \ 626 CPU601_KERN_LEAVE(2,3); \ 627 RESTORE_USER_SRS(2,3); \ 6281: mfsprg 2,1; /* restore cr */ \ 629 mtcr 2; \ 630 lwz 2,savearea(0); \ 631 lwz 3,savearea+4(0); \ 632 mtsrr0 2; \ 633 mtsrr1 3; \ 634 mfsprg 2,2; /* restore r2 & r3 */ \ 635 mfsprg 3,3 636 637/* 638 * Preamble code for DSI/ISI traps 639 */ 640disitrap: 641 lmw 30,disisave(0) 642 stmw 30,tempsave(0) 643 lmw 30,disisave+8(0) 644 stmw 30,tempsave+8(0) 645 mfdar 30 646 mfdsisr 31 647 stmw 30,tempsave+16(0) 648 .globl _C_LABEL(trapstart) 649_C_LABEL(trapstart): 650realtrap: 651/* Test whether we already had PR set */ 652 mfsrr1 1 653 mtcr 1 654 mfsprg 1,1 /* restore SP (might have been 655 overwritten) */ 656s_trap: 657 bc 4,17,k_trap /* branch if PSL_PR is false */ 658 lis 1,_C_LABEL(curpcb)@ha 659 lwz 1,_C_LABEL(curpcb)@l(1) 660 addi 1,1,USPACE /* stack is top of user struct */ 661 662/* 663 * Now the common trap catching code. 664 */ 665 666 RESTORE_KERN_SRS(30,31) /* First enable KERNEL mapping */ 667 CPU601_KERN_ENTRY(30,31) 668 669k_trap: 670 FRAME_SETUP(tempsave) 671trapagain: 672/* Now we can recover interrupts again: */ 673 mfmsr 7 674 ori 7,7,(PSL_EE|PSL_ME|PSL_RI)@l 675 mtmsr 7 676 isync 677/* Call C trap code: */ 678 addi 3,1,8 679 bl _C_LABEL(trap) 680 .globl trapexit 681trapexit: 682/* Disable interrupts: */ 683 mfmsr 3 684 andi. 3,3,~PSL_EE@l 685 mtmsr 3 686/* Test AST pending: */ 687 lwz 5,FRAME_SRR1+8(1) 688 mtcr 5 689 bc 4,17,1f /* branch if PSL_PR is false */ 690 lis 3,_C_LABEL(astpending)@ha 691 lwz 4,_C_LABEL(astpending)@l(3) 692 andi. 4,4,1 693 beq 1f 694 li 6,EXC_AST 695 stw 6,FRAME_EXC+8(1) 696 b trapagain 6971: 698 FRAME_LEAVE(tempsave) 699 rfi 700 701/* 702 * Trap handler for syscalls (EXC_SC) 703 */ 704 705 .globl _C_LABEL(sctrap),_C_LABEL(scsize) 706_C_LABEL(sctrap): 707 mtsprg 1,1 /* save SP */ 708 stmw 28,tempsave(0) /* free r28-r31 */ 709 mflr 28 /* save LR */ 710 mfcr 29 /* save CR */ 711 bla s_sctrap 712 _C_LABEL(scsize) = .-_C_LABEL(sctrap) 713 714s_sctrap: 715 lis 1,_C_LABEL(curpcb)@ha 716 lwz 1,_C_LABEL(curpcb)@l(1) 717 addi 1,1,USPACE /* stack is top of user struct */ 718 RESTORE_KERN_SRS(30,31) /* First enable KERNEL mapping */ 719 CPU601_KERN_ENTRY(30,31) 720 FRAME_SETUP(tempsave) 721/* Now we can recover interrupts again: */ 722 mfmsr 7 723 ori 7,7,(PSL_EE|PSL_ME|PSL_RI)@l 724 mtmsr 7 725 isync 726 addi 3,1,8 727/* Call the appropriate syscall handler: */ 728 lis 4,_C_LABEL(curproc)@ha 729 lwz 4,_C_LABEL(curproc)@l(4) 730 lwz 4,P_MD_SYSCALL@l(4) 731 mtctr 4 732 bctrl 733/* Disable interrupts: */ 734 mfmsr 3 735 andi. 3,3,~PSL_EE@l 736 mtmsr 3 737/* Test AST pending: */ 738 lis 3,_C_LABEL(astpending)@ha 739 lwz 4,_C_LABEL(astpending)@l(3) 740 andi. 4,4,1 741 beq 1f 742 li 6,EXC_AST 743 stw 6,FRAME_EXC+8(1) 744 b trapagain 7451: 746 FRAME_LEAVE(tempsave) 747 rfi 748 749/* 750 * External interrupt second level handler 751 */ 752#define INTRENTER \ 753/* Save non-volatile registers: */ \ 754 stwu 1,-IFRAMELEN(1); /* temporarily */ \ 755 stw 0,IFRAME_R0(1); \ 756 mfsprg 0,1; /* get original SP */ \ 757 stw 0,IFRAME_R1(1); /* and store it */ \ 758 stw 3,IFRAME_R3(1); \ 759 stw 4,IFRAME_R4(1); \ 760 stw 5,IFRAME_R5(1); \ 761 stw 6,IFRAME_R6(1); \ 762 stw 7,IFRAME_R7(1); \ 763 stw 8,IFRAME_R8(1); \ 764 stw 9,IFRAME_R9(1); \ 765 stw 10,IFRAME_R10(1); \ 766 stw 11,IFRAME_R11(1); \ 767 stw 12,IFRAME_R12(1); \ 768 stw 28,IFRAME_LR(1); /* saved LR */ \ 769 stw 29,IFRAME_CR(1); /* saved CR */ \ 770 stw 30,IFRAME_XER(1); /* saved XER */ \ 771 lmw 28,tempsave(0); /* restore r28-r31 */ \ 772 mfctr 6; \ 773 lis 5,_C_LABEL(intr_depth)@ha; \ 774 lwz 5,_C_LABEL(intr_depth)@l(5); \ 775 mfsrr0 4; \ 776 mfsrr1 3; \ 777 stw 6,IFRAME_CTR(1); \ 778 stw 5,IFRAME_INTR_DEPTH(1); \ 779 stw 4,IFRAME_SRR0(1); \ 780 stw 3,IFRAME_SRR1(1); \ 781 mtcr 3; \ 782 bc 4,17,99f; /* branch if PSL_PR is false */ \ 783/* interrupts are recoverable here, and enable translation */ \ 784 RESTORE_KERN_SRS(3,4); \ 785 CPU601_KERN_ENTRY(3,4); \ 78699: mfmsr 5; \ 787 ori 5,5,(PSL_IR|PSL_DR|PSL_RI); \ 788 mtmsr 5; \ 789 isync 790 791 .globl _C_LABEL(extint_call) 792extintr: 793 INTRENTER 794_C_LABEL(extint_call): 795 bl _C_LABEL(extint_call) /* to be filled in later */ 796 797intr_exit: 798/* Disable interrupts (should already be disabled) and MMU here: */ 799 mfmsr 3 800 andi. 3,3,~(PSL_EE|PSL_ME|PSL_RI|PSL_DR|PSL_IR)@l 801 mtmsr 3 802 isync 803/* restore possibly overwritten registers: */ 804 lwz 12,IFRAME_R12(1) 805 lwz 11,IFRAME_R11(1) 806 lwz 10,IFRAME_R10(1) 807 lwz 9,IFRAME_R9(1) 808 lwz 8,IFRAME_R8(1) 809 lwz 7,IFRAME_R7(1) 810 lwz 6,IFRAME_SRR1(1) 811 lwz 5,IFRAME_SRR0(1) 812 lwz 4,IFRAME_CTR(1) 813 lwz 3,IFRAME_XER(1) 814 mtsrr1 6 815 mtsrr0 5 816 mtctr 4 817 mtxer 3 818/* Returning to user mode? */ 819 mtcr 6 /* saved SRR1 */ 820 bc 4,17,1f /* branch if PSL_PR is false */ 821 CPU601_KERN_LEAVE(3,4) 822 RESTORE_USER_SRS(3,4) 823 lis 3,_C_LABEL(astpending)@ha /* Test AST pending */ 824 lwz 4,_C_LABEL(astpending)@l(3) 825 andi. 4,4,1 826 beq 1f 827/* Setup for entry to realtrap: */ 828 lwz 3,IFRAME_R1(1) /* get saved SP */ 829 mtsprg 1,3 830 li 6,EXC_AST 831 stmw 28,tempsave(0) /* establish tempsave again */ 832 mtlr 6 833 lwz 28,IFRAME_LR(1) /* saved LR */ 834 lwz 29,IFRAME_CR(1) /* saved CR */ 835 lwz 6,IFRAME_R6(1) 836 lwz 5,IFRAME_R5(1) 837 lwz 4,IFRAME_R4(1) 838 lwz 3,IFRAME_R3(1) 839 lwz 0,IFRAME_R0(1) 840 lis 30,_C_LABEL(intr_depth)@ha /* adjust reentrancy count */ 841 lwz 31,_C_LABEL(intr_depth)@l(30) 842 addi 31,31,-1 843 stw 31,_C_LABEL(intr_depth)@l(30) 844 b realtrap 8451: 846/* Here is the normal exit of extintr: */ 847 lwz 5,IFRAME_CR(1) 848 lwz 6,IFRAME_LR(1) 849 mtcr 5 850 mtlr 6 851 lwz 6,IFRAME_R6(1) 852 lwz 5,IFRAME_R5(1) 853 lis 3,_C_LABEL(intr_depth)@ha 854 lwz 4,_C_LABEL(intr_depth)@l(3) 855 addi 4,4,-1 /* adjust reentrancy count */ 856 stw 4,_C_LABEL(intr_depth)@l(3) 857 lwz 4,IFRAME_R4(1) 858 lwz 3,IFRAME_R3(1) 859 lwz 0,IFRAME_R0(1) 860 lwz 1,IFRAME_R1(1) 861 rfi 862 863/* 864 * Decrementer interrupt second level handler 865 */ 866decrintr: 867 INTRENTER 868 addi 3,1,8 /* intr frame -> clock frame */ 869 bl _C_LABEL(decr_intr) 870 b intr_exit 871 872#ifdef DDB 873/* 874 * Deliberate entry to ddbtrap 875 */ 876 .globl _C_LABEL(ddb_trap) 877_C_LABEL(ddb_trap): 878 mtsprg 1,1 879 mfmsr 3 880 mtsrr1 3 881 andi. 3,3,~(PSL_EE|PSL_ME)@l 882 mtmsr 3 /* disable interrupts */ 883 isync 884 stmw 28,ddbsave(0) 885 mflr 28 886 li 29,EXC_BPT 887 mtlr 29 888 mfcr 29 889 mtsrr0 28 890#endif /* DDB */ 891 892#if defined(DDB) || defined(KGDB) 893/* 894 * Now the ddb trap catching code. 895 */ 896ddbtrap: 897 FRAME_SETUP(ddbsave) 898/* Call C trap code: */ 899 addi 3,1,8 900 bl _C_LABEL(ddb_trap_glue) 901 or. 3,3,3 902 bne ddbleave 903/* This wasn't for DDB, so switch to real trap: */ 904 lwz 3,FRAME_EXC+8(1) /* save exception */ 905 stw 3,ddbsave+8(0) 906 FRAME_LEAVE(ddbsave) 907 mtsprg 1,1 /* prepare for entrance to realtrap */ 908 stmw 28,tempsave(0) 909 mflr 28 910 mfcr 29 911 lwz 31,ddbsave+8(0) 912 mtlr 31 913 b realtrap 914ddbleave: 915 FRAME_LEAVE(ddbsave) 916 rfi 917#endif /* DDB || KGDB */ 918 919#ifdef IPKDB 920/* 921 * Deliberate entry to ipkdbtrap 922 */ 923 .globl _C_LABEL(ipkdb_trap) 924_C_LABEL(ipkdb_trap): 925 mtsprg 1,1 926 mfmsr 3 927 mtsrr1 3 928 andi. 3,3,~(PSL_EE|PSL_ME)@l 929 mtmsr 3 /* disable interrupts */ 930 isync 931 stmw 28,ipkdbsave(0) 932 mflr 28 933 li 29,EXC_BPT 934 mtlr 29 935 mfcr 29 936 mtsrr0 28 937 938/* 939 * Now the ipkdb trap catching code. 940 */ 941ipkdbtrap: 942 FRAME_SETUP(ipkdbsave) 943/* Call C trap code: */ 944 addi 3,1,8 945 bl _C_LABEL(ipkdb_trap_glue) 946 or. 3,3,3 947 bne ipkdbleave 948/* This wasn't for IPKDB, so switch to real trap: */ 949 lwz 3,FRAME_EXC+8(1) /* save exception */ 950 stw 3,ipkdbsave+8(0) 951 FRAME_LEAVE(ipkdbsave) 952 mtsprg 1,1 /* prepare for entrance to realtrap */ 953 stmw 28,tempsave(0) 954 mflr 28 955 mfcr 29 956 lwz 31,ipkdbsave+8(0) 957 mtlr 31 958 b realtrap 959ipkdbleave: 960 FRAME_LEAVE(ipkdbsave) 961 rfi 962 963ipkdbfault: 964 ba _ipkdbfault 965_ipkdbfault: 966 mfsrr0 3 967 addi 3,3,4 968 mtsrr0 3 969 li 3,-1 970 rfi 971 972/* 973 * int ipkdbfbyte(unsigned char *p) 974 */ 975 .globl _C_LABEL(ipkdbfbyte) 976_C_LABEL(ipkdbfbyte): 977 li 9,EXC_DSI /* establish new fault routine */ 978 lwz 5,0(9) 979 lis 6,ipkdbfault@ha 980 lwz 6,ipkdbfault@l(6) 981 stw 6,0(9) 982#ifdef IPKDBUSERHACK 983 lis 8,_C_LABEL(ipkdbsr)@ha 984 lwz 8,_C_LABEL(ipkdbsr)@l(8) 985 mtsr USER_SR,8 986 isync 987#endif 988 dcbst 0,9 /* flush data... */ 989 sync 990 icbi 0,9 /* and instruction caches */ 991 lbz 3,0(3) /* fetch data */ 992 stw 5,0(9) /* restore previous fault handler */ 993 dcbst 0,9 /* and flush data... */ 994 sync 995 icbi 0,9 /* and instruction caches */ 996 blr 997 998/* 999 * int ipkdbsbyte(unsigned char *p, int c) 1000 */ 1001 .globl _C_LABEL(ipkdbsbyte) 1002_C_LABEL(ipkdbsbyte): 1003 li 9,EXC_DSI /* establish new fault routine */ 1004 lwz 5,0(9) 1005 lis 6,ipkdbfault@ha 1006 lwz 6,ipkdbfault@l(6) 1007 stw 6,0(9) 1008#ifdef IPKDBUSERHACK 1009 lis 8,_C_LABEL(ipkdbsr)@ha 1010 lwz 8,_C_LABEL(ipkdbsr)@l(8) 1011 mtsr USER_SR,8 1012 isync 1013#endif 1014 dcbst 0,9 /* flush data... */ 1015 sync 1016 icbi 0,9 /* and instruction caches */ 1017 mr 6,3 1018 xor 3,3,3 1019 stb 4,0(6) 1020 dcbst 0,6 /* Now do appropriate flushes 1021 to data... */ 1022 sync 1023 icbi 0,6 /* and instruction caches */ 1024 stw 5,0(9) /* restore previous fault handler */ 1025 dcbst 0,9 /* and flush data... */ 1026 sync 1027 icbi 0,9 /* and instruction caches */ 1028 blr 1029#endif /* IPKDB */ 1030 .globl _C_LABEL(trapend) 1031_C_LABEL(trapend): 1032