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