]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/powerpc/booke/trap_subr.S
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / powerpc / booke / trap_subr.S
1 /*-
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.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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.
17  *
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.
28  *
29  * $FreeBSD$
30  */
31 /*-
32  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
33  * Copyright (C) 1995, 1996 TooLs GmbH.
34  * All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. All advertising materials mentioning features or use of this software
45  *    must display the following acknowledgement:
46  *      This product includes software developed by TooLs GmbH.
47  * 4. The name of TooLs GmbH may not be used to endorse or promote products
48  *    derived from this software without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
51  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
52  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
53  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
54  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
55  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
56  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
57  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
58  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
59  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60  *
61  *      from: $NetBSD: trap_subr.S,v 1.20 2002/04/22 23:20:08 kleink Exp $
62  */
63
64 /*
65  * NOTICE: This is not a standalone file.  to use it, #include it in
66  * your port's locore.S, like so:
67  *
68  *      #include <powerpc/booke/trap_subr.S>
69  */
70
71 /*
72  * SPRG usage notes
73  *
74  * SPRG0 - pcpu pointer
75  * SPRG1 - all interrupts except TLB miss, critical, machine check
76  * SPRG2 - critical
77  * SPRG3 - machine check
78  * SPRG4-6 - scratch
79  *
80  */
81
82 /* Get the per-CPU data structure */
83 #define GET_CPUINFO(r) mfsprg0 r
84
85 #define RES_GRANULE     32
86 #define RES_LOCK        0       /* offset to the 'lock' word */
87 #define RES_RECURSE     4       /* offset to the 'recurse' word */
88
89 /*
90  * Standard interrupt prolog
91  *
92  * sprg_sp - SPRG{1-3} reg used to temporarily store the SP
93  * savearea - temp save area (pc_{tempsave, disisave, critsave, mchksave})
94  * isrr0-1 - save restore registers with CPU state at interrupt time (may be
95  *           SRR0-1, CSRR0-1, MCSRR0-1
96  *
97  * 1. saves in the given savearea:
98  *   - R30-31
99  *   - DEAR, ESR
100  *   - xSRR0-1
101  *
102  * 2. saves CR -> R30
103  *
104  * 3. switches to kstack if needed
105  *
106  * 4. notes:
107  *   - R31 can be used as scratch register until a new frame is layed on
108  *     the stack with FRAME_SETUP
109  *
110  *   - potential TLB miss: NO. Saveareas are always acessible via TLB1 
111  *     permanent entries, and within this prolog we do not dereference any
112  *     locations potentially not in the TLB
113  */
114 #define STANDARD_PROLOG(sprg_sp, savearea, isrr0, isrr1)                \
115         mtspr   sprg_sp, %r1;           /* Save SP */                   \
116         GET_CPUINFO(%r1);               /* Per-cpu structure */         \
117         stw     %r30, (savearea+CPUSAVE_R30)(%r1);                      \
118         stw     %r31, (savearea+CPUSAVE_R31)(%r1);                      \
119         mfdear  %r30;                                                   \
120         mfesr   %r31;                                                   \
121         stw     %r30, (savearea+CPUSAVE_BOOKE_DEAR)(%r1);               \
122         stw     %r31, (savearea+CPUSAVE_BOOKE_ESR)(%r1);                \
123         mfspr   %r30, isrr0;                                            \
124         mfspr   %r31, isrr1;            /* MSR at interrupt time */     \
125         stw     %r30, (savearea+CPUSAVE_SRR0)(%r1);                     \
126         stw     %r31, (savearea+CPUSAVE_SRR1)(%r1);                     \
127         isync;                                                          \
128         mfspr   %r1, sprg_sp;           /* Restore SP */                \
129         mfcr    %r30;                   /* Save CR */                   \
130         /* switch to per-thread kstack if intr taken in user mode */    \
131         mtcr    %r31;                   /* MSR at interrupt time  */    \
132         bf      17, 1f;                                                 \
133         GET_CPUINFO(%r1);               /* Per-cpu structure */         \
134         lwz     %r1, PC_CURPCB(%r1);    /* Per-thread kernel stack */   \
135 1:
136
137 #define STANDARD_CRIT_PROLOG(sprg_sp, savearea, isrr0, isrr1)           \
138         mtspr   sprg_sp, %r1;           /* Save SP */                   \
139         GET_CPUINFO(%r1);               /* Per-cpu structure */         \
140         stw     %r30, (savearea+CPUSAVE_R30)(%r1);                      \
141         stw     %r31, (savearea+CPUSAVE_R31)(%r1);                      \
142         mfdear  %r30;                                                   \
143         mfesr   %r31;                                                   \
144         stw     %r30, (savearea+CPUSAVE_BOOKE_DEAR)(%r1);               \
145         stw     %r31, (savearea+CPUSAVE_BOOKE_ESR)(%r1);                \
146         mfspr   %r30, isrr0;                                            \
147         mfspr   %r31, isrr1;            /* MSR at interrupt time */     \
148         stw     %r30, (savearea+CPUSAVE_SRR0)(%r1);                     \
149         stw     %r31, (savearea+CPUSAVE_SRR1)(%r1);                     \
150         mfspr   %r30, SPR_SRR0;                                         \
151         mfspr   %r31, SPR_SRR1;         /* MSR at interrupt time */     \
152         stw     %r30, (savearea+CPUSAVE_SRR0+8)(%r1);                   \
153         stw     %r31, (savearea+CPUSAVE_SRR1+8)(%r1);                   \
154         isync;                                                          \
155         mfspr   %r1, sprg_sp;           /* Restore SP */                \
156         mfcr    %r30;                   /* Save CR */                   \
157         /* switch to per-thread kstack if intr taken in user mode */    \
158         mtcr    %r31;                   /* MSR at interrupt time  */    \
159         bf      17, 1f;                                                 \
160         GET_CPUINFO(%r1);               /* Per-cpu structure */         \
161         lwz     %r1, PC_CURPCB(%r1);    /* Per-thread kernel stack */   \
162 1:
163
164 /*
165  * FRAME_SETUP assumes:
166  *      SPRG{1-3}       SP at the time interrupt occured
167  *      savearea        r30-r31, DEAR, ESR, xSRR0-1
168  *      r30             CR
169  *      r31             scratch
170  *      r1              kernel stack
171  *
172  * sprg_sp - SPRG reg containing SP at the time interrupt occured
173  * savearea - temp save
174  * exc - exception number (EXC_xxx)
175  *
176  * 1. sets a new frame
177  * 2. saves in the frame:
178  *   - R0, R1 (SP at the time of interrupt), R2, LR, CR
179  *   - R3-31 (R30-31 first restored from savearea)
180  *   - XER, CTR, DEAR, ESR (from savearea), xSRR0-1
181  *
182  * Notes:
183  * - potential TLB miss: YES, since we make dereferences to kstack, which
184  *   can happen not covered (we can have up to two DTLB misses if fortunate
185  *   enough i.e. when kstack crosses page boundary and both pages are
186  *   untranslated)
187  */
188 #define FRAME_SETUP(sprg_sp, savearea, exc)                             \
189         mfspr   %r31, sprg_sp;          /* get saved SP */              \
190         /* establish a new stack frame and put everything on it */      \
191         stwu    %r31, -FRAMELEN(%r1);                                   \
192         stw     %r0, FRAME_0+8(%r1);    /* save r0 in the trapframe */  \
193         stw     %r31, FRAME_1+8(%r1);   /* save SP   "      "       */  \
194         stw     %r2, FRAME_2+8(%r1);    /* save r2   "      "       */  \
195         mflr    %r31;                                                   \
196         stw     %r31, FRAME_LR+8(%r1);  /* save LR   "      "       */  \
197         stw     %r30, FRAME_CR+8(%r1);  /* save CR   "      "       */  \
198         GET_CPUINFO(%r2);                                               \
199         lwz     %r30, (savearea+CPUSAVE_R30)(%r2); /* get saved r30 */  \
200         lwz     %r31, (savearea+CPUSAVE_R31)(%r2); /* get saved r31 */  \
201         /* save R3-31 */                                                \
202         stmw    %r3,  FRAME_3+8(%r1) ;                                  \
203         /* save DEAR, ESR */                                            \
204         lwz     %r28, (savearea+CPUSAVE_BOOKE_DEAR)(%r2);               \
205         lwz     %r29, (savearea+CPUSAVE_BOOKE_ESR)(%r2);                \
206         stw     %r28, FRAME_BOOKE_DEAR+8(%r1);                          \
207         stw     %r29, FRAME_BOOKE_ESR+8(%r1);                           \
208         /* save XER, CTR, exc number */                                 \
209         mfxer   %r3;                                                    \
210         mfctr   %r4;                                                    \
211         stw     %r3, FRAME_XER+8(%r1);                                  \
212         stw     %r4, FRAME_CTR+8(%r1);                                  \
213         li      %r5, exc;                                               \
214         stw     %r5, FRAME_EXC+8(%r1);                                  \
215         /* save DBCR0 */                                                \
216         mfspr   %r3, SPR_DBCR0;                                         \
217         stw     %r3, FRAME_BOOKE_DBCR0+8(%r1);                          \
218         /* save xSSR0-1 */                                              \
219         lwz     %r30, (savearea+CPUSAVE_SRR0)(%r2);                     \
220         lwz     %r31, (savearea+CPUSAVE_SRR1)(%r2);                     \
221         stw     %r30, FRAME_SRR0+8(%r1);                                \
222         stw     %r31, FRAME_SRR1+8(%r1)
223
224 /*
225  *
226  * isrr0-1 - save restore registers to restore CPU state to (may be
227  *           SRR0-1, CSRR0-1, MCSRR0-1
228  *
229  * Notes:
230  *  - potential TLB miss: YES. The deref'd kstack may be not covered
231  */
232 #define FRAME_LEAVE(isrr0, isrr1)                                       \
233         /* restore CTR, XER, LR, CR */                                  \
234         lwz     %r4, FRAME_CTR+8(%r1);                                  \
235         lwz     %r5, FRAME_XER+8(%r1);                                  \
236         lwz     %r6, FRAME_LR+8(%r1);                                   \
237         lwz     %r7, FRAME_CR+8(%r1);                                   \
238         mtctr   %r4;                                                    \
239         mtxer   %r5;                                                    \
240         mtlr    %r6;                                                    \
241         mtcr    %r7;                                                    \
242         /* restore DBCR0 */                                             \
243         lwz     %r4, FRAME_BOOKE_DBCR0+8(%r1);                          \
244         mtspr   SPR_DBCR0, %r4;                                         \
245         /* restore xSRR0-1 */                                           \
246         lwz     %r30, FRAME_SRR0+8(%r1);                                \
247         lwz     %r31, FRAME_SRR1+8(%r1);                                \
248         mtspr   isrr0, %r30;                                            \
249         mtspr   isrr1, %r31;                                            \
250         /* restore R2-31, SP */                                         \
251         lmw     %r2, FRAME_2+8(%r1) ;                                   \
252         lwz     %r0, FRAME_0+8(%r1);                                    \
253         lwz     %r1, FRAME_1+8(%r1);                                    \
254         isync
255
256 /*
257  * TLB miss prolog
258  *
259  * saves LR, CR, SRR0-1, R20-31 in the TLBSAVE area
260  *
261  * Notes:
262  *  - potential TLB miss: NO. It is crucial that we do not generate a TLB
263  *    miss within the TLB prolog itself!
264  *  - TLBSAVE is always translated
265  */
266 #define TLB_PROLOG                                                      \
267         mtsprg4 %r1;                    /* Save SP */                   \
268         mtsprg5 %r28;                                                   \
269         mtsprg6 %r29;                                                   \
270         /* calculate TLB nesting level and TLBSAVE instance address */  \
271         GET_CPUINFO(%r1);               /* Per-cpu structure */         \
272         lwz     %r28, PC_BOOKE_TLB_LEVEL(%r1);                          \
273         rlwinm  %r29, %r28, 6, 23, 25;  /* 4 x TLBSAVE_LEN */           \
274         addi    %r28, %r28, 1;                                          \
275         stw     %r28, PC_BOOKE_TLB_LEVEL(%r1);                          \
276         addi    %r29, %r29, PC_BOOKE_TLBSAVE@l;                         \
277         add     %r1, %r1, %r29;         /* current TLBSAVE ptr */       \
278                                                                         \
279         /* save R20-31 */                                               \
280         mfsprg5 %r28;                                                   \
281         mfsprg6 %r29;                                                   \
282         stmw    %r20, (TLBSAVE_BOOKE_R20)(%r1);                         \
283         /* save LR, CR */                                               \
284         mflr    %r30;                                                   \
285         mfcr    %r31;                                                   \
286         stw     %r30, (TLBSAVE_BOOKE_LR)(%r1);                          \
287         stw     %r31, (TLBSAVE_BOOKE_CR)(%r1);                          \
288         /* save SRR0-1 */                                               \
289         mfsrr0  %r30;           /* execution addr at interrupt time */  \
290         mfsrr1  %r31;           /* MSR at interrupt time*/              \
291         stw     %r30, (TLBSAVE_BOOKE_SRR0)(%r1);        /* save SRR0 */ \
292         stw     %r31, (TLBSAVE_BOOKE_SRR1)(%r1);        /* save SRR1 */ \
293         isync;                                                          \
294         mfsprg4 %r1
295
296 /*
297  * restores LR, CR, SRR0-1, R20-31 from the TLBSAVE area
298  *
299  * same notes as for the TLB_PROLOG
300  */
301 #define TLB_RESTORE                                                     \
302         mtsprg4 %r1;                    /* Save SP */                   \
303         GET_CPUINFO(%r1);               /* Per-cpu structure */         \
304         /* calculate TLB nesting level and TLBSAVE instance addr */     \
305         lwz     %r28, PC_BOOKE_TLB_LEVEL(%r1);                          \
306         subi    %r28, %r28, 1;                                          \
307         stw     %r28, PC_BOOKE_TLB_LEVEL(%r1);                          \
308         rlwinm  %r29, %r28, 6, 23, 25; /* 4 x TLBSAVE_LEN */            \
309         addi    %r29, %r29, PC_BOOKE_TLBSAVE@l;                         \
310         add     %r1, %r1, %r29;                                         \
311                                                                         \
312         /* restore LR, CR */                                            \
313         lwz     %r30, (TLBSAVE_BOOKE_LR)(%r1);                          \
314         lwz     %r31, (TLBSAVE_BOOKE_CR)(%r1);                          \
315         mtlr    %r30;                                                   \
316         mtcr    %r31;                                                   \
317         /* restore SRR0-1 */                                            \
318         lwz     %r30, (TLBSAVE_BOOKE_SRR0)(%r1);                        \
319         lwz     %r31, (TLBSAVE_BOOKE_SRR1)(%r1);                        \
320         mtsrr0  %r30;                                                   \
321         mtsrr1  %r31;                                                   \
322         /* restore R20-31 */                                            \
323         lmw     %r20, (TLBSAVE_BOOKE_R20)(%r1);                         \
324         mfsprg4 %r1
325
326 #ifdef SMP
327 #define TLB_LOCK                                                        \
328         GET_CPUINFO(%r20);                                              \
329         lwz     %r21, PC_CURTHREAD(%r20);                               \
330         lwz     %r22, PC_BOOKE_TLB_LOCK(%r20);                          \
331                                                                         \
332 1:      lwarx   %r23, 0, %r22;                                          \
333         cmpwi   %r23, TLB_UNLOCKED;                                     \
334         beq     2f;                                                     \
335                                                                         \
336         /* check if this is recursion */                                \
337         cmplw   cr0, %r21, %r23;                                        \
338         bne-    1b;                                                     \
339                                                                         \
340 2:      /* try to acquire lock */                                       \
341         stwcx.  %r21, 0, %r22;                                          \
342         bne-    1b;                                                     \
343                                                                         \
344         /* got it, update recursion counter */                          \
345         lwz     %r21, RES_RECURSE(%r22);                                \
346         addi    %r21, %r21, 1;                                          \
347         stw     %r21, RES_RECURSE(%r22);                                \
348         isync;                                                          \
349         msync
350
351 #define TLB_UNLOCK                                                      \
352         GET_CPUINFO(%r20);                                              \
353         lwz     %r21, PC_CURTHREAD(%r20);                               \
354         lwz     %r22, PC_BOOKE_TLB_LOCK(%r20);                          \
355                                                                         \
356         /* update recursion counter */                                  \
357         lwz     %r23, RES_RECURSE(%r22);                                \
358         subi    %r23, %r23, 1;                                          \
359         stw     %r23, RES_RECURSE(%r22);                                \
360                                                                         \
361         cmpwi   %r23, 0;                                                \
362         bne     1f;                                                     \
363         isync;                                                          \
364         msync;                                                          \
365                                                                         \
366         /* release the lock */                                          \
367         li      %r23, TLB_UNLOCKED;                                     \
368         stw     %r23, 0(%r22);                                          \
369 1:      isync;                                                          \
370         msync
371 #else
372 #define TLB_LOCK
373 #define TLB_UNLOCK
374 #endif  /* SMP */
375
376 #define INTERRUPT(label)                                                \
377         .globl  label;                                                  \
378         .align  5;                                                      \
379         CNAME(label):
380
381 /*
382  * Interrupt handling routines in BookE can be flexibly placed and do not have
383  * to live in pre-defined vectors location. Note they need to be TLB-mapped at
384  * all times in order to be able to handle exceptions. We thus arrange for
385  * them to be part of kernel text which is always TLB-accessible.
386  *
387  * The interrupt handling routines have to be 16 bytes aligned: we align them
388  * to 32 bytes (cache line length) which supposedly performs better.
389  *
390  */
391         .text
392         .globl CNAME(interrupt_vector_base)
393         .align 5
394 interrupt_vector_base:
395
396 /*****************************************************************************
397  * Critical input interrupt
398  ****************************************************************************/
399 INTERRUPT(int_critical_input)
400         STANDARD_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)
401         FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_CRIT)
402         addi    %r3, %r1, 8
403         bl      CNAME(powerpc_crit_interrupt)
404         FRAME_LEAVE(SPR_CSRR0, SPR_CSRR1)
405         rfci
406
407
408 /*****************************************************************************
409  * Machine check interrupt
410  ****************************************************************************/
411 INTERRUPT(int_machine_check)
412         STANDARD_PROLOG(SPR_SPRG3, PC_BOOKE_MCHKSAVE, SPR_MCSRR0, SPR_MCSRR1)
413         FRAME_SETUP(SPR_SPRG3, PC_BOOKE_MCHKSAVE, EXC_MCHK)
414         addi    %r3, %r1, 8
415         bl      CNAME(powerpc_mchk_interrupt)
416         FRAME_LEAVE(SPR_MCSRR0, SPR_MCSRR1)
417         rfmci
418
419
420 /*****************************************************************************
421  * Data storage interrupt
422  ****************************************************************************/
423 INTERRUPT(int_data_storage)
424         STANDARD_PROLOG(SPR_SPRG1, PC_DISISAVE, SPR_SRR0, SPR_SRR1)
425         FRAME_SETUP(SPR_SPRG1, PC_DISISAVE, EXC_DSI)
426         b       trap_common
427
428
429 /*****************************************************************************
430  * Instruction storage interrupt
431  ****************************************************************************/
432 INTERRUPT(int_instr_storage)
433         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
434         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_ISI)
435         b       trap_common
436
437
438 /*****************************************************************************
439  * External input interrupt
440  ****************************************************************************/
441 INTERRUPT(int_external_input)
442         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
443         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_EXI)
444         addi    %r3, %r1, 8
445         bl      CNAME(powerpc_extr_interrupt)
446         b       trapexit
447
448
449 INTERRUPT(int_alignment)
450         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
451         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_ALI)
452         b       trap_common
453
454
455 INTERRUPT(int_program)
456         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
457         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_PGM)
458         b       trap_common
459
460
461 /*****************************************************************************
462  * System call
463  ****************************************************************************/
464 INTERRUPT(int_syscall)
465         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
466         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_SC)
467         b       trap_common
468
469
470 /*****************************************************************************
471  * Decrementer interrupt
472  ****************************************************************************/
473 INTERRUPT(int_decrementer)
474         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
475         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_DECR)
476         addi    %r3, %r1, 8
477         bl      CNAME(powerpc_decr_interrupt)
478         b       trapexit
479
480
481 /*****************************************************************************
482  * Fixed interval timer
483  ****************************************************************************/
484 INTERRUPT(int_fixed_interval_timer)
485         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
486         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_FIT)
487         b       trap_common
488
489
490 /*****************************************************************************
491  * Watchdog interrupt
492  ****************************************************************************/
493 INTERRUPT(int_watchdog)
494         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
495         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_WDOG)
496         b       trap_common
497
498
499 /*****************************************************************************
500  * Data TLB miss interrupt
501  *
502  * There can be nested TLB misses - while handling a TLB miss we reference
503  * data structures that may be not covered by translations. We support up to
504  * TLB_NESTED_MAX-1 nested misses.
505  * 
506  * Registers use:
507  *      r31 - dear
508  *      r30 - unused
509  *      r29 - saved mas0
510  *      r28 - saved mas1
511  *      r27 - saved mas2
512  *      r26 - pmap address
513  *      r25 - pte address
514  *
515  *      r20:r23 - scratch registers
516  ****************************************************************************/
517 INTERRUPT(int_data_tlb_error)
518         TLB_PROLOG
519         TLB_LOCK
520
521         mfdear  %r31
522
523         /*
524          * Save MAS0-MAS2 registers. There might be another tlb miss during
525          * pte lookup overwriting current contents (which was hw filled).
526          */
527         mfspr   %r29, SPR_MAS0
528         mfspr   %r28, SPR_MAS1
529         mfspr   %r27, SPR_MAS2
530
531         /* Check faulting address. */
532         lis     %r21, VM_MAXUSER_ADDRESS@h
533         ori     %r21, %r21, VM_MAXUSER_ADDRESS@l
534         cmplw   cr0, %r31, %r21
535         blt     search_user_pmap
536         
537         /* If it's kernel address, allow only supervisor mode misses. */
538         mfsrr1  %r21
539         mtcr    %r21
540         bt      17, search_failed       /* check MSR[PR] */
541
542 search_kernel_pmap:
543         /* Load r26 with kernel_pmap address */
544         lis     %r26, kernel_pmap_store@h
545         ori     %r26, %r26, kernel_pmap_store@l
546
547         /* Force kernel tid, set TID to 0 in MAS1. */
548         li      %r21, 0
549         rlwimi  %r28, %r21, 0, 8, 15    /* clear TID bits */
550
551 tlb_miss_handle:
552         /* This may result in nested tlb miss. */
553         bl      pte_lookup              /* returns PTE address in R25 */
554
555         cmpwi   %r25, 0                 /* pte found? */
556         beq     search_failed
557
558         /* Finish up, write TLB entry. */
559         bl      tlb_fill_entry
560
561 tlb_miss_return:
562         TLB_UNLOCK
563         TLB_RESTORE
564         rfi
565
566 search_user_pmap:
567         /* Load r26 with current user space process pmap */
568         GET_CPUINFO(%r26)
569         lwz     %r26, PC_CURPMAP(%r26)
570
571         b       tlb_miss_handle
572
573 search_failed:
574         /*
575          * Whenever we don't find a TLB mapping in PT, set a TLB0 entry with
576          * the faulting virtual address anyway, but put a fake RPN and no
577          * access rights. This should cause a following {D,I}SI exception.
578          */
579         lis     %r23, 0xffff0000@h      /* revoke all permissions */
580
581         /* Load MAS registers. */
582         mtspr   SPR_MAS0, %r29
583         isync
584         mtspr   SPR_MAS1, %r28
585         isync
586         mtspr   SPR_MAS2, %r27
587         isync
588         mtspr   SPR_MAS3, %r23
589         isync
590
591         tlbwe
592         msync
593         isync
594         b       tlb_miss_return
595
596 /*****************************************************************************
597  *
598  * Return pte address that corresponds to given pmap/va.  If there is no valid
599  * entry return 0.
600  *
601  * input: r26 - pmap
602  * input: r31 - dear
603  * output: r25 - pte address
604  *
605  * scratch regs used: r21
606  *
607  ****************************************************************************/
608 pte_lookup:
609         cmpwi   %r26, 0
610         beq     1f                      /* fail quickly if pmap is invalid */
611
612         srwi    %r21, %r31, PDIR_SHIFT          /* pdir offset */
613         slwi    %r21, %r21, PDIR_ENTRY_SHIFT    /* multiply by pdir entry size */
614
615         addi    %r25, %r26, PM_PDIR     /* pmap pm_dir[] address */
616         add     %r25, %r25, %r21        /* offset within pm_pdir[] table */
617         /*
618          * Get ptbl address, i.e. pmap->pm_pdir[pdir_idx]
619          * This load may cause a Data TLB miss for non-kernel pmap!
620          */
621         lwz     %r25, 0(%r25)
622         cmpwi   %r25, 0
623         beq     2f
624
625         lis     %r21, PTBL_MASK@h
626         ori     %r21, %r21, PTBL_MASK@l
627         and     %r21, %r21, %r31
628
629         /* ptbl offset, multiply by ptbl entry size */
630         srwi    %r21, %r21, (PTBL_SHIFT - PTBL_ENTRY_SHIFT)
631
632         add     %r25, %r25, %r21                /* address of pte entry */
633         /*
634          * Get pte->flags
635          * This load may cause a Data TLB miss for non-kernel pmap!
636          */
637         lwz     %r21, PTE_FLAGS(%r25)
638         andis.  %r21, %r21, PTE_VALID@h
639         bne     2f
640 1:
641         li      %r25, 0
642 2:
643         blr
644
645 /*****************************************************************************
646  *
647  * Load MAS1-MAS3 registers with data, write TLB entry
648  *
649  * input:
650  * r29 - mas0
651  * r28 - mas1
652  * r27 - mas2
653  * r25 - pte
654  *
655  * output: none
656  *
657  * scratch regs: r21-r23
658  *
659  ****************************************************************************/
660 tlb_fill_entry:
661         /*
662          * Update PTE flags: we have to do it atomically, as pmap_protect()
663          * running on other CPUs could attempt to update the flags at the same
664          * time.
665          */
666         li      %r23, PTE_FLAGS
667 1:
668         lwarx   %r21, %r23, %r25                /* get pte->flags */
669         oris    %r21, %r21, PTE_REFERENCED@h    /* set referenced bit */
670
671         andi.   %r22, %r21, (PTE_SW | PTE_UW)@l /* check if writable */
672         beq     2f
673         oris    %r21, %r21, PTE_MODIFIED@h      /* set modified bit */
674 2:
675         stwcx.  %r21, %r23, %r25                /* write it back */
676         bne-    1b
677
678         /* Update MAS2. */
679         rlwimi  %r27, %r21, 0, 27, 30           /* insert WIMG bits from pte */
680
681         /* Setup MAS3 value in r23. */
682         lwz     %r23, PTE_RPN(%r25)             /* get pte->rpn */
683
684         rlwimi  %r23, %r21, 24, 26, 31          /* insert protection bits from pte */
685
686         /* Load MAS registers. */
687         mtspr   SPR_MAS0, %r29
688         isync
689         mtspr   SPR_MAS1, %r28
690         isync
691         mtspr   SPR_MAS2, %r27
692         isync
693         mtspr   SPR_MAS3, %r23
694         isync
695
696         tlbwe
697         isync
698         msync
699         blr
700
701 /*****************************************************************************
702  * Instruction TLB miss interrupt
703  *
704  * Same notes as for the Data TLB miss
705  ****************************************************************************/
706 INTERRUPT(int_inst_tlb_error)
707         TLB_PROLOG
708         TLB_LOCK
709
710         mfsrr0  %r31                    /* faulting address */
711
712         /*
713          * Save MAS0-MAS2 registers. There might be another tlb miss during pte
714          * lookup overwriting current contents (which was hw filled).
715          */
716         mfspr   %r29, SPR_MAS0
717         mfspr   %r28, SPR_MAS1
718         mfspr   %r27, SPR_MAS2
719
720         mfsrr1  %r21
721         mtcr    %r21
722
723         /* check MSR[PR] */
724         bt      17, search_user_pmap
725         b       search_kernel_pmap
726
727
728         .globl  interrupt_vector_top
729 interrupt_vector_top:
730
731 /*****************************************************************************
732  * Debug interrupt
733  ****************************************************************************/
734 INTERRUPT(int_debug)
735         STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)
736         FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_DEBUG)
737         lwz     %r3, (PC_BOOKE_CRITSAVE+CPUSAVE_SRR0)(%r2);
738         lis     %r4, interrupt_vector_base@ha
739         addi    %r4, %r4, interrupt_vector_base@l
740         cmplw   cr0, %r3, %r4
741         blt     1f
742         lis     %r4, interrupt_vector_top@ha
743         addi    %r4, %r4, interrupt_vector_top@l
744         cmplw   cr0, %r3, %r4
745         bge     1f
746         /* Disable single-stepping for the interrupt handlers. */
747         lwz     %r3, FRAME_SRR1+8(%r1);
748         rlwinm  %r3, %r3, 0, 23, 21
749         stw     %r3, FRAME_SRR1+8(%r1);
750         /* Restore srr0 and srr1 as they could have been clobbered. */
751         lwz     %r3, (PC_BOOKE_CRITSAVE+CPUSAVE_SRR0+8)(%r2);
752         mtspr   SPR_SRR0, %r3
753         lwz     %r4, (PC_BOOKE_CRITSAVE+CPUSAVE_SRR1+8)(%r2);
754         mtspr   SPR_SRR1, %r4
755         b       9f
756 1:
757         addi    %r3, %r1, 8
758         bl      CNAME(trap)
759         /*
760          * Handle ASTs, needed for proper support of single-stepping.
761          * We actually need to return to the process with an rfi.
762          */
763         b       trapexit
764 9:
765         FRAME_LEAVE(SPR_CSRR0, SPR_CSRR1)
766         rfci
767
768
769 /*****************************************************************************
770  * Common trap code
771  ****************************************************************************/
772 trap_common:
773         /* Call C trap dispatcher */
774         addi    %r3, %r1, 8
775         bl      CNAME(trap)
776
777         .globl  CNAME(trapexit)         /* exported for db_backtrace use */
778 CNAME(trapexit):
779         /* disable interrupts */
780         wrteei  0
781
782         /* Test AST pending - makes sense for user process only */
783         lwz     %r5, FRAME_SRR1+8(%r1)
784         mtcr    %r5
785         bf      17, 1f
786
787         GET_CPUINFO(%r3)
788         lwz     %r4, PC_CURTHREAD(%r3)
789         lwz     %r4, TD_FLAGS(%r4)
790         lis     %r5, (TDF_ASTPENDING | TDF_NEEDRESCHED)@h
791         ori     %r5, %r5, (TDF_ASTPENDING | TDF_NEEDRESCHED)@l
792         and.    %r4, %r4, %r5
793         beq     1f
794
795         /* re-enable interrupts before calling ast() */
796         wrteei  1
797
798         addi    %r3, %r1, 8
799         bl      CNAME(ast)
800         .globl  CNAME(asttrapexit)      /* db_backtrace code sentinel #2 */
801 CNAME(asttrapexit):
802         b       trapexit                /* test ast ret value ? */
803 1:
804         FRAME_LEAVE(SPR_SRR0, SPR_SRR1)
805         rfi
806
807
808 #if defined(KDB)
809 /*
810  * Deliberate entry to dbtrap
811  */
812         .globl  CNAME(breakpoint)
813 CNAME(breakpoint):
814         mtsprg1 %r1
815         mfmsr   %r3
816         mtsrr1  %r3
817         andi.   %r3, %r3, ~(PSL_EE | PSL_ME)@l
818         mtmsr   %r3                     /* disable interrupts */
819         isync
820         GET_CPUINFO(%r3)
821         stw     %r30, (PC_DBSAVE+CPUSAVE_R30)(%r3)
822         stw     %r31, (PC_DBSAVE+CPUSAVE_R31)(%r3)
823
824         mflr    %r31
825         mtsrr0  %r31
826
827         mfdear  %r30
828         mfesr   %r31
829         stw     %r30, (PC_DBSAVE+CPUSAVE_BOOKE_DEAR)(%r3)
830         stw     %r31, (PC_DBSAVE+CPUSAVE_BOOKE_ESR)(%r3)
831
832         mfsrr0  %r30
833         mfsrr1  %r31
834         stw     %r30, (PC_DBSAVE+CPUSAVE_SRR0)(%r3)
835         stw     %r31, (PC_DBSAVE+CPUSAVE_SRR1)(%r3)
836         isync
837
838         mfcr    %r30
839
840 /*
841  * Now the kdb trap catching code.
842  */
843 dbtrap:
844         FRAME_SETUP(SPR_SPRG1, PC_DBSAVE, EXC_DEBUG)
845 /* Call C trap code: */
846         addi    %r3, %r1, 8
847         bl      CNAME(db_trap_glue)
848         or.     %r3, %r3, %r3
849         bne     dbleave
850 /* This wasn't for KDB, so switch to real trap: */
851         b       trap_common
852
853 dbleave:
854         FRAME_LEAVE(SPR_SRR0, SPR_SRR1)
855         rfi
856 #endif /* KDB */
857
858 #ifdef SMP
859 ENTRY(tlb_lock)
860         GET_CPUINFO(%r5)
861         lwz     %r5, PC_CURTHREAD(%r5)
862 1:      lwarx   %r4, 0, %r3
863         cmpwi   %r4, TLB_UNLOCKED
864         bne     1b
865         stwcx.  %r5, 0, %r3
866         bne-    1b
867         isync
868         msync
869         blr
870
871 ENTRY(tlb_unlock)
872         isync
873         msync
874         li      %r4, TLB_UNLOCKED
875         stw     %r4, 0(%r3)
876         isync
877         msync
878         blr
879
880 /*
881  * TLB miss spin locks. For each CPU we have a reservation granule (32 bytes);
882  * only a single word from this granule will actually be used as a spin lock
883  * for mutual exclusion between TLB miss handler and pmap layer that
884  * manipulates page table contents.
885  */
886         .data
887         .align  5
888 GLOBAL(tlb0_miss_locks)
889         .space  RES_GRANULE * MAXCPU
890 #endif