]> CyberLeo.Net >> Repos - FreeBSD/releng/8.0.git/blob - sys/powerpc/booke/trap_subr.S
Adjust to reflect 8.0-RELEASE.
[FreeBSD/releng/8.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, MTX_UNOWNED;                                      \
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, MTX_UNOWNED;                                      \
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         bl      CNAME(powerpc_extr_interrupt)
445         b       trapexit
446
447
448 INTERRUPT(int_alignment)
449         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
450         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_ALI)
451         b       trap_common
452
453
454 INTERRUPT(int_program)
455         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
456         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_PGM)
457         b       trap_common
458
459
460 /*****************************************************************************
461  * System call
462  ****************************************************************************/
463 INTERRUPT(int_syscall)
464         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
465         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_SC)
466         b       trap_common
467
468
469 /*****************************************************************************
470  * Decrementer interrupt
471  ****************************************************************************/
472 INTERRUPT(int_decrementer)
473         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
474         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_DECR)
475         addi    %r3, %r1, 8
476         bl      CNAME(powerpc_decr_interrupt)
477         b       trapexit
478
479
480 /*****************************************************************************
481  * Fixed interval timer
482  ****************************************************************************/
483 INTERRUPT(int_fixed_interval_timer)
484         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
485         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_FIT)
486         b       trap_common
487
488
489 /*****************************************************************************
490  * Watchdog interrupt
491  ****************************************************************************/
492 INTERRUPT(int_watchdog)
493         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
494         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_WDOG)
495         b       trap_common
496
497
498 /*****************************************************************************
499  * Data TLB miss interrupt
500  *
501  * There can be nested TLB misses - while handling a TLB miss we reference
502  * data structures that may be not covered by translations. We support up to
503  * TLB_NESTED_MAX-1 nested misses.
504  * 
505  * Registers use:
506  *      r31 - dear
507  *      r30 - unused
508  *      r29 - saved mas0
509  *      r28 - saved mas1
510  *      r27 - saved mas2
511  *      r26 - pmap address
512  *      r25 - pte address
513  *
514  *      r20:r23 - scratch registers
515  ****************************************************************************/
516 INTERRUPT(int_data_tlb_error)
517         TLB_PROLOG
518         TLB_LOCK
519
520         mfdear  %r31
521
522         /*
523          * Save MAS0-MAS2 registers. There might be another tlb miss during
524          * pte lookup overwriting current contents (which was hw filled).
525          */
526         mfspr   %r29, SPR_MAS0
527         mfspr   %r28, SPR_MAS1
528         mfspr   %r27, SPR_MAS2
529
530         /* Check faulting address. */
531         lis     %r21, VM_MAXUSER_ADDRESS@h
532         ori     %r21, %r21, VM_MAXUSER_ADDRESS@l
533         cmplw   cr0, %r31, %r21
534         blt     search_user_pmap
535         
536         /* If it's kernel address, allow only supervisor mode misses. */
537         mfsrr1  %r21
538         mtcr    %r21
539         bt      17, search_failed       /* check MSR[PR] */
540
541 search_kernel_pmap:
542         /* Load r26 with kernel_pmap address */
543         lis     %r26, kernel_pmap_store@h
544         ori     %r26, %r26, kernel_pmap_store@l
545
546         /* Force kernel tid, set TID to 0 in MAS1. */
547         li      %r21, 0
548         rlwimi  %r28, %r21, 0, 8, 15    /* clear TID bits */
549
550 tlb_miss_handle:
551         /* This may result in nested tlb miss. */
552         bl      pte_lookup              /* returns PTE address in R25 */
553
554         cmpwi   %r25, 0                 /* pte found? */
555         beq     search_failed
556
557         /* Finish up, write TLB entry. */
558         bl      tlb_fill_entry
559
560 tlb_miss_return:
561         TLB_UNLOCK
562         TLB_RESTORE
563         rfi
564
565 search_user_pmap:
566         /* Load r26 with current user space process pmap */
567         GET_CPUINFO(%r26)
568         lwz     %r26, PC_CURPMAP(%r26)
569
570         b       tlb_miss_handle
571
572 search_failed:
573         /*
574          * Whenever we don't find a TLB mapping in PT, set a TLB0 entry with
575          * the faulting virtual address anyway, but put a fake RPN and no
576          * access rights. This should cause a following {D,I}SI exception.
577          */
578         lis     %r23, 0xffff0000@h      /* revoke all permissions */
579
580         /* Load MAS registers. */
581         mtspr   SPR_MAS0, %r29
582         isync
583         mtspr   SPR_MAS1, %r28
584         isync
585         mtspr   SPR_MAS2, %r27
586         isync
587         mtspr   SPR_MAS3, %r23
588         isync
589
590         tlbwe
591         msync
592         isync
593         b       tlb_miss_return
594
595 /*****************************************************************************
596  *
597  * Return pte address that corresponds to given pmap/va.  If there is no valid
598  * entry return 0.
599  *
600  * input: r26 - pmap
601  * input: r31 - dear
602  * output: r25 - pte address
603  *
604  * scratch regs used: r21
605  *
606  ****************************************************************************/
607 pte_lookup:
608         cmpwi   %r26, 0
609         beq     1f                      /* fail quickly if pmap is invalid */
610
611         srwi    %r21, %r31, PDIR_SHIFT          /* pdir offset */
612         slwi    %r21, %r21, PDIR_ENTRY_SHIFT    /* multiply by pdir entry size */
613
614         addi    %r25, %r26, PM_PDIR     /* pmap pm_dir[] address */
615         add     %r25, %r25, %r21        /* offset within pm_pdir[] table */
616         /*
617          * Get ptbl address, i.e. pmap->pm_pdir[pdir_idx]
618          * This load may cause a Data TLB miss for non-kernel pmap!
619          */
620         lwz     %r25, 0(%r25)
621         cmpwi   %r25, 0
622         beq     2f
623
624         lis     %r21, PTBL_MASK@h
625         ori     %r21, %r21, PTBL_MASK@l
626         and     %r21, %r21, %r31
627
628         /* ptbl offset, multiply by ptbl entry size */
629         srwi    %r21, %r21, (PTBL_SHIFT - PTBL_ENTRY_SHIFT)
630
631         add     %r25, %r25, %r21                /* address of pte entry */
632         /*
633          * Get pte->flags
634          * This load may cause a Data TLB miss for non-kernel pmap!
635          */
636         lwz     %r21, PTE_FLAGS(%r25)
637         andis.  %r21, %r21, PTE_VALID@h
638         bne     2f
639 1:
640         li      %r25, 0
641 2:
642         blr
643
644 /*****************************************************************************
645  *
646  * Load MAS1-MAS3 registers with data, write TLB entry
647  *
648  * input:
649  * r29 - mas0
650  * r28 - mas1
651  * r27 - mas2
652  * r25 - pte
653  *
654  * output: none
655  *
656  * scratch regs: r21-r23
657  *
658  ****************************************************************************/
659 tlb_fill_entry:
660         /*
661          * Update PTE flags: we have to do it atomically, as pmap_protect()
662          * running on other CPUs could attempt to update the flags at the same
663          * time.
664          */
665         li      %r23, PTE_FLAGS
666 1:
667         lwarx   %r21, %r23, %r25                /* get pte->flags */
668         oris    %r21, %r21, PTE_REFERENCED@h    /* set referenced bit */
669
670         andi.   %r22, %r21, (PTE_UW | PTE_UW)@l /* check if writable */
671         beq     2f
672         oris    %r21, %r21, PTE_MODIFIED@h      /* set modified bit */
673 2:
674         stwcx.  %r21, %r23, %r25                /* write it back */
675         bne-    1b
676
677         /* Update MAS2. */
678         rlwimi  %r27, %r21, 0, 27, 30           /* insert WIMG bits from pte */
679
680         /* Setup MAS3 value in r23. */
681         lwz     %r23, PTE_RPN(%r25)             /* get pte->rpn */
682
683         rlwimi  %r23, %r21, 24, 26, 31          /* insert protection bits from pte */
684
685         /* Load MAS registers. */
686         mtspr   SPR_MAS0, %r29
687         isync
688         mtspr   SPR_MAS1, %r28
689         isync
690         mtspr   SPR_MAS2, %r27
691         isync
692         mtspr   SPR_MAS3, %r23
693         isync
694
695         tlbwe
696         isync
697         msync
698         blr
699
700 /*****************************************************************************
701  * Instruction TLB miss interrupt
702  *
703  * Same notes as for the Data TLB miss
704  ****************************************************************************/
705 INTERRUPT(int_inst_tlb_error)
706         TLB_PROLOG
707         TLB_LOCK
708
709         mfsrr0  %r31                    /* faulting address */
710
711         /*
712          * Save MAS0-MAS2 registers. There might be another tlb miss during pte
713          * lookup overwriting current contents (which was hw filled).
714          */
715         mfspr   %r29, SPR_MAS0
716         mfspr   %r28, SPR_MAS1
717         mfspr   %r27, SPR_MAS2
718
719         mfsrr1  %r21
720         mtcr    %r21
721
722         /* check MSR[PR] */
723         bt      17, search_user_pmap
724         b       search_kernel_pmap
725
726
727         .globl  interrupt_vector_top
728 interrupt_vector_top:
729
730 /*****************************************************************************
731  * Debug interrupt
732  ****************************************************************************/
733 INTERRUPT(int_debug)
734         STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)
735         FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_DEBUG)
736         lwz     %r3, (PC_BOOKE_CRITSAVE+CPUSAVE_SRR0)(%r2);
737         lis     %r4, interrupt_vector_base@ha
738         addi    %r4, %r4, interrupt_vector_base@l
739         cmplw   cr0, %r3, %r4
740         blt     1f
741         lis     %r4, interrupt_vector_top@ha
742         addi    %r4, %r4, interrupt_vector_top@l
743         cmplw   cr0, %r3, %r4
744         bge     1f
745         /* Disable single-stepping for the interrupt handlers. */
746         lwz     %r3, FRAME_SRR1+8(%r1);
747         rlwinm  %r3, %r3, 0, 23, 21
748         stw     %r3, FRAME_SRR1+8(%r1);
749         /* Restore srr0 and srr1 as they could have been clobbered. */
750         lwz     %r3, (PC_BOOKE_CRITSAVE+CPUSAVE_SRR0+8)(%r2);
751         mtspr   SPR_SRR0, %r3
752         lwz     %r4, (PC_BOOKE_CRITSAVE+CPUSAVE_SRR1+8)(%r2);
753         mtspr   SPR_SRR1, %r4
754         b       9f
755 1:
756         addi    %r3, %r1, 8
757         bl      CNAME(trap)
758         /*
759          * Handle ASTs, needed for proper support of single-stepping.
760          * We actually need to return to the process with an rfi.
761          */
762         b       trapexit
763 9:
764         FRAME_LEAVE(SPR_CSRR0, SPR_CSRR1)
765         rfci
766
767
768 /*****************************************************************************
769  * Common trap code
770  ****************************************************************************/
771 trap_common:
772         /* Call C trap dispatcher */
773         addi    %r3, %r1, 8
774         bl      CNAME(trap)
775
776         .globl  CNAME(trapexit)         /* exported for db_backtrace use */
777 CNAME(trapexit):
778         /* disable interrupts */
779         wrteei  0
780
781         /* Test AST pending - makes sense for user process only */
782         lwz     %r5, FRAME_SRR1+8(%r1)
783         mtcr    %r5
784         bf      17, 1f
785
786         GET_CPUINFO(%r3)
787         lwz     %r4, PC_CURTHREAD(%r3)
788         lwz     %r4, TD_FLAGS(%r4)
789         lis     %r5, (TDF_ASTPENDING | TDF_NEEDRESCHED)@h
790         ori     %r5, %r5, (TDF_ASTPENDING | TDF_NEEDRESCHED)@l
791         and.    %r4, %r4, %r5
792         beq     1f
793
794         /* re-enable interrupts before calling ast() */
795         wrteei  1
796
797         addi    %r3, %r1, 8
798         bl      CNAME(ast)
799         .globl  CNAME(asttrapexit)      /* db_backtrace code sentinel #2 */
800 CNAME(asttrapexit):
801         b       trapexit                /* test ast ret value ? */
802 1:
803         FRAME_LEAVE(SPR_SRR0, SPR_SRR1)
804         rfi
805
806
807 #if defined(KDB)
808 /*
809  * Deliberate entry to dbtrap
810  */
811         .globl  CNAME(breakpoint)
812 CNAME(breakpoint):
813         mtsprg1 %r1
814         mfmsr   %r3
815         mtsrr1  %r3
816         andi.   %r3, %r3, ~(PSL_EE | PSL_ME)@l
817         mtmsr   %r3                     /* disable interrupts */
818         isync
819         GET_CPUINFO(%r3)
820         stw     %r30, (PC_DBSAVE+CPUSAVE_R30)(%r3)
821         stw     %r31, (PC_DBSAVE+CPUSAVE_R31)(%r3)
822
823         mflr    %r31
824         mtsrr0  %r31
825
826         mfdear  %r30
827         mfesr   %r31
828         stw     %r30, (PC_DBSAVE+CPUSAVE_BOOKE_DEAR)(%r3)
829         stw     %r31, (PC_DBSAVE+CPUSAVE_BOOKE_ESR)(%r3)
830
831         mfsrr0  %r30
832         mfsrr1  %r31
833         stw     %r30, (PC_DBSAVE+CPUSAVE_SRR0)(%r3)
834         stw     %r31, (PC_DBSAVE+CPUSAVE_SRR1)(%r3)
835         isync
836
837         mfcr    %r30
838
839 /*
840  * Now the kdb trap catching code.
841  */
842 dbtrap:
843         FRAME_SETUP(SPR_SPRG1, PC_DBSAVE, EXC_DEBUG)
844 /* Call C trap code: */
845         addi    %r3, %r1, 8
846         bl      CNAME(db_trap_glue)
847         or.     %r3, %r3, %r3
848         bne     dbleave
849 /* This wasn't for KDB, so switch to real trap: */
850         b       trap_common
851
852 dbleave:
853         FRAME_LEAVE(SPR_SRR0, SPR_SRR1)
854         rfi
855 #endif /* KDB */
856
857 #ifdef SMP
858 ENTRY(tlb_lock)
859         GET_CPUINFO(%r5)
860         lwz     %r5, PC_CURTHREAD(%r5)
861 1:      lwarx   %r4, 0, %r3
862         cmpwi   %r4, MTX_UNOWNED
863         bne     1b
864         stwcx.  %r5, 0, %r3
865         bne-    1b
866         isync
867         msync
868         blr
869
870 ENTRY(tlb_unlock)
871         isync
872         msync
873         li      %r4, MTX_UNOWNED
874         stw     %r4, 0(%r3)
875         isync
876         msync
877         blr
878 /*
879  * TLB miss spin locks. For each CPU we have a reservation granule (32 bytes);
880  * only a single word from this granule will actually be used as a spin lock
881  * for mutual exclusion between TLB miss handler and pmap layer that
882  * manipulates page table contents.
883  */
884         .data
885         .align  5
886 GLOBAL(tlb0_miss_locks)
887         .space  RES_GRANULE * MAXCPU
888 #endif