]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/powerpc/booke/trap_subr.S
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.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         lwz     %r2,PC_CURTHREAD(%r2)   /* set curthread pointer */
224
225 /*
226  *
227  * isrr0-1 - save restore registers to restore CPU state to (may be
228  *           SRR0-1, CSRR0-1, MCSRR0-1
229  *
230  * Notes:
231  *  - potential TLB miss: YES. The deref'd kstack may be not covered
232  */
233 #define FRAME_LEAVE(isrr0, isrr1)                                       \
234         /* restore CTR, XER, LR, CR */                                  \
235         lwz     %r4, FRAME_CTR+8(%r1);                                  \
236         lwz     %r5, FRAME_XER+8(%r1);                                  \
237         lwz     %r6, FRAME_LR+8(%r1);                                   \
238         lwz     %r7, FRAME_CR+8(%r1);                                   \
239         mtctr   %r4;                                                    \
240         mtxer   %r5;                                                    \
241         mtlr    %r6;                                                    \
242         mtcr    %r7;                                                    \
243         /* restore DBCR0 */                                             \
244         lwz     %r4, FRAME_BOOKE_DBCR0+8(%r1);                          \
245         mtspr   SPR_DBCR0, %r4;                                         \
246         /* restore xSRR0-1 */                                           \
247         lwz     %r30, FRAME_SRR0+8(%r1);                                \
248         lwz     %r31, FRAME_SRR1+8(%r1);                                \
249         mtspr   isrr0, %r30;                                            \
250         mtspr   isrr1, %r31;                                            \
251         /* restore R2-31, SP */                                         \
252         lmw     %r2, FRAME_2+8(%r1) ;                                   \
253         lwz     %r0, FRAME_0+8(%r1);                                    \
254         lwz     %r1, FRAME_1+8(%r1);                                    \
255         isync
256
257 /*
258  * TLB miss prolog
259  *
260  * saves LR, CR, SRR0-1, R20-31 in the TLBSAVE area
261  *
262  * Notes:
263  *  - potential TLB miss: NO. It is crucial that we do not generate a TLB
264  *    miss within the TLB prolog itself!
265  *  - TLBSAVE is always translated
266  */
267 #define TLB_PROLOG                                                      \
268         mtsprg4 %r1;                    /* Save SP */                   \
269         mtsprg5 %r28;                                                   \
270         mtsprg6 %r29;                                                   \
271         /* calculate TLB nesting level and TLBSAVE instance address */  \
272         GET_CPUINFO(%r1);               /* Per-cpu structure */         \
273         lwz     %r28, PC_BOOKE_TLB_LEVEL(%r1);                          \
274         rlwinm  %r29, %r28, 6, 23, 25;  /* 4 x TLBSAVE_LEN */           \
275         addi    %r28, %r28, 1;                                          \
276         stw     %r28, PC_BOOKE_TLB_LEVEL(%r1);                          \
277         addi    %r29, %r29, PC_BOOKE_TLBSAVE@l;                         \
278         add     %r1, %r1, %r29;         /* current TLBSAVE ptr */       \
279                                                                         \
280         /* save R20-31 */                                               \
281         mfsprg5 %r28;                                                   \
282         mfsprg6 %r29;                                                   \
283         stmw    %r20, (TLBSAVE_BOOKE_R20)(%r1);                         \
284         /* save LR, CR */                                               \
285         mflr    %r30;                                                   \
286         mfcr    %r31;                                                   \
287         stw     %r30, (TLBSAVE_BOOKE_LR)(%r1);                          \
288         stw     %r31, (TLBSAVE_BOOKE_CR)(%r1);                          \
289         /* save SRR0-1 */                                               \
290         mfsrr0  %r30;           /* execution addr at interrupt time */  \
291         mfsrr1  %r31;           /* MSR at interrupt time*/              \
292         stw     %r30, (TLBSAVE_BOOKE_SRR0)(%r1);        /* save SRR0 */ \
293         stw     %r31, (TLBSAVE_BOOKE_SRR1)(%r1);        /* save SRR1 */ \
294         isync;                                                          \
295         mfsprg4 %r1
296
297 /*
298  * restores LR, CR, SRR0-1, R20-31 from the TLBSAVE area
299  *
300  * same notes as for the TLB_PROLOG
301  */
302 #define TLB_RESTORE                                                     \
303         mtsprg4 %r1;                    /* Save SP */                   \
304         GET_CPUINFO(%r1);               /* Per-cpu structure */         \
305         /* calculate TLB nesting level and TLBSAVE instance addr */     \
306         lwz     %r28, PC_BOOKE_TLB_LEVEL(%r1);                          \
307         subi    %r28, %r28, 1;                                          \
308         stw     %r28, PC_BOOKE_TLB_LEVEL(%r1);                          \
309         rlwinm  %r29, %r28, 6, 23, 25; /* 4 x TLBSAVE_LEN */            \
310         addi    %r29, %r29, PC_BOOKE_TLBSAVE@l;                         \
311         add     %r1, %r1, %r29;                                         \
312                                                                         \
313         /* restore LR, CR */                                            \
314         lwz     %r30, (TLBSAVE_BOOKE_LR)(%r1);                          \
315         lwz     %r31, (TLBSAVE_BOOKE_CR)(%r1);                          \
316         mtlr    %r30;                                                   \
317         mtcr    %r31;                                                   \
318         /* restore SRR0-1 */                                            \
319         lwz     %r30, (TLBSAVE_BOOKE_SRR0)(%r1);                        \
320         lwz     %r31, (TLBSAVE_BOOKE_SRR1)(%r1);                        \
321         mtsrr0  %r30;                                                   \
322         mtsrr1  %r31;                                                   \
323         /* restore R20-31 */                                            \
324         lmw     %r20, (TLBSAVE_BOOKE_R20)(%r1);                         \
325         mfsprg4 %r1
326
327 #ifdef SMP
328 #define TLB_LOCK                                                        \
329         GET_CPUINFO(%r20);                                              \
330         lwz     %r21, PC_CURTHREAD(%r20);                               \
331         lwz     %r22, PC_BOOKE_TLB_LOCK(%r20);                          \
332                                                                         \
333 1:      lwarx   %r23, 0, %r22;                                          \
334         cmpwi   %r23, TLB_UNLOCKED;                                     \
335         beq     2f;                                                     \
336                                                                         \
337         /* check if this is recursion */                                \
338         cmplw   cr0, %r21, %r23;                                        \
339         bne-    1b;                                                     \
340                                                                         \
341 2:      /* try to acquire lock */                                       \
342         stwcx.  %r21, 0, %r22;                                          \
343         bne-    1b;                                                     \
344                                                                         \
345         /* got it, update recursion counter */                          \
346         lwz     %r21, RES_RECURSE(%r22);                                \
347         addi    %r21, %r21, 1;                                          \
348         stw     %r21, RES_RECURSE(%r22);                                \
349         isync;                                                          \
350         msync
351
352 #define TLB_UNLOCK                                                      \
353         GET_CPUINFO(%r20);                                              \
354         lwz     %r21, PC_CURTHREAD(%r20);                               \
355         lwz     %r22, PC_BOOKE_TLB_LOCK(%r20);                          \
356                                                                         \
357         /* update recursion counter */                                  \
358         lwz     %r23, RES_RECURSE(%r22);                                \
359         subi    %r23, %r23, 1;                                          \
360         stw     %r23, RES_RECURSE(%r22);                                \
361                                                                         \
362         cmpwi   %r23, 0;                                                \
363         bne     1f;                                                     \
364         isync;                                                          \
365         msync;                                                          \
366                                                                         \
367         /* release the lock */                                          \
368         li      %r23, TLB_UNLOCKED;                                     \
369         stw     %r23, 0(%r22);                                          \
370 1:      isync;                                                          \
371         msync
372 #else
373 #define TLB_LOCK
374 #define TLB_UNLOCK
375 #endif  /* SMP */
376
377 #define INTERRUPT(label)                                                \
378         .globl  label;                                                  \
379         .align  5;                                                      \
380         CNAME(label):
381
382 /*
383  * Interrupt handling routines in BookE can be flexibly placed and do not have
384  * to live in pre-defined vectors location. Note they need to be TLB-mapped at
385  * all times in order to be able to handle exceptions. We thus arrange for
386  * them to be part of kernel text which is always TLB-accessible.
387  *
388  * The interrupt handling routines have to be 16 bytes aligned: we align them
389  * to 32 bytes (cache line length) which supposedly performs better.
390  *
391  */
392         .text
393         .globl CNAME(interrupt_vector_base)
394         .align 5
395 interrupt_vector_base:
396
397 /*****************************************************************************
398  * Critical input interrupt
399  ****************************************************************************/
400 INTERRUPT(int_critical_input)
401         STANDARD_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)
402         FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_CRIT)
403         addi    %r3, %r1, 8
404         bl      CNAME(powerpc_crit_interrupt)
405         FRAME_LEAVE(SPR_CSRR0, SPR_CSRR1)
406         rfci
407
408
409 /*****************************************************************************
410  * Machine check interrupt
411  ****************************************************************************/
412 INTERRUPT(int_machine_check)
413         STANDARD_PROLOG(SPR_SPRG3, PC_BOOKE_MCHKSAVE, SPR_MCSRR0, SPR_MCSRR1)
414         FRAME_SETUP(SPR_SPRG3, PC_BOOKE_MCHKSAVE, EXC_MCHK)
415         addi    %r3, %r1, 8
416         bl      CNAME(powerpc_mchk_interrupt)
417         FRAME_LEAVE(SPR_MCSRR0, SPR_MCSRR1)
418         rfmci
419
420
421 /*****************************************************************************
422  * Data storage interrupt
423  ****************************************************************************/
424 INTERRUPT(int_data_storage)
425         STANDARD_PROLOG(SPR_SPRG1, PC_DISISAVE, SPR_SRR0, SPR_SRR1)
426         FRAME_SETUP(SPR_SPRG1, PC_DISISAVE, EXC_DSI)
427         b       trap_common
428
429
430 /*****************************************************************************
431  * Instruction storage interrupt
432  ****************************************************************************/
433 INTERRUPT(int_instr_storage)
434         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
435         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_ISI)
436         b       trap_common
437
438
439 /*****************************************************************************
440  * External input interrupt
441  ****************************************************************************/
442 INTERRUPT(int_external_input)
443         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
444         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_EXI)
445         addi    %r3, %r1, 8
446         bl      CNAME(powerpc_extr_interrupt)
447         b       trapexit
448
449
450 INTERRUPT(int_alignment)
451         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
452         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_ALI)
453         b       trap_common
454
455
456 INTERRUPT(int_program)
457         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
458         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_PGM)
459         b       trap_common
460
461
462 /*****************************************************************************
463  * System call
464  ****************************************************************************/
465 INTERRUPT(int_syscall)
466         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
467         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_SC)
468         b       trap_common
469
470
471 /*****************************************************************************
472  * Decrementer interrupt
473  ****************************************************************************/
474 INTERRUPT(int_decrementer)
475         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
476         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_DECR)
477         addi    %r3, %r1, 8
478         bl      CNAME(powerpc_decr_interrupt)
479         b       trapexit
480
481
482 /*****************************************************************************
483  * Fixed interval timer
484  ****************************************************************************/
485 INTERRUPT(int_fixed_interval_timer)
486         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
487         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_FIT)
488         b       trap_common
489
490
491 /*****************************************************************************
492  * Watchdog interrupt
493  ****************************************************************************/
494 INTERRUPT(int_watchdog)
495         STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
496         FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_WDOG)
497         b       trap_common
498
499
500 /*****************************************************************************
501  * Data TLB miss interrupt
502  *
503  * There can be nested TLB misses - while handling a TLB miss we reference
504  * data structures that may be not covered by translations. We support up to
505  * TLB_NESTED_MAX-1 nested misses.
506  * 
507  * Registers use:
508  *      r31 - dear
509  *      r30 - unused
510  *      r29 - saved mas0
511  *      r28 - saved mas1
512  *      r27 - saved mas2
513  *      r26 - pmap address
514  *      r25 - pte address
515  *
516  *      r20:r23 - scratch registers
517  ****************************************************************************/
518 INTERRUPT(int_data_tlb_error)
519         TLB_PROLOG
520         TLB_LOCK
521
522         mfdear  %r31
523
524         /*
525          * Save MAS0-MAS2 registers. There might be another tlb miss during
526          * pte lookup overwriting current contents (which was hw filled).
527          */
528         mfspr   %r29, SPR_MAS0
529         mfspr   %r28, SPR_MAS1
530         mfspr   %r27, SPR_MAS2
531
532         /* Check faulting address. */
533         lis     %r21, VM_MAXUSER_ADDRESS@h
534         ori     %r21, %r21, VM_MAXUSER_ADDRESS@l
535         cmplw   cr0, %r31, %r21
536         blt     search_user_pmap
537         
538         /* If it's kernel address, allow only supervisor mode misses. */
539         mfsrr1  %r21
540         mtcr    %r21
541         bt      17, search_failed       /* check MSR[PR] */
542
543 search_kernel_pmap:
544         /* Load r26 with kernel_pmap address */
545         lis     %r26, kernel_pmap_store@h
546         ori     %r26, %r26, kernel_pmap_store@l
547
548         /* Force kernel tid, set TID to 0 in MAS1. */
549         li      %r21, 0
550         rlwimi  %r28, %r21, 0, 8, 15    /* clear TID bits */
551
552 tlb_miss_handle:
553         /* This may result in nested tlb miss. */
554         bl      pte_lookup              /* returns PTE address in R25 */
555
556         cmpwi   %r25, 0                 /* pte found? */
557         beq     search_failed
558
559         /* Finish up, write TLB entry. */
560         bl      tlb_fill_entry
561
562 tlb_miss_return:
563         TLB_UNLOCK
564         TLB_RESTORE
565         rfi
566
567 search_user_pmap:
568         /* Load r26 with current user space process pmap */
569         GET_CPUINFO(%r26)
570         lwz     %r26, PC_CURPMAP(%r26)
571
572         b       tlb_miss_handle
573
574 search_failed:
575         /*
576          * Whenever we don't find a TLB mapping in PT, set a TLB0 entry with
577          * the faulting virtual address anyway, but put a fake RPN and no
578          * access rights. This should cause a following {D,I}SI exception.
579          */
580         lis     %r23, 0xffff0000@h      /* revoke all permissions */
581
582         /* Load MAS registers. */
583         mtspr   SPR_MAS0, %r29
584         isync
585         mtspr   SPR_MAS1, %r28
586         isync
587         mtspr   SPR_MAS2, %r27
588         isync
589         mtspr   SPR_MAS3, %r23
590         isync
591
592         tlbwe
593         msync
594         isync
595         b       tlb_miss_return
596
597 /*****************************************************************************
598  *
599  * Return pte address that corresponds to given pmap/va.  If there is no valid
600  * entry return 0.
601  *
602  * input: r26 - pmap
603  * input: r31 - dear
604  * output: r25 - pte address
605  *
606  * scratch regs used: r21
607  *
608  ****************************************************************************/
609 pte_lookup:
610         cmpwi   %r26, 0
611         beq     1f                      /* fail quickly if pmap is invalid */
612
613         srwi    %r21, %r31, PDIR_SHIFT          /* pdir offset */
614         slwi    %r21, %r21, PDIR_ENTRY_SHIFT    /* multiply by pdir entry size */
615
616         addi    %r25, %r26, PM_PDIR     /* pmap pm_dir[] address */
617         add     %r25, %r25, %r21        /* offset within pm_pdir[] table */
618         /*
619          * Get ptbl address, i.e. pmap->pm_pdir[pdir_idx]
620          * This load may cause a Data TLB miss for non-kernel pmap!
621          */
622         lwz     %r25, 0(%r25)
623         cmpwi   %r25, 0
624         beq     2f
625
626         lis     %r21, PTBL_MASK@h
627         ori     %r21, %r21, PTBL_MASK@l
628         and     %r21, %r21, %r31
629
630         /* ptbl offset, multiply by ptbl entry size */
631         srwi    %r21, %r21, (PTBL_SHIFT - PTBL_ENTRY_SHIFT)
632
633         add     %r25, %r25, %r21                /* address of pte entry */
634         /*
635          * Get pte->flags
636          * This load may cause a Data TLB miss for non-kernel pmap!
637          */
638         lwz     %r21, PTE_FLAGS(%r25)
639         andis.  %r21, %r21, PTE_VALID@h
640         bne     2f
641 1:
642         li      %r25, 0
643 2:
644         blr
645
646 /*****************************************************************************
647  *
648  * Load MAS1-MAS3 registers with data, write TLB entry
649  *
650  * input:
651  * r29 - mas0
652  * r28 - mas1
653  * r27 - mas2
654  * r25 - pte
655  *
656  * output: none
657  *
658  * scratch regs: r21-r23
659  *
660  ****************************************************************************/
661 tlb_fill_entry:
662         /*
663          * Update PTE flags: we have to do it atomically, as pmap_protect()
664          * running on other CPUs could attempt to update the flags at the same
665          * time.
666          */
667         li      %r23, PTE_FLAGS
668 1:
669         lwarx   %r21, %r23, %r25                /* get pte->flags */
670         oris    %r21, %r21, PTE_REFERENCED@h    /* set referenced bit */
671
672         andi.   %r22, %r21, (PTE_SW | PTE_UW)@l /* check if writable */
673         beq     2f
674         oris    %r21, %r21, PTE_MODIFIED@h      /* set modified bit */
675 2:
676         stwcx.  %r21, %r23, %r25                /* write it back */
677         bne-    1b
678
679         /* Update MAS2. */
680         rlwimi  %r27, %r21, 0, 27, 30           /* insert WIMG bits from pte */
681
682         /* Setup MAS3 value in r23. */
683         lwz     %r23, PTE_RPN(%r25)             /* get pte->rpn */
684
685         rlwimi  %r23, %r21, 24, 26, 31          /* insert protection bits from pte */
686
687         /* Load MAS registers. */
688         mtspr   SPR_MAS0, %r29
689         isync
690         mtspr   SPR_MAS1, %r28
691         isync
692         mtspr   SPR_MAS2, %r27
693         isync
694         mtspr   SPR_MAS3, %r23
695         isync
696
697         tlbwe
698         isync
699         msync
700         blr
701
702 /*****************************************************************************
703  * Instruction TLB miss interrupt
704  *
705  * Same notes as for the Data TLB miss
706  ****************************************************************************/
707 INTERRUPT(int_inst_tlb_error)
708         TLB_PROLOG
709         TLB_LOCK
710
711         mfsrr0  %r31                    /* faulting address */
712
713         /*
714          * Save MAS0-MAS2 registers. There might be another tlb miss during pte
715          * lookup overwriting current contents (which was hw filled).
716          */
717         mfspr   %r29, SPR_MAS0
718         mfspr   %r28, SPR_MAS1
719         mfspr   %r27, SPR_MAS2
720
721         mfsrr1  %r21
722         mtcr    %r21
723
724         /* check MSR[PR] */
725         bt      17, search_user_pmap
726         b       search_kernel_pmap
727
728
729         .globl  interrupt_vector_top
730 interrupt_vector_top:
731
732 /*****************************************************************************
733  * Debug interrupt
734  ****************************************************************************/
735 INTERRUPT(int_debug)
736         STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)
737         FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_DEBUG)
738         GET_CPUINFO(%r3)
739         lwz     %r3, (PC_BOOKE_CRITSAVE+CPUSAVE_SRR0)(%r3)
740         lis     %r4, interrupt_vector_base@ha
741         addi    %r4, %r4, interrupt_vector_base@l
742         cmplw   cr0, %r3, %r4
743         blt     1f
744         lis     %r4, interrupt_vector_top@ha
745         addi    %r4, %r4, interrupt_vector_top@l
746         cmplw   cr0, %r3, %r4
747         bge     1f
748         /* Disable single-stepping for the interrupt handlers. */
749         lwz     %r3, FRAME_SRR1+8(%r1);
750         rlwinm  %r3, %r3, 0, 23, 21
751         stw     %r3, FRAME_SRR1+8(%r1);
752         /* Restore srr0 and srr1 as they could have been clobbered. */
753         GET_CPUINFO(%r4)
754         lwz     %r3, (PC_BOOKE_CRITSAVE+CPUSAVE_SRR0+8)(%r4);
755         mtspr   SPR_SRR0, %r3
756         lwz     %r4, (PC_BOOKE_CRITSAVE+CPUSAVE_SRR1+8)(%r4);
757         mtspr   SPR_SRR1, %r4
758         b       9f
759 1:
760         addi    %r3, %r1, 8
761         bl      CNAME(trap)
762         /*
763          * Handle ASTs, needed for proper support of single-stepping.
764          * We actually need to return to the process with an rfi.
765          */
766         b       trapexit
767 9:
768         FRAME_LEAVE(SPR_CSRR0, SPR_CSRR1)
769         rfci
770
771
772 /*****************************************************************************
773  * Common trap code
774  ****************************************************************************/
775 trap_common:
776         /* Call C trap dispatcher */
777         addi    %r3, %r1, 8
778         bl      CNAME(trap)
779
780         .globl  CNAME(trapexit)         /* exported for db_backtrace use */
781 CNAME(trapexit):
782         /* disable interrupts */
783         wrteei  0
784
785         /* Test AST pending - makes sense for user process only */
786         lwz     %r5, FRAME_SRR1+8(%r1)
787         mtcr    %r5
788         bf      17, 1f
789
790         GET_CPUINFO(%r3)
791         lwz     %r4, PC_CURTHREAD(%r3)
792         lwz     %r4, TD_FLAGS(%r4)
793         lis     %r5, (TDF_ASTPENDING | TDF_NEEDRESCHED)@h
794         ori     %r5, %r5, (TDF_ASTPENDING | TDF_NEEDRESCHED)@l
795         and.    %r4, %r4, %r5
796         beq     1f
797
798         /* re-enable interrupts before calling ast() */
799         wrteei  1
800
801         addi    %r3, %r1, 8
802         bl      CNAME(ast)
803         .globl  CNAME(asttrapexit)      /* db_backtrace code sentinel #2 */
804 CNAME(asttrapexit):
805         b       trapexit                /* test ast ret value ? */
806 1:
807         FRAME_LEAVE(SPR_SRR0, SPR_SRR1)
808         rfi
809
810
811 #if defined(KDB)
812 /*
813  * Deliberate entry to dbtrap
814  */
815         .globl  CNAME(breakpoint)
816 CNAME(breakpoint):
817         mtsprg1 %r1
818         mfmsr   %r3
819         mtsrr1  %r3
820         andi.   %r3, %r3, ~(PSL_EE | PSL_ME)@l
821         mtmsr   %r3                     /* disable interrupts */
822         isync
823         GET_CPUINFO(%r3)
824         stw     %r30, (PC_DBSAVE+CPUSAVE_R30)(%r3)
825         stw     %r31, (PC_DBSAVE+CPUSAVE_R31)(%r3)
826
827         mflr    %r31
828         mtsrr0  %r31
829
830         mfdear  %r30
831         mfesr   %r31
832         stw     %r30, (PC_DBSAVE+CPUSAVE_BOOKE_DEAR)(%r3)
833         stw     %r31, (PC_DBSAVE+CPUSAVE_BOOKE_ESR)(%r3)
834
835         mfsrr0  %r30
836         mfsrr1  %r31
837         stw     %r30, (PC_DBSAVE+CPUSAVE_SRR0)(%r3)
838         stw     %r31, (PC_DBSAVE+CPUSAVE_SRR1)(%r3)
839         isync
840
841         mfcr    %r30
842
843 /*
844  * Now the kdb trap catching code.
845  */
846 dbtrap:
847         FRAME_SETUP(SPR_SPRG1, PC_DBSAVE, EXC_DEBUG)
848 /* Call C trap code: */
849         addi    %r3, %r1, 8
850         bl      CNAME(db_trap_glue)
851         or.     %r3, %r3, %r3
852         bne     dbleave
853 /* This wasn't for KDB, so switch to real trap: */
854         b       trap_common
855
856 dbleave:
857         FRAME_LEAVE(SPR_SRR0, SPR_SRR1)
858         rfi
859 #endif /* KDB */
860
861 #ifdef SMP
862 ENTRY(tlb_lock)
863         GET_CPUINFO(%r5)
864         lwz     %r5, PC_CURTHREAD(%r5)
865 1:      lwarx   %r4, 0, %r3
866         cmpwi   %r4, TLB_UNLOCKED
867         bne     1b
868         stwcx.  %r5, 0, %r3
869         bne-    1b
870         isync
871         msync
872         blr
873
874 ENTRY(tlb_unlock)
875         isync
876         msync
877         li      %r4, TLB_UNLOCKED
878         stw     %r4, 0(%r3)
879         isync
880         msync
881         blr
882
883 /*
884  * TLB miss spin locks. For each CPU we have a reservation granule (32 bytes);
885  * only a single word from this granule will actually be used as a spin lock
886  * for mutual exclusion between TLB miss handler and pmap layer that
887  * manipulates page table contents.
888  */
889         .data
890         .align  5
891 GLOBAL(tlb0_miss_locks)
892         .space  RES_GRANULE * MAXCPU
893 #endif