1/* $NetBSD: trap_subr.S,v 1.86 2022/05/18 13:56:32 andvar 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#ifdef _KERNEL_OPT 42#include "opt_altivec.h" 43#include "opt_ddb.h" 44#include "opt_kgdb.h" 45#include "opt_ppcarch.h" 46#endif 47 48/* LINTSTUB: include <sys/param.h> */ 49/* LINTSTUB: include <powerpc/oea/bat.h> */ 50 51#ifdef ALTIVEC 52#define SAVE_VRSAVE(tf,b) \ 53 mfspr b,SPR_VRSAVE; \ 54 stint b,FRAME_VRSAVE(tf); 55 56#define RESTORE_VRSAVE(tf,b) \ 57 ldint b,FRAME_VRSAVE(tf); \ 58 mtspr SPR_VRSAVE,b; 59#else 60#define SAVE_VRSAVE(tf,b) 61#define RESTORE_VRSAVE(tf,b) 62#endif 63 64#if defined (PPC_OEA64) || defined (PPC_OEA64_BRIDGE) 65#define RFI rfid 66#else 67#define RFI rfi 68#endif /* PPC_OEA64 || PPC_OEA64_BRIDGE*/ 69 70#if defined (PPC_OEA64_BRIDGE) 71#define ENABLE_64BIT_BRIDGE(t0) \ 72 mfmsr t0; \ 73 clrldi t0,t0,1; \ 74 mtmsrd t0; 75#else 76#define ENABLE_64BIT_BRIDGE(t0) 77#endif /* PPC_OEA64_BRIDGE */ 78 79#if defined(PPC_OEA64) 80/* 81 * User segment table is loaded through a pointer to the current pmap. 82 */ 83#define RESTORE_USER_SRS(t0,t1) \ 84 GET_CPUINFO(t0); \ 85 ldptr t0,CI_CURPM(t0); \ 86 ldreg t0,PM_STEG(t0); \ 87 mtasr t0 88 89/* 90 * Kernel segment table is loaded directly from kernel_pmap_ 91 */ 92#define RESTORE_KERN_SRS(t0,t1) \ 93 lis t0,_C_LABEL(kernel_pmap_)@ha; \ 94 ldreg t0,_C_LABEL(kernel_pmap_)+PM_STEG@l(t0); \ 95 mtasr t0 96 97#elif defined(PPC_MPC8XX) 98 99/* 100 * PPC_MPC8XX don't have SRs to load 101 */ 102#define RESTORE_USER_SRS(t0,t1) 103#define RESTORE_KERN_SRS(t0,t1) 104 105#else /* not OEA64 */ 106 107/* 108 * Restore segment registers from array. 109 */ 110#define RESTORE_SRS(pmap,sr) mtsr 0,sr; \ 111 ldreg sr,4(pmap); mtsr 1,sr; \ 112 ldreg sr,8(pmap); mtsr 2,sr; \ 113 ldreg sr,12(pmap); mtsr 3,sr; \ 114 ldreg sr,16(pmap); mtsr 4,sr; \ 115 ldreg sr,20(pmap); mtsr 5,sr; \ 116 ldreg sr,24(pmap); mtsr 6,sr; \ 117 ldreg sr,28(pmap); mtsr 7,sr; \ 118 ldreg sr,32(pmap); mtsr 8,sr; \ 119 ldreg sr,36(pmap); mtsr 9,sr; \ 120 ldreg sr,40(pmap); mtsr 10,sr; \ 121 ldreg sr,44(pmap); mtsr 11,sr; \ 122 ldreg sr,48(pmap); mtsr 12,sr; \ 123 ldreg sr,52(pmap); mtsr 13,sr; \ 124 ldreg sr,56(pmap); mtsr 14,sr; \ 125 ldreg sr,60(pmap); mtsr 15,sr; isync; 126 127/* 128 * User SRs are loaded through a pointer to the current pmap. 129 * Note: oea_init() relies on the 601 instruction sequence. 130 */ 131#define RESTORE_USER_SRS(pmap,sr) \ 132 GET_CPUINFO(pmap); \ 133 ldptr pmap,CI_CURPM(pmap); \ 134 ldregu sr,PM_SR(pmap); \ 135 RESTORE_SRS(pmap,sr); \ 136 /* Obliterate BATs on 601; reuse temporary registers. */ \ 137 li sr,0; \ 138 mtibatl 0,sr; \ 139 mtibatl 1,sr; \ 140 mtibatl 2,sr; \ 141 mtibatl 3,sr 142 143/* 144 * Kernel SRs are loaded directly from kernel_pmap_. 145 * Note: oea_init() relies on the 601 instruction sequence. 146 */ 147#define RESTORE_KERN_SRS(pmap,sr) \ 148 lis pmap,_C_LABEL(kernel_pmap_)@ha; \ 149 ldregu sr,_C_LABEL(kernel_pmap_)+PM_SR@l(pmap); \ 150 RESTORE_SRS(pmap,sr); \ 151 /* Restore fixed BATs on 601; reuse temporary registers. */ \ 152 lis pmap,_C_LABEL(battable)@ha; \ 153 ldregu sr,_C_LABEL(battable)@l(pmap); \ 154 mtibatu 0,sr; \ 155 ldreg sr,4(pmap); mtibatl 0,sr; \ 156 ldreg sr,8(pmap); mtibatu 1,sr; \ 157 ldreg sr,12(pmap); mtibatl 1,sr 158#endif /* (PPC_OEA64) */ 159 160/* 161 * Save/restore MPC601 MQ register. 162 * Note: oea_init() relies on this instruction sequence. 163 */ 164#if defined(PPC_OEA601) 165#define SAVE_MQ(tf,b) \ 166 mfspr b,SPR_MQ; \ 167 streg b,FRAME_MQ(tf); 168 169#define RESTORE_MQ(tf,b) \ 170 ldreg b,FRAME_MQ(tf); \ 171 mtspr SPR_MQ,b; 172#else 173#define SAVE_MQ(tf,b) 174#define RESTORE_MQ(tf,b) 175#endif 176 177/* 178 * This code gets copied to all the trap vectors 179 * (except ISI/DSI, ALI, the interrupts). 180 */ 181 182/* LINTSTUB: Var: int trapcode[1], trapsize[1]; */ 183 .text 184 .globl _C_LABEL(trapcode),_C_LABEL(trapsize) 185_C_LABEL(trapcode): 186 mtsprg1 %r1 /* save SP */ 187 ENABLE_64BIT_BRIDGE(%r1) 188 GET_CPUINFO(%r1) 189 streg %r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1) /* free r28 */ 190 streg %r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1) /* free r29 */ 191 streg %r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1) /* free r30 */ 192 streg %r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1) /* free r31 */ 193 mfsprg1 %r1 /* restore SP */ 194 mflr %r28 /* save LR */ 195 mfcr %r29 /* save CR */ 196/* Test whether we already had PR set */ 197 mfsrr1 %r31 198 mtcr %r31 199#if defined(DISTANT_KERNEL) 200 lis %r31,s_trap@ha 201 addi %r31,%r31,s_trap@l 202 mtlr %r31 203 blrl 204#else 205 bla s_trap 206#endif 207_C_LABEL(trapsize) = .-_C_LABEL(trapcode) 208 209/* 210 * For ALI: has to save DSISR and DAR 211 * Also used as dsitrap for BATless cpus. 212 */ 213/* LINTSTUB: Var: int alicode[1], alisize[1]; */ 214 .globl _C_LABEL(alitrap),_C_LABEL(alisize) 215_C_LABEL(alitrap): 216 mtsprg1 %r1 /* save SP */ 217 ENABLE_64BIT_BRIDGE(%r1) 218 GET_CPUINFO(%r1) 219 streg %r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1) /* save r28 */ 220 streg %r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1) /* save r29 */ 221 streg %r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1) /* save r30 */ 222 streg %r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1) /* save r31 */ 223 mfdar %r30 224 mfdsisr %r31 225 streg %r30,(CI_TEMPSAVE+CPUSAVE_DAR)(%r1) /* save dar */ 226 streg %r31,(CI_TEMPSAVE+CPUSAVE_DSISR)(%r1) /* save dsisr */ 227 mfsprg1 %r1 /* restore SP */ 228 mflr %r28 /* save LR */ 229 mfcr %r29 /* save CR */ 230/* Test whether we already had PR set */ 231 mfsrr1 %r31 232 mtcr %r31 233#if defined(DISTANT_KERNEL) 234 lis %r31,s_trap@ha 235 addi %r31,%r31,s_trap@l 236 mtlr %r31 237 blrl 238#else 239 bla s_trap 240#endif 241_C_LABEL(alisize) = .-_C_LABEL(alitrap) 242 243#if !defined(PPC_MPC8XX) 244/* 245 * Similar to the above for DSI 246 * Has to handle BAT spills 247 * and standard pagetable spills 248 */ 249/* LINTSTUB: Var: int dsicode[1], dsisize[1]; */ 250 .globl _C_LABEL(dsitrap),_C_LABEL(dsisize) 251_C_LABEL(dsitrap): 252 mtsprg1 %r1 253 ENABLE_64BIT_BRIDGE(%r1) 254 GET_CPUINFO(%r1) 255 streg %r28,(CI_DISISAVE+CPUSAVE_R28)(%r1) /* save r28 */ 256 streg %r29,(CI_DISISAVE+CPUSAVE_R29)(%r1) /* save r29 */ 257 streg %r30,(CI_DISISAVE+CPUSAVE_R30)(%r1) /* save r30 */ 258 streg %r31,(CI_DISISAVE+CPUSAVE_R31)(%r1) /* save r31 */ 259 mfsprg1 %r1 260 mfcr %r29 /* save CR */ 261 mfsrr1 %r31 /* test kernel mode */ 262 mtcr %r31 263#if !defined(PPC_MPC8XX) 264 mfxer %r30 /* save XER */ 265 mtsprg2 %r30 /* in SPRG2 */ 266 bt MSR_PR,1f /* branch if PSL_PR is set */ 267 mfdar %r31 /* get fault address */ 268 rlwinm %r31,%r31,3+(32-BAT_ADDR_SHIFT),BAT_ADDR_SHIFT-3,28 269 /* get segment * 8 */ 270 271 /* Get address of this CPU's current battable */ 272 GET_CPUINFO(%r30) 273 ldreg %r30,CI_BATTABLE(%r30) 274 275 /* Add offset to the slot we care about. */ 276 add %r31,%r31,%r30 277 278 /* get batu */ 279 ldreg %r30,0(%r31) 280 mtcr %r30 281 bf 30,1f /* branch if supervisor valid is 282 false */ 283 /* get batl */ 284 ldreg %r31,SZREG(%r31) 285/* We randomly use the highest two bat registers here */ 286 mftb %r28 287 mtcr %r28 288 .globl dsitrap_fix_dbat4, dsitrap_fix_dbat5 289 .globl dsitrap_fix_dbat6, dsitrap_fix_dbat7 290dsitrap_fix_dbat4: 291 bt 31,3f 292 /* 293 * If we are running on a CPU that has HIGHBAT, these will be replaced 294 * by instructions to test bit 30 (aka bit 1 for normal people) and if 295 * set skip ahead to 5f (4 instructions), follored by instructions to 296 * update BAT4. 297 */ 298 mtspr SPR_DBAT2U,%r30 /* bt 30,dsitrap_fix_dbat5 */ 299 mtspr SPR_DBAT2L,%r31 /* mtspr SPR_DBAT4U,%r30 */ 300 b 8f /* mtspr SPR_DBAT4L,%r31 */ 301 b 8f /* do not remove */ 302dsitrap_fix_dbat5: 303 mtspr SPR_DBAT5U,%r30 304 mtspr SPR_DBAT5L,%r31 305 b 8f 306dsitrap_fix_dbat6: 307 bt 30,3f 308 mtspr SPR_DBAT6U,%r30 309 mtspr SPR_DBAT6L,%r31 310 b 8f 3113: 312dsitrap_fix_dbat7: 313 /* 314 * If we are running on a CPU that has HIGHBAT, these will be replaced 315 * by instructions to update BAT7. 316 */ 317 mtspr SPR_DBAT3U,%r30 /* mtspr SPR_DBAT7U,%r30 */ 318 mtspr SPR_DBAT3L,%r31 /* mtspr SPR_DBAT7L,%r31 */ 3198: 320 mfsprg2 %r30 /* restore XER */ 321 mtxer %r30 322 mtcr %r29 /* restore CR */ 323 mtsprg1 %r1 324 GET_CPUINFO(%r1) 325 ldreg %r28,(CI_DISISAVE+CPUSAVE_R28)(%r1) /* restore r28 */ 326 ldreg %r29,(CI_DISISAVE+CPUSAVE_R29)(%r1) /* restore r29 */ 327 ldreg %r30,(CI_DISISAVE+CPUSAVE_R30)(%r1) /* restore r30 */ 328 ldreg %r31,(CI_DISISAVE+CPUSAVE_R31)(%r1) /* restore r31 */ 329 mfsprg1 %r1 330 RFI /* return to trapped code */ 3311: 332#endif /* !PPC_MPC8XX */ 333 mflr %r28 /* save LR */ 334 mtsprg1 %r1 /* save SP */ 335#if defined(DISTANT_KERNEL) 336 lis %r31,disitrap@ha 337 addi %r31,%r31,disitrap@l 338 mtlr %r31 339 blrl 340#else 341 bla disitrap 342#endif 343_C_LABEL(dsisize) = .-_C_LABEL(dsitrap) 344#endif /* !PPC_MPC8XX */ 345 346#if defined(PPC_OEA601) 347/* 348 * Dedicated MPC601 version of the above. 349 * Considers different BAT format and combined implementation 350 * (being addressed as I-BAT). 351 */ 352/* LINTSTUB: Var: int dsi601code[1], dsi601size[1]; */ 353 .globl _C_LABEL(dsi601trap),_C_LABEL(dsi601size) 354_C_LABEL(dsi601trap): 355 mtsprg1 %r1 356 ENABLE_64BIT_BRIDGE(%r1) 357 GET_CPUINFO(%r1) 358 streg %r28,(CI_DISISAVE+CPUSAVE_R28)(%r1) /* save r28 */ 359 streg %r29,(CI_DISISAVE+CPUSAVE_R29)(%r1) /* save r29 */ 360 streg %r30,(CI_DISISAVE+CPUSAVE_R30)(%r1) /* save r30 */ 361 streg %r31,(CI_DISISAVE+CPUSAVE_R31)(%r1) /* save r31 */ 362 mfsprg1 %r1 363 mfcr %r29 /* save CR */ 364 mfxer %r30 /* save XER */ 365 mtsprg2 %r30 /* in SPRG2 */ 366 mfsrr1 %r31 /* test kernel mode */ 367 mtcr %r31 368 bt MSR_PR,1f /* branch if PSL_PR is set */ 369 mfdar %r31 /* get fault address */ 370 rlwinm %r31,%r31,12,20,28 /* get "segment" battable offset */ 371 372 /* Get address of this CPU's current battable */ 373 GET_CPUINFO(%r30) 374 ldreg %r30,CI_BATTABLE(%r30) 375 376 /* Add offset to the slot we care about. */ 377 add %r31,%r31,%r30 378 379 /* get batl */ 380 ldreg %r30,SZREG(%r31) 381 mtcr %r30 382 bf 25,1f /* branch if Valid is false, 383 presently assumes supervisor only */ 384 385 /* get batu */ 386 ldreg %r31,0(%r31) 387/* We randomly use the highest two bat registers here */ 388 mfspr %r28,SPR_RTCL_R 389 andi. %r28,%r28,128 390 bne 2f 391 mtibatu 2,%r31 392 mtibatl 2,%r30 393 b 3f 3942: 395 mtibatu 3,%r31 396 mtibatl 3,%r30 3973: 398 mfsprg2 %r30 /* restore XER */ 399 mtxer %r30 400 mtcr %r29 /* restore CR */ 401 mtsprg1 %r1 402 GET_CPUINFO(%r1) 403 ldreg %r28,(CI_DISISAVE+CPUSAVE_R28)(%r1) /* restore r28 */ 404 ldreg %r29,(CI_DISISAVE+CPUSAVE_R29)(%r1) /* restore r29 */ 405 ldreg %r30,(CI_DISISAVE+CPUSAVE_R30)(%r1) /* restore r30 */ 406 ldreg %r31,(CI_DISISAVE+CPUSAVE_R31)(%r1) /* restore r31 */ 407 mfsprg1 %r1 408 RFI /* return to trapped code */ 4091: 410 mflr %r28 /* save LR */ 411 mtsprg1 %r1 412#if defined(DISTANT_KERNEL) 413 lis %r31,disitrap@ha 414 addi %r31,%r31,disitrap@l 415 mtlr %r31 416 blrl 417#else 418 bla disitrap 419#endif 420_C_LABEL(dsi601size) = .-_C_LABEL(dsi601trap) 421#endif /* defined(PPC_OEA601) */ 422 423/* 424 * This one for the external interrupt handler. 425 */ 426/* LINTSTUB: Var: int extint[1], extsize[1]; */ 427 .globl _C_LABEL(extint),_C_LABEL(extsize) 428_C_LABEL(extint): 429 mtsprg1 %r1 /* save SP */ 430 ENABLE_64BIT_BRIDGE(%r1) 431 GET_CPUINFO(%r1) 432 streg %r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1) /* save r28 */ 433 streg %r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1) /* save r29 */ 434 streg %r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1) /* save r30 */ 435 streg %r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1) /* save r31 */ 436 mflr %r28 /* save LR */ 437 mfcr %r29 /* save CR */ 438 mfsrr1 %r31 439 mtcr %r31 440 mr %r30,%r1 441 mfsprg1 %r1 /* get old SP */ 442 bf MSR_PR,1f /* branch if PSL_PR is true */ 443 ldptr %r1,CI_CURPCB(%r30) /* get kernel stack */ 444 addi %r1,%r1,USPACE-CALLFRAMELEN /* stack is top of user struct */ 445 RESTORE_KERN_SRS(%r30, %r31) 4461: 447#if defined(DISTANT_KERNEL) 448 lis %r31,extintr@ha 449 addi %r31,%r31,extintr@l 450 mtlr %r31 451 blr 452#else 453 ba extintr 454#endif 455_C_LABEL(extsize) = .-_C_LABEL(extint) 456 457/* 458 * And this one for the decrementer interrupt handler. 459 */ 460/* LINTSTUB: Var: int decrint[1], decrsize[1]; */ 461 .globl _C_LABEL(decrint),_C_LABEL(decrsize) 462_C_LABEL(decrint): 463 mtsprg1 %r1 /* save SP */ 464 ENABLE_64BIT_BRIDGE(%r1) 465 GET_CPUINFO(%r1) 466 streg %r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1) /* save r28 */ 467 streg %r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1) /* save r29 */ 468 streg %r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1) /* save r30 */ 469 streg %r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1) /* save r31 */ 470 mflr %r28 /* save LR */ 471 mfcr %r29 /* save CR */ 472 mfsrr1 %r31 473 mtcr %r31 474 mr %r30,%r1 475 mfsprg1 %r1 /* yes, get old SP */ 476 bf MSR_PR,1f /* branch if PSL_PR is true */ 477 ldptr %r1,CI_CURPCB(%r30) /* get kernel stack */ 478 addi %r1,%r1,USPACE-CALLFRAMELEN /* stack is top of user struct */ 479 RESTORE_KERN_SRS(%r30, %r31) 4801: 481#if defined(DISTANT_KERNEL) 482 lis %r31,decrintr@ha 483 addi %r31,%r31,decrintr@l 484 mtlr %r31 485 blr 486#else 487 ba decrintr 488#endif 489_C_LABEL(decrsize) = .-_C_LABEL(decrint) 490 491#if !defined(PPC_OEA64) && !defined(PPC_MPC8XX) 492/* 493 * Now the tlb software load for 603 processors: 494 * (Code essentially from the 603e User Manual, Chapter 5, but 495 * corrected a lot.) 496 */ 497/* LINTSTUB: Var: int tlbimiss[1], tlbimsize[1]; */ 498 .globl _C_LABEL(tlbimiss),_C_LABEL(tlbimsize) 499_C_LABEL(tlbimiss): 500 mfspr %r2,SPR_HASH1 /* get first pointer */ 501 li %r1,8 502 mfctr %r0 /* save counter */ 503 mfspr %r3,SPR_ICMP /* get first compare value */ 504 addi %r2,%r2,-8 /* predec pointer */ 5051: 506 mtctr %r1 /* load counter */ 5072: 508 ldregu %r1,8(%r2) /* get next pte */ 509 cmplw %r1,%r3 /* see if found pte */ 510 bdneq 2b /* loop if not eq */ 511 bne 3f /* not found */ 512 ldreg %r1,4(%r2) /* load tlb entry lower word */ 513 andi. %r3,%r1,PTE_G /* check G-bit */ 514 bne 4f /* if guarded, take ISI */ 515 mtctr %r0 /* restore counter */ 516 mfspr %r0,SPR_IMISS /* get the miss address for the tlbli */ 517 mfsrr1 %r3 /* get the saved cr0 bits */ 518 mtcrf 0x80,%r3 /* and restore */ 519 ori %r1,%r1,PTE_REF /* set the reference bit */ 520 mtspr SPR_RPA,1 /* set the pte */ 521 srwi %r1,%r1,8 /* get byte 7 of pte */ 522 tlbli %r0 /* load the itlb */ 523 stb %r1,6(%r2) /* update page table */ 524 RFI 525 5263: /* not found in pteg */ 527 andi. %r1,%r3,PTE_HID /* have we already done second hash? */ 528 bne 5f 529 mfspr %r2,SPR_HASH2 /* get the second pointer */ 530 ori %r3,%r3,PTE_HID /* change the compare value */ 531 li %r1,8 532 addi %r2,%r2,-8 /* predec pointer */ 533 b 1b 5344: /* guarded */ 535 mfsrr1 %r3 536 andi. %r2,%r3,0xffff /* clean upper srr1 */ 537 oris %r2,%r2,DSISR_PROTECT@h /* set srr<4> to flag prot violation */ 538 b 6f 5395: /* not found anywhere */ 540 mfsrr1 %r3 541 andi. %r2,%r3,0xffff /* clean upper srr1 */ 542 oris %r2,%r2,DSISR_NOTFOUND@h /* set srr1<1> to flag pte not found */ 5436: 544 mtctr %r0 /* restore counter */ 545 mtsrr1 %r2 546 mfmsr %r0 547 xoris %r0,%r0,PSL_TGPR@h /* flip the msr<tgpr> bit */ 548 mtcrf 0x80,%r3 /* restore cr0 */ 549 mtmsr %r0 /* now with native gprs */ 550 isync 551#if defined(PPC_HIGH_VEC) 552 ba EXC_HIGHVEC+EXC_ISI 553#else 554 ba EXC_ISI 555#endif 556_C_LABEL(tlbimsize) = .-_C_LABEL(tlbimiss) 557 558/* LINTSTUB: Var: int tlbdlmiss[1], tlbdlmsize[1]; */ 559 .globl _C_LABEL(tlbdlmiss),_C_LABEL(tlbdlmsize) 560_C_LABEL(tlbdlmiss): 561 mfspr %r2,SPR_HASH1 /* get first pointer */ 562 li %r1,8 563 mfctr %r0 /* save counter */ 564 mfspr %r3,SPR_DCMP /* get first compare value */ 565 addi %r2,%r2,-8 /* predec pointer */ 5661: 567 mtctr %r1 /* load counter */ 5682: 569 ldregu %r1,8(%r2) /* get next pte */ 570 cmplw %r1,%r3 /* see if found pte */ 571 bdneq 2b /* loop if not eq */ 572 bne 3f /* not found */ 573 ldreg %r1,4(%r2) /* load tlb entry lower word */ 574 mtctr %r0 /* restore counter */ 575 mfspr %r0,SPR_DMISS /* get the miss address for the tlbld */ 576 mfsrr1 %r3 /* get the saved cr0 bits */ 577 mtcrf 0x80,%r3 /* and restore */ 578 ori %r1,%r1,PTE_REF /* set the reference bit */ 579 mtspr SPR_RPA,%r1 /* set the pte */ 580 srwi %r1,%r1,8 /* get byte 7 of pte */ 581 tlbld %r0 /* load the dtlb */ 582 stb %r1,6(%r2) /* update page table */ 583 RFI 584 5853: /* not found in pteg */ 586 andi. %r1,%r3,PTE_HID /* have we already done second hash? */ 587 bne 5f 588 mfspr %r2,SPR_HASH2 /* get the second pointer */ 589 ori %r3,%r3,PTE_HID /* change the compare value */ 590 li %r1,8 591 addi %r2,%r2,-8 /* predec pointer */ 592 b 1b 5935: /* not found anywhere */ 594 mfsrr1 %r3 595 lis %r1,DSISR_NOTFOUND@h /* set dsisr<1> to flag pte not found */ 596 mtctr %r0 /* restore counter */ 597 andi. %r2,%r3,0xffff /* clean upper srr1 */ 598 mtsrr1 %r2 599 mtdsisr %r1 /* load the dsisr */ 600 mfspr %r1,SPR_DMISS /* get the miss address */ 601 mtdar %r1 /* put in dar */ 602 mfmsr %r0 603 xoris %r0,%r0,PSL_TGPR@h /* flip the msr<tgpr> bit */ 604 mtcrf 0x80,%r3 /* restore cr0 */ 605 mtmsr %r0 /* now with native gprs */ 606 isync 607#if defined(PPC_HIGH_VEC) 608 ba EXC_HIGHVEC+EXC_DSI 609#else 610 ba EXC_DSI 611#endif 612_C_LABEL(tlbdlmsize) = .-_C_LABEL(tlbdlmiss) 613 614/* LINTSTUB: Var: int tlbdsmiss[1], tlbdsmsize[1]; */ 615 .globl _C_LABEL(tlbdsmiss),_C_LABEL(tlbdsmsize) 616_C_LABEL(tlbdsmiss): 617 mfspr %r2,SPR_HASH1 /* get first pointer */ 618 li %r1,8 619 mfctr %r0 /* save counter */ 620 mfspr %r3,SPR_DCMP /* get first compare value */ 621 addi %r2,%r2,-8 /* predec pointer */ 6221: 623 mtctr %r1 /* load counter */ 6242: 625 ldregu %r1,8(%r2) /* get next pte */ 626 cmplw %r1,%r3 /* see if found pte */ 627 bdneq 2b /* loop if not eq */ 628 bne 3f /* not found */ 629 ldreg %r1,4(%r2) /* load tlb entry lower word */ 630 andi. %r3,%r1,PTE_CHG /* check the C-bit */ 631 beq 4f 6325: 633 mtctr %r0 /* restore counter */ 634 mfspr %r0,SPR_DMISS /* get the miss address for the tlbld */ 635 mfsrr1 %r3 /* get the saved cr0 bits */ 636 mtcrf 0x80,%r3 /* and restore */ 637 mtspr SPR_RPA,%r1 /* set the pte */ 638 tlbld %r0 /* load the dtlb */ 639 RFI 640 6413: /* not found in pteg */ 642 andi. %r1,%r3,PTE_HID /* have we already done second hash? */ 643 bne 5f 644 mfspr %r2,SPR_HASH2 /* get the second pointer */ 645 ori %r3,%r3,PTE_HID /* change the compare value */ 646 li %r1,8 647 addi %r2,%r2,-8 /* predec pointer */ 648 b 1b 6494: /* found, but C-bit = 0 */ 650 rlwinm. %r3,%r1,30,0,1 /* test PP */ 651 bge- 7f 652 andi. %r3,%r1,1 653 beq+ 8f 6549: /* found, but protection violation (PP==00)*/ 655 mfsrr1 %r3 656 lis %r1,(DSISR_PROTECT|DSISR_STORE)@h 657 /* indicate protection violation 658 on store */ 659 b 1f 6607: /* found, PP=1x */ 661 mfspr %r3,SPR_DMISS /* get the miss address */ 662 mfsrin %r1,%r3 /* get the segment register */ 663 mfsrr1 %r3 664 rlwinm %r3,%r3,18,31,31 /* get PR-bit */ 665 rlwnm. %r1,%r1,%r3,1,1 /* get the key */ 666 bne- 9b /* protection violation */ 6678: /* found, set reference/change bits */ 668 ldreg %r1,4(%r2) /* reload tlb entry */ 669 ori %r1,%r1,(PTE_REF|PTE_CHG) 670 sth %r1,6(%r2) 671 b 5b 6725: /* not found anywhere */ 673 mfsrr1 %r3 674 lis %r1,(DSISR_NOTFOUND|DSISR_STORE)@h 675 /* set dsisr<1> to flag pte not found */ 676 /* dsisr<6> to flag store */ 6771: 678 mtctr %r0 /* restore counter */ 679 andi. %r2,%r3,0xffff /* clean upper srr1 */ 680 mtsrr1 %r2 681 mtdsisr %r1 /* load the dsisr */ 682 mfspr %r1,SPR_DMISS /* get the miss address */ 683 mtdar %r1 /* put in dar */ 684 mfmsr %r0 685 xoris %r0,%r0,PSL_TGPR@h /* flip the msr<tgpr> bit */ 686 mtcrf 0x80,%r3 /* restore cr0 */ 687 mtmsr %r0 /* now with native gprs */ 688 isync 689#if defined(PPC_HIGH_VEC) 690 ba EXC_HIGHVEC+EXC_DSI 691#else 692 ba EXC_DSI 693#endif 694_C_LABEL(tlbdsmsize) = .-_C_LABEL(tlbdsmiss) 695#endif /* !PPC_OEA64 && !PPC_MPC8XX */ 696 697#if defined(DDB) || defined(KGDB) 698/* 699 * In case of DDB we want a separate trap catcher for it 700 */ 701 .local ddbstk 702 .comm ddbstk,INTSTK,8 /* ddb stack */ 703 704/* LINTSTUB: Var: int ddblow[1], ddbsize[1]; */ 705 .globl _C_LABEL(ddblow),_C_LABEL(ddbsize) 706_C_LABEL(ddblow): 707 mtsprg1 %r1 /* save SP */ 708 ENABLE_64BIT_BRIDGE(%r1) 709 mtsprg2 %r29 /* save r29 */ 710 mfcr %r29 /* save CR in r29 */ 711 mfsrr1 %r1 712 mtcr %r1 713 GET_CPUINFO(%r1) 714 bf MSR_PR,1f /* branch if privileged */ 715 streg %r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1) /* free r28 */ 716 mfsprg2 %r28 717 streg %r28,(CI_TEMPSAVE+CPUSAVE_R29)(%r1) /* free r29 */ 718 streg %r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1) /* free r30 */ 719 streg %r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1) /* free r31 */ 720 mflr %r28 /* save LR */ 721#if defined(DISTANT_KERNEL) 722 lis %r31,u_trap@ha 723 addi %r31,%r31,u_trap@l 724 mtlr %r31 725 blrl 726#else 727 bla u_trap 728#endif 7291: 730 streg %r28,(CI_DDBSAVE+CPUSAVE_R28)(%r1) /* save r28 */ 731 mfsprg2 %r28 732 streg %r28,(CI_DDBSAVE+CPUSAVE_R29)(%r1) /* save r29 */ 733 streg %r30,(CI_DDBSAVE+CPUSAVE_R30)(%r1) /* save r30 */ 734 streg %r31,(CI_DDBSAVE+CPUSAVE_R31)(%r1) /* save r31 */ 735 mflr %r28 /* save LR */ 736 lis %r1,ddbstk+INTSTK@ha /* get new SP */ 737 addi %r1,%r1,ddbstk+INTSTK@l 738#if defined(DISTANT_KERNEL) 739 lis %r31,ddbtrap@ha 740 addi %r31,%r31,ddbtrap@l 741 mtlr %r31 742 blrl 743#else 744 bla ddbtrap 745#endif 746_C_LABEL(ddbsize) = .-_C_LABEL(ddblow) 747#endif /* DDB || KGDB */ 748 749/* 750 * FRAME_SETUP assumes: 751 * SPRG1 SP (%r1) 752 * savearea r28-r31,DAR,DSISR (DAR & DSISR only for DSI traps) 753 * 28 LR 754 * 29 CR 755 * 30 scratch 756 * 31 scratch 757 * 1 kernel stack 758 * LR trap type 759 * SRR0/1 as at start of trap 760 */ 761#define FRAME_SETUP(savearea) \ 762/* Have to enable translation to allow access of kernel stack: */ \ 763 GET_CPUINFO(%r31); \ 764 mfsrr0 %r30; \ 765 streg %r30,(savearea+CPUSAVE_SRR0)(%r31); /* save SRR0 */ \ 766 mfsrr1 %r30; \ 767 streg %r30,(savearea+CPUSAVE_SRR1)(%r31); /* save SRR1 */ \ 768 mfmsr %r30; \ 769 ori %r30,%r30,(PSL_DR|PSL_IR); /* turn on relocation */ \ 770 mtmsr %r30; /* stack can be accessed now */ \ 771 isync; \ 772 mfsprg1 %r31; /* get saved SP */ \ 773 stregu %r31,-FRAMELEN(%r1); /* save it in the callframe */ \ 774 streg %r0,FRAME_R0(%r1); /* save R0 in the trapframe */ \ 775 streg %r31,FRAME_R1(%r1); /* save SP in the trapframe */ \ 776 streg %r2,FRAME_R2(%r1); /* save R2 in the trapframe */ \ 777 streg %r28,FRAME_LR(%r1); \ 778 stint %r29,FRAME_CR(%r1); \ 779 GET_CPUINFO(%r2); \ 780 ldreg %r31,(savearea+CPUSAVE_R31)(%r2); /* get saved r31 */ \ 781 ldreg %r30,(savearea+CPUSAVE_R30)(%r2); /* get saved r30 */ \ 782 ldreg %r29,(savearea+CPUSAVE_R29)(%r2); /* get saved r29 */ \ 783 ldreg %r28,(savearea+CPUSAVE_R28)(%r2); /* get saved r28 */ \ 784 streg %r3,FRAME_R3(%r1); /* save r3 */ \ 785 streg %r4,FRAME_R4(%r1); /* save r4 */ \ 786 streg %r5,FRAME_R5(%r1); /* save r5 */ \ 787 streg %r6,FRAME_R6(%r1); /* save r6 */ \ 788 streg %r7,FRAME_R7(%r1); /* save r7 */ \ 789 streg %r8,FRAME_R8(%r1); /* save r8 */ \ 790 streg %r9,FRAME_R9(%r1); /* save r9 */ \ 791 streg %r10,FRAME_R10(%r1); /* save r10 */ \ 792 streg %r11,FRAME_R11(%r1); /* save r11 */ \ 793 streg %r12,FRAME_R12(%r1); /* save r12 */ \ 794 streg %r13,FRAME_R13(%r1); /* save r13 */ \ 795 streg %r14,FRAME_R14(%r1); /* save r14 */ \ 796 streg %r15,FRAME_R15(%r1); /* save r15 */ \ 797 streg %r16,FRAME_R16(%r1); /* save r16 */ \ 798 streg %r17,FRAME_R17(%r1); /* save r17 */ \ 799 streg %r18,FRAME_R18(%r1); /* save r18 */ \ 800 streg %r19,FRAME_R19(%r1); /* save r19 */ \ 801 streg %r20,FRAME_R20(%r1); /* save r20 */ \ 802 streg %r21,FRAME_R21(%r1); /* save r21 */ \ 803 streg %r22,FRAME_R22(%r1); /* save r22 */ \ 804 streg %r23,FRAME_R23(%r1); /* save r23 */ \ 805 streg %r24,FRAME_R24(%r1); /* save r24 */ \ 806 streg %r25,FRAME_R25(%r1); /* save r25 */ \ 807 streg %r26,FRAME_R26(%r1); /* save r26 */ \ 808 streg %r27,FRAME_R27(%r1); /* save r27 */ \ 809 streg %r28,FRAME_R28(%r1); /* save r28 */ \ 810 streg %r29,FRAME_R29(%r1); /* save r29 */ \ 811 streg %r30,FRAME_R30(%r1); /* save r30 */ \ 812 streg %r31,FRAME_R31(%r1); /* save r31 */ \ 813 ldreg %r28,(savearea+CPUSAVE_DAR)(%r2); /* get saved DAR */ \ 814 ldreg %r29,(savearea+CPUSAVE_DSISR)(%r2); /* get saved DSISR */ \ 815 ldreg %r30,(savearea+CPUSAVE_SRR0)(%r2); /* get saved SRR0 */ \ 816 ldreg %r31,(savearea+CPUSAVE_SRR1)(%r2); /* get saved SRR1 */ \ 817 ldptr %r13,CI_CURLWP(%r2); /* get curlwp */ \ 818 mfxer %r3; \ 819 mfctr %r4; \ 820 mflr %r5; \ 821 andi. %r5,%r5,0xff00; \ 822 stint %r3,FRAME_XER(%r1); \ 823 streg %r4,FRAME_CTR(%r1); \ 824 streg %r30,FRAME_SRR0(%r1); \ 825 streg %r31,FRAME_SRR1(%r1); \ 826 streg %r28,FRAME_DAR(%r1); \ 827 stint %r29,FRAME_DSISR(%r1); \ 828 stint %r5,FRAME_EXC(%r1); \ 829 SAVE_VRSAVE(%r1,%r6); \ 830 SAVE_MQ(%r1,%r7) 831 832#define FRAME_RESTORE_CALLEE \ 833 ldreg %r31,FRAME_R31(%r1); /* restore r31 */ \ 834 ldreg %r30,FRAME_R30(%r1); /* restore r30 */ \ 835 ldreg %r29,FRAME_R29(%r1); /* restore r29 */ \ 836 ldreg %r28,FRAME_R28(%r1); /* restore r28 */ \ 837 ldreg %r27,FRAME_R27(%r1); /* restore r27 */ \ 838 ldreg %r26,FRAME_R26(%r1); /* restore r26 */ \ 839 ldreg %r25,FRAME_R25(%r1); /* restore r25 */ \ 840 ldreg %r24,FRAME_R24(%r1); /* restore r24 */ \ 841 ldreg %r23,FRAME_R23(%r1); /* restore r23 */ \ 842 ldreg %r22,FRAME_R22(%r1); /* restore r22 */ \ 843 ldreg %r21,FRAME_R21(%r1); /* restore r21 */ \ 844 ldreg %r20,FRAME_R20(%r1); /* restore r20 */ \ 845 ldreg %r19,FRAME_R19(%r1); /* restore r19 */ \ 846 ldreg %r18,FRAME_R18(%r1); /* restore r18 */ \ 847 ldreg %r17,FRAME_R17(%r1); /* restore r17 */ \ 848 ldreg %r16,FRAME_R16(%r1); /* restore r16 */ \ 849 ldreg %r15,FRAME_R15(%r1); /* restore r15 */ \ 850 ldreg %r14,FRAME_R14(%r1); /* restore r14 */ 851 852#define FRAME_LEAVE(savearea) \ 853/* Now restore regs: */ \ 854 ldreg %r2,FRAME_SRR0(%r1); \ 855 ldreg %r3,FRAME_SRR1(%r1); \ 856 ldreg %r4,FRAME_CTR(%r1); \ 857 ldint %r5,FRAME_XER(%r1); \ 858 ldreg %r6,FRAME_LR(%r1); \ 859 RESTORE_MQ(%r1,%r8); \ 860 RESTORE_VRSAVE(%r1,%r9); \ 861 GET_CPUINFO(%r7); \ 862 streg %r2,(savearea+CPUSAVE_SRR0)(%r7); /* save SRR0 */ \ 863 streg %r3,(savearea+CPUSAVE_SRR1)(%r7); /* save SRR1 */ \ 864 ldint %r7,FRAME_CR(%r1); \ 865 mtctr %r4; \ 866 mtxer %r5; \ 867 mtlr %r6; \ 868 mtsprg1 %r7; /* save cr */ \ 869 ldreg %r13,FRAME_R13(%r1); /* restore r13 */ \ 870 ldreg %r12,FRAME_R12(%r1); /* restore r12 */ \ 871 ldreg %r11,FRAME_R11(%r1); /* restore r11 */ \ 872 ldreg %r10,FRAME_R10(%r1); /* restore r10 */ \ 873 ldreg %r9,FRAME_R9(%r1); /* restore r9 */ \ 874 ldreg %r8,FRAME_R8(%r1); /* restore r8 */ \ 875 ldreg %r7,FRAME_R7(%r1); /* restore r7 */ \ 876 ldreg %r6,FRAME_R6(%r1); /* restore r6 */ \ 877 ldreg %r5,FRAME_R5(%r1); /* restore r5 */ \ 878 ldreg %r4,FRAME_R4(%r1); /* restore r4 */ \ 879 ldreg %r3,FRAME_R3(%r1); /* restore r3 */ \ 880 ldreg %r2,FRAME_R2(%r1); /* restore r2 */ \ 881 ldreg %r0,FRAME_R0(%r1); /* restore r0 */ \ 882 ldreg %r1,FRAME_R1(%r1); /* restore old sp in r1 */ \ 883/* Can't touch %r1 from here on */ \ 884 mtsprg2 %r2; /* save r2 & r3 */ \ 885 mtsprg3 %r3; \ 886/* Disable translation, machine check and recoverability: */ \ 887 mfmsr %r2; \ 888 andi. %r2,%r2,~(PSL_DR|PSL_IR|PSL_ME|PSL_RI)@l; \ 889 mtmsr %r2; \ 890 isync; \ 891/* Decide whether we return to user mode: */ \ 892 GET_CPUINFO(%r2); \ 893 ldreg %r3,(savearea+CPUSAVE_SRR1)(%r2); \ 894 mtcr %r3; \ 895 bf MSR_PR,1f; /* branch if PSL_PR is false */ \ 896/* Restore user SRs */ \ 897 RESTORE_USER_SRS(%r2,%r3); \ 8981: mfsprg1 %r2; /* restore cr */ \ 899 mtcr %r2; \ 900 GET_CPUINFO(%r2); \ 901 ldreg %r3,(savearea+CPUSAVE_SRR0)(%r2); \ 902 mtsrr0 %r3; \ 903 ldreg %r3,(savearea+CPUSAVE_SRR1)(%r2); \ 904 mtsrr1 %r3; \ 905 mfsprg2 %r2; /* restore r2 & r3 */ \ 906 mfsprg3 %r3 907 908/* 909 * Preamble code for DSI/ISI traps 910 */ 911disitrap: 912 GET_CPUINFO(%r1) 913 ldreg %r30,(CI_DISISAVE+CPUSAVE_R28)(%r1) 914 streg %r30,(CI_TEMPSAVE+CPUSAVE_R28)(%r1) 915 ldreg %r31,(CI_DISISAVE+CPUSAVE_R29)(%r1) 916 streg %r31,(CI_TEMPSAVE+CPUSAVE_R29)(%r1) 917 ldreg %r30,(CI_DISISAVE+CPUSAVE_R30)(%r1) 918 streg %r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1) 919 ldreg %r31,(CI_DISISAVE+CPUSAVE_R31)(%r1) 920 streg %r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1) 921 mfdar %r30 922 mfdsisr %r31 923 streg %r30,(CI_TEMPSAVE+CPUSAVE_DAR)(%r1) 924 streg %r31,(CI_TEMPSAVE+CPUSAVE_DSISR)(%r1) 925 926#ifdef DDB 927 mfsrr1 %r31 928 mtcr %r31 929 bt MSR_PR,trapstart /* branch is user mode */ 930 mfsprg1 %r31 /* get old SP */ 931#if 0 932 subf %r30,%r30,%r31 /* subtract DAR from it */ 933 addi %r30,%r30,2048 /* offset result 1/2 page */ 934 cmplwi %cr0,%r30,4096 /* is DAR +- 1/2 page of SP? */ 935#else 936 xor. %r30,%r30,%r31 /* try xor most significant bits */ 937 cmplwi %cr0,%r30,4096 /* is DAR on same page as SP? */ 938#endif 939 bge %cr0,trapstart /* no, too far away. */ 940 /* Now convert this DSI into a DDB trap. */ 941 GET_CPUINFO(%r1) 942 ldreg %r30,(CI_DISISAVE+CPUSAVE_R28)(%r1) /* get r28 */ 943 streg %r30,(CI_DDBSAVE +CPUSAVE_R28)(%r1) /* save r28 */ 944 ldreg %r31,(CI_DISISAVE+CPUSAVE_R29)(%r1) /* get r29 */ 945 streg %r31,(CI_DDBSAVE +CPUSAVE_R29)(%r1) /* save r29 */ 946 ldreg %r30,(CI_DISISAVE+CPUSAVE_R30)(%r1) /* get r30 */ 947 streg %r30,(CI_DDBSAVE +CPUSAVE_R30)(%r1) /* save r30 */ 948 ldreg %r31,(CI_DISISAVE+CPUSAVE_R31)(%r1) /* get r31 */ 949 streg %r31,(CI_DDBSAVE +CPUSAVE_R31)(%r1) /* save r31 */ 950 lis %r1,ddbstk+INTSTK@ha /* get new SP */ 951 addi %r1,%r1,ddbstk+INTSTK@l 952 b ddbtrap 953#endif 954 955 .globl _C_LABEL(trapstart) 956 .type _C_LABEL(trapstart),@function 957_C_LABEL(trapstart): 958realtrap: 959/* Test whether we already had PR set */ 960 mfsrr1 %r1 961 mtcr %r1 962 mfsprg1 %r1 /* restore SP (might have been 963 overwritten) */ 964s_trap: 965 bf MSR_PR,k_trap /* branch if PSL_PR is false */ 966 GET_CPUINFO(%r1) /* get cpu_info for this cpu */ 967u_trap: 968 ldptr %r1,CI_CURPCB(%r1) 969 addi %r1,%r1,USPACE-CALLFRAMELEN /* stack is top of user struct */ 970 971/* 972 * Now the common trap catching code. 973 */ 974 975 RESTORE_KERN_SRS(%r30,%r31) /* First enable KERNEL mapping */ 976 977k_trap: 978 FRAME_SETUP(CI_TEMPSAVE) 979trapagain: 980/* Now we can recover interrupts again: */ 981 mfmsr %r7 982 ldreg %r6, FRAME_SRR1(%r1) 983 andi. %r6,%r6,(PSL_EE|PSL_ME|PSL_RI)@l 984 or %r7,%r7,%r6 985 mtmsr %r7 986 isync 987/* Call C trap code: */ 988 addi %r3,%r1,FRAME_TF 989 bl _C_LABEL(trap) 990/* LINTSTUB: Var: int trapexit[1]; */ 991 .globl trapexit 992trapexit: 993/* Disable interrupts: */ 994 mfmsr %r3 995 andi. %r3,%r3,~PSL_EE@l 996 mtmsr %r3 997/* Test AST pending: */ 998 mtcr %r31 999 bf MSR_PR,trapleave /* branch if PSL_PR is false */ 1000 ldint %r4,L_MD_ASTPENDING(%r13) 1001 andi. %r4,%r4,1 1002 beq trapleave 1003 1004 li %r6,EXC_AST 1005 stint %r6,FRAME_EXC(%r1) 1006 b trapagain 1007 1008trapleave: 1009 FRAME_RESTORE_CALLEE 1010intrleave: 1011 FRAME_LEAVE(CI_TEMPSAVE) 1012 RFI 1013 1014/* 1015 * Trap handler for syscalls (EXC_SC) 1016 */ 1017/* LINTSTUB: Var: int sctrap[1], scsize[1]; */ 1018 .globl _C_LABEL(sctrap),_C_LABEL(scsize),_C_LABEL(sctrapexit) 1019_C_LABEL(sctrap): 1020 mtsprg1 %r1 /* save SP */ 1021 ENABLE_64BIT_BRIDGE(%r1) 1022 GET_CPUINFO(%r1) 1023 streg %r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1) /* save r28 */ 1024 streg %r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1) /* save r20 */ 1025 streg %r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1) /* save r30 */ 1026 streg %r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1) /* save r31 */ 1027 mflr %r28 /* save LR */ 1028 mfcr %r29 /* save CR */ 1029#if defined(DISTANT_KERNEL) 1030 lis %r31,s_sctrap@ha 1031 addi %r31,%r31,s_sctrap@l 1032 mtlr %r31 1033 blrl 1034#else 1035 bla s_sctrap 1036#endif 1037 _C_LABEL(scsize) = .-_C_LABEL(sctrap) 1038 1039s_sctrap: 1040 GET_CPUINFO(%r1) 1041 ldptr %r1,CI_CURPCB(%r1) 1042 addi %r1,%r1,USPACE-CALLFRAMELEN /* stack is top of user struct */ 1043 RESTORE_KERN_SRS(%r30,%r31) /* First enable KERNEL mapping */ 1044 FRAME_SETUP(CI_TEMPSAVE) 1045/* Now we can recover interrupts again: */ 1046 mfmsr %r7 1047 ori %r7,%r7,(PSL_EE|PSL_ME|PSL_RI)@l 1048 mtmsr %r7 1049 isync 1050 addi %r3,%r1,FRAME_TF 1051/* Call the appropriate syscall handler: */ 1052 ldptr %r4,L_PROC(%r13) 1053 ldptr %r4,P_MD_SYSCALL(%r4) 1054 mtctr %r4 1055 bctrl 1056_C_LABEL(sctrapexit): 1057 b trapexit 1058 1059/* 1060 * External interrupt second level handler 1061 */ 1062/* 1063 * INTR_SETUP assumes: 1064 * SPRG1 SP (%r1) 1065 * savearea r28-r31 1066 * 28 LR 1067 * 29 CR 1068 * 30 scratch 1069 * 31 scratch 1070 * 1 kernel stack 1071 * SRR0/1 as at start of exception 1072 */ 1073#define INTR_SETUP(savearea,exc) \ 1074/* Have to enable translation to allow access of kernel stack: */ \ 1075 GET_CPUINFO(%r31); \ 1076 mfsrr0 %r30; \ 1077 streg %r30,(savearea+CPUSAVE_SRR0)(%r31); /* save SRR0 */ \ 1078 mfsrr1 %r30; \ 1079 streg %r30,(savearea+CPUSAVE_SRR1)(%r31); /* save SRR1 */ \ 1080 mfmsr %r30; \ 1081 ori %r30,%r30,(PSL_DR|PSL_IR); /* turn on relocation */ \ 1082 mtmsr %r30; /* stack can be accessed now */ \ 1083 isync; \ 1084 mfsprg1 %r31; /* get saved SP */ \ 1085 stregu %r31,-FRAMELEN(%r1); /* save it in the callframe */ \ 1086 streg %r0,FRAME_R0(%r1); /* save R0 in the trapframe */ \ 1087 streg %r31,FRAME_R1(%r1); /* save SP in the trapframe */ \ 1088 streg %r2,FRAME_R2(%r1); /* save R2 in the trapframe */ \ 1089 streg %r28,FRAME_LR(%r1); \ 1090 stint %r29,FRAME_CR(%r1); \ 1091 GET_CPUINFO(%r2); \ 1092 ldreg %r31,(savearea+CPUSAVE_R31)(%r2); /* get saved r31 */ \ 1093 ldreg %r30,(savearea+CPUSAVE_R30)(%r2); /* get saved r30 */ \ 1094 ldreg %r29,(savearea+CPUSAVE_R29)(%r2); /* get saved r29 */ \ 1095 ldreg %r28,(savearea+CPUSAVE_R28)(%r2); /* get saved r28 */ \ 1096 streg %r3,FRAME_R3(%r1); /* save r3 */ \ 1097 streg %r4,FRAME_R4(%r1); /* save r4 */ \ 1098 streg %r5,FRAME_R5(%r1); /* save r5 */ \ 1099 streg %r6,FRAME_R6(%r1); /* save r6 */ \ 1100 streg %r7,FRAME_R7(%r1); /* save r7 */ \ 1101 streg %r8,FRAME_R8(%r1); /* save r8 */ \ 1102 streg %r9,FRAME_R9(%r1); /* save r9 */ \ 1103 streg %r10,FRAME_R10(%r1); /* save r10 */ \ 1104 streg %r11,FRAME_R11(%r1); /* save r11 */ \ 1105 streg %r12,FRAME_R12(%r1); /* save r12 */ \ 1106 streg %r13,FRAME_R13(%r1); /* save r13 */ \ 1107 ldreg %r11,(savearea+CPUSAVE_SRR0)(%r2); /* get saved SRR0 */ \ 1108 ldreg %r12,(savearea+CPUSAVE_SRR1)(%r2); /* get saved SRR1 */ \ 1109 ldptr %r13,CI_CURLWP(%r2); /* get curlwp */ \ 1110 ldint %r3,CI_IDEPTH(%r2); \ 1111 stint %r3,FRAME_IDEPTH(%r1); \ 1112 mfxer %r3; \ 1113 mfctr %r4; \ 1114 li %r5,exc; \ 1115 stint %r5,FRAME_EXC(%r1); \ 1116 stint %r3,FRAME_XER(%r1); \ 1117 streg %r4,FRAME_CTR(%r1); \ 1118 streg %r11,FRAME_SRR0(%r1); \ 1119 streg %r12,FRAME_SRR1(%r1); \ 1120 mfmsr %r6; \ 1121 ori %r6,%r6,PSL_RI; /* turn on recovery interrupt */\ 1122 mtmsr %r6; \ 1123 SAVE_VRSAVE(%r1,%r6); \ 1124 SAVE_MQ(%r1,%r7) 1125 1126/* LINTSTUB: Var: int extint_call[1]; */ 1127/* 1128 * R1=sp, R28=LR, R29=CR, R30=scratch, R31=scratch 1129 */ 1130 .globl _C_LABEL(extint_call) 1131extintr: 1132 INTR_SETUP(CI_TEMPSAVE, EXC_EXI) 1133 /* make trapframe available */ 1134 addi %r3,%r1,FRAME_TF /* kern frame -> trap frame */ 1135_C_LABEL(extint_call): 1136 bl _C_LABEL(extint_call) /* to be filled in later */ 1137 1138intr_exit: 1139/* Disable interrupts (should already be disabled) but not MMU here: */ 1140 mfmsr %r3 1141 andi. %r3,%r3,~(PSL_EE|PSL_ME|PSL_RI)@l 1142 mtmsr %r3 1143 isync 1144 1145/* Returning to user mode? */ 1146 ldreg %r4,FRAME_SRR1(%r1) 1147 mtcr %r4 /* saved SRR1 */ 1148 bf MSR_PR,intrleave /* branch if PSL_PR is false */ 1149 1150 ldint %r3,L_MD_ASTPENDING(%r13) /* Test AST pending */ 1151 andi. %r3,%r3,1 1152 beq intrleave /* common frame exit */ 1153 1154/* 1155 * Since interrupts save their state in a std trapframe, all we need to do to 1156 * process the AST is finish filling the trapframe with the rest of the fixed 1157 * registers and let trap deal with it. 1158 */ 1159 streg %r14,FRAME_R14(%r1) 1160 streg %r15,FRAME_R15(%r1) 1161 streg %r16,FRAME_R16(%r1) 1162 streg %r17,FRAME_R17(%r1) 1163 streg %r18,FRAME_R18(%r1) 1164 streg %r19,FRAME_R19(%r1) 1165 streg %r20,FRAME_R20(%r1) 1166 streg %r21,FRAME_R21(%r1) 1167 streg %r22,FRAME_R22(%r1) 1168 streg %r23,FRAME_R23(%r1) 1169 streg %r24,FRAME_R24(%r1) 1170 streg %r25,FRAME_R25(%r1) 1171 streg %r26,FRAME_R26(%r1) 1172 streg %r27,FRAME_R27(%r1) 1173 streg %r28,FRAME_R28(%r1) 1174 streg %r29,FRAME_R29(%r1) 1175 streg %r30,FRAME_R30(%r1) 1176 streg %r31,FRAME_R31(%r1) 1177 1178 /* 1179 * Tell trap we are doing an AST. 1180 */ 1181 li %r6,EXC_AST 1182 stint %r6,FRAME_EXC(%r1) 1183 1184 mr %r31, %r4 /* trapagain wants SRR1 in %r31 */ 1185 b trapagain 1186 1187/* 1188 * Decrementer interrupt second level handler 1189 */ 1190decrintr: 1191 INTR_SETUP(CI_TEMPSAVE, EXC_DECR) 1192 1193 addi %r3,%r1,FRAME_CF /* intr frame -> clock frame */ 1194 bl _C_LABEL(decr_intr) 1195 b intr_exit 1196 1197#ifdef DDB 1198/* 1199 * Deliberate entry to ddbtrap 1200 */ 1201 .globl _C_LABEL(ddb_trap) 1202_C_LABEL(ddb_trap): 1203 mtsprg1 %r1 1204 mfmsr %r3 1205 mtsrr1 %r3 1206 andi. %r3,%r3,~(PSL_EE|PSL_ME)@l 1207 mtmsr %r3 /* disable interrupts */ 1208 isync 1209 ENABLE_64BIT_BRIDGE(%r3) 1210 GET_CPUINFO(%r3) 1211 streg %r28,(CI_DDBSAVE+CPUSAVE_R28)(%r3) 1212 streg %r29,(CI_DDBSAVE+CPUSAVE_R29)(%r3) 1213 streg %r30,(CI_DDBSAVE+CPUSAVE_R30)(%r3) 1214 streg %r31,(CI_DDBSAVE+CPUSAVE_R31)(%r3) 1215 mflr %r28 1216 li %r29,EXC_BPT 1217 mtlr %r29 1218 mfcr %r29 1219 mtsrr0 %r28 1220#endif /* DDB */ 1221 1222#if defined(DDB) || defined(KGDB) 1223/* 1224 * Now the ddb trap catching code. 1225 */ 1226ddbtrap: 1227 FRAME_SETUP(CI_DDBSAVE) 1228/* Call C trap code: */ 1229 addi %r3,%r1,FRAME_TF 1230 bl _C_LABEL(ddb_trap_glue) 1231 or. %r3,%r3,%r3 1232 beq trapagain 1233 FRAME_RESTORE_CALLEE 1234 FRAME_LEAVE(CI_DDBSAVE) 1235 RFI 1236#endif /* DDB || KGDB */ 1237 1238 .globl _C_LABEL(trapend) 1239_C_LABEL(trapend): 1240 1241/* 1242 * All OEA have FPUs so include this too. Some OEA have AltiVec so include 1243 * that too. 1244 */ 1245#if !defined(PPC_MPC8XX) 1246#include <powerpc/powerpc/fpu_subr.S> 1247#include <powerpc/oea/altivec_subr.S> 1248#endif 1249