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