2 * Copyright (C) 2006-2009 Semihalf, Rafal Jaworowski <raj@semihalf.com>
3 * Copyright (C) 2006 Semihalf, Marian Balakowicz <m8@semihalf.com>
4 * Copyright (C) 2006 Juniper Networks, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
21 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
23 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
31 * Copyright (C) 1995, 1996 TooLs GmbH.
32 * All rights reserved.
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 * 3. All advertising materials mentioning features or use of this software
43 * must display the following acknowledgement:
44 * This product includes software developed by TooLs GmbH.
45 * 4. The name of TooLs GmbH may not be used to endorse or promote products
46 * derived from this software without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
49 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
50 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
51 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
53 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
54 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
55 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
56 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
57 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59 * from: $NetBSD: trap_subr.S,v 1.20 2002/04/22 23:20:08 kleink Exp $
63 * NOTICE: This is not a standalone file. to use it, #include it in
64 * your port's locore.S, like so:
66 * #include <powerpc/booke/trap_subr.S>
72 * SPRG0 - pcpu pointer
73 * SPRG1 - all interrupts except TLB miss, critical, machine check
75 * SPRG3 - machine check
80 /* Get the per-CPU data structure */
81 #define GET_CPUINFO(r) mfsprg0 r
83 #define RES_GRANULE 64
84 #define RES_LOCK 0 /* offset to the 'lock' word */
86 #define RES_RECURSE 8 /* offset to the 'recurse' word */
88 #define RES_RECURSE 4 /* offset to the 'recurse' word */
92 * Standard interrupt prolog
94 * sprg_sp - SPRG{1-3} reg used to temporarily store the SP
95 * savearea - temp save area (pc_{tempsave, disisave, critsave, mchksave})
96 * isrr0-1 - save restore registers with CPU state at interrupt time (may be
97 * SRR0-1, CSRR0-1, MCSRR0-1
99 * 1. saves in the given savearea:
106 * 3. switches to kstack if needed
109 * - R31 can be used as scratch register until a new frame is laid on
110 * the stack with FRAME_SETUP
112 * - potential TLB miss: NO. Saveareas are always acessible via TLB1
113 * permanent entries, and within this prolog we do not dereference any
114 * locations potentially not in the TLB
116 #define STANDARD_PROLOG(sprg_sp, savearea, isrr0, isrr1) \
117 mtspr sprg_sp, %r1; /* Save SP */ \
118 GET_CPUINFO(%r1); /* Per-cpu structure */ \
119 STORE %r30, (savearea+CPUSAVE_R30)(%r1); \
120 STORE %r31, (savearea+CPUSAVE_R31)(%r1); \
121 mfspr %r30, SPR_DEAR; \
122 mfspr %r31, SPR_ESR; \
123 STORE %r30, (savearea+CPUSAVE_BOOKE_DEAR)(%r1); \
124 STORE %r31, (savearea+CPUSAVE_BOOKE_ESR)(%r1); \
126 mfspr %r31, isrr1; /* MSR at interrupt time */ \
127 STORE %r30, (savearea+CPUSAVE_SRR0)(%r1); \
128 STORE %r31, (savearea+CPUSAVE_SRR1)(%r1); \
130 mfspr %r1, sprg_sp; /* Restore SP */ \
131 mfcr %r30; /* Save CR */ \
132 /* switch to per-thread kstack if intr taken in user mode */ \
133 mtcr %r31; /* MSR at interrupt time */ \
135 GET_CPUINFO(%r1); /* Per-cpu structure */ \
136 LOAD %r1, PC_CURPCB(%r1); /* Per-thread kernel stack */ \
139 #define STANDARD_CRIT_PROLOG(sprg_sp, savearea, isrr0, isrr1) \
140 mtspr sprg_sp, %r1; /* Save SP */ \
141 GET_CPUINFO(%r1); /* Per-cpu structure */ \
142 STORE %r30, (savearea+CPUSAVE_R30)(%r1); \
143 STORE %r31, (savearea+CPUSAVE_R31)(%r1); \
144 mfspr %r30, SPR_DEAR; \
145 mfspr %r31, SPR_ESR; \
146 STORE %r30, (savearea+CPUSAVE_BOOKE_DEAR)(%r1); \
147 STORE %r31, (savearea+CPUSAVE_BOOKE_ESR)(%r1); \
149 mfspr %r31, isrr1; /* MSR at interrupt time */ \
150 STORE %r30, (savearea+CPUSAVE_SRR0)(%r1); \
151 STORE %r31, (savearea+CPUSAVE_SRR1)(%r1); \
152 mfspr %r30, SPR_SRR0; \
153 mfspr %r31, SPR_SRR1; /* MSR at interrupt time */ \
154 STORE %r30, (savearea+BOOKE_CRITSAVE_SRR0)(%r1); \
155 STORE %r31, (savearea+BOOKE_CRITSAVE_SRR1)(%r1); \
157 mfspr %r1, sprg_sp; /* Restore SP */ \
158 mfcr %r30; /* Save CR */ \
159 /* switch to per-thread kstack if intr taken in user mode */ \
160 mtcr %r31; /* MSR at interrupt time */ \
162 GET_CPUINFO(%r1); /* Per-cpu structure */ \
163 LOAD %r1, PC_CURPCB(%r1); /* Per-thread kernel stack */ \
167 * FRAME_SETUP assumes:
168 * SPRG{1-3} SP at the time interrupt occurred
169 * savearea r30-r31, DEAR, ESR, xSRR0-1
174 * sprg_sp - SPRG reg containing SP at the time interrupt occurred
175 * savearea - temp save
176 * exc - exception number (EXC_xxx)
178 * 1. sets a new frame
179 * 2. saves in the frame:
180 * - R0, R1 (SP at the time of interrupt), R2, LR, CR
181 * - R3-31 (R30-31 first restored from savearea)
182 * - XER, CTR, DEAR, ESR (from savearea), xSRR0-1
185 * - potential TLB miss: YES, since we make dereferences to kstack, which
186 * can happen not covered (we can have up to two DTLB misses if fortunate
187 * enough i.e. when kstack crosses page boundary and both pages are
191 #define SAVE_REGS(r) \
192 std %r3, FRAME_3+CALLSIZE(r); \
193 std %r4, FRAME_4+CALLSIZE(r); \
194 std %r5, FRAME_5+CALLSIZE(r); \
195 std %r6, FRAME_6+CALLSIZE(r); \
196 std %r7, FRAME_7+CALLSIZE(r); \
197 std %r8, FRAME_8+CALLSIZE(r); \
198 std %r9, FRAME_9+CALLSIZE(r); \
199 std %r10, FRAME_10+CALLSIZE(r); \
200 std %r11, FRAME_11+CALLSIZE(r); \
201 std %r12, FRAME_12+CALLSIZE(r); \
202 std %r13, FRAME_13+CALLSIZE(r); \
203 std %r14, FRAME_14+CALLSIZE(r); \
204 std %r15, FRAME_15+CALLSIZE(r); \
205 std %r16, FRAME_16+CALLSIZE(r); \
206 std %r17, FRAME_17+CALLSIZE(r); \
207 std %r18, FRAME_18+CALLSIZE(r); \
208 std %r19, FRAME_19+CALLSIZE(r); \
209 std %r20, FRAME_20+CALLSIZE(r); \
210 std %r21, FRAME_21+CALLSIZE(r); \
211 std %r22, FRAME_22+CALLSIZE(r); \
212 std %r23, FRAME_23+CALLSIZE(r); \
213 std %r24, FRAME_24+CALLSIZE(r); \
214 std %r25, FRAME_25+CALLSIZE(r); \
215 std %r26, FRAME_26+CALLSIZE(r); \
216 std %r27, FRAME_27+CALLSIZE(r); \
217 std %r28, FRAME_28+CALLSIZE(r); \
218 std %r29, FRAME_29+CALLSIZE(r); \
219 std %r30, FRAME_30+CALLSIZE(r); \
220 std %r31, FRAME_31+CALLSIZE(r)
222 ld %r3, FRAME_3+CALLSIZE(r); \
223 ld %r4, FRAME_4+CALLSIZE(r); \
224 ld %r5, FRAME_5+CALLSIZE(r); \
225 ld %r6, FRAME_6+CALLSIZE(r); \
226 ld %r7, FRAME_7+CALLSIZE(r); \
227 ld %r8, FRAME_8+CALLSIZE(r); \
228 ld %r9, FRAME_9+CALLSIZE(r); \
229 ld %r10, FRAME_10+CALLSIZE(r); \
230 ld %r11, FRAME_11+CALLSIZE(r); \
231 ld %r12, FRAME_12+CALLSIZE(r); \
232 ld %r13, FRAME_13+CALLSIZE(r); \
233 ld %r14, FRAME_14+CALLSIZE(r); \
234 ld %r15, FRAME_15+CALLSIZE(r); \
235 ld %r16, FRAME_16+CALLSIZE(r); \
236 ld %r17, FRAME_17+CALLSIZE(r); \
237 ld %r18, FRAME_18+CALLSIZE(r); \
238 ld %r19, FRAME_19+CALLSIZE(r); \
239 ld %r20, FRAME_20+CALLSIZE(r); \
240 ld %r21, FRAME_21+CALLSIZE(r); \
241 ld %r22, FRAME_22+CALLSIZE(r); \
242 ld %r23, FRAME_23+CALLSIZE(r); \
243 ld %r24, FRAME_24+CALLSIZE(r); \
244 ld %r25, FRAME_25+CALLSIZE(r); \
245 ld %r26, FRAME_26+CALLSIZE(r); \
246 ld %r27, FRAME_27+CALLSIZE(r); \
247 ld %r28, FRAME_28+CALLSIZE(r); \
248 ld %r29, FRAME_29+CALLSIZE(r); \
249 ld %r30, FRAME_30+CALLSIZE(r); \
250 ld %r31, FRAME_31+CALLSIZE(r)
252 #define SAVE_REGS(r) \
253 stmw %r3, FRAME_3+CALLSIZE(r)
255 lmw %r3, FRAME_3+CALLSIZE(r)
257 #define FRAME_SETUP(sprg_sp, savearea, exc) \
258 mfspr %r31, sprg_sp; /* get saved SP */ \
259 /* establish a new stack frame and put everything on it */ \
260 STU %r31, -(FRAMELEN+REDZONE)(%r1); \
261 STORE %r0, FRAME_0+CALLSIZE(%r1); /* save r0 in the trapframe */ \
262 STORE %r31, FRAME_1+CALLSIZE(%r1); /* save SP " " */ \
263 STORE %r2, FRAME_2+CALLSIZE(%r1); /* save r2 " " */ \
265 STORE %r31, FRAME_LR+CALLSIZE(%r1); /* save LR " " */ \
266 STORE %r30, FRAME_CR+CALLSIZE(%r1); /* save CR " " */ \
268 LOAD %r30, (savearea+CPUSAVE_R30)(%r2); /* get saved r30 */ \
269 LOAD %r31, (savearea+CPUSAVE_R31)(%r2); /* get saved r31 */ \
272 /* save DEAR, ESR */ \
273 LOAD %r28, (savearea+CPUSAVE_BOOKE_DEAR)(%r2); \
274 LOAD %r29, (savearea+CPUSAVE_BOOKE_ESR)(%r2); \
275 STORE %r28, FRAME_BOOKE_DEAR+CALLSIZE(%r1); \
276 STORE %r29, FRAME_BOOKE_ESR+CALLSIZE(%r1); \
277 /* save XER, CTR, exc number */ \
280 STORE %r3, FRAME_XER+CALLSIZE(%r1); \
281 STORE %r4, FRAME_CTR+CALLSIZE(%r1); \
283 STORE %r5, FRAME_EXC+CALLSIZE(%r1); \
285 mfspr %r3, SPR_DBCR0; \
286 STORE %r3, FRAME_BOOKE_DBCR0+CALLSIZE(%r1); \
288 LOAD %r30, (savearea+CPUSAVE_SRR0)(%r2); \
289 LOAD %r31, (savearea+CPUSAVE_SRR1)(%r2); \
290 STORE %r30, FRAME_SRR0+CALLSIZE(%r1); \
291 STORE %r31, FRAME_SRR1+CALLSIZE(%r1); \
292 LOAD THREAD_REG, PC_CURTHREAD(%r2); \
296 * isrr0-1 - save restore registers to restore CPU state to (may be
297 * SRR0-1, CSRR0-1, MCSRR0-1
300 * - potential TLB miss: YES. The deref'd kstack may be not covered
302 #define FRAME_LEAVE(isrr0, isrr1) \
304 /* restore CTR, XER, LR, CR */ \
305 LOAD %r4, FRAME_CTR+CALLSIZE(%r1); \
306 LOAD %r5, FRAME_XER+CALLSIZE(%r1); \
307 LOAD %r6, FRAME_LR+CALLSIZE(%r1); \
308 LOAD %r7, FRAME_CR+CALLSIZE(%r1); \
313 /* restore DBCR0 */ \
314 LOAD %r4, FRAME_BOOKE_DBCR0+CALLSIZE(%r1); \
315 mtspr SPR_DBCR0, %r4; \
316 /* restore xSRR0-1 */ \
317 LOAD %r30, FRAME_SRR0+CALLSIZE(%r1); \
318 LOAD %r31, FRAME_SRR1+CALLSIZE(%r1); \
321 /* restore R2-31, SP */ \
323 LOAD %r2, FRAME_2+CALLSIZE(%r1); \
324 LOAD %r0, FRAME_0+CALLSIZE(%r1); \
325 LOAD %r1, FRAME_1+CALLSIZE(%r1); \
331 * saves LR, CR, SRR0-1, R20-31 in the TLBSAVE area
334 * - potential TLB miss: NO. It is crucial that we do not generate a TLB
335 * miss within the TLB prolog itself!
336 * - TLBSAVE is always translated
339 #define TLB_SAVE_REGS(br) \
340 std %r20, (TLBSAVE_BOOKE_R20)(br); \
341 std %r21, (TLBSAVE_BOOKE_R21)(br); \
342 std %r22, (TLBSAVE_BOOKE_R22)(br); \
343 std %r23, (TLBSAVE_BOOKE_R23)(br); \
344 std %r24, (TLBSAVE_BOOKE_R24)(br); \
345 std %r25, (TLBSAVE_BOOKE_R25)(br); \
346 std %r26, (TLBSAVE_BOOKE_R26)(br); \
347 std %r27, (TLBSAVE_BOOKE_R27)(br); \
348 std %r28, (TLBSAVE_BOOKE_R28)(br); \
349 std %r29, (TLBSAVE_BOOKE_R29)(br); \
350 std %r30, (TLBSAVE_BOOKE_R30)(br); \
351 std %r31, (TLBSAVE_BOOKE_R31)(br);
352 #define TLB_RESTORE_REGS(br) \
353 ld %r20, (TLBSAVE_BOOKE_R20)(br); \
354 ld %r21, (TLBSAVE_BOOKE_R21)(br); \
355 ld %r22, (TLBSAVE_BOOKE_R22)(br); \
356 ld %r23, (TLBSAVE_BOOKE_R23)(br); \
357 ld %r24, (TLBSAVE_BOOKE_R24)(br); \
358 ld %r25, (TLBSAVE_BOOKE_R25)(br); \
359 ld %r26, (TLBSAVE_BOOKE_R26)(br); \
360 ld %r27, (TLBSAVE_BOOKE_R27)(br); \
361 ld %r28, (TLBSAVE_BOOKE_R28)(br); \
362 ld %r29, (TLBSAVE_BOOKE_R29)(br); \
363 ld %r30, (TLBSAVE_BOOKE_R30)(br); \
364 ld %r31, (TLBSAVE_BOOKE_R31)(br);
365 #define TLB_NEST(outr,inr) \
366 rlwinm outr, inr, 7, 23, 24; /* 8 x TLBSAVE_LEN */
368 #define TLB_SAVE_REGS(br) \
369 stmw %r20, TLBSAVE_BOOKE_R20(br)
370 #define TLB_RESTORE_REGS(br) \
371 lmw %r20, TLBSAVE_BOOKE_R20(br)
372 #define TLB_NEST(outr,inr) \
373 rlwinm outr, inr, 6, 24, 25; /* 4 x TLBSAVE_LEN */
376 mtspr SPR_SPRG4, %r1; /* Save SP */ \
377 mtspr SPR_SPRG5, %r28; \
378 mtspr SPR_SPRG6, %r29; \
379 /* calculate TLB nesting level and TLBSAVE instance address */ \
380 GET_CPUINFO(%r1); /* Per-cpu structure */ \
381 LOAD %r28, PC_BOOKE_TLB_LEVEL(%r1); \
382 TLB_NEST(%r29,%r28); \
383 addi %r28, %r28, 1; \
384 STORE %r28, PC_BOOKE_TLB_LEVEL(%r1); \
385 addi %r29, %r29, PC_BOOKE_TLBSAVE@l; \
386 add %r1, %r1, %r29; /* current TLBSAVE ptr */ \
389 mfspr %r28, SPR_SPRG5; \
390 mfspr %r29, SPR_SPRG6; \
391 TLB_SAVE_REGS(%r1); \
395 STORE %r30, (TLBSAVE_BOOKE_LR)(%r1); \
396 STORE %r31, (TLBSAVE_BOOKE_CR)(%r1); \
398 mfsrr0 %r30; /* execution addr at interrupt time */ \
399 mfsrr1 %r31; /* MSR at interrupt time*/ \
400 STORE %r30, (TLBSAVE_BOOKE_SRR0)(%r1); /* save SRR0 */ \
401 STORE %r31, (TLBSAVE_BOOKE_SRR1)(%r1); /* save SRR1 */ \
406 * restores LR, CR, SRR0-1, R20-31 from the TLBSAVE area
408 * same notes as for the TLB_PROLOG
410 #define TLB_RESTORE \
411 mtspr SPR_SPRG4, %r1; /* Save SP */ \
412 GET_CPUINFO(%r1); /* Per-cpu structure */ \
413 /* calculate TLB nesting level and TLBSAVE instance addr */ \
414 LOAD %r28, PC_BOOKE_TLB_LEVEL(%r1); \
415 subi %r28, %r28, 1; \
416 STORE %r28, PC_BOOKE_TLB_LEVEL(%r1); \
417 TLB_NEST(%r29,%r28); \
418 addi %r29, %r29, PC_BOOKE_TLBSAVE@l; \
419 add %r1, %r1, %r29; \
421 /* restore LR, CR */ \
422 LOAD %r30, (TLBSAVE_BOOKE_LR)(%r1); \
423 LOAD %r31, (TLBSAVE_BOOKE_CR)(%r1); \
426 /* restore SRR0-1 */ \
427 LOAD %r30, (TLBSAVE_BOOKE_SRR0)(%r1); \
428 LOAD %r31, (TLBSAVE_BOOKE_SRR1)(%r1); \
431 /* restore R20-31 */ \
432 TLB_RESTORE_REGS(%r1); \
438 LOAD %r21, PC_CURTHREAD(%r20); \
439 LOAD %r22, PC_BOOKE_TLB_LOCK(%r20); \
441 1: LOADX %r23, 0, %r22; \
442 CMPI %r23, TLB_UNLOCKED; \
445 /* check if this is recursion */ \
446 CMPL cr0, %r21, %r23; \
449 2: /* try to acquire lock */ \
450 STOREX %r21, 0, %r22; \
453 /* got it, update recursion counter */ \
454 lwz %r21, RES_RECURSE(%r22); \
455 addi %r21, %r21, 1; \
456 stw %r21, RES_RECURSE(%r22); \
462 LOAD %r21, PC_CURTHREAD(%r20); \
463 LOAD %r22, PC_BOOKE_TLB_LOCK(%r20); \
465 /* update recursion counter */ \
466 lwz %r23, RES_RECURSE(%r22); \
467 subi %r23, %r23, 1; \
468 stw %r23, RES_RECURSE(%r22); \
475 /* release the lock */ \
476 li %r23, TLB_UNLOCKED; \
477 STORE %r23, 0(%r22); \
485 #define INTERRUPT(label) \
491 * Interrupt handling routines in BookE can be flexibly placed and do not have
492 * to live in pre-defined vectors location. Note they need to be TLB-mapped at
493 * all times in order to be able to handle exceptions. We thus arrange for
494 * them to be part of kernel text which is always TLB-accessible.
496 * The interrupt handling routines have to be 16 bytes aligned: we align them
497 * to 32 bytes (cache line length) which supposedly performs better.
501 .globl CNAME(interrupt_vector_base)
503 interrupt_vector_base:
504 /*****************************************************************************
505 * Catch-all handler to handle uninstalled IVORs
506 ****************************************************************************/
507 INTERRUPT(int_unknown)
508 STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
509 FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_RSVD)
512 /*****************************************************************************
513 * Critical input interrupt
514 ****************************************************************************/
515 INTERRUPT(int_critical_input)
516 STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)
517 FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_CRIT)
519 addi %r3, %r1, CALLSIZE
520 bl CNAME(powerpc_interrupt)
522 FRAME_LEAVE(SPR_CSRR0, SPR_CSRR1)
526 /*****************************************************************************
527 * Machine check interrupt
528 ****************************************************************************/
529 INTERRUPT(int_machine_check)
530 STANDARD_PROLOG(SPR_SPRG3, PC_BOOKE_MCHKSAVE, SPR_MCSRR0, SPR_MCSRR1)
531 FRAME_SETUP(SPR_SPRG3, PC_BOOKE_MCHKSAVE, EXC_MCHK)
533 addi %r3, %r1, CALLSIZE
534 bl CNAME(powerpc_interrupt)
536 FRAME_LEAVE(SPR_MCSRR0, SPR_MCSRR1)
540 /*****************************************************************************
541 * Data storage interrupt
542 ****************************************************************************/
543 INTERRUPT(int_data_storage)
544 STANDARD_PROLOG(SPR_SPRG1, PC_DISISAVE, SPR_SRR0, SPR_SRR1)
545 FRAME_SETUP(SPR_SPRG1, PC_DISISAVE, EXC_DSI)
549 /*****************************************************************************
550 * Instruction storage interrupt
551 ****************************************************************************/
552 INTERRUPT(int_instr_storage)
553 STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
554 FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_ISI)
558 /*****************************************************************************
559 * External input interrupt
560 ****************************************************************************/
561 INTERRUPT(int_external_input)
562 STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
563 FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_EXI)
567 INTERRUPT(int_alignment)
568 STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
569 FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_ALI)
573 INTERRUPT(int_program)
574 STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
575 FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_PGM)
580 STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
581 FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_FPU)
585 /*****************************************************************************
587 ****************************************************************************/
588 INTERRUPT(int_syscall)
589 STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
590 FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_SC)
594 /*****************************************************************************
595 * Decrementer interrupt
596 ****************************************************************************/
597 INTERRUPT(int_decrementer)
598 STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
599 FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_DECR)
603 /*****************************************************************************
604 * Fixed interval timer
605 ****************************************************************************/
606 INTERRUPT(int_fixed_interval_timer)
607 STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
608 FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_FIT)
612 /*****************************************************************************
614 ****************************************************************************/
615 INTERRUPT(int_watchdog)
616 STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
617 FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_WDOG)
621 /*****************************************************************************
622 * Altivec Unavailable interrupt
623 ****************************************************************************/
625 STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
626 FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_VEC)
630 /*****************************************************************************
631 * Altivec Assist interrupt
632 ****************************************************************************/
633 INTERRUPT(int_vecast)
634 STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
635 FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_VECAST_E)
640 /*****************************************************************************
641 * Floating point Assist interrupt
642 ****************************************************************************/
643 INTERRUPT(int_spe_fpdata)
644 STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
645 FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_SPFPD)
646 addi %r3, %r1, CALLSIZE
648 FRAME_LEAVE(SPR_SRR0, SPR_SRR1)
651 INTERRUPT(int_spe_fpround)
652 STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
653 FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_SPFPR)
654 addi %r3, %r1, CALLSIZE
655 bl spe_handle_fpround
656 FRAME_LEAVE(SPR_SRR0, SPR_SRR1)
662 /*****************************************************************************
664 ****************************************************************************/
665 INTERRUPT(int_performance_counter)
666 STANDARD_PROLOG(SPR_SPRG3, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
667 FRAME_SETUP(SPR_SPRG3, PC_TEMPSAVE, EXC_PERF)
672 /*****************************************************************************
673 * Data TLB miss interrupt
675 * There can be nested TLB misses - while handling a TLB miss we reference
676 * data structures that may be not covered by translations. We support up to
677 * TLB_NESTED_MAX-1 nested misses.
688 * r20:r23 - scratch registers
689 ****************************************************************************/
690 INTERRUPT(int_data_tlb_error)
697 * Save MAS0-MAS2 registers. There might be another tlb miss during
698 * pte lookup overwriting current contents (which was hw filled).
704 /* Check faulting address. */
705 LOAD_ADDR(%r21, VM_MAXUSER_ADDRESS)
709 /* If it's kernel address, allow only supervisor mode misses. */
712 bt 17, search_failed /* check MSR[PR] */
716 cmpldi cr0, %r21, VM_MIN_KERNEL_ADDRESS@highest
718 lis %r21, VM_MIN_KERNEL_ADDRESS@h
719 cmplw cr0, %r31, %r21
724 /* Load r26 with kernel_pmap address */
727 .llong kernel_pmap_store-.
729 .long kernel_pmap_store-.
733 add %r26, %r21, %r26 /* kernel_pmap_store in r26 */
735 /* Force kernel tid, set TID to 0 in MAS1. */
737 rlwimi %r28, %r21, 0, 8, 15 /* clear TID bits */
740 /* This may result in nested tlb miss. */
741 bl pte_lookup /* returns PTE address in R25 */
743 CMPI %r25, 0 /* pte found? */
746 /* Finish up, write TLB entry. */
755 /* Load r26 with current user space process pmap */
757 LOAD %r26, PC_CURPMAP(%r26)
763 * Whenever we don't find a TLB mapping in PT, set a TLB0 entry with
764 * the faulting virtual address anyway, but put a fake RPN and no
765 * access rights. This should cause a following {D,I}SI exception.
767 lis %r23, 0xffff0000@h /* revoke all permissions */
769 /* Load MAS registers. */
784 /*****************************************************************************
786 * Return pte address that corresponds to given pmap/va. If there is no valid
791 * output: r25 - pte address
793 * scratch regs used: r21
795 ****************************************************************************/
798 beq 1f /* fail quickly if pmap is invalid */
801 rldicl %r21, %r31, (64 - PG_ROOT_L), (64 - PG_ROOT_NUM) /* pp2d offset */
802 slwi %r21, %r21, PG_ROOT_ENTRY_SHIFT /* multiply by pp2d entry size */
803 ld %r25, PM_ROOT(%r26) /* pmap pm_pp2d[] address */
804 ldx %r25, %r25, %r21 /* get pdir address, i.e. pmap->pm_pp2d[pp2d_idx] * */
809 rldicl %r21, %r31, (64 - PDIR_L1_L), (64 - PDIR_L1_NUM) /* pp2d offset */
810 slwi %r21, %r21, PDIR_L1_ENTRY_SHIFT /* multiply by pp2d entry size */
811 ldx %r25, %r25, %r21 /* get pdir address, i.e. pmap->pm_pp2d[pp2d_idx] * */
816 rldicl %r21, %r31, (64 - PDIR_L), (64 - PDIR_NUM) /* pdir offset */
817 slwi %r21, %r21, PDIR_ENTRY_SHIFT /* multiply by pdir entry size */
818 ldx %r25, %r25, %r21 /* get ptbl address, i.e. pmap->pm_pp2d[pp2d_idx][pdir_idx] */
823 rldicl %r21, %r31, (64 - PTBL_L), (64 - PTBL_NUM) /* ptbl offset */
824 slwi %r21, %r21, PTBL_ENTRY_SHIFT /* multiply by pte entry size */
827 srwi %r21, %r31, PDIR_SHIFT /* pdir offset */
828 slwi %r21, %r21, PDIR_ENTRY_SHIFT /* multiply by pdir entry size */
830 lwz %r25, PM_PDIR(%r26) /* pmap pm_dir[] address */
832 * Get ptbl address, i.e. pmap->pm_pdir[pdir_idx]
833 * This load may cause a Data TLB miss for non-kernel pmap!
835 lwzx %r25, %r25, %r21 /* offset within pm_pdir[] table */
839 lis %r21, PTBL_MASK@h
840 ori %r21, %r21, PTBL_MASK@l
843 /* ptbl offset, multiply by ptbl entry size */
844 srwi %r21, %r21, (PTBL_SHIFT - PTBL_ENTRY_SHIFT)
847 add %r25, %r25, %r21 /* address of pte entry */
850 * This load may cause a Data TLB miss for non-kernel pmap!
852 lwz %r21, PTE_FLAGS(%r25)
853 andi. %r21, %r21, PTE_VALID@l
860 /*****************************************************************************
862 * Load MAS1-MAS3 registers with data, write TLB entry
872 * scratch regs: r21-r23
874 ****************************************************************************/
877 * Update PTE flags: we have to do it atomically, as pmap_protect()
878 * running on other CPUs could attempt to update the flags at the same
883 lwarx %r21, %r23, %r25 /* get pte->flags */
884 oris %r21, %r21, PTE_REFERENCED@h /* set referenced bit */
886 andi. %r22, %r21, (PTE_SW | PTE_UW)@l /* check if writable */
888 ori %r21, %r21, PTE_MODIFIED@l /* set modified bit */
890 stwcx. %r21, %r23, %r25 /* write it back */
894 rlwimi %r27, %r21, 13, 27, 30 /* insert WIMG bits from pte */
896 /* Setup MAS3 value in r23. */
897 LOAD %r23, PTE_RPN(%r25) /* get pte->rpn */
899 rldicr %r22, %r23, 52, 51 /* extract MAS3 portion of RPN */
900 rldicl %r23, %r23, 20, 54 /* extract MAS7 portion of RPN */
902 rlwimi %r22, %r21, 30, 26, 31 /* insert protection bits from pte */
904 rlwinm %r22, %r23, 20, 0, 11 /* extract MAS3 portion of RPN */
906 rlwimi %r22, %r21, 30, 26, 31 /* insert protection bits from pte */
907 rlwimi %r22, %r21, 20, 12, 19 /* insert lower 8 RPN bits to MAS3 */
908 rlwinm %r23, %r23, 20, 24, 31 /* MAS7 portion of RPN */
911 /* Load MAS registers. */
924 /*****************************************************************************
925 * Instruction TLB miss interrupt
927 * Same notes as for the Data TLB miss
928 ****************************************************************************/
929 INTERRUPT(int_inst_tlb_error)
933 mfsrr0 %r31 /* faulting address */
936 * Save MAS0-MAS2 registers. There might be another tlb miss during pte
937 * lookup overwriting current contents (which was hw filled).
947 bt 17, search_user_pmap
951 .globl interrupt_vector_top
952 interrupt_vector_top:
954 /*****************************************************************************
956 ****************************************************************************/
958 STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)
959 FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_DEBUG)
961 FRAME_LEAVE(SPR_CSRR0, SPR_CSRR1)
964 INTERRUPT(int_debug_ed)
965 STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_DSRR0, SPR_DSRR1)
966 FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_DEBUG)
968 FRAME_LEAVE(SPR_DSRR0, SPR_DSRR1)
970 /* .long 0x4c00004e */
972 /* Internal helper for debug interrupt handling. */
973 /* Common code between e500v1/v2 and e500mc-based cores. */
977 LOAD %r3, (PC_BOOKE_CRITSAVE+CPUSAVE_SRR0)(%r3)
979 ADDR(interrupt_vector_base-.)
980 ADDR(interrupt_vector_top-.)
982 LOAD %r4,0(%r5) /* interrupt_vector_base in r4 */
986 LOAD %r4,WORD_SIZE(%r5) /* interrupt_vector_top in r4 */
991 /* Disable single-stepping for the interrupt handlers. */
992 LOAD %r3, FRAME_SRR1+CALLSIZE(%r1);
993 rlwinm %r3, %r3, 0, 23, 21
994 STORE %r3, FRAME_SRR1+CALLSIZE(%r1);
995 /* Restore srr0 and srr1 as they could have been clobbered. */
997 LOAD %r3, (PC_BOOKE_CRITSAVE+BOOKE_CRITSAVE_SRR0)(%r4);
999 LOAD %r4, (PC_BOOKE_CRITSAVE+BOOKE_CRITSAVE_SRR1)(%r4);
1004 /*****************************************************************************
1006 ****************************************************************************/
1008 /* Call C trap dispatcher */
1010 addi %r3, %r1, CALLSIZE
1011 bl CNAME(powerpc_interrupt)
1014 .globl CNAME(trapexit) /* exported for db_backtrace use */
1016 /* disable interrupts */
1019 /* Test AST pending - makes sense for user process only */
1020 LOAD %r5, FRAME_SRR1+CALLSIZE(%r1)
1025 LOAD %r4, PC_CURTHREAD(%r3)
1026 lwz %r4, TD_AST(%r4)
1030 /* re-enable interrupts before calling ast() */
1033 addi %r3, %r1, CALLSIZE
1036 .globl CNAME(asttrapexit) /* db_backtrace code sentinel #2 */
1038 b trapexit /* test ast ret value ? */
1040 FRAME_LEAVE(SPR_SRR0, SPR_SRR1)
1046 * Deliberate entry to dbtrap
1048 /* .globl CNAME(breakpoint)*/
1049 ASENTRY_NOPROF(breakpoint)
1053 li %r4, ~(PSL_EE | PSL_ME)@l
1054 oris %r4, %r4, ~(PSL_EE | PSL_ME)@h
1056 mtmsr %r3 /* disable interrupts */
1059 STORE %r30, (PC_DBSAVE+CPUSAVE_R30)(%r3)
1060 STORE %r31, (PC_DBSAVE+CPUSAVE_R31)(%r3)
1065 mfspr %r30, SPR_DEAR
1067 STORE %r30, (PC_DBSAVE+CPUSAVE_BOOKE_DEAR)(%r3)
1068 STORE %r31, (PC_DBSAVE+CPUSAVE_BOOKE_ESR)(%r3)
1072 STORE %r30, (PC_DBSAVE+CPUSAVE_SRR0)(%r3)
1073 STORE %r31, (PC_DBSAVE+CPUSAVE_SRR1)(%r3)
1079 * Now the kdb trap catching code.
1082 FRAME_SETUP(SPR_SPRG1, PC_DBSAVE, EXC_DEBUG)
1083 /* Call C trap code: */
1085 addi %r3, %r1, CALLSIZE
1086 bl CNAME(db_trap_glue)
1090 /* This wasn't for KDB, so switch to real trap: */
1094 FRAME_LEAVE(SPR_SRR0, SPR_SRR1)
1102 LOAD %r5, PC_CURTHREAD(%r5)
1103 1: LOADX %r4, 0, %r3
1104 CMPI %r4, TLB_UNLOCKED
1116 li %r4, TLB_UNLOCKED
1124 * TLB miss spin locks. For each CPU we have a reservation granule (32 bytes);
1125 * only a single word from this granule will actually be used as a spin lock
1126 * for mutual exclusion between TLB miss handler and pmap layer that
1127 * manipulates page table contents.
1131 GLOBAL(tlb0_miss_locks)
1132 .space RES_GRANULE * MAXCPU