1/* $NetBSD: trap_subr.S,v 1.8 2012/08/01 16:19:43 matt Exp $ */ 2/*- 3 * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Raytheon BBN Technologies Corp and Defense Advanced Research Projects 8 * Agency and which was developed by Matt Thomas of 3am Software Foundry. 9 * 10 * This material is based upon work supported by the Defense Advanced Research 11 * Projects Agency and Space and Naval Warfare Systems Center, Pacific, under 12 * Contract No. N66001-09-C-2073. 13 * Approved for Public Release, Distribution Unlimited 14 * 15 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted provided that the following conditions 17 * are met: 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in the 22 * documentation and/or other materials provided with the distribution. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37RCSID("$NetBSD: trap_subr.S,v 1.8 2012/08/01 16:19:43 matt Exp $") 38 39 .globl _C_LABEL(sctrapexit), _C_LABEL(trapexit), _C_LABEL(intrcall) 40 41 /* 42 * We have a problem with critical (MSR[CE] or machine check (MSR[ME]) 43 * or debug (MSR[DE]) interrupts/exception in that they could happen 44 * inbewtween the mtsprg1 %r2 and mfsprg1 %r2. If that happens, %r2 45 * will be lost. Even if we moved to a different sprg, subsequent 46 * expceptions would use SPRG1 and its value would be lost. The only 47 * way to be safe for CE/ME/DE faults to save and restore SPRG1. 48 * 49 * Since CE/ME/DE faults may happen anytime, we need r1 to always 50 * contain a valid kernel stack pointer. Therefore we use r2 as 51 * our temporary register. 52 * 53 * To prevent %r2 being overwritten, each "level" (normal, critical, 54 * mchk) uses a unique sprg to save %r2 (sprg1, sprg4, sprg5). 55 * 56 * Since we can't control how many nested exceptions we might get, 57 * we don't use a dedicated save area. Instead we have a upwards 58 * growing "stack" of them; the pointer to which is kept in sprg3. 59 * 60 * To allocate from the stack, one fetches sprg3, adds the amount 61 * needed, saves sprg3, and then refers to the save using a 62 * displacement of -amount. 63 */ 64#define FRAME_EXC_PROLOGUE(start, sprg, srr) \ 65 mt##sprg %r2; /* save r2 */ \ 66 mfsprg3 %r2; /* get save_area pointer */ \ 67 addi %r2,%r2,4*(32-start); \ 68 /* allocate save area */ \ 69 mtsprg3 %r2; /* save updated pointer */ \ 70 stmw %r##start,-4*(32-start)(%r2); \ 71 /* free r24-r31 for use */ \ 72 mf##sprg %r26; /* get saved r2 */ \ 73 mfcr %r27; /* get Condition Register */ \ 74 mfxer %r28; /* get XER */ \ 75 mfspr %r30, SPR_##srr##0; /* get SRR0 */ \ 76 mfspr %r31, SPR_##srr##1 /* get SRR1 */ 77 78#define PROLOGUE_GET_DEAR mfspr %r24, SPR_DEAR 79#define PROLOGUE_GET_ESR mfspr %r25, SPR_ESR 80#define PROLOGUE_GET_SRRS mfsrr0 %r24; \ 81 mfsrr1 %r25 82#define PROLOGUE_GET_SPRG1 mfsprg1 %r29 83#define PROLOGUE_GET_DBSR mfspr %r25, SPR_DBSR 84#define SAVE_ESR stw %r25, FRAME_ESR(%r1) 85#define SAVE_DEAR stw %r24, FRAME_DEAR(%r1) 86#define SAVE_DEAR_ESR SAVE_ESR; SAVE_DEAR 87#define SAVE_SRRS SAVE_DEAR_ESR 88#define SAVE_SPRG1 stw %r29, FRAME_SPRG1(%r1) 89#define SAVE_DBSR stw %r25, FRAME_DBSR(%r1) 90#define SAVE_NOTHING /* nothing */ 91#define RESTORE_SPRG1(r) lwz r, FRAME_SPRG1(%r1); \ 92 mtsprg1 r 93#define RESTORE_SRR0(r) lwz r, FRAME_DEAR(%r1); \ 94 mtsrr0 r 95#define RESTORE_SRR1(r) lwz r, FRAME_ESR(%r1); \ 96 mtsrr1 r 97 98#define FRAME_PROLOGUE \ 99 FRAME_EXC_PROLOGUE(26, sprg1, SRR) 100 101#define FRAME_PROLOGUE_DEAR_ESR \ 102 FRAME_EXC_PROLOGUE(24, sprg1, SRR); \ 103 PROLOGUE_GET_ESR; \ 104 PROLOGUE_GET_DEAR 105 106#define FRAME_PROLOGUE_ESR \ 107 FRAME_EXC_PROLOGUE(25, sprg1, SRR); \ 108 PROLOGUE_GET_ESR 109 110#define FRAME_TLBPROLOGUE \ 111 FRAME_EXC_PROLOGUE(20, sprg1, SRR); \ 112 PROLOGUE_GET_ESR; \ 113 PROLOGUE_GET_DEAR 114 115#define FRAME_INTR_PROLOGUE \ 116 FRAME_EXC_PROLOGUE(26, sprg1, SRR) 117 118/* 119 * These need to save SRR0/SRR1 as well their SRR0/SRR1 in case normal 120 * exceptions happened during their execution. 121 */ 122#define FRAME_CRIT_PROLOGUE \ 123 FRAME_EXC_PROLOGUE(24, sprg4, CSRR); \ 124 PROLOGUE_GET_SPRG1; \ 125 PROLOGUE_GET_SRRS 126 127#define FRAME_MCHK_PROLOGUE \ 128 FRAME_EXC_PROLOGUE(24, sprg5, MCSRR); \ 129 PROLOGUE_GET_SPRG1; \ 130 PROLOGUE_GET_SRRS 131 132#define FRAME_DEBUG_PROLOGUE \ 133 FRAME_EXC_PROLOGUE(24, sprg4, CSRR); \ 134 PROLOGUE_GET_SPRG1; \ 135 PROLOGUE_GET_SRRS 136 137/* 138 * DDB expects to fetch the LR from the previous frame. But it also 139 * expects to be pointing at the instruction after the branch link. Since 140 * we didn't branch, we need to advance it by to fake out DDB. But there's 141 * problem. If the routine is in either its first or last two instructions 142 * (before or after its adjusted its stack pointer), we could possibly 143 * overwrite stored return address. So that stored return address needs to 144 * saved and restored. 145 */ 146#if defined(DDB) 147#define FRAME_SAVE_SRR0_FOR_DDB \ 148 lwz %r29, FRAMELEN+CFRAME_LR(%r1); /* fetch old return address */\ 149 stw %r29, FRAME_CFRAME_LR(%r1); /* save it */ \ 150 addi %r30, %r30, 4; /* point to s the next insn */ \ 151 stw %r30, FRAMELEN+CFRAME_LR(%r1) /* appease ddb stacktrace */ 152#define FRAME_RESTORE_RETURN_ADDRESS \ 153 lwz %r3, FRAME_CFRAME_LR(%r1); /* fetch old return address */ \ 154 stw %r3, FRAMELEN+CFRAME_LR(%r1) /* restore it */ 155#else 156#define FRAME_SAVE_SRR0_FOR_DDB 157#define FRAME_RESTORE_RETURN_ADDRESS 158#endif 159 160#ifdef PPC_HAVE_SPE 161#define FRAME_SAVE_SPEFSCR \ 162 mfspefscr %r0; /* get spefscr */ \ 163 stw %r0, FRAME_SPEFSCR(%r1) /* save into trapframe */ 164#define FRAME_RESTORE_SPEFSCR \ 165 lwz %r0, FRAME_SPEFSCR(%r1); /* fetch from trapframe */ \ 166 mtspefscr %r0 /* save spefscr */ 167#else 168#define FRAME_SAVE_SPEFSCR 169#define FRAME_RESTORE_SPEFSCR 170#endif 171/* 172 * Before the first memory refernence, we must have our state inside registers 173 * since the first memory access might cause an exception which would cause 174 * SRR0/SRR1 and DEAR/ESR to become unrecoverable. CR and XER also need to be 175 * saved early since they will modified by instrction flow. The saved stack 176 * pointer is also critical but LR and CTR can be deferred being saved until 177 * we are actually filling a trapframe. 178 */ 179#define FRAME_EXC_ENTER(exc, tf, start, save_prologue) \ 180 mtcr %r31; /* user mode exception? */ \ 181 mr %r31, %r1; /* save SP (SRR1 is safe in CR) */ \ 182 bf MSR_PR, 1f; /* nope, sp is good */ \ 183 mfsprg2 %r2; /* get curlwp */ \ 184 lwz %r2, L_PCB(%r2); /* get uarea of curlwp */ \ 185 addi %r1, %r2, USPACE-CALLFRAMELEN; \ 186 /* start stack at top of it */ \ 1871: \ 188 stwu %r31, -FRAMELEN(%r1); /* get space for trapframe */ \ 189 stw %r0, FRAME_R0(%r1); /* save r0 */ \ 190 stw %r31, FRAME_R1(%r1); /* save (saved) r1 */ \ 191 stw %r26, FRAME_R2(%r1); /* save (saved) r2 */ \ 192 save_prologue; /* save SPRG1/ESR/DEAR */ \ 193 /* At this point, r26, r29, and r31 have been saved so we */ \ 194 /* can use them for LR, CTR, and SRR1. */ \ 195 mflr %r26; /* get Link Register */ \ 196 mfctr %r29; /* get CTR */ \ 197 mfcr %r31; /* get SRR1 */ \ 198 stmw %r26, FRAME_LR(%r1); /* save LR CR XER CTR SRR0/1 */ \ 199 FRAME_SAVE_SRR0_FOR_DDB; \ 200 mr %r0, %r31; /* save SRR1 for a bit */ \ 201 mfsprg3 %r2; /* get save_area pointer */ \ 202 addi %r2,%r2,-4*(32-start); /* find our save area */ \ 203 lmw %r##start,0(%r2); /* get start-r31 */ \ 204 mtsprg3 %r2; /* save updated pointer */ \ 205 stmw %r3, FRAME_R3(%r1); /* save r2-r31 */ \ 206 /* Now everything has been saved */ \ 207 mr %r31, %r0; /* move SRR1 back to r31 */ \ 208 mfsprg2 %r13; /* put curlwp in r13 */ \ 209 FRAME_SAVE_SPEFSCR; \ 210 li %r7, exc; /* load EXC_* */ \ 211 stw %r7, FRAME_EXC(%r1); /* save into trapframe */ \ 212 addi tf, %r1, FRAME_TF /* get address of trap frame */ 213 214#define FRAME_EXC_EXIT(rfi, srr) \ 215 FRAME_RESTORE_RETURN_ADDRESS; /* restore return address */ \ 216 lmw %r26, FRAME_LR(%r1); /* get LR CR XER CTR SRR0/1 */ \ 217 oris %r31,%r31,PSL_CE@h; \ 218 mtspr SPR_##srr##1, %r31; /* restore SRR1 */ \ 219 mtspr SPR_##srr##0, %r30; /* restore SRR0 */ \ 220 FRAME_RESTORE_SPEFSCR; \ 221 mtctr %r29; /* restore CTR */ \ 222 mtxer %r28; /* restore XER */ \ 223 mtcr %r27; /* restore CR */ \ 224 mtlr %r26; /* restore LR */ \ 225 lmw %r2, FRAME_R2(%r1); /* restore r2-r31 */ \ 226 lwz %r0, FRAME_R0(%r1); /* restore r0 */ \ 227 lwz %r1, FRAME_R1(%r1); /* restore r1 */ \ 228 rfi /* return from interrupt */ 229 230 231#define FRAME_ENTER(exc, tf) \ 232 FRAME_EXC_ENTER(exc, tf, 26, SAVE_NOTHING) 233 234#define FRAME_ENTER_ESR(exc, tf) \ 235 FRAME_EXC_ENTER(exc, tf, 25, SAVE_ESR) 236 237#define FRAME_ENTER_DEAR_ESR(exc, tf) \ 238 FRAME_EXC_ENTER(exc, tf, 24, SAVE_DEAR_ESR) 239 240#define FRAME_EXIT FRAME_EXC_EXIT(rfi, SRR) 241 242#define FRAME_TLBENTER(exc) \ 243 FRAME_EXC_ENTER(exc, %r4, 20, SAVE_DEAR_ESR) 244#define FRAME_TLBEXIT FRAME_EXC_EXIT(rfi, SRR) 245 246#define FRAME_MCHK_ENTER(exc) \ 247 FRAME_EXC_ENTER(exc, %r3, 26, SAVE_SPRG1; SAVE_SRRS) 248#define FRAME_MCHK_EXIT \ 249 RESTORE_SRR0(%r28); \ 250 RESTORE_SRR1(%r27); \ 251 RESTORE_SPRG1(%r26); \ 252 FRAME_EXC_EXIT(rfmci, MCSRR) 253 254#define FRAME_DEBUG_ENTER(exc) \ 255 FRAME_EXC_ENTER(exc, %r4, 26, SAVE_SPRG1; SAVE_SRRS) 256#define FRAME_DEBUG_EXIT \ 257 RESTORE_SPRG1(%r26); FRAME_EXC_EXIT(rfci, CSRR) 258 259#define FRAME_INTR_SP \ 260 bf MSR_PR, 1f; /* nope, sp is good */ \ 261 mfsprg2 %r2; /* get curlwp */ \ 262 lwz %r2, L_PCB(%r2); /* get uarea of curlwp */ \ 263 addi %r1, %r2, USPACE-CALLFRAMELEN; \ 264 /* start stack at top of it */ \ 2651: 266 267#define FRAME_INTR_SP_NEW(sym) \ 268 lis %r2,(sym)@ha; \ 269 addi %r1,%r2,(sym)@l 270 271#define FRAME_INTR_XENTER(exc, start, get_intr_sp, save_prologue) \ 272 mtcr %r31; /* user mode exception? */ \ 273 mr %r31, %r1; /* save SP (SRR1 is safe in CR) */ \ 274 get_intr_sp; /* get kernel stack pointer */ \ 275 stwu %r31, -FRAMELEN(%r1); /* get space for trapframe */ \ 276 stw %r0, FRAME_R0(%r1); /* save r0 */ \ 277 stw %r31, FRAME_R1(%r1); /* save (saved) r1 */ \ 278 stw %r26, FRAME_R2(%r1); /* save (saved) r2 */ \ 279 save_prologue; /* save SPRG1 (maybe) */ \ 280 mflr %r26; /* get LR */ \ 281 mfctr %r29; /* get CTR */ \ 282 mfcr %r31; /* get SRR1 */ \ 283 stmw %r26, FRAME_LR(%r1); /* save LR CR XER CTR SRR0/1 */ \ 284 FRAME_SAVE_SRR0_FOR_DDB; \ 285 stw %r3, FRAME_R3(%r1); /* save r3 */ \ 286 stw %r4, FRAME_R4(%r1); /* save r4 */ \ 287 stw %r5, FRAME_R5(%r1); /* save r5 */ \ 288 stw %r6, FRAME_R6(%r1); /* save r6 */ \ 289 stw %r7, FRAME_R7(%r1); /* save r7 */ \ 290 stw %r8, FRAME_R8(%r1); /* save r8 */ \ 291 stw %r9, FRAME_R9(%r1); /* save r9 */ \ 292 stw %r10, FRAME_R10(%r1); /* save r10 */ \ 293 stw %r11, FRAME_R11(%r1); /* save r11 */ \ 294 stw %r12, FRAME_R12(%r1); /* save r12 */ \ 295 stw %r13, FRAME_R13(%r1); /* save r13 */ \ 296 mfsprg3 %r2; /* get save_area pointer */ \ 297 addi %r2,%r2,-4*(32-start); /* find our save area */ \ 298 lmw %r##start,0(%r2); /* get start-r31 */ \ 299 mtsprg3 %r2; /* save updated pointer */ \ 300 mfsprg2 %r13; /* put curlwp into r13 */ \ 301 li %r7, exc; /* load EXC_* */ \ 302 stw %r7, FRAME_EXC(%r1); /* save into trapframe */ \ 303 addi %r3, %r1, FRAME_TF /* only argument is trapframe */ 304 305#define FRAME_INTR_XEXIT(rfi, srr) \ 306 FRAME_RESTORE_RETURN_ADDRESS; /* restore return address */ \ 307 lwz %r8, FRAME_LR(%r1); /* get LR */ \ 308 lwz %r9, FRAME_CR(%r1); /* get CR */ \ 309 lwz %r10, FRAME_XER(%r1); /* get XER */ \ 310 lwz %r11, FRAME_CTR(%r1); /* get CTR */ \ 311 lwz %r12, FRAME_SRR0(%r1); /* get SRR0 */ \ 312 lwz %r13, FRAME_SRR1(%r1); /* get SRR1 */ \ 313 mtspr SPR_##srr##1, %r13; /* restore SRR1 */ \ 314 mtspr SPR_##srr##0, %r12; /* restore SRR0 */ \ 315 mtctr %r11; /* restore CTR */ \ 316 mtxer %r10; /* restore XER */ \ 317 mtcr %r9; /* restore CR */ \ 318 mtlr %r8; /* restore LR */ \ 319 lwz %r13, FRAME_R13(%r1); /* restore r13 */ \ 320 lwz %r12, FRAME_R12(%r1); /* restore r12 */ \ 321 lwz %r11, FRAME_R11(%r1); /* restore r11 */ \ 322 lwz %r10, FRAME_R10(%r1); /* restore r10 */ \ 323 lwz %r9, FRAME_R9(%r1); /* restore r9 */ \ 324 lwz %r8, FRAME_R8(%r1); /* restore r8 */ \ 325 lwz %r7, FRAME_R7(%r1); /* restore r7 */ \ 326 lwz %r6, FRAME_R6(%r1); /* restore r6 */ \ 327 lwz %r5, FRAME_R5(%r1); /* restore r5 */ \ 328 lwz %r4, FRAME_R4(%r1); /* restore r4 */ \ 329 lwz %r3, FRAME_R3(%r1); /* restore r3 */ \ 330 lwz %r2, FRAME_R2(%r1); /* restore r2 */ \ 331 lwz %r0, FRAME_R0(%r1); /* restore r0 */ \ 332 lwz %r1, FRAME_R1(%r1); /* restore r1 */ \ 333 rfi /* return from interrupt */ 334 335#define FRAME_INTR_ENTER(exc) \ 336 FRAME_INTR_XENTER(exc, 26, FRAME_INTR_SP, SAVE_NOTHING) 337#define FRAME_INTR_EXIT \ 338 FRAME_INTR_XEXIT(rfi, SRR) 339#define FRAME_CRIT_ENTER(exc) \ 340 FRAME_INTR_XENTER(exc, 24, FRAME_INTR_SP, SAVE_SPRG1) 341#define FRAME_WDOG_ENTER(exc, sym) \ 342 FRAME_INTR_XENTER(exc, 24, FRAME_INTR_SP_NEW(sym), SAVE_SPRG1) 343#define FRAME_CRIT_EXIT \ 344 RESTORE_SRR0(%r4); \ 345 RESTORE_SRR1(%r5); \ 346 RESTORE_SPRG1(%r6); \ 347 FRAME_INTR_XEXIT(rfci, CSRR) 348 349 .text 350 .p2align 4 351_C_LABEL(critical_input_vector): 352 /* MSR[ME] is unchanged, all others cleared */ 353 FRAME_CRIT_PROLOGUE /* save SP r26-31 CR LR XER */ 354 FRAME_CRIT_ENTER(EXC_CII) 355 bl _C_LABEL(intr_critintr) /* critintr(tf) */ 356 FRAME_CRIT_EXIT 357 358 .p2align 4 359_C_LABEL(machine_check_vector): 360 /* all MSR bits are cleared */ 361 FRAME_MCHK_PROLOGUE /* save SP r25-31 CR LR XER */ 362 FRAME_MCHK_ENTER(EXC_MCHK) 363 /* 364 * MCAR/MCSR don't need to be saved early since MSR[ME] is cleared 365 * on entry. 366 */ 367 mfspr %r7, SPR_MCAR 368 mfspr %r6, SPR_MCSR 369 stw %r6, FRAME_MCSR(%r1) 370 stw %r7, FRAME_MCAR(%r1) 371 li %r3, T_MACHINE_CHECK 372 bl _C_LABEL(trap) /* trap(T_MACHINE_CHECK, tf) */ 373 FRAME_MCHK_EXIT 374 375 .p2align 4 376_C_LABEL(data_storage_vector): 377 /* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */ 378 FRAME_PROLOGUE_DEAR_ESR /* save r2 DEAR ESR r24-31 CR XER SRR */ 379 FRAME_ENTER_DEAR_ESR(EXC_DSI, %r4) 380 li %r3, T_DSI 381 /* FRAME_ENTER leaves SRR1 in %r31 */ 382trapenter: 383trapagain: 384 wrtee %r31 /* restore MSR[EE] */ 385 386 bl _C_LABEL(trap) /* trap(trapcode, tf) */ 387_C_LABEL(trapexit): 388 wrteei 0 /* disable interrupts */ 389# andis. %r0, %r31, PSL_CE@h 390# tweqi %r0, 0 391 andi. %r4, %r31, PSL_PR /* lets look at PSL_PR */ 392 beq trapdone /* if clear, skip to exit */ 393 lwz %r4, L_MD_ASTPENDING(%r13) /* get ast pending */ 394 cmplwi %r4, 0 /* is there an ast pending */ 395 beq+ trapdone /* nope, proceed to exit */ 396 li %r6, EXC_AST /* yes. */ 397 stw %r6, FRAME_EXC(%r1) /* pretend this is an AST */ 398 addi %r4, %r1, FRAME_TF /* get address of trap frame */ 399 li %r3, T_AST 400 b trapagain /* and deal with it */ 401trapdone: 402 FRAME_EXIT 403 404 .p2align 4 405_C_LABEL(instruction_storage_vector): 406 /* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */ 407 FRAME_PROLOGUE_ESR /* save ESR r2 r25-31 CR XER SRR0/1 */ 408 FRAME_ENTER_ESR(EXC_ISI, %r4) 409 li %r3, T_ISI 410 b trapenter 411 412 .p2align 4 413_ENTRY(external_input_vector) 414 /* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */ 415 FRAME_INTR_PROLOGUE /* save SP r25-31 CR LR XER */ 416 FRAME_INTR_ENTER(EXC_EXI) 417 418 bl _C_LABEL(intr_extintr) 419_C_LABEL(intrcall): 420 GET_CPUINFO(%r6) /* get curcpu() */ 421 lwz %r5, FRAME_SRR1(%r1) /* get saved SRR1 */ 422# andis. %r0, %r5, PSL_CE@h 423# tweqi %r0, 0 424 andi. %r4, %r5, PSL_PR /* lets look at PSL_PR */ 425 beq intrexit /* if clear, skip to exit */ 426 lwz %r4, L_MD_ASTPENDING(%r13) /* get ast pending */ 427 cmplwi %r4, 0 /* is there an ast pending */ 428 beq+ intrexit /* nope, proceed to exit */ 429 stmw %r14, FRAME_R14(%r1) /* save rest of registers */ 430 FRAME_SAVE_SPEFSCR 431 mr %r31, %r5 /* needed for trapagain */ 432 li %r4, EXC_AST /* */ 433 stw %r4, FRAME_EXC(%r1) /* pretend this is an AST */ 434 addi %r4, %r1, FRAME_TF /* get address of trap frame */ 435 li %r3, T_AST 436 b trapagain /* and deal with it */ 437intrexit: 438 FRAME_INTR_EXIT 439 440 .p2align 4 441_C_LABEL(alignment_vector): 442 /* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */ 443 FRAME_PROLOGUE_DEAR_ESR /* save SP r25-31 CR LR XER */ 444 FRAME_ENTER_DEAR_ESR(EXC_ALI, %r4) 445 li %r3, T_ALIGNMENT 446 b trapenter 447 448 .p2align 4 449_C_LABEL(program_vector): 450 /* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */ 451 FRAME_PROLOGUE_ESR /* save SP r25-31 CR LR XER */ 452 FRAME_ENTER_ESR(EXC_PGM, %r4) 453 li %r3, T_PROGRAM 454 b trapenter 455 456#ifdef SPR_IVOR7 457 .p2align 4 458_C_LABEL(fp_unavailable_vector): 459 /* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */ 460 FRAME_PROLOGUE_ESR /* save SP r25-31 CR LR XER */ 461 FRAME_ENTER_ESR(EXC_FPU, %r4) 462 li %r3, T_FP_UNAVAILABLE 463 b trapenter 464#endif 465 466 .p2align 4 467_C_LABEL(system_call_vector): 468 /* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */ 469 FRAME_PROLOGUE /* save SP r26-31 CR LR XER */ 470 FRAME_ENTER(EXC_SC, %r3) 471 472 wrteei 1 /* enable interrupts */ 473 lwz %r7, L_PROC(%r13) /* get proc for lwp */ 474 lwz %r8, P_MD_SYSCALL(%r7) /* get syscall */ 475 mtlr %r8 /* need to call indirect */ 476 blrl /* syscall(tf) */ 477_C_LABEL(sctrapexit): 478 wrteei 0 /* disable interrupts */ 479 lwz %r4, L_MD_ASTPENDING(%r13) /* get ast pending */ 480 cmplwi %r4, 0 /* is there an ast pending */ 481 beq+ trapdone /* nope, proceed to exit */ 482 li %r0, EXC_AST /* yes. */ 483 stw %r0, FRAME_EXC(%r1) /* pretend this is an AST */ 484 addi %r4, %r1, FRAME_TF /* get address of trap frame */ 485 li %r3, T_AST 486 b trapenter /* and deal with it */ 487 488#ifdef SPR_IVOR9 489 .p2align 4 490_C_LABEL(ap_unavailable_vector): 491 /* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */ 492 FRAME_PROLOGUE /* save SP r25-31 CR LR XER */ 493 FRAME_ENTER(EXC_PGM, %r4) 494 li %r3, T_AP_UNAVAILABLE 495 b trapenter 496#endif 497 498 .p2align 4 499_C_LABEL(decrementer_vector): 500 /* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */ 501 FRAME_INTR_PROLOGUE /* save SP r25-31 CR LR XER */ 502 FRAME_INTR_ENTER(EXC_DECR) 503 504 bl _C_LABEL(intr_decrintr) 505 b intrexit 506 507 .p2align 4 508_C_LABEL(fixed_interval_timer_vector): 509 /* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */ 510 FRAME_PROLOGUE /* save SP r25-31 CR LR XER */ 511 FRAME_INTR_ENTER(EXC_FIT) 512 513 bl _C_LABEL(intr_fitintr) 514 b intrexit 515 516#ifdef E500_WDOG_STACK 517 .data 518 .lcomm wdogstk,4096 519#endif 520 .text 521 .p2align 4 522_C_LABEL(watchdog_timer_vector): 523 /* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */ 524 FRAME_CRIT_PROLOGUE /* save SP r25-31 CR LR XER */ 525#ifdef E500_WDOG_STACK 526 FRAME_WDOG_ENTER(EXC_WDOG, wdogstk+4096-CALLFRAMELEN) 527#else 528 FRAME_CRIT_ENTER(EXC_WDOG); 529#endif 530 531 bl _C_LABEL(intr_wdogintr) 532 FRAME_CRIT_EXIT 533 534 .p2align 4 535_C_LABEL(data_tlb_error_vector): 536 /* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */ 537 FRAME_TLBPROLOGUE 538 /* 539 * Registers as this point: 540 * 541 * r2 = cpu_info 542 * r20 = scratch 543 * r21 = scratch 544 * r22 = scratch 545 * r23 = scratch 546 * r24 = DEAR 547 * r25 = ESR 548 * r26 = saved r2 549 * r27 = CR 550 * r28 = XER 551 * r29 = scratch 552 * r30 = SRR0 553 * r31 = SRR1 554 * 555 * Except for r29, these values must be retained. However we must 556 * be cognizant of nesting. There are two cases here, both related. 557 * 558 * We get a critical input or machine check exception and the kernel 559 * stack doesn't have a TLB entry so we take an exception. The other 560 * nesting path is some page used by the exception handler will cause 561 * a TLB data error. 562 * 563 * The second case (more probable) is that the PTE loading will fail 564 * so we will have to do a hard trap to resolve it. But in doing so 565 * we need to save a trapframe which could result in another DTLB 566 * fault. 567 * 568 * In all cases, the save area stack shall protect us. 569 */ 570 /* 571 * Attempt to update the TLB from the page table. 572 */ 573 mflr %r29 /* save LR */ 574 mr %r23, %r24 /* address of exception */ 575 rlwinm %r22, %r31, /* index into ci_pmap_segtab */\ 576 MSR_DS+PTR_SCALESHIFT+1, \ 577 31-PTR_SCALESHIFT, \ 578 31-PTR_SCALESHIFT /* move PSL_DS[27] to bit 29 */ 579 bl pte_load 580 mtlr %r29 /* restore LR */ 581 /* 582 * If we returned, pte load failed so let trap deal with it but 583 * has kept the contents of r24-r31 (expect r29) intact. 584 */ 585 FRAME_TLBENTER(EXC_DSI) 586 li %r3, T_DATA_TLB_ERROR 587 b trapenter 588 589 .p2align 4 590_C_LABEL(instruction_tlb_error_vector): 591 /* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */ 592 FRAME_TLBPROLOGUE 593 /* 594 * Attempt to update the TLB from the page table. 595 */ 596 mflr %r29 /* save LR */ 597 mr %r23, %r30 /* PC of exception */ 598 rlwinm %r22, %r31, /* index into ci_pmap_segtab */\ 599 MSR_IS+PTR_SCALESHIFT+1, \ 600 31-PTR_SCALESHIFT, \ 601 31-PTR_SCALESHIFT /* move PSL_IS[26] to bit 29 */ 602 bl pte_load 603 mtlr %r29 /* restore LR */ 604 /* 605 * If we returned, pte load failed so let trap deal with it but 606 * has kept the contents of r24-r31 (expect r29) intact. 607 */ 608 FRAME_TLBENTER(EXC_ISI) 609 li %r3, T_INSTRUCTION_TLB_ERROR 610 b trapenter 611 612 .p2align 4 613_C_LABEL(debug_vector): 614 FRAME_CRIT_PROLOGUE /* save SP r25-31 CR LR XER */ 615 FRAME_CRIT_ENTER(EXC_DEBUG) 616 mfspr %r6, SPR_DBSR 617 stw %r6, FRAME_ESR(%r1) 618 li %r3, T_DEBUG 619 bl _C_LABEL(trap) 620 FRAME_CRIT_EXIT 621 622 .p2align 4 623_C_LABEL(spv_unavailable_vector): 624 FRAME_PROLOGUE_ESR /* save SP r25-31 CR LR XER */ 625 FRAME_ENTER_ESR(EXC_VEC, %r4) 626 li %r3, T_SPE_UNAVAILABLE 627 b trapenter 628 629 .p2align 4 630_C_LABEL(fpdata_vector): 631 FRAME_PROLOGUE_ESR /* save SP r25-31 CR LR XER */ 632 FRAME_ENTER_ESR(EXC_FPA, %r4) 633 li %r3, T_EMBEDDED_FP_DATA 634 b trapenter 635 636 .p2align 4 637_C_LABEL(fpround_vector): 638 FRAME_PROLOGUE_ESR /* save SP r25-31 CR LR XER */ 639 FRAME_ENTER_ESR(EXC_FPA, %r4) 640 li %r3, T_EMBEDDED_FP_ROUND 641 b trapenter 642 643 .p2align 4 644_C_LABEL(perfmon_vector): 645 FRAME_PROLOGUE_ESR /* save SP r25-31 CR LR XER */ 646 FRAME_ENTER_ESR(EXC_PERF, %r4) 647 li %r3, T_EMBEDDED_PERF_MONITOR 648 b trapenter 649 650 .p2align 4 651pte_load: 652 /* 653 * r2 = scratch 654 * r20 = scratch 655 * r21 = scratch 656 * r22 = index into ci_pmap_{kern,user}_segtab 657 * r23 = faulting address 658 * The rest are for reference and aren't modifiable. If the load 659 * fails, they will be used by FRAME_TLBENTER to create the trapframe. 660 * r24 = DEAR 661 * r25 = ESR 662 * r26 = saved r2 663 * r27 = CR 664 * r28 = XER 665 * r29 = LR 666 * r30 = SRR0 667 * r31 = SRR1 668 */ 669 cmplwi %cr2, %r22, 0 /* remember address space */ 670 GET_CPUINFO(%r2) 671 addi %r22, %r22, CI_PMAP_SEGTAB /* index into segtab(s) */ 672 lwzx %r20, %r22, %r2 /* load kern/user L1 PT addr */ 673 cmplwi %r20, 0 /* is segtab null? */ 674 beqlr %cr0 /* yes, return to fallback to trap */ 675 676 rlwinm %r22, %r23, NSEGPG_SCALESHIFT + PTR_SCALESHIFT, \ 677 31-(NSEGPG_SCALESHIFT + PTR_SCALESHIFT - 1), \ 678 31-PTR_SCALESHIFT /* extract addr bits [0:9] to [20:29] */ 679 lwzx %r20, %r22, %r20 /* load address of page table page */ 680 cmplwi %r20, 0 /* is page null? */ 681 beqlr %cr0 /* yes, return to fallback to trap */ 682 683 rlwinm %r22, %r23, \ 684 NSEGPG_SCALESHIFT + NPTEPG_SCALESHIFT + PTE_SCALESHIFT, \ 685 31-(NPTEPG_SCALESHIFT + PTE_SCALESHIFT - 1), \ 686 31-PTE_SCALESHIFT /* extract addr bits [10:19] to [20:29] */ 687 lwzx %r20, %r22, %r20 /* load PTE from page table page */ 688 cmplwi %r20, 0 /* is there a valid PTE? */ 689 beqlr %cr0 /* no, return to fallback to trap */ 690 691#if (PTE_UNSYNCED << 1) != PTE_xX 692#error PTE_UNSYNCED definition error 693#endif 694#if (PTE_UNMODIFIED << 1) != PTE_xW 695#error PTE_UNMODIFIED definition error 696#endif 697 andi. %r22, %r20, (PTE_UNSYNCED|PTE_UNMODIFIED) 698 /* Does the PTE need to be changed? */ 699 rotlwi %r22, %r22, 1 /* if so, clear the right PTE bits */ 700 andc %r20, %r20, %r22 /* pte &= ~((pte & (PTE_UNSYNCED|PTE_UNMODIFIED)) << 1)*/ 701 702 /* 703 * r24-r32 = (no touch) 704 * r23 = scratch (was fault addr) 705 * r22 = scratch 706 * r21 = scratch 707 * r20 = pte 708 * cr2 = AS 0=eq/!0=ne 709 */ 710 711 /* 712 * This is all E500 specific. We should have a patchable branch 713 * to support other BookE (440) implementations. 714 */ 715e500_pte_load: 716 bne+ %cr2, 1f /* user access? MAS1 is ok. */ 717 mfspr %r22, SPR_MAS1 /* get MAS1 */ 718 lis %r21, MAS1_TID@h /* get TID mask */ 719 andc %r22, %r22, %r21 /* clear TID */ 720 mtspr SPR_MAS1, %r22 /* save MAS1 */ 7211: 722 andi. %r21, %r20, PTE_WIMGE_MASK /* extract WIMGE from PTE */ 723 cmplwi %r21, PTE_M /* if just PTE_M is set, */ 724 beq+ %cr0, 2f /* skip munging mas2 */ 725 mfspr %r22, SPR_MAS2 /* get MAS2 (updated by error) */ 726 clrrwi %r22, %r22, PTE_RWX_SHIFT /* clear WIMGE bits */ 727 or %r22, %r22, %r21 /* combine with MAS2 contents */ 728 mtspr SPR_MAS2, %r22 /* put back into MAS2 */ 7292: 730 /* 731 * r23 = fault addr 732 * r22 = scratch 733 * r21 = scratch 734 * r20 = pte 735 */ 736 737 /* 738 * In MAS3, the protection bits are in the low 6 bits: 739 * UX SX UW SW UR SR 740 * The User bits are 1 bit left of their Supervisor counterparts. 741 * Rotate the PTE protection bits left until they wrap around to become 742 * the least significant bits, where the Supervisor protection bits 743 * are located. Increase the rotate amount by 1 to place them where 744 * the User protection bits are located. We get that 1 by extracting 745 * the MAS1[TS] (set for User access) and moving it to bit 31 (LSB). 746 */ 747 mfspr %r21, SPR_MAS1 /* get MAS1 which has TS bit */ 748 extrwi %r21, %r21, 1, 31-MAS1_TS_SHIFT 749 /* extract MAS1_TS to LSB */ 750 clrrwi %r23, %r20, PAGE_SHIFT /* clear non-RPN bits from PTE */ 751 andi. %r20, %r20, PTE_RWX_MASK /* isolate protection bits */ 752 rotrwi %r20, %r20, PTE_RWX_SHIFT 753 andi. %r22, %r20, (MAS3_SW|MAS3_SR) /* user pages need to be R/W by kernel */ 754 rotlw %r20, %r20, %r21 /* rotate protection to correct loc */ 755 or %r20, %r20, %r22 /* combine system protection bits */ 756 or %r23, %r23, %r20 /* combine RPN and protection bits */ 757 mtspr SPR_MAS3, %r23 /* put into MAS3 */ 758 isync /* because ECORE500RM tells us too */ 759 tlbwe /* write the TLB entry */ 760 /* 761 * Increment a counter to show how many tlb misses we've handled here. 762 */ 763 lmw %r30, CI_EV_TLBMISS_SOFT(%r2) 764 addic %r31, %r31, 1 765 addze %r30, %r30 766 stmw %r30, CI_EV_TLBMISS_SOFT(%r2) 767 /* 768 * Cleanup and leave. We know any higher priority exception will 769 * save and restore SPRG1 and %r2 thereby preserving their values. 770 * 771 * r24 = DEAR (don't care) 772 * r25 = ESR (don't care) 773 * r26 = saved r2 774 * r27 = CR 775 * r28 = XER 776 * r29 = LR 777 * r30 = LSW of counter 778 * r31 = MSW of counter 779 */ 780 mtlr %r29 /* restore Link Register */ 781 mtxer %r28 /* restore XER */ 782 mtcr %r27 /* restore Condition Register */ 783 mtsprg1 %r26 /* save saved r2 across load multiple */ 784 mfsprg3 %r2 /* get end of save area */ 785 addi %r2,%r2,-4*(32-20) /* adjust save area down */ 786 lmw %r20,0(%r2) /* restore r20-r31 */ 787 mtsprg3 %r2 /* save new end of save area */ 788 mfsprg1 %r2 /* restore r2 */ 789 rfi 790 791 .p2align 4 792 .globl _C_LABEL(exception_init) 793_C_LABEL(exception_init): 794 lis %r6,_C_LABEL(critical_input_vector)@h 795 mtspr SPR_IVPR, %r6 796 797 ori %r5,%r6,_C_LABEL(critical_input_vector)@l 798 mtspr SPR_IVOR0, %r5 799 800 ori %r5,%r6,_C_LABEL(machine_check_vector)@l 801 mtspr SPR_IVOR1, %r5 802 803 ori %r5,%r6,_C_LABEL(data_storage_vector)@l 804 mtspr SPR_IVOR2, %r5 805 806 ori %r5,%r6,_C_LABEL(instruction_storage_vector)@l 807 mtspr SPR_IVOR3, %r5 808 809 ori %r5,%r6,_C_LABEL(external_input_vector)@l 810 mtspr SPR_IVOR4, %r5 811 812 ori %r5,%r6,_C_LABEL(alignment_vector)@l 813 mtspr SPR_IVOR5, %r5 814 815 ori %r5,%r6,_C_LABEL(program_vector)@l 816 mtspr SPR_IVOR6, %r5 817 818#ifdef SPR_IVOR7 819 ori %r5,%r6,_C_LABEL(fp_unavailable_vector)@l 820 mtspr SPR_IVOR7, %r5 821#endif 822 823 ori %r5,%r6,_C_LABEL(system_call_vector)@l 824 mtspr SPR_IVOR8, %r5 825 826#ifdef SPR_IVOR9 827 ori %r5,%r6,_C_LABEL(ap_unavailable_vector)@l 828 mtspr SPR_IVOR9, %r5 829#endif 830 831 ori %r5,%r6,_C_LABEL(decrementer_vector)@l 832 mtspr SPR_IVOR10, %r5 833 834 ori %r5,%r6,_C_LABEL(fixed_interval_timer_vector)@l 835 mtspr SPR_IVOR11, %r5 836 837 ori %r5,%r6,_C_LABEL(watchdog_timer_vector)@l 838 mtspr SPR_IVOR12, %r5 839 840 ori %r5,%r6,_C_LABEL(data_tlb_error_vector)@l 841 mtspr SPR_IVOR13, %r5 842 843 ori %r5,%r6,_C_LABEL(instruction_tlb_error_vector)@l 844 mtspr SPR_IVOR14, %r5 845 846 ori %r5,%r6,_C_LABEL(debug_vector)@l 847 mtspr SPR_IVOR15, %r5 848 849 ori %r5,%r6,_C_LABEL(spv_unavailable_vector)@l 850 mtspr SPR_IVOR32, %r5 851 852 ori %r5,%r6,_C_LABEL(fpdata_vector)@l 853 mtspr SPR_IVOR33, %r5 854 855 ori %r5,%r6,_C_LABEL(fpround_vector)@l 856 mtspr SPR_IVOR34, %r5 857 858 ori %r5,%r6,_C_LABEL(perfmon_vector)@l 859 mtspr SPR_IVOR35, %r5 860 861 mfpir %r5 /* get Process ID register */ 862 cmplwi %r5,0 863 bnelr /* return if non-0 (non-primary) */ 864 865 lis %r5,_C_LABEL(powerpc_intrsw)@ha 866 stw %r3,_C_LABEL(powerpc_intrsw)@l(%r5) 867 868 blr 869 870#ifdef notyet 871 .data 872 .lcomm ddbstk,4096 873 .text 874 875_ENTRY(cpu_Debugger) 876 mflr %r0 877 stw %r0, CFRAME_LR(%r1) 878 879 mfmsr %r3 880 wrteei 0 881 mr %r4,%r1 882 lis %r10,ddbstk@ha 883 addi %r10,%r10,ddbstk@l 884 sub %r5,%r1,%r10 885 cmplwi %r5,4096 886 blt %cr0, 1f 887 addi %r1,%r10,4096-CALLFRAMELEN 8881: 889 stwu %r4,-FRAMELEN(%r1) 890 stw %r4,FRAME_R1(%r1) 891 stmw %r13,FRAME_R13(%r1) 892 mr %r26,%r0 893 mfcr %r27 894 mfxer %r28 895 mfctr %r29 896 mr %r30,%r0 897 mr %r31,%r3 898 stmw %r26,FRAME_LR(%r1) 899 mr %r31,%r1 900 mr %r1,%r10 901 addi %r4,%r1,FRAME_TF 902 li %r3,EXC_PGM 903 stw %r3,FRAME_EXC(%r1) 904 li %r3,T_PROGRAM 905 bl _C_LABEL(trap) 906 lmw %r26,FRAME_LR(%r1) 907 mtlr %r26 908 mtcr %r27 909 mtxer %r28 910 mtctr %r29 911 mr %r0,%r31 912 lmw %r13,FRAME_R13(%r1) 913 lwz %r1,FRAME_R1(%r1) 914 wrtee %r0 915 blr 916#endif /* notyet */ 917