xref: /freebsd/sys/powerpc/booke/trap_subr.S (revision 734e82fe33aa764367791a7d603b383996c6b40b)
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/*-
30 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
31 * Copyright (C) 1995, 1996 TooLs GmbH.
32 * All rights reserved.
33 *
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
36 * are met:
37 * 1. Redistributions of source code must retain the above copyright
38 *    notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 *    notice, this list of conditions and the following disclaimer in the
41 *    documentation and/or other materials provided with the distribution.
42 * 3. All advertising materials mentioning features or use of this software
43 *    must display the following acknowledgement:
44 *	This product includes software developed by TooLs GmbH.
45 * 4. The name of TooLs GmbH may not be used to endorse or promote products
46 *    derived from this software without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
49 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
50 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
51 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
53 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
54 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
55 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
56 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
57 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 *
59 *	from: $NetBSD: trap_subr.S,v 1.20 2002/04/22 23:20:08 kleink Exp $
60 */
61
62/*
63 * NOTICE: This is not a standalone file.  to use it, #include it in
64 * your port's locore.S, like so:
65 *
66 *	#include <powerpc/booke/trap_subr.S>
67 */
68
69/*
70 * SPRG usage notes
71 *
72 * SPRG0 - pcpu pointer
73 * SPRG1 - all interrupts except TLB miss, critical, machine check
74 * SPRG2 - critical
75 * SPRG3 - machine check
76 * SPRG4-6 - scratch
77 *
78 */
79
80/* Get the per-CPU data structure */
81#define GET_CPUINFO(r) mfsprg0 r
82
83#define RES_GRANULE	64
84#define RES_LOCK	0	/* offset to the 'lock' word */
85#ifdef __powerpc64__
86#define RES_RECURSE	8	/* offset to the 'recurse' word */
87#else
88#define RES_RECURSE	4	/* offset to the 'recurse' word */
89#endif
90
91/*
92 * Standard interrupt prolog
93 *
94 * sprg_sp - SPRG{1-3} reg used to temporarily store the SP
95 * savearea - temp save area (pc_{tempsave, disisave, critsave, mchksave})
96 * isrr0-1 - save restore registers with CPU state at interrupt time (may be
97 *           SRR0-1, CSRR0-1, MCSRR0-1
98 *
99 * 1. saves in the given savearea:
100 *   - R30-31
101 *   - DEAR, ESR
102 *   - xSRR0-1
103 *
104 * 2. saves CR -> R30
105 *
106 * 3. switches to kstack if needed
107 *
108 * 4. notes:
109 *   - R31 can be used as scratch register until a new frame is laid on
110 *     the stack with FRAME_SETUP
111 *
112 *   - potential TLB miss: NO. Saveareas are always acessible via TLB1
113 *     permanent entries, and within this prolog we do not dereference any
114 *     locations potentially not in the TLB
115 */
116#define STANDARD_PROLOG(sprg_sp, savearea, isrr0, isrr1)		\
117	mtspr	sprg_sp, %r1;		/* Save SP */			\
118	GET_CPUINFO(%r1);		/* Per-cpu structure */		\
119	STORE	%r30, (savearea+CPUSAVE_R30)(%r1);			\
120	STORE	%r31, (savearea+CPUSAVE_R31)(%r1); 			\
121	mfspr	%r30, SPR_DEAR;						\
122	mfspr	%r31, SPR_ESR;						\
123	STORE	%r30, (savearea+CPUSAVE_BOOKE_DEAR)(%r1); 		\
124	STORE	%r31, (savearea+CPUSAVE_BOOKE_ESR)(%r1); 		\
125	mfspr	%r30, isrr0;						\
126	mfspr	%r31, isrr1;	 	/* MSR at interrupt time */	\
127	STORE	%r30, (savearea+CPUSAVE_SRR0)(%r1);			\
128	STORE	%r31, (savearea+CPUSAVE_SRR1)(%r1);			\
129	isync;			 					\
130	mfspr	%r1, sprg_sp;	 	/* Restore SP */		\
131	mfcr	%r30;		 	/* Save CR */			\
132	/* switch to per-thread kstack if intr taken in user mode */	\
133	mtcr	%r31;			/* MSR at interrupt time  */	\
134	bf	17, 1f;							\
135	GET_CPUINFO(%r1);		/* Per-cpu structure */		\
136	LOAD	%r1, PC_CURPCB(%r1); 	/* Per-thread kernel stack */	\
1371:
138
139#define	STANDARD_CRIT_PROLOG(sprg_sp, savearea, isrr0, isrr1)		\
140	mtspr	sprg_sp, %r1;		/* Save SP */			\
141	GET_CPUINFO(%r1);		/* Per-cpu structure */		\
142	STORE	%r30, (savearea+CPUSAVE_R30)(%r1);			\
143	STORE	%r31, (savearea+CPUSAVE_R31)(%r1);			\
144	mfspr	%r30, SPR_DEAR;						\
145	mfspr	%r31, SPR_ESR;						\
146	STORE	%r30, (savearea+CPUSAVE_BOOKE_DEAR)(%r1);		\
147	STORE	%r31, (savearea+CPUSAVE_BOOKE_ESR)(%r1);		\
148	mfspr	%r30, isrr0;						\
149	mfspr	%r31, isrr1;		/* MSR at interrupt time */	\
150	STORE	%r30, (savearea+CPUSAVE_SRR0)(%r1);			\
151	STORE	%r31, (savearea+CPUSAVE_SRR1)(%r1);			\
152	mfspr	%r30, SPR_SRR0;						\
153	mfspr	%r31, SPR_SRR1;		/* MSR at interrupt time */	\
154	STORE	%r30, (savearea+BOOKE_CRITSAVE_SRR0)(%r1);		\
155	STORE	%r31, (savearea+BOOKE_CRITSAVE_SRR1)(%r1);		\
156	isync;								\
157	mfspr	%r1, sprg_sp;		/* Restore SP */		\
158	mfcr	%r30;			/* Save CR */			\
159	/* switch to per-thread kstack if intr taken in user mode */	\
160	mtcr	%r31;			/* MSR at interrupt time  */	\
161	bf	17, 1f;							\
162	GET_CPUINFO(%r1);		/* Per-cpu structure */		\
163	LOAD	%r1, PC_CURPCB(%r1);	/* Per-thread kernel stack */	\
1641:
165
166/*
167 * FRAME_SETUP assumes:
168 *	SPRG{1-3}	SP at the time interrupt occurred
169 *	savearea	r30-r31, DEAR, ESR, xSRR0-1
170 *	r30		CR
171 *	r31		scratch
172 *	r1		kernel stack
173 *
174 * sprg_sp - SPRG reg containing SP at the time interrupt occurred
175 * savearea - temp save
176 * exc - exception number (EXC_xxx)
177 *
178 * 1. sets a new frame
179 * 2. saves in the frame:
180 *   - R0, R1 (SP at the time of interrupt), R2, LR, CR
181 *   - R3-31 (R30-31 first restored from savearea)
182 *   - XER, CTR, DEAR, ESR (from savearea), xSRR0-1
183 *
184 * Notes:
185 * - potential TLB miss: YES, since we make dereferences to kstack, which
186 *   can happen not covered (we can have up to two DTLB misses if fortunate
187 *   enough i.e. when kstack crosses page boundary and both pages are
188 *   untranslated)
189 */
190#ifdef __powerpc64__
191#define SAVE_REGS(r)							\
192	std	%r3, FRAME_3+CALLSIZE(r);				\
193	std	%r4, FRAME_4+CALLSIZE(r);				\
194	std	%r5, FRAME_5+CALLSIZE(r);				\
195	std	%r6, FRAME_6+CALLSIZE(r);				\
196	std	%r7, FRAME_7+CALLSIZE(r);				\
197	std	%r8, FRAME_8+CALLSIZE(r);				\
198	std	%r9, FRAME_9+CALLSIZE(r);				\
199	std	%r10, FRAME_10+CALLSIZE(r);				\
200	std	%r11, FRAME_11+CALLSIZE(r);				\
201	std	%r12, FRAME_12+CALLSIZE(r);				\
202	std	%r13, FRAME_13+CALLSIZE(r);				\
203	std	%r14, FRAME_14+CALLSIZE(r);				\
204	std	%r15, FRAME_15+CALLSIZE(r);				\
205	std	%r16, FRAME_16+CALLSIZE(r);				\
206	std	%r17, FRAME_17+CALLSIZE(r);				\
207	std	%r18, FRAME_18+CALLSIZE(r);				\
208	std	%r19, FRAME_19+CALLSIZE(r);				\
209	std	%r20, FRAME_20+CALLSIZE(r);				\
210	std	%r21, FRAME_21+CALLSIZE(r);				\
211	std	%r22, FRAME_22+CALLSIZE(r);				\
212	std	%r23, FRAME_23+CALLSIZE(r);				\
213	std	%r24, FRAME_24+CALLSIZE(r);				\
214	std	%r25, FRAME_25+CALLSIZE(r);				\
215	std	%r26, FRAME_26+CALLSIZE(r);				\
216	std	%r27, FRAME_27+CALLSIZE(r);				\
217	std	%r28, FRAME_28+CALLSIZE(r);				\
218	std	%r29, FRAME_29+CALLSIZE(r);				\
219	std	%r30, FRAME_30+CALLSIZE(r);				\
220	std	%r31, FRAME_31+CALLSIZE(r)
221#define LD_REGS(r)							\
222	ld	%r3, FRAME_3+CALLSIZE(r);				\
223	ld	%r4, FRAME_4+CALLSIZE(r);				\
224	ld	%r5, FRAME_5+CALLSIZE(r);				\
225	ld	%r6, FRAME_6+CALLSIZE(r);				\
226	ld	%r7, FRAME_7+CALLSIZE(r);				\
227	ld	%r8, FRAME_8+CALLSIZE(r);				\
228	ld	%r9, FRAME_9+CALLSIZE(r);				\
229	ld	%r10, FRAME_10+CALLSIZE(r);				\
230	ld	%r11, FRAME_11+CALLSIZE(r);				\
231	ld	%r12, FRAME_12+CALLSIZE(r);				\
232	ld	%r13, FRAME_13+CALLSIZE(r);				\
233	ld	%r14, FRAME_14+CALLSIZE(r);				\
234	ld	%r15, FRAME_15+CALLSIZE(r);				\
235	ld	%r16, FRAME_16+CALLSIZE(r);				\
236	ld	%r17, FRAME_17+CALLSIZE(r);				\
237	ld	%r18, FRAME_18+CALLSIZE(r);				\
238	ld	%r19, FRAME_19+CALLSIZE(r);				\
239	ld	%r20, FRAME_20+CALLSIZE(r);				\
240	ld	%r21, FRAME_21+CALLSIZE(r);				\
241	ld	%r22, FRAME_22+CALLSIZE(r);				\
242	ld	%r23, FRAME_23+CALLSIZE(r);				\
243	ld	%r24, FRAME_24+CALLSIZE(r);				\
244	ld	%r25, FRAME_25+CALLSIZE(r);				\
245	ld	%r26, FRAME_26+CALLSIZE(r);				\
246	ld	%r27, FRAME_27+CALLSIZE(r);				\
247	ld	%r28, FRAME_28+CALLSIZE(r);				\
248	ld	%r29, FRAME_29+CALLSIZE(r);				\
249	ld	%r30, FRAME_30+CALLSIZE(r);				\
250	ld	%r31, FRAME_31+CALLSIZE(r)
251#else
252#define SAVE_REGS(r)							\
253	stmw	%r3,  FRAME_3+CALLSIZE(r)
254#define LD_REGS(r)							\
255	lmw	%r3,  FRAME_3+CALLSIZE(r)
256#endif
257#define	FRAME_SETUP(sprg_sp, savearea, exc)				\
258	mfspr	%r31, sprg_sp;		/* get saved SP */		\
259	/* establish a new stack frame and put everything on it */	\
260	STU	%r31, -(FRAMELEN+REDZONE)(%r1);				\
261	STORE	%r0, FRAME_0+CALLSIZE(%r1);	/* save r0 in the trapframe */	\
262	STORE	%r31, FRAME_1+CALLSIZE(%r1);	/* save SP   "     " */	\
263	STORE	%r2, FRAME_2+CALLSIZE(%r1);	/* save r2   "     " */	\
264	mflr	%r31;		 					\
265	STORE	%r31, FRAME_LR+CALLSIZE(%r1);	/* save LR   "     " */	\
266	STORE	%r30, FRAME_CR+CALLSIZE(%r1);	/* save CR   "     " */	\
267	GET_CPUINFO(%r2);						\
268	LOAD	%r30, (savearea+CPUSAVE_R30)(%r2); /* get saved r30 */	\
269	LOAD	%r31, (savearea+CPUSAVE_R31)(%r2); /* get saved r31 */	\
270	/* save R3-31 */						\
271	SAVE_REGS(%r1);							\
272	/* save DEAR, ESR */						\
273	LOAD	%r28, (savearea+CPUSAVE_BOOKE_DEAR)(%r2);		\
274	LOAD	%r29, (savearea+CPUSAVE_BOOKE_ESR)(%r2);		\
275	STORE	%r28, FRAME_BOOKE_DEAR+CALLSIZE(%r1);			\
276	STORE	%r29, FRAME_BOOKE_ESR+CALLSIZE(%r1);			\
277	/* save XER, CTR, exc number */					\
278	mfxer	%r3;							\
279	mfctr	%r4;							\
280	STORE	%r3, FRAME_XER+CALLSIZE(%r1);				\
281	STORE	%r4, FRAME_CTR+CALLSIZE(%r1);				\
282	li	%r5, exc;						\
283	STORE	%r5, FRAME_EXC+CALLSIZE(%r1);				\
284	/* save DBCR0 */						\
285	mfspr	%r3, SPR_DBCR0;						\
286	STORE	%r3, FRAME_BOOKE_DBCR0+CALLSIZE(%r1);			\
287	/* save xSSR0-1 */						\
288	LOAD	%r30, (savearea+CPUSAVE_SRR0)(%r2);			\
289	LOAD	%r31, (savearea+CPUSAVE_SRR1)(%r2);			\
290	STORE	%r30, FRAME_SRR0+CALLSIZE(%r1);				\
291	STORE	%r31, FRAME_SRR1+CALLSIZE(%r1);				\
292	LOAD	THREAD_REG, PC_CURTHREAD(%r2);				\
293
294/*
295 *
296 * isrr0-1 - save restore registers to restore CPU state to (may be
297 *           SRR0-1, CSRR0-1, MCSRR0-1
298 *
299 * Notes:
300 *  - potential TLB miss: YES. The deref'd kstack may be not covered
301 */
302#define	FRAME_LEAVE(isrr0, isrr1)					\
303	wrteei 0;							\
304	/* restore CTR, XER, LR, CR */					\
305	LOAD	%r4, FRAME_CTR+CALLSIZE(%r1);				\
306	LOAD	%r5, FRAME_XER+CALLSIZE(%r1);				\
307	LOAD	%r6, FRAME_LR+CALLSIZE(%r1);				\
308	LOAD	%r7, FRAME_CR+CALLSIZE(%r1);				\
309	mtctr	%r4;							\
310	mtxer	%r5;							\
311	mtlr	%r6;							\
312	mtcr	%r7;							\
313	/* restore DBCR0 */						\
314	LOAD	%r4, FRAME_BOOKE_DBCR0+CALLSIZE(%r1);			\
315	mtspr	SPR_DBCR0, %r4;						\
316	/* restore xSRR0-1 */						\
317	LOAD	%r30, FRAME_SRR0+CALLSIZE(%r1);				\
318	LOAD	%r31, FRAME_SRR1+CALLSIZE(%r1);				\
319	mtspr	isrr0, %r30;						\
320	mtspr	isrr1, %r31;						\
321	/* restore R2-31, SP */						\
322	LD_REGS(%r1);							\
323	LOAD	%r2, FRAME_2+CALLSIZE(%r1);				\
324	LOAD	%r0, FRAME_0+CALLSIZE(%r1);				\
325	LOAD	%r1, FRAME_1+CALLSIZE(%r1);				\
326	isync
327
328/*
329 * TLB miss prolog
330 *
331 * saves LR, CR, SRR0-1, R20-31 in the TLBSAVE area
332 *
333 * Notes:
334 *  - potential TLB miss: NO. It is crucial that we do not generate a TLB
335 *    miss within the TLB prolog itself!
336 *  - TLBSAVE is always translated
337 */
338#ifdef __powerpc64__
339#define	TLB_SAVE_REGS(br)						\
340	std	%r20, (TLBSAVE_BOOKE_R20)(br);				\
341	std	%r21, (TLBSAVE_BOOKE_R21)(br);				\
342	std	%r22, (TLBSAVE_BOOKE_R22)(br);				\
343	std	%r23, (TLBSAVE_BOOKE_R23)(br);				\
344	std	%r24, (TLBSAVE_BOOKE_R24)(br);				\
345	std	%r25, (TLBSAVE_BOOKE_R25)(br);				\
346	std	%r26, (TLBSAVE_BOOKE_R26)(br);				\
347	std	%r27, (TLBSAVE_BOOKE_R27)(br);				\
348	std	%r28, (TLBSAVE_BOOKE_R28)(br);				\
349	std	%r29, (TLBSAVE_BOOKE_R29)(br);				\
350	std	%r30, (TLBSAVE_BOOKE_R30)(br);				\
351	std	%r31, (TLBSAVE_BOOKE_R31)(br);
352#define	TLB_RESTORE_REGS(br)						\
353	ld	%r20, (TLBSAVE_BOOKE_R20)(br);				\
354	ld	%r21, (TLBSAVE_BOOKE_R21)(br);				\
355	ld	%r22, (TLBSAVE_BOOKE_R22)(br);				\
356	ld	%r23, (TLBSAVE_BOOKE_R23)(br);				\
357	ld	%r24, (TLBSAVE_BOOKE_R24)(br);				\
358	ld	%r25, (TLBSAVE_BOOKE_R25)(br);				\
359	ld	%r26, (TLBSAVE_BOOKE_R26)(br);				\
360	ld	%r27, (TLBSAVE_BOOKE_R27)(br);				\
361	ld	%r28, (TLBSAVE_BOOKE_R28)(br);				\
362	ld	%r29, (TLBSAVE_BOOKE_R29)(br);				\
363	ld	%r30, (TLBSAVE_BOOKE_R30)(br);				\
364	ld	%r31, (TLBSAVE_BOOKE_R31)(br);
365#define TLB_NEST(outr,inr)						\
366	rlwinm	outr, inr, 7, 23, 24;	/* 8 x TLBSAVE_LEN */
367#else
368#define TLB_SAVE_REGS(br)						\
369	stmw	%r20, TLBSAVE_BOOKE_R20(br)
370#define TLB_RESTORE_REGS(br)						\
371	lmw	%r20, TLBSAVE_BOOKE_R20(br)
372#define TLB_NEST(outr,inr)						\
373	rlwinm	outr, inr, 6, 24, 25;	/* 4 x TLBSAVE_LEN */
374#endif
375#define TLB_PROLOG							\
376	mtspr	SPR_SPRG4, %r1;			/* Save SP */		\
377	mtspr	SPR_SPRG5, %r28;					\
378	mtspr	SPR_SPRG6, %r29;					\
379	/* calculate TLB nesting level and TLBSAVE instance address */	\
380	GET_CPUINFO(%r1);	 	/* Per-cpu structure */		\
381	LOAD	%r28, PC_BOOKE_TLB_LEVEL(%r1);				\
382	TLB_NEST(%r29,%r28);						\
383	addi	%r28, %r28, 1;						\
384	STORE	%r28, PC_BOOKE_TLB_LEVEL(%r1);				\
385	addi	%r29, %r29, PC_BOOKE_TLBSAVE@l; 			\
386	add	%r1, %r1, %r29;		/* current TLBSAVE ptr */	\
387									\
388	/* save R20-31 */						\
389	mfspr	%r28, SPR_SPRG5;		 			\
390	mfspr	%r29, SPR_SPRG6;					\
391	TLB_SAVE_REGS(%r1);			\
392	/* save LR, CR */						\
393	mflr	%r30;		 					\
394	mfcr	%r31;							\
395	STORE	%r30, (TLBSAVE_BOOKE_LR)(%r1);				\
396	STORE	%r31, (TLBSAVE_BOOKE_CR)(%r1);				\
397	/* save SRR0-1 */						\
398	mfsrr0	%r30;		/* execution addr at interrupt time */	\
399	mfsrr1	%r31;		/* MSR at interrupt time*/		\
400	STORE	%r30, (TLBSAVE_BOOKE_SRR0)(%r1);	/* save SRR0 */	\
401	STORE	%r31, (TLBSAVE_BOOKE_SRR1)(%r1);	/* save SRR1 */	\
402	isync;								\
403	mfspr	%r1, SPR_SPRG4
404
405/*
406 * restores LR, CR, SRR0-1, R20-31 from the TLBSAVE area
407 *
408 * same notes as for the TLB_PROLOG
409 */
410#define TLB_RESTORE							\
411	mtspr	SPR_SPRG4, %r1;			/* Save SP */		\
412	GET_CPUINFO(%r1);	 	/* Per-cpu structure */		\
413	/* calculate TLB nesting level and TLBSAVE instance addr */	\
414	LOAD	%r28, PC_BOOKE_TLB_LEVEL(%r1);				\
415	subi	%r28, %r28, 1;						\
416	STORE	%r28, PC_BOOKE_TLB_LEVEL(%r1);				\
417	TLB_NEST(%r29,%r28);						\
418	addi	%r29, %r29, PC_BOOKE_TLBSAVE@l;				\
419	add	%r1, %r1, %r29;						\
420									\
421	/* restore LR, CR */						\
422	LOAD	%r30, (TLBSAVE_BOOKE_LR)(%r1);				\
423	LOAD	%r31, (TLBSAVE_BOOKE_CR)(%r1);				\
424	mtlr	%r30;							\
425	mtcr	%r31;							\
426	/* restore SRR0-1 */						\
427	LOAD	%r30, (TLBSAVE_BOOKE_SRR0)(%r1);			\
428	LOAD	%r31, (TLBSAVE_BOOKE_SRR1)(%r1);			\
429	mtsrr0	%r30;							\
430	mtsrr1	%r31;							\
431	/* restore R20-31 */						\
432	TLB_RESTORE_REGS(%r1);						\
433	mfspr	%r1, SPR_SPRG4
434
435#ifdef SMP
436#define TLB_LOCK							\
437	GET_CPUINFO(%r20);						\
438	LOAD	%r21, PC_CURTHREAD(%r20);				\
439	LOAD	%r22, PC_BOOKE_TLB_LOCK(%r20);				\
440									\
4411:	LOADX	%r23, 0, %r22;						\
442	CMPI	%r23, TLB_UNLOCKED;					\
443	beq	2f;							\
444									\
445	/* check if this is recursion */				\
446	CMPL	cr0, %r21, %r23;					\
447	bne-	1b;							\
448									\
4492:	/* try to acquire lock */					\
450	STOREX	%r21, 0, %r22;						\
451	bne-	1b;							\
452									\
453	/* got it, update recursion counter */				\
454	lwz	%r21, RES_RECURSE(%r22);				\
455	addi	%r21, %r21, 1;						\
456	stw	%r21, RES_RECURSE(%r22);				\
457	isync;								\
458	msync
459
460#define TLB_UNLOCK							\
461	GET_CPUINFO(%r20);						\
462	LOAD	%r21, PC_CURTHREAD(%r20);				\
463	LOAD	%r22, PC_BOOKE_TLB_LOCK(%r20);				\
464									\
465	/* update recursion counter */					\
466	lwz	%r23, RES_RECURSE(%r22);				\
467	subi	%r23, %r23, 1;						\
468	stw	%r23, RES_RECURSE(%r22);				\
469									\
470	cmplwi	%r23, 0;						\
471	bne	1f;							\
472	isync;								\
473	msync;								\
474									\
475	/* release the lock */						\
476	li	%r23, TLB_UNLOCKED;					\
477	STORE	%r23, 0(%r22);						\
4781:	isync;								\
479	msync
480#else
481#define TLB_LOCK
482#define TLB_UNLOCK
483#endif	/* SMP */
484
485#define INTERRUPT(label)						\
486	.globl	label;							\
487	.align	5;							\
488	CNAME(label):
489
490/*
491 * Interrupt handling routines in BookE can be flexibly placed and do not have
492 * to live in pre-defined vectors location. Note they need to be TLB-mapped at
493 * all times in order to be able to handle exceptions. We thus arrange for
494 * them to be part of kernel text which is always TLB-accessible.
495 *
496 * The interrupt handling routines have to be 16 bytes aligned: we align them
497 * to 32 bytes (cache line length) which supposedly performs better.
498 *
499 */
500	.text
501	.globl CNAME(interrupt_vector_base)
502	.align 5
503interrupt_vector_base:
504/*****************************************************************************
505 * Catch-all handler to handle uninstalled IVORs
506 ****************************************************************************/
507INTERRUPT(int_unknown)
508	STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
509	FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_RSVD)
510	b	trap_common
511
512/*****************************************************************************
513 * Critical input interrupt
514 ****************************************************************************/
515INTERRUPT(int_critical_input)
516	STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)
517	FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_CRIT)
518	GET_TOCBASE(%r2)
519	addi	%r3, %r1, CALLSIZE
520	bl	CNAME(powerpc_interrupt)
521	TOC_RESTORE
522	FRAME_LEAVE(SPR_CSRR0, SPR_CSRR1)
523	rfci
524
525
526/*****************************************************************************
527 * Machine check interrupt
528 ****************************************************************************/
529INTERRUPT(int_machine_check)
530	STANDARD_PROLOG(SPR_SPRG3, PC_BOOKE_MCHKSAVE, SPR_MCSRR0, SPR_MCSRR1)
531	FRAME_SETUP(SPR_SPRG3, PC_BOOKE_MCHKSAVE, EXC_MCHK)
532	GET_TOCBASE(%r2)
533	addi	%r3, %r1, CALLSIZE
534	bl	CNAME(powerpc_interrupt)
535	TOC_RESTORE
536	FRAME_LEAVE(SPR_MCSRR0, SPR_MCSRR1)
537	rfmci
538
539
540/*****************************************************************************
541 * Data storage interrupt
542 ****************************************************************************/
543INTERRUPT(int_data_storage)
544	STANDARD_PROLOG(SPR_SPRG1, PC_DISISAVE, SPR_SRR0, SPR_SRR1)
545	FRAME_SETUP(SPR_SPRG1, PC_DISISAVE, EXC_DSI)
546	b	trap_common
547
548
549/*****************************************************************************
550 * Instruction storage interrupt
551 ****************************************************************************/
552INTERRUPT(int_instr_storage)
553	STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
554	FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_ISI)
555	b	trap_common
556
557
558/*****************************************************************************
559 * External input interrupt
560 ****************************************************************************/
561INTERRUPT(int_external_input)
562	STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
563	FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_EXI)
564	b	trap_common
565
566
567INTERRUPT(int_alignment)
568	STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
569	FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_ALI)
570	b	trap_common
571
572
573INTERRUPT(int_program)
574	STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
575	FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_PGM)
576	b	trap_common
577
578
579INTERRUPT(int_fpu)
580	STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
581	FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_FPU)
582	b	trap_common
583
584
585/*****************************************************************************
586 * System call
587 ****************************************************************************/
588INTERRUPT(int_syscall)
589	STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
590	FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_SC)
591	b	trap_common
592
593
594/*****************************************************************************
595 * Decrementer interrupt
596 ****************************************************************************/
597INTERRUPT(int_decrementer)
598	STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
599	FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_DECR)
600	b	trap_common
601
602
603/*****************************************************************************
604 * Fixed interval timer
605 ****************************************************************************/
606INTERRUPT(int_fixed_interval_timer)
607	STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
608	FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_FIT)
609	b	trap_common
610
611
612/*****************************************************************************
613 * Watchdog interrupt
614 ****************************************************************************/
615INTERRUPT(int_watchdog)
616	STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
617	FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_WDOG)
618	b	trap_common
619
620
621/*****************************************************************************
622 * Altivec Unavailable interrupt
623 ****************************************************************************/
624INTERRUPT(int_vec)
625	STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
626	FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_VEC)
627	b	trap_common
628
629
630/*****************************************************************************
631 * Altivec Assist interrupt
632 ****************************************************************************/
633INTERRUPT(int_vecast)
634	STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
635	FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_VECAST_E)
636	b	trap_common
637
638
639#ifdef __SPE__
640/*****************************************************************************
641 * Floating point Assist interrupt
642 ****************************************************************************/
643INTERRUPT(int_spe_fpdata)
644	STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
645	FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_SPFPD)
646	addi	%r3, %r1, CALLSIZE
647	bl	spe_handle_fpdata
648	FRAME_LEAVE(SPR_SRR0, SPR_SRR1)
649	rfi
650
651INTERRUPT(int_spe_fpround)
652	STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
653	FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_SPFPR)
654	addi	%r3, %r1, CALLSIZE
655	bl	spe_handle_fpround
656	FRAME_LEAVE(SPR_SRR0, SPR_SRR1)
657	rfi
658#endif
659
660
661#ifdef HWPMC_HOOKS
662/*****************************************************************************
663 * PMC Interrupt
664 ****************************************************************************/
665INTERRUPT(int_performance_counter)
666	STANDARD_PROLOG(SPR_SPRG3, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
667	FRAME_SETUP(SPR_SPRG3, PC_TEMPSAVE, EXC_PERF)
668	b	trap_common
669#endif
670
671
672/*****************************************************************************
673 * Data TLB miss interrupt
674 *
675 * There can be nested TLB misses - while handling a TLB miss we reference
676 * data structures that may be not covered by translations. We support up to
677 * TLB_NESTED_MAX-1 nested misses.
678 *
679 * Registers use:
680 *	r31 - dear
681 *	r30 - unused
682 *	r29 - saved mas0
683 *	r28 - saved mas1
684 *	r27 - saved mas2
685 *	r26 - pmap address
686 *	r25 - pte address
687 *
688 *	r20:r23 - scratch registers
689 ****************************************************************************/
690INTERRUPT(int_data_tlb_error)
691	TLB_PROLOG
692	TLB_LOCK
693
694	mfspr	%r31, SPR_DEAR
695
696	/*
697	 * Save MAS0-MAS2 registers. There might be another tlb miss during
698	 * pte lookup overwriting current contents (which was hw filled).
699	 */
700	mfspr	%r29, SPR_MAS0
701	mfspr	%r28, SPR_MAS1
702	mfspr	%r27, SPR_MAS2
703
704	/* Check faulting address. */
705	LOAD_ADDR(%r21, VM_MAXUSER_ADDRESS)
706	CMPL	cr0, %r31, %r21
707	blt	search_user_pmap
708
709	/* If it's kernel address, allow only supervisor mode misses. */
710	mfsrr1	%r21
711	mtcr	%r21
712	bt	17, search_failed	/* check MSR[PR] */
713
714#ifdef __powerpc64__
715	srdi	%r21, %r31, 48
716	cmpldi	cr0, %r21, VM_MIN_KERNEL_ADDRESS@highest
717#else
718	lis	%r21, VM_MIN_KERNEL_ADDRESS@h
719	cmplw	cr0, %r31, %r21
720#endif
721	blt	search_failed
722
723search_kernel_pmap:
724	/* Load r26 with kernel_pmap address */
725	bl	1f
726#ifdef __powerpc64__
727	.llong kernel_pmap_store-.
728#else
729	.long kernel_pmap_store-.
730#endif
7311:	mflr	%r21
732	LOAD	%r26, 0(%r21)
733	add	%r26, %r21, %r26	/* kernel_pmap_store in r26 */
734
735	/* Force kernel tid, set TID to 0 in MAS1. */
736	li	%r21, 0
737	rlwimi	%r28, %r21, 0, 8, 15	/* clear TID bits */
738
739tlb_miss_handle:
740	/* This may result in nested tlb miss. */
741	bl	pte_lookup		/* returns PTE address in R25 */
742
743	CMPI	%r25, 0			/* pte found? */
744	beq	search_failed
745
746	/* Finish up, write TLB entry. */
747	bl	tlb_fill_entry
748
749tlb_miss_return:
750	TLB_UNLOCK
751	TLB_RESTORE
752	rfi
753
754search_user_pmap:
755	/* Load r26 with current user space process pmap */
756	GET_CPUINFO(%r26)
757	LOAD	%r26, PC_CURPMAP(%r26)
758
759	b	tlb_miss_handle
760
761search_failed:
762	/*
763	 * Whenever we don't find a TLB mapping in PT, set a TLB0 entry with
764	 * the faulting virtual address anyway, but put a fake RPN and no
765	 * access rights. This should cause a following {D,I}SI exception.
766	 */
767	lis	%r23, 0xffff0000@h	/* revoke all permissions */
768
769	/* Load MAS registers. */
770	mtspr	SPR_MAS0, %r29
771	mtspr	SPR_MAS1, %r28
772	mtspr	SPR_MAS2, %r27
773	mtspr	SPR_MAS3, %r23
774
775	li	%r23, 0
776	mtspr	SPR_MAS7, %r23
777
778	isync
779	tlbwe
780	msync
781	isync
782	b	tlb_miss_return
783
784/*****************************************************************************
785 *
786 * Return pte address that corresponds to given pmap/va.  If there is no valid
787 * entry return 0.
788 *
789 * input: r26 - pmap
790 * input: r31 - dear
791 * output: r25 - pte address
792 *
793 * scratch regs used: r21
794 *
795 ****************************************************************************/
796pte_lookup:
797	CMPI	%r26, 0
798	beq	1f			/* fail quickly if pmap is invalid */
799
800#ifdef __powerpc64__
801	rldicl  %r21, %r31, (64 - PG_ROOT_L), (64 - PG_ROOT_NUM) /* pp2d offset */
802	slwi    %r21, %r21, PG_ROOT_ENTRY_SHIFT	/* multiply by pp2d entry size */
803	ld	%r25, PM_ROOT(%r26)		/* pmap pm_pp2d[] address */
804	ldx	%r25, %r25, %r21		/* get pdir address, i.e.  pmap->pm_pp2d[pp2d_idx] * */
805
806	cmpdi   %r25, 0
807	beq 2f
808
809	rldicl  %r21, %r31, (64 - PDIR_L1_L), (64 - PDIR_L1_NUM) /* pp2d offset */
810	slwi    %r21, %r21, PDIR_L1_ENTRY_SHIFT	/* multiply by pp2d entry size */
811	ldx	%r25, %r25, %r21		/* get pdir address, i.e.  pmap->pm_pp2d[pp2d_idx] * */
812
813	cmpdi   %r25, 0
814	beq 2f
815
816	rldicl  %r21, %r31, (64 - PDIR_L), (64 - PDIR_NUM)	/* pdir offset */
817	slwi    %r21, %r21, PDIR_ENTRY_SHIFT	/* multiply by pdir entry size */
818	ldx	%r25, %r25, %r21		/* get ptbl address, i.e.  pmap->pm_pp2d[pp2d_idx][pdir_idx] */
819
820	cmpdi   %r25, 0
821	beq     2f
822
823	rldicl  %r21, %r31, (64 - PTBL_L), (64 - PTBL_NUM) /* ptbl offset */
824	slwi    %r21, %r21, PTBL_ENTRY_SHIFT   /* multiply by pte entry size */
825
826#else
827	srwi	%r21, %r31, PDIR_SHIFT		/* pdir offset */
828	slwi	%r21, %r21, PDIR_ENTRY_SHIFT	/* multiply by pdir entry size */
829
830	lwz	%r25, PM_PDIR(%r26)	/* pmap pm_dir[] address */
831	/*
832	 * Get ptbl address, i.e. pmap->pm_pdir[pdir_idx]
833	 * This load may cause a Data TLB miss for non-kernel pmap!
834	 */
835	lwzx	%r25, %r25, %r21	/* offset within pm_pdir[] table */
836	cmpwi	%r25, 0
837	beq	2f
838
839	lis	%r21, PTBL_MASK@h
840	ori	%r21, %r21, PTBL_MASK@l
841	and	%r21, %r21, %r31
842
843	/* ptbl offset, multiply by ptbl entry size */
844	srwi	%r21, %r21, (PTBL_SHIFT - PTBL_ENTRY_SHIFT)
845#endif
846
847	add	%r25, %r25, %r21		/* address of pte entry */
848	/*
849	 * Get pte->flags
850	 * This load may cause a Data TLB miss for non-kernel pmap!
851	 */
852	lwz	%r21, PTE_FLAGS(%r25)
853	andi.	%r21, %r21, PTE_VALID@l
854	bne	2f
8551:
856	li	%r25, 0
8572:
858	blr
859
860/*****************************************************************************
861 *
862 * Load MAS1-MAS3 registers with data, write TLB entry
863 *
864 * input:
865 * r29 - mas0
866 * r28 - mas1
867 * r27 - mas2
868 * r25 - pte
869 *
870 * output: none
871 *
872 * scratch regs: r21-r23
873 *
874 ****************************************************************************/
875tlb_fill_entry:
876	/*
877	 * Update PTE flags: we have to do it atomically, as pmap_protect()
878	 * running on other CPUs could attempt to update the flags at the same
879	 * time.
880	 */
881	li	%r23, PTE_FLAGS
8821:
883	lwarx	%r21, %r23, %r25		/* get pte->flags */
884	oris	%r21, %r21, PTE_REFERENCED@h	/* set referenced bit */
885
886	andi.	%r22, %r21, (PTE_SW | PTE_UW)@l	/* check if writable */
887	beq	2f
888	ori	%r21, %r21, PTE_MODIFIED@l	/* set modified bit */
8892:
890	stwcx.	%r21, %r23, %r25		/* write it back */
891	bne-	1b
892
893	/* Update MAS2. */
894	rlwimi	%r27, %r21, 13, 27, 30		/* insert WIMG bits from pte */
895
896	/* Setup MAS3 value in r23. */
897	LOAD	%r23, PTE_RPN(%r25)		/* get pte->rpn */
898#ifdef __powerpc64__
899	rldicr	%r22, %r23, 52, 51		/* extract MAS3 portion of RPN */
900	rldicl	%r23, %r23, 20, 54		/* extract MAS7 portion of RPN */
901
902	rlwimi	%r22, %r21, 30, 26, 31		/* insert protection bits from pte */
903#else
904	rlwinm	%r22, %r23, 20, 0, 11		/* extract MAS3 portion of RPN */
905
906	rlwimi	%r22, %r21, 30, 26, 31		/* insert protection bits from pte */
907	rlwimi	%r22, %r21, 20, 12, 19		/* insert lower 8 RPN bits to MAS3 */
908	rlwinm	%r23, %r23, 20, 24, 31		/* MAS7 portion of RPN */
909#endif
910
911	/* Load MAS registers. */
912	mtspr	SPR_MAS0, %r29
913	mtspr	SPR_MAS1, %r28
914	mtspr	SPR_MAS2, %r27
915	mtspr	SPR_MAS3, %r22
916	mtspr	SPR_MAS7, %r23
917
918	isync
919	tlbwe
920	isync
921	msync
922	blr
923
924/*****************************************************************************
925 * Instruction TLB miss interrupt
926 *
927 * Same notes as for the Data TLB miss
928 ****************************************************************************/
929INTERRUPT(int_inst_tlb_error)
930	TLB_PROLOG
931	TLB_LOCK
932
933	mfsrr0	%r31			/* faulting address */
934
935	/*
936	 * Save MAS0-MAS2 registers. There might be another tlb miss during pte
937	 * lookup overwriting current contents (which was hw filled).
938	 */
939	mfspr	%r29, SPR_MAS0
940	mfspr	%r28, SPR_MAS1
941	mfspr	%r27, SPR_MAS2
942
943	mfsrr1	%r21
944	mtcr	%r21
945
946	/* check MSR[PR] */
947	bt	17, search_user_pmap
948	b	search_kernel_pmap
949
950
951	.globl	interrupt_vector_top
952interrupt_vector_top:
953
954/*****************************************************************************
955 * Debug interrupt
956 ****************************************************************************/
957INTERRUPT(int_debug)
958	STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)
959	FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_DEBUG)
960	bl	int_debug_int
961	FRAME_LEAVE(SPR_CSRR0, SPR_CSRR1)
962	rfci
963
964INTERRUPT(int_debug_ed)
965	STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_DSRR0, SPR_DSRR1)
966	FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_DEBUG)
967	bl	int_debug_int
968	FRAME_LEAVE(SPR_DSRR0, SPR_DSRR1)
969	rfdi
970	/* .long 0x4c00004e */
971
972/* Internal helper for debug interrupt handling. */
973/* Common code between e500v1/v2 and e500mc-based cores. */
974int_debug_int:
975	mflr	%r14
976	GET_CPUINFO(%r3)
977	LOAD	%r3, (PC_BOOKE_CRITSAVE+CPUSAVE_SRR0)(%r3)
978	bl	0f
979	ADDR(interrupt_vector_base-.)
980	ADDR(interrupt_vector_top-.)
9810:	mflr	%r5
982	LOAD	%r4,0(%r5)	/* interrupt_vector_base in r4 */
983	add	%r4,%r4,%r5
984	CMPL	cr0, %r3, %r4
985	blt	trap_common
986	LOAD	%r4,WORD_SIZE(%r5)	/* interrupt_vector_top in r4 */
987	add	%r4,%r4,%r5
988	addi	%r4,%r4,4
989	CMPL	cr0, %r3, %r4
990	bge	trap_common
991	/* Disable single-stepping for the interrupt handlers. */
992	LOAD	%r3, FRAME_SRR1+CALLSIZE(%r1);
993	rlwinm	%r3, %r3, 0, 23, 21
994	STORE	%r3, FRAME_SRR1+CALLSIZE(%r1);
995	/* Restore srr0 and srr1 as they could have been clobbered. */
996	GET_CPUINFO(%r4)
997	LOAD	%r3, (PC_BOOKE_CRITSAVE+BOOKE_CRITSAVE_SRR0)(%r4);
998	mtspr	SPR_SRR0, %r3
999	LOAD	%r4, (PC_BOOKE_CRITSAVE+BOOKE_CRITSAVE_SRR1)(%r4);
1000	mtspr	SPR_SRR1, %r4
1001	mtlr	%r14
1002	blr
1003
1004/*****************************************************************************
1005 * Common trap code
1006 ****************************************************************************/
1007trap_common:
1008	/* Call C trap dispatcher */
1009	GET_TOCBASE(%r2)
1010	addi	%r3, %r1, CALLSIZE
1011	bl	CNAME(powerpc_interrupt)
1012	TOC_RESTORE
1013
1014	.globl	CNAME(trapexit)		/* exported for db_backtrace use */
1015CNAME(trapexit):
1016	/* disable interrupts */
1017	wrteei	0
1018
1019	/* Test AST pending - makes sense for user process only */
1020	LOAD	%r5, FRAME_SRR1+CALLSIZE(%r1)
1021	mtcr	%r5
1022	bf	17, 1f
1023
1024	GET_CPUINFO(%r3)
1025	LOAD	%r4, PC_CURTHREAD(%r3)
1026	lwz	%r4, TD_AST(%r4)
1027	cmpwi	%r4, 0
1028	beq	1f
1029
1030	/* re-enable interrupts before calling ast() */
1031	wrteei	1
1032
1033	addi	%r3, %r1, CALLSIZE
1034	bl	CNAME(ast)
1035	TOC_RESTORE
1036	.globl	CNAME(asttrapexit)	/* db_backtrace code sentinel #2 */
1037CNAME(asttrapexit):
1038	b	trapexit		/* test ast ret value ? */
10391:
1040	FRAME_LEAVE(SPR_SRR0, SPR_SRR1)
1041	rfi
1042
1043
1044#if defined(KDB)
1045/*
1046 * Deliberate entry to dbtrap
1047 */
1048	/* .globl	CNAME(breakpoint)*/
1049ASENTRY_NOPROF(breakpoint)
1050	mtsprg1	%r1
1051	mfmsr	%r3
1052	mtsrr1	%r3
1053	li	%r4, ~(PSL_EE | PSL_ME)@l
1054	oris	%r4, %r4, ~(PSL_EE | PSL_ME)@h
1055	and	%r3, %r3, %r4
1056	mtmsr	%r3			/* disable interrupts */
1057	isync
1058	GET_CPUINFO(%r3)
1059	STORE	%r30, (PC_DBSAVE+CPUSAVE_R30)(%r3)
1060	STORE	%r31, (PC_DBSAVE+CPUSAVE_R31)(%r3)
1061
1062	mflr	%r31
1063	mtsrr0	%r31
1064
1065	mfspr	%r30, SPR_DEAR
1066	mfspr	%r31, SPR_ESR
1067	STORE	%r30, (PC_DBSAVE+CPUSAVE_BOOKE_DEAR)(%r3)
1068	STORE	%r31, (PC_DBSAVE+CPUSAVE_BOOKE_ESR)(%r3)
1069
1070	mfsrr0	%r30
1071	mfsrr1	%r31
1072	STORE	%r30, (PC_DBSAVE+CPUSAVE_SRR0)(%r3)
1073	STORE	%r31, (PC_DBSAVE+CPUSAVE_SRR1)(%r3)
1074	isync
1075
1076	mfcr	%r30
1077
1078/*
1079 * Now the kdb trap catching code.
1080 */
1081dbtrap:
1082	FRAME_SETUP(SPR_SPRG1, PC_DBSAVE, EXC_DEBUG)
1083/* Call C trap code: */
1084	GET_TOCBASE(%r2)
1085	addi	%r3, %r1, CALLSIZE
1086	bl	CNAME(db_trap_glue)
1087	TOC_RESTORE
1088	or.	%r3, %r3, %r3
1089	bne	dbleave
1090/* This wasn't for KDB, so switch to real trap: */
1091	b	trap_common
1092
1093dbleave:
1094	FRAME_LEAVE(SPR_SRR0, SPR_SRR1)
1095	rfi
1096ASEND(breakpoint)
1097#endif /* KDB */
1098
1099#ifdef SMP
1100ENTRY(tlb_lock)
1101	GET_CPUINFO(%r5)
1102	LOAD	%r5, PC_CURTHREAD(%r5)
11031:	LOADX	%r4, 0, %r3
1104	CMPI	%r4, TLB_UNLOCKED
1105	bne	1b
1106	STOREX	%r5, 0, %r3
1107	bne-	1b
1108	isync
1109	msync
1110	blr
1111END(tlb_lock)
1112
1113ENTRY(tlb_unlock)
1114	isync
1115	msync
1116	li	%r4, TLB_UNLOCKED
1117	STORE	%r4, 0(%r3)
1118	isync
1119	msync
1120	blr
1121END(tlb_unlock)
1122
1123/*
1124 * TLB miss spin locks. For each CPU we have a reservation granule (32 bytes);
1125 * only a single word from this granule will actually be used as a spin lock
1126 * for mutual exclusion between TLB miss handler and pmap layer that
1127 * manipulates page table contents.
1128 */
1129	.data
1130	.align	5
1131GLOBAL(tlb0_miss_locks)
1132	.space	RES_GRANULE * MAXCPU
1133#endif
1134