xref: /netbsd-src/sys/arch/powerpc/booke/trap_subr.S (revision a4ddc2c8fb9af816efe3b1c375a5530aef0e89e9)
1/*	$NetBSD: trap_subr.S,v 1.8 2012/08/01 16:19:43 matt Exp $	*/
2/*-
3 * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Raytheon BBN Technologies Corp and Defense Advanced Research Projects
8 * Agency and which was developed by Matt Thomas of 3am Software Foundry.
9 *
10 * This material is based upon work supported by the Defense Advanced Research
11 * Projects Agency and Space and Naval Warfare Systems Center, Pacific, under
12 * Contract No. N66001-09-C-2073.
13 * Approved for Public Release, Distribution Unlimited
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 *    notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 *    notice, this list of conditions and the following disclaimer in the
22 *    documentation and/or other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37RCSID("$NetBSD: trap_subr.S,v 1.8 2012/08/01 16:19:43 matt Exp $")
38
39	.globl	_C_LABEL(sctrapexit), _C_LABEL(trapexit), _C_LABEL(intrcall)
40
41	/*
42	 * We have a problem with critical (MSR[CE] or machine check (MSR[ME])
43	 * or debug (MSR[DE]) interrupts/exception in that they could happen
44	 * inbewtween the mtsprg1 %r2 and mfsprg1 %r2.  If that happens, %r2
45	 * will be lost.  Even if we moved to a different sprg, subsequent
46	 * expceptions would use SPRG1 and its value would be lost.  The only
47	 * way to be safe for CE/ME/DE faults to save and restore SPRG1.
48	 *
49	 * Since CE/ME/DE faults may happen anytime, we need r1 to always
50	 * contain a valid kernel stack pointer.  Therefore we use r2 as
51	 * our temporary register.
52	 *
53	 * To prevent %r2 being overwritten, each "level" (normal, critical,
54	 * mchk) uses a unique sprg to save %r2 (sprg1, sprg4, sprg5).
55	 *
56	 * Since we can't control how many nested exceptions we might get,
57	 * we don't use a dedicated save area.  Instead we have a upwards
58	 * growing "stack" of them; the pointer to which is kept in sprg3.
59	 *
60	 * To allocate from the stack, one fetches sprg3, adds the amount
61	 * needed, saves sprg3, and then refers to the save using a
62	 * displacement of -amount.
63	 */
64#define	FRAME_EXC_PROLOGUE(start, sprg, srr)				\
65	mt##sprg %r2;			/* save r2 */			\
66	mfsprg3	%r2;			/* get save_area pointer */	\
67	addi	%r2,%r2,4*(32-start);					\
68					/* allocate save area */	\
69	mtsprg3	%r2;			/* save updated pointer */	\
70	stmw	%r##start,-4*(32-start)(%r2);				\
71					/* free r24-r31 for use */	\
72	mf##sprg %r26;			/* get saved r2 */		\
73	mfcr	%r27;			/* get Condition Register */	\
74	mfxer	%r28;			/* get XER */			\
75	mfspr	%r30, SPR_##srr##0;	/* get SRR0 */			\
76	mfspr	%r31, SPR_##srr##1	/* get SRR1 */
77
78#define	PROLOGUE_GET_DEAR	mfspr	%r24, SPR_DEAR
79#define	PROLOGUE_GET_ESR	mfspr	%r25, SPR_ESR
80#define	PROLOGUE_GET_SRRS	mfsrr0	%r24; \
81				mfsrr1	%r25
82#define	PROLOGUE_GET_SPRG1	mfsprg1	%r29
83#define	PROLOGUE_GET_DBSR	mfspr	%r25, SPR_DBSR
84#define	SAVE_ESR		stw	%r25, FRAME_ESR(%r1)
85#define	SAVE_DEAR		stw	%r24, FRAME_DEAR(%r1)
86#define	SAVE_DEAR_ESR		SAVE_ESR; SAVE_DEAR
87#define	SAVE_SRRS		SAVE_DEAR_ESR
88#define	SAVE_SPRG1		stw	%r29, FRAME_SPRG1(%r1)
89#define	SAVE_DBSR		stw	%r25, FRAME_DBSR(%r1)
90#define	SAVE_NOTHING		/* nothing */
91#define	RESTORE_SPRG1(r)	lwz	r, FRAME_SPRG1(%r1); \
92				mtsprg1 r
93#define	RESTORE_SRR0(r)		lwz	r, FRAME_DEAR(%r1); \
94				mtsrr0	r
95#define	RESTORE_SRR1(r)		lwz	r, FRAME_ESR(%r1); \
96				mtsrr1	r
97
98#define	FRAME_PROLOGUE		\
99	FRAME_EXC_PROLOGUE(26, sprg1, SRR)
100
101#define	FRAME_PROLOGUE_DEAR_ESR	\
102	FRAME_EXC_PROLOGUE(24, sprg1, SRR); \
103	PROLOGUE_GET_ESR; \
104	PROLOGUE_GET_DEAR
105
106#define	FRAME_PROLOGUE_ESR	\
107	FRAME_EXC_PROLOGUE(25, sprg1, SRR); \
108	PROLOGUE_GET_ESR
109
110#define	FRAME_TLBPROLOGUE	\
111	FRAME_EXC_PROLOGUE(20, sprg1, SRR); \
112	PROLOGUE_GET_ESR; \
113	PROLOGUE_GET_DEAR
114
115#define	FRAME_INTR_PROLOGUE	\
116	FRAME_EXC_PROLOGUE(26, sprg1, SRR)
117
118/*
119 * These need to save SRR0/SRR1 as well their SRR0/SRR1 in case normal
120 * exceptions happened during their execution.
121 */
122#define	FRAME_CRIT_PROLOGUE	\
123	FRAME_EXC_PROLOGUE(24, sprg4, CSRR); \
124	PROLOGUE_GET_SPRG1; \
125	PROLOGUE_GET_SRRS
126
127#define	FRAME_MCHK_PROLOGUE	\
128	FRAME_EXC_PROLOGUE(24, sprg5, MCSRR); \
129	PROLOGUE_GET_SPRG1; \
130	PROLOGUE_GET_SRRS
131
132#define	FRAME_DEBUG_PROLOGUE	\
133	FRAME_EXC_PROLOGUE(24, sprg4, CSRR); \
134	PROLOGUE_GET_SPRG1; \
135	PROLOGUE_GET_SRRS
136
137/*
138 * DDB expects to fetch the LR from the previous frame.  But it also
139 * expects to be pointing at the instruction after the branch link.  Since
140 * we didn't branch, we need to advance it by to fake out DDB.  But there's
141 * problem.  If the routine is in either its first or last two instructions
142 * (before or after its adjusted its stack pointer), we could possibly
143 * overwrite stored return address.  So that stored return address needs to
144 * saved and restored.
145 */
146#if defined(DDB)
147#define FRAME_SAVE_SRR0_FOR_DDB						\
148	lwz	%r29, FRAMELEN+CFRAME_LR(%r1);	/* fetch old return address */\
149	stw	%r29, FRAME_CFRAME_LR(%r1);	/* save it */		 \
150	addi	%r30, %r30, 4;			/* point to s the next insn */ \
151	stw	%r30, FRAMELEN+CFRAME_LR(%r1)	/* appease ddb stacktrace */
152#define FRAME_RESTORE_RETURN_ADDRESS					\
153	lwz	%r3, FRAME_CFRAME_LR(%r1);	/* fetch old return address */ \
154	stw	%r3, FRAMELEN+CFRAME_LR(%r1)	/* restore it */
155#else
156#define FRAME_SAVE_SRR0_FOR_DDB
157#define FRAME_RESTORE_RETURN_ADDRESS
158#endif
159
160#ifdef PPC_HAVE_SPE
161#define	FRAME_SAVE_SPEFSCR						\
162	mfspefscr %r0;			/* get spefscr */		\
163	stw	%r0, FRAME_SPEFSCR(%r1) /* save into trapframe */
164#define	FRAME_RESTORE_SPEFSCR						\
165	lwz	%r0, FRAME_SPEFSCR(%r1); /* fetch from trapframe */	\
166	mtspefscr %r0			/* save spefscr */
167#else
168#define	FRAME_SAVE_SPEFSCR
169#define	FRAME_RESTORE_SPEFSCR
170#endif
171/*
172 * Before the first memory refernence, we must have our state inside registers
173 * since the first memory access might cause an exception which would cause
174 * SRR0/SRR1 and DEAR/ESR to become unrecoverable.  CR and XER also need to be
175 * saved early since they will modified by instrction flow.  The saved stack
176 * pointer is also critical but LR and CTR can be deferred being saved until
177 * we are actually filling a trapframe.
178 */
179#define	FRAME_EXC_ENTER(exc, tf, start, save_prologue)			\
180	mtcr	%r31;			/* user mode exception? */	\
181	mr	%r31, %r1;		/* save SP (SRR1 is safe in CR) */ \
182	bf	MSR_PR, 1f;		/*   nope, sp is good */	\
183	mfsprg2	%r2;			/* get curlwp */		\
184	lwz	%r2, L_PCB(%r2);	/* get uarea of curlwp */	\
185	addi	%r1, %r2, USPACE-CALLFRAMELEN;				\
186					/* start stack at top of it */	\
1871:									\
188	stwu	%r31, -FRAMELEN(%r1);	/* get space for trapframe */	\
189	stw	%r0, FRAME_R0(%r1);	/* save r0 */			\
190	stw	%r31, FRAME_R1(%r1);	/* save (saved) r1 */		\
191	stw	%r26, FRAME_R2(%r1);	/* save (saved) r2 */		\
192	save_prologue;			/* save SPRG1/ESR/DEAR */	\
193	/* At this point, r26, r29, and r31 have been saved so we */	\
194	/* can use them for LR, CTR, and SRR1.			  */	\
195	mflr	%r26;			/* get Link Register */		\
196	mfctr	%r29;			/* get CTR */			\
197	mfcr	%r31;			/* get SRR1 */			\
198	stmw	%r26, FRAME_LR(%r1);	/* save LR CR XER CTR SRR0/1 */	\
199	FRAME_SAVE_SRR0_FOR_DDB;					\
200	mr	%r0, %r31;		/* save SRR1 for a bit */	\
201	mfsprg3	%r2;			/* get save_area pointer */	\
202	addi	%r2,%r2,-4*(32-start);	/* find our save area */	\
203	lmw	%r##start,0(%r2);	/* get start-r31 */		\
204	mtsprg3	%r2;			/* save updated pointer */	\
205	stmw	%r3, FRAME_R3(%r1);	/* save r2-r31 */		\
206	/* Now everything has been saved */				\
207	mr	%r31, %r0;		/* move SRR1 back to r31 */	\
208	mfsprg2	%r13;			/* put curlwp in r13 */		\
209	FRAME_SAVE_SPEFSCR;						\
210	li	%r7, exc;		/* load EXC_* */		\
211	stw	%r7, FRAME_EXC(%r1);	/* save into trapframe */	\
212	addi	tf, %r1, FRAME_TF	/* get address of trap frame */
213
214#define FRAME_EXC_EXIT(rfi, srr)					\
215	FRAME_RESTORE_RETURN_ADDRESS;	/* restore return address */	\
216	lmw	%r26, FRAME_LR(%r1);	/* get LR CR XER CTR SRR0/1 */	\
217	oris	%r31,%r31,PSL_CE@h;					\
218	mtspr	SPR_##srr##1, %r31;	/* restore SRR1 */		\
219	mtspr	SPR_##srr##0, %r30;	/* restore SRR0 */		\
220	FRAME_RESTORE_SPEFSCR;						\
221	mtctr	%r29;			/* restore CTR */		\
222	mtxer	%r28;			/* restore XER */		\
223	mtcr	%r27;			/* restore CR */		\
224	mtlr	%r26;			/* restore LR */		\
225	lmw	%r2, FRAME_R2(%r1);	/* restore r2-r31 */		\
226	lwz	%r0, FRAME_R0(%r1);	/* restore r0 */		\
227	lwz	%r1, FRAME_R1(%r1);	/* restore r1 */		\
228	rfi				/* return from interrupt */
229
230
231#define	FRAME_ENTER(exc, tf)		\
232	FRAME_EXC_ENTER(exc, tf, 26, SAVE_NOTHING)
233
234#define	FRAME_ENTER_ESR(exc, tf)	\
235	FRAME_EXC_ENTER(exc, tf, 25, SAVE_ESR)
236
237#define	FRAME_ENTER_DEAR_ESR(exc, tf)	\
238	FRAME_EXC_ENTER(exc, tf, 24, SAVE_DEAR_ESR)
239
240#define	FRAME_EXIT		FRAME_EXC_EXIT(rfi, SRR)
241
242#define	FRAME_TLBENTER(exc)	\
243	FRAME_EXC_ENTER(exc, %r4, 20, SAVE_DEAR_ESR)
244#define	FRAME_TLBEXIT		FRAME_EXC_EXIT(rfi, SRR)
245
246#define	FRAME_MCHK_ENTER(exc)	\
247	FRAME_EXC_ENTER(exc, %r3, 26, SAVE_SPRG1; SAVE_SRRS)
248#define	FRAME_MCHK_EXIT		\
249	RESTORE_SRR0(%r28);	\
250	RESTORE_SRR1(%r27);	\
251	RESTORE_SPRG1(%r26);	\
252	FRAME_EXC_EXIT(rfmci, MCSRR)
253
254#define	FRAME_DEBUG_ENTER(exc)	\
255	FRAME_EXC_ENTER(exc, %r4, 26, SAVE_SPRG1; SAVE_SRRS)
256#define	FRAME_DEBUG_EXIT	\
257	RESTORE_SPRG1(%r26); FRAME_EXC_EXIT(rfci, CSRR)
258
259#define	FRAME_INTR_SP							\
260	bf	MSR_PR, 1f;		/*    nope, sp is good */	\
261	mfsprg2	%r2;			/* get curlwp */		\
262	lwz	%r2, L_PCB(%r2);	/* get uarea of curlwp */	\
263	addi	%r1, %r2, USPACE-CALLFRAMELEN;				\
264					/* start stack at top of it */	\
2651:
266
267#define	FRAME_INTR_SP_NEW(sym)						\
268	lis	%r2,(sym)@ha;						\
269	addi	%r1,%r2,(sym)@l
270
271#define	FRAME_INTR_XENTER(exc, start, get_intr_sp, save_prologue)	\
272	mtcr	%r31;			/* user mode exception? */	\
273	mr	%r31, %r1;		/* save SP (SRR1 is safe in CR) */ \
274	get_intr_sp;			/* get kernel stack pointer */	\
275	stwu	%r31, -FRAMELEN(%r1);	/* get space for trapframe */	\
276	stw	%r0, FRAME_R0(%r1);	/* save r0 */			\
277	stw	%r31, FRAME_R1(%r1);	/* save (saved) r1 */		\
278	stw	%r26, FRAME_R2(%r1);	/* save (saved) r2 */		\
279	save_prologue;			/* save SPRG1 (maybe) */	\
280	mflr	%r26;			/* get LR */			\
281	mfctr	%r29;			/* get CTR */			\
282	mfcr	%r31;			/* get SRR1 */			\
283	stmw	%r26, FRAME_LR(%r1);	/* save LR CR XER CTR SRR0/1 */	\
284	FRAME_SAVE_SRR0_FOR_DDB;					\
285	stw	%r3, FRAME_R3(%r1);	/* save r3 */			\
286	stw	%r4, FRAME_R4(%r1);	/* save r4 */			\
287	stw	%r5, FRAME_R5(%r1);	/* save r5 */			\
288	stw	%r6, FRAME_R6(%r1);	/* save r6 */			\
289	stw	%r7, FRAME_R7(%r1);	/* save r7 */			\
290	stw	%r8, FRAME_R8(%r1);	/* save r8 */			\
291	stw	%r9, FRAME_R9(%r1);	/* save r9 */			\
292	stw	%r10, FRAME_R10(%r1);	/* save r10 */			\
293	stw	%r11, FRAME_R11(%r1);	/* save r11 */			\
294	stw	%r12, FRAME_R12(%r1);	/* save r12 */			\
295	stw	%r13, FRAME_R13(%r1);	/* save r13 */			\
296	mfsprg3	%r2;			/* get save_area pointer */	\
297	addi	%r2,%r2,-4*(32-start);	/* find our save area */	\
298	lmw	%r##start,0(%r2);	/* get start-r31 */		\
299	mtsprg3	%r2;			/* save updated pointer */	\
300	mfsprg2	%r13;			/* put curlwp into r13 */	\
301	li	%r7, exc;		/* load EXC_* */		\
302	stw	%r7, FRAME_EXC(%r1);	/* save into trapframe */	\
303	addi	%r3, %r1, FRAME_TF	/* only argument is trapframe */
304
305#define FRAME_INTR_XEXIT(rfi, srr)					\
306	FRAME_RESTORE_RETURN_ADDRESS;	/* restore return address */	\
307	lwz	%r8, FRAME_LR(%r1);	/* get LR */			\
308	lwz	%r9, FRAME_CR(%r1);	/* get CR */			\
309	lwz	%r10, FRAME_XER(%r1);	/* get XER */			\
310	lwz	%r11, FRAME_CTR(%r1);	/* get CTR */			\
311	lwz	%r12, FRAME_SRR0(%r1);	/* get SRR0 */			\
312	lwz	%r13, FRAME_SRR1(%r1);	/* get SRR1 */			\
313	mtspr	SPR_##srr##1, %r13;	/* restore SRR1 */		\
314	mtspr	SPR_##srr##0, %r12;	/* restore SRR0 */		\
315	mtctr	%r11;			/* restore CTR */		\
316	mtxer	%r10;			/* restore XER */		\
317	mtcr	%r9;			/* restore CR */		\
318	mtlr	%r8;			/* restore LR */		\
319	lwz	%r13, FRAME_R13(%r1);	/* restore r13 */		\
320	lwz	%r12, FRAME_R12(%r1);	/* restore r12 */		\
321	lwz	%r11, FRAME_R11(%r1);	/* restore r11 */		\
322	lwz	%r10, FRAME_R10(%r1);	/* restore r10 */		\
323	lwz	%r9, FRAME_R9(%r1);	/* restore r9 */		\
324	lwz	%r8, FRAME_R8(%r1);	/* restore r8 */		\
325	lwz	%r7, FRAME_R7(%r1);	/* restore r7 */		\
326	lwz	%r6, FRAME_R6(%r1);	/* restore r6 */		\
327	lwz	%r5, FRAME_R5(%r1);	/* restore r5 */		\
328	lwz	%r4, FRAME_R4(%r1);	/* restore r4 */		\
329	lwz	%r3, FRAME_R3(%r1);	/* restore r3 */		\
330	lwz	%r2, FRAME_R2(%r1);	/* restore r2 */		\
331	lwz	%r0, FRAME_R0(%r1);	/* restore r0 */		\
332	lwz	%r1, FRAME_R1(%r1);	/* restore r1 */		\
333	rfi				/* return from interrupt */
334
335#define	FRAME_INTR_ENTER(exc)	\
336	FRAME_INTR_XENTER(exc, 26, FRAME_INTR_SP, SAVE_NOTHING)
337#define	FRAME_INTR_EXIT		\
338	FRAME_INTR_XEXIT(rfi, SRR)
339#define	FRAME_CRIT_ENTER(exc)	\
340	FRAME_INTR_XENTER(exc, 24, FRAME_INTR_SP, SAVE_SPRG1)
341#define	FRAME_WDOG_ENTER(exc, sym)	\
342	FRAME_INTR_XENTER(exc, 24, FRAME_INTR_SP_NEW(sym), SAVE_SPRG1)
343#define	FRAME_CRIT_EXIT		\
344	RESTORE_SRR0(%r4);	\
345	RESTORE_SRR1(%r5);	\
346	RESTORE_SPRG1(%r6);	\
347	FRAME_INTR_XEXIT(rfci, CSRR)
348
349	.text
350	.p2align 4
351_C_LABEL(critical_input_vector):
352	/* MSR[ME] is unchanged, all others cleared */
353	FRAME_CRIT_PROLOGUE			/* save SP r26-31 CR LR XER */
354	FRAME_CRIT_ENTER(EXC_CII)
355	bl	_C_LABEL(intr_critintr)		/* critintr(tf) */
356	FRAME_CRIT_EXIT
357
358	.p2align 4
359_C_LABEL(machine_check_vector):
360	/* all MSR bits are cleared */
361	FRAME_MCHK_PROLOGUE			/* save SP r25-31 CR LR XER */
362	FRAME_MCHK_ENTER(EXC_MCHK)
363	/*
364	 * MCAR/MCSR don't need to be saved early since MSR[ME] is cleared
365	 * on entry.
366	 */
367	mfspr	%r7, SPR_MCAR
368	mfspr	%r6, SPR_MCSR
369	stw	%r6, FRAME_MCSR(%r1)
370	stw	%r7, FRAME_MCAR(%r1)
371	li	%r3, T_MACHINE_CHECK
372	bl	_C_LABEL(trap)			/* trap(T_MACHINE_CHECK, tf) */
373	FRAME_MCHK_EXIT
374
375	.p2align 4
376_C_LABEL(data_storage_vector):
377	/* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */
378	FRAME_PROLOGUE_DEAR_ESR		/* save r2 DEAR ESR r24-31 CR XER SRR */
379	FRAME_ENTER_DEAR_ESR(EXC_DSI, %r4)
380	li	%r3, T_DSI
381	/* FRAME_ENTER leaves SRR1 in %r31 */
382trapenter:
383trapagain:
384	wrtee	%r31				/* restore MSR[EE] */
385
386	bl	_C_LABEL(trap)			/* trap(trapcode, tf) */
387_C_LABEL(trapexit):
388	wrteei	0				/* disable interrupts */
389#	andis.	%r0, %r31, PSL_CE@h
390#	tweqi	%r0, 0
391	andi.	%r4, %r31, PSL_PR		/* lets look at PSL_PR */
392	beq	trapdone			/* if clear, skip to exit  */
393	lwz	%r4, L_MD_ASTPENDING(%r13)	/* get ast pending */
394	cmplwi	%r4, 0				/* is there an ast pending */
395	beq+	trapdone			/*    nope, proceed to exit */
396	li	%r6, EXC_AST			/* yes. */
397	stw	%r6, FRAME_EXC(%r1)		/* pretend this is an AST */
398	addi	%r4, %r1, FRAME_TF		/* get address of trap frame */
399	li	%r3, T_AST
400	b	trapagain			/* and deal with it */
401trapdone:
402	FRAME_EXIT
403
404	.p2align 4
405_C_LABEL(instruction_storage_vector):
406	/* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */
407	FRAME_PROLOGUE_ESR		/* save ESR r2 r25-31 CR XER SRR0/1 */
408	FRAME_ENTER_ESR(EXC_ISI, %r4)
409	li	%r3, T_ISI
410	b	trapenter
411
412	.p2align 4
413_ENTRY(external_input_vector)
414	/* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */
415	FRAME_INTR_PROLOGUE			/* save SP r25-31 CR LR XER */
416	FRAME_INTR_ENTER(EXC_EXI)
417
418	bl	_C_LABEL(intr_extintr)
419_C_LABEL(intrcall):
420	GET_CPUINFO(%r6)			/* get curcpu() */
421	lwz	%r5, FRAME_SRR1(%r1)		/* get saved SRR1 */
422#	andis.	%r0, %r5, PSL_CE@h
423#	tweqi	%r0, 0
424	andi.	%r4, %r5, PSL_PR		/* lets look at PSL_PR */
425	beq	intrexit			/* if clear, skip to exit  */
426	lwz	%r4, L_MD_ASTPENDING(%r13)	/* get ast pending */
427	cmplwi	%r4, 0				/* is there an ast pending */
428	beq+	intrexit			/*    nope, proceed to exit */
429	stmw	%r14, FRAME_R14(%r1)		/* save rest of registers */
430	FRAME_SAVE_SPEFSCR
431	mr	%r31, %r5			/* needed for trapagain */
432	li	%r4, EXC_AST			/* */
433	stw	%r4, FRAME_EXC(%r1)		/* pretend this is an AST */
434	addi	%r4, %r1, FRAME_TF		/* get address of trap frame */
435	li	%r3, T_AST
436	b	trapagain			/* and deal with it */
437intrexit:
438	FRAME_INTR_EXIT
439
440	.p2align 4
441_C_LABEL(alignment_vector):
442	/* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */
443	FRAME_PROLOGUE_DEAR_ESR			/* save SP r25-31 CR LR XER */
444	FRAME_ENTER_DEAR_ESR(EXC_ALI, %r4)
445	li	%r3, T_ALIGNMENT
446	b	trapenter
447
448	.p2align 4
449_C_LABEL(program_vector):
450	/* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */
451	FRAME_PROLOGUE_ESR			/* save SP r25-31 CR LR XER */
452	FRAME_ENTER_ESR(EXC_PGM, %r4)
453	li	%r3, T_PROGRAM
454	b	trapenter
455
456#ifdef SPR_IVOR7
457	.p2align 4
458_C_LABEL(fp_unavailable_vector):
459	/* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */
460	FRAME_PROLOGUE_ESR			/* save SP r25-31 CR LR XER */
461	FRAME_ENTER_ESR(EXC_FPU, %r4)
462	li	%r3, T_FP_UNAVAILABLE
463	b	trapenter
464#endif
465
466	.p2align 4
467_C_LABEL(system_call_vector):
468	/* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */
469	FRAME_PROLOGUE				/* save SP r26-31 CR LR XER */
470	FRAME_ENTER(EXC_SC, %r3)
471
472	wrteei	1				/* enable interrupts */
473	lwz	%r7, L_PROC(%r13)		/* get proc for lwp */
474	lwz	%r8, P_MD_SYSCALL(%r7)		/* get syscall */
475	mtlr	%r8				/* need to call indirect */
476	blrl					/* syscall(tf) */
477_C_LABEL(sctrapexit):
478	wrteei	0				/* disable interrupts */
479	lwz	%r4, L_MD_ASTPENDING(%r13)	/* get ast pending */
480	cmplwi	%r4, 0				/* is there an ast pending */
481	beq+	trapdone			/*    nope, proceed to exit */
482	li	%r0, EXC_AST			/* yes. */
483	stw	%r0, FRAME_EXC(%r1)		/* pretend this is an AST */
484	addi	%r4, %r1, FRAME_TF		/* get address of trap frame */
485	li	%r3, T_AST
486	b	trapenter			/* and deal with it */
487
488#ifdef SPR_IVOR9
489	.p2align 4
490_C_LABEL(ap_unavailable_vector):
491	/* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */
492	FRAME_PROLOGUE				/* save SP r25-31 CR LR XER */
493	FRAME_ENTER(EXC_PGM, %r4)
494	li	%r3, T_AP_UNAVAILABLE
495	b	trapenter
496#endif
497
498	.p2align 4
499_C_LABEL(decrementer_vector):
500	/* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */
501	FRAME_INTR_PROLOGUE			/* save SP r25-31 CR LR XER */
502	FRAME_INTR_ENTER(EXC_DECR)
503
504	bl	_C_LABEL(intr_decrintr)
505	b	intrexit
506
507	.p2align 4
508_C_LABEL(fixed_interval_timer_vector):
509	/* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */
510	FRAME_PROLOGUE				/* save SP r25-31 CR LR XER */
511	FRAME_INTR_ENTER(EXC_FIT)
512
513	bl	_C_LABEL(intr_fitintr)
514	b	intrexit
515
516#ifdef E500_WDOG_STACK
517	.data
518	.lcomm wdogstk,4096
519#endif
520	.text
521	.p2align 4
522_C_LABEL(watchdog_timer_vector):
523	/* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */
524	FRAME_CRIT_PROLOGUE			/* save SP r25-31 CR LR XER */
525#ifdef E500_WDOG_STACK
526	FRAME_WDOG_ENTER(EXC_WDOG, wdogstk+4096-CALLFRAMELEN)
527#else
528	FRAME_CRIT_ENTER(EXC_WDOG);
529#endif
530
531	bl	_C_LABEL(intr_wdogintr)
532	FRAME_CRIT_EXIT
533
534	.p2align 4
535_C_LABEL(data_tlb_error_vector):
536	/* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */
537	FRAME_TLBPROLOGUE
538	/*
539	 * Registers as this point:
540	 *
541	 * r2  = cpu_info
542	 * r20 = scratch
543	 * r21 = scratch
544	 * r22 = scratch
545	 * r23 = scratch
546	 * r24 = DEAR
547	 * r25 = ESR
548	 * r26 = saved r2
549	 * r27 = CR
550	 * r28 = XER
551	 * r29 = scratch
552	 * r30 = SRR0
553	 * r31 = SRR1
554	 *
555	 * Except for r29, these values must be retained.  However we must
556	 * be cognizant of nesting.  There are two cases here, both related.
557	 *
558	 * We get a critical input or machine check exception and the kernel
559	 * stack doesn't have a TLB entry so we take an exception.  The other
560	 * nesting path is some page used by the exception handler will cause
561	 * a TLB data error.
562	 *
563	 * The second case (more probable) is that the PTE loading will fail
564	 * so we will have to do a hard trap to resolve it.  But in doing so
565	 * we need to save a trapframe which could result in another DTLB
566	 * fault.
567	 *
568	 * In all cases, the save area stack shall protect us.
569	 */
570	/*
571	 * Attempt to update the TLB from the page table.
572	 */
573	mflr	%r29				/* save LR */
574	mr	%r23, %r24			/* address of exception */
575	rlwinm	%r22, %r31,			/* index into ci_pmap_segtab */\
576		MSR_DS+PTR_SCALESHIFT+1, \
577		31-PTR_SCALESHIFT, \
578		31-PTR_SCALESHIFT		/* move PSL_DS[27] to bit 29 */
579	bl	pte_load
580	mtlr	%r29				/* restore LR */
581	/*
582	 * If we returned, pte load failed so let trap deal with it but
583	 * has kept the contents of r24-r31 (expect r29) intact.
584	 */
585	FRAME_TLBENTER(EXC_DSI)
586	li	%r3, T_DATA_TLB_ERROR
587	b	trapenter
588
589	.p2align 4
590_C_LABEL(instruction_tlb_error_vector):
591	/* MSR[CE], MSR[ME], MSR[DE] are unchanged, all others cleared */
592	FRAME_TLBPROLOGUE
593	/*
594	 * Attempt to update the TLB from the page table.
595	 */
596	mflr	%r29				/* save LR */
597	mr	%r23, %r30			/* PC of exception */
598	rlwinm	%r22, %r31,			/* index into ci_pmap_segtab */\
599		MSR_IS+PTR_SCALESHIFT+1, \
600		31-PTR_SCALESHIFT, \
601		31-PTR_SCALESHIFT		/* move PSL_IS[26] to bit 29 */
602	bl	pte_load
603	mtlr	%r29				/* restore LR */
604	/*
605	 * If we returned, pte load failed so let trap deal with it but
606	 * has kept the contents of r24-r31 (expect r29) intact.
607	 */
608	FRAME_TLBENTER(EXC_ISI)
609	li	%r3, T_INSTRUCTION_TLB_ERROR
610	b	trapenter
611
612	.p2align 4
613_C_LABEL(debug_vector):
614	FRAME_CRIT_PROLOGUE			/* save SP r25-31 CR LR XER */
615	FRAME_CRIT_ENTER(EXC_DEBUG)
616	mfspr	%r6, SPR_DBSR
617	stw	%r6, FRAME_ESR(%r1)
618	li	%r3, T_DEBUG
619	bl	_C_LABEL(trap)
620	FRAME_CRIT_EXIT
621
622	.p2align 4
623_C_LABEL(spv_unavailable_vector):
624	FRAME_PROLOGUE_ESR			/* save SP r25-31 CR LR XER */
625	FRAME_ENTER_ESR(EXC_VEC, %r4)
626	li	%r3, T_SPE_UNAVAILABLE
627	b	trapenter
628
629	.p2align 4
630_C_LABEL(fpdata_vector):
631	FRAME_PROLOGUE_ESR			/* save SP r25-31 CR LR XER */
632	FRAME_ENTER_ESR(EXC_FPA, %r4)
633	li	%r3, T_EMBEDDED_FP_DATA
634	b	trapenter
635
636	.p2align 4
637_C_LABEL(fpround_vector):
638	FRAME_PROLOGUE_ESR			/* save SP r25-31 CR LR XER */
639	FRAME_ENTER_ESR(EXC_FPA, %r4)
640	li	%r3, T_EMBEDDED_FP_ROUND
641	b	trapenter
642
643	.p2align 4
644_C_LABEL(perfmon_vector):
645	FRAME_PROLOGUE_ESR			/* save SP r25-31 CR LR XER */
646	FRAME_ENTER_ESR(EXC_PERF, %r4)
647	li	%r3, T_EMBEDDED_PERF_MONITOR
648	b	trapenter
649
650	.p2align 4
651pte_load:
652	/*
653	 * r2 = scratch
654	 * r20 = scratch
655	 * r21 = scratch
656	 * r22 = index into ci_pmap_{kern,user}_segtab
657	 * r23 = faulting address
658	 * The rest are for reference and aren't modifiable.  If the load
659	 * fails, they will be used by FRAME_TLBENTER to create the trapframe.
660	 * r24 = DEAR
661	 * r25 = ESR
662	 * r26 = saved r2
663	 * r27 = CR
664	 * r28 = XER
665	 * r29 = LR
666	 * r30 = SRR0
667	 * r31 = SRR1
668	 */
669	cmplwi	%cr2, %r22, 0		/* remember address space */
670	GET_CPUINFO(%r2)
671	addi	%r22, %r22, CI_PMAP_SEGTAB /* index into segtab(s) */
672	lwzx	%r20, %r22, %r2		/* load kern/user L1 PT addr */
673	cmplwi	%r20, 0			/* is segtab null? */
674	beqlr	%cr0			/* yes, return to fallback to trap */
675
676	rlwinm	%r22, %r23, NSEGPG_SCALESHIFT + PTR_SCALESHIFT, \
677		31-(NSEGPG_SCALESHIFT + PTR_SCALESHIFT - 1), \
678		31-PTR_SCALESHIFT	/* extract addr bits [0:9] to [20:29] */
679	lwzx	%r20, %r22, %r20	/* load address of page table page */
680	cmplwi	%r20, 0			/* is page null? */
681	beqlr	%cr0			/* yes, return to fallback to trap */
682
683	rlwinm	%r22, %r23, \
684		NSEGPG_SCALESHIFT + NPTEPG_SCALESHIFT + PTE_SCALESHIFT, \
685		31-(NPTEPG_SCALESHIFT + PTE_SCALESHIFT - 1), \
686		31-PTE_SCALESHIFT	/* extract addr bits [10:19] to [20:29] */
687	lwzx	%r20, %r22, %r20	/* load PTE from page table page */
688	cmplwi	%r20, 0			/* is there a valid PTE? */
689	beqlr	%cr0			/* no, return to fallback to trap */
690
691#if (PTE_UNSYNCED << 1) != PTE_xX
692#error PTE_UNSYNCED definition error
693#endif
694#if (PTE_UNMODIFIED << 1) != PTE_xW
695#error PTE_UNMODIFIED definition error
696#endif
697	andi.	%r22, %r20, (PTE_UNSYNCED|PTE_UNMODIFIED)
698					/* Does the PTE need to be changed? */
699	rotlwi	%r22, %r22, 1		/* if so, clear the right PTE bits */
700	andc	%r20, %r20, %r22	/* pte &= ~((pte & (PTE_UNSYNCED|PTE_UNMODIFIED)) << 1)*/
701
702	/*
703	 * r24-r32 = (no touch)
704	 * r23 = scratch (was fault addr)
705	 * r22 = scratch
706	 * r21 = scratch
707	 * r20 = pte
708	 * cr2 = AS 0=eq/!0=ne
709	 */
710
711	/*
712	 * This is all E500 specific.  We should have a patchable branch
713	 * to support other BookE (440) implementations.
714	 */
715e500_pte_load:
716	bne+	%cr2, 1f		/* user access? MAS1 is ok. */
717	mfspr	%r22, SPR_MAS1		/* get MAS1 */
718	lis	%r21, MAS1_TID@h	/* get TID mask */
719	andc	%r22, %r22, %r21	/* clear TID */
720	mtspr	SPR_MAS1, %r22		/* save MAS1 */
7211:
722	andi.	%r21, %r20, PTE_WIMGE_MASK /* extract WIMGE from PTE */
723	cmplwi	%r21, PTE_M		/* if just PTE_M is set, */
724	beq+	%cr0, 2f		/*    skip munging mas2 */
725	mfspr	%r22, SPR_MAS2		/* get MAS2 (updated by error) */
726	clrrwi	%r22, %r22, PTE_RWX_SHIFT /* clear WIMGE bits */
727	or	%r22, %r22, %r21	/* combine with MAS2 contents */
728	mtspr	SPR_MAS2, %r22 		/* put back into MAS2 */
7292:
730	/*
731	 * r23 = fault addr
732	 * r22 = scratch
733	 * r21 = scratch
734	 * r20 = pte
735	 */
736
737	/*
738	 * In MAS3, the protection bits are in the low 6 bits:
739	 *    UX SX UW SW UR SR
740	 * The User bits are 1 bit left of their Supervisor counterparts.
741	 * Rotate the PTE protection bits left until they wrap around to become
742	 * the least significant bits, where the Supervisor protection bits
743	 * are located.  Increase the rotate amount by 1 to place them where
744	 * the User protection bits are located.  We get that 1 by extracting
745	 * the MAS1[TS] (set for User access) and moving it to bit 31 (LSB).
746	 */
747	mfspr	%r21, SPR_MAS1		/* get MAS1 which has TS bit */
748	extrwi	%r21, %r21, 1, 31-MAS1_TS_SHIFT
749					/* extract MAS1_TS to LSB */
750	clrrwi	%r23, %r20, PAGE_SHIFT	/* clear non-RPN bits from PTE */
751	andi.	%r20, %r20, PTE_RWX_MASK /* isolate protection bits */
752	rotrwi	%r20, %r20, PTE_RWX_SHIFT
753	andi.	%r22, %r20, (MAS3_SW|MAS3_SR) /* user pages need to be R/W by kernel */
754	rotlw	%r20, %r20, %r21	/* rotate protection to correct loc */
755	or	%r20, %r20, %r22	/* combine system protection bits */
756	or	%r23, %r23, %r20	/* combine RPN and protection bits */
757	mtspr	SPR_MAS3, %r23		/* put into MAS3 */
758	isync				/* because ECORE500RM tells us too */
759	tlbwe				/* write the TLB entry */
760	/*
761	 * Increment a counter to show how many tlb misses we've handled here.
762	 */
763	lmw	%r30, CI_EV_TLBMISS_SOFT(%r2)
764	addic	%r31, %r31, 1
765	addze	%r30, %r30
766	stmw	%r30, CI_EV_TLBMISS_SOFT(%r2)
767	/*
768	 * Cleanup and leave.  We know any higher priority exception will
769	 * save and restore SPRG1 and %r2 thereby preserving their values.
770	 *
771	 * r24 = DEAR (don't care)
772	 * r25 = ESR (don't care)
773	 * r26 = saved r2
774	 * r27 = CR
775	 * r28 = XER
776	 * r29 = LR
777	 * r30 = LSW of counter
778	 * r31 = MSW of counter
779	 */
780	mtlr	%r29			/* restore Link Register */
781	mtxer	%r28			/* restore XER */
782	mtcr	%r27			/* restore Condition Register */
783	mtsprg1 %r26			/* save saved r2 across load multiple */
784	mfsprg3 %r2			/* get end of save area */
785	addi	%r2,%r2,-4*(32-20)	/* adjust save area down */
786	lmw	%r20,0(%r2)		/* restore r20-r31 */
787	mtsprg3 %r2			/* save new end of save area */
788	mfsprg1	%r2			/* restore r2 */
789	rfi
790
791	.p2align 4
792	.globl _C_LABEL(exception_init)
793_C_LABEL(exception_init):
794	lis	%r6,_C_LABEL(critical_input_vector)@h
795	mtspr	SPR_IVPR, %r6
796
797	ori	%r5,%r6,_C_LABEL(critical_input_vector)@l
798	mtspr	SPR_IVOR0, %r5
799
800	ori	%r5,%r6,_C_LABEL(machine_check_vector)@l
801	mtspr	SPR_IVOR1, %r5
802
803	ori	%r5,%r6,_C_LABEL(data_storage_vector)@l
804	mtspr	SPR_IVOR2, %r5
805
806	ori	%r5,%r6,_C_LABEL(instruction_storage_vector)@l
807	mtspr	SPR_IVOR3, %r5
808
809	ori	%r5,%r6,_C_LABEL(external_input_vector)@l
810	mtspr	SPR_IVOR4, %r5
811
812	ori	%r5,%r6,_C_LABEL(alignment_vector)@l
813	mtspr	SPR_IVOR5, %r5
814
815	ori	%r5,%r6,_C_LABEL(program_vector)@l
816	mtspr	SPR_IVOR6, %r5
817
818#ifdef SPR_IVOR7
819	ori	%r5,%r6,_C_LABEL(fp_unavailable_vector)@l
820	mtspr	SPR_IVOR7, %r5
821#endif
822
823	ori	%r5,%r6,_C_LABEL(system_call_vector)@l
824	mtspr	SPR_IVOR8, %r5
825
826#ifdef SPR_IVOR9
827	ori	%r5,%r6,_C_LABEL(ap_unavailable_vector)@l
828	mtspr	SPR_IVOR9, %r5
829#endif
830
831	ori	%r5,%r6,_C_LABEL(decrementer_vector)@l
832	mtspr	SPR_IVOR10, %r5
833
834	ori	%r5,%r6,_C_LABEL(fixed_interval_timer_vector)@l
835	mtspr	SPR_IVOR11, %r5
836
837	ori	%r5,%r6,_C_LABEL(watchdog_timer_vector)@l
838	mtspr	SPR_IVOR12, %r5
839
840	ori	%r5,%r6,_C_LABEL(data_tlb_error_vector)@l
841	mtspr	SPR_IVOR13, %r5
842
843	ori	%r5,%r6,_C_LABEL(instruction_tlb_error_vector)@l
844	mtspr	SPR_IVOR14, %r5
845
846	ori	%r5,%r6,_C_LABEL(debug_vector)@l
847	mtspr	SPR_IVOR15, %r5
848
849	ori	%r5,%r6,_C_LABEL(spv_unavailable_vector)@l
850	mtspr	SPR_IVOR32, %r5
851
852	ori	%r5,%r6,_C_LABEL(fpdata_vector)@l
853	mtspr	SPR_IVOR33, %r5
854
855	ori	%r5,%r6,_C_LABEL(fpround_vector)@l
856	mtspr	SPR_IVOR34, %r5
857
858	ori	%r5,%r6,_C_LABEL(perfmon_vector)@l
859	mtspr	SPR_IVOR35, %r5
860
861	mfpir	%r5		/* get Process ID register */
862	cmplwi	%r5,0
863	bnelr			/* return if non-0 (non-primary) */
864
865	lis	%r5,_C_LABEL(powerpc_intrsw)@ha
866	stw	%r3,_C_LABEL(powerpc_intrsw)@l(%r5)
867
868	blr
869
870#ifdef notyet
871	.data
872	.lcomm	ddbstk,4096
873	.text
874
875_ENTRY(cpu_Debugger)
876	mflr	%r0
877	stw	%r0, CFRAME_LR(%r1)
878
879	mfmsr	%r3
880	wrteei	0
881	mr	%r4,%r1
882	lis	%r10,ddbstk@ha
883	addi	%r10,%r10,ddbstk@l
884	sub	%r5,%r1,%r10
885	cmplwi	%r5,4096
886	blt	%cr0, 1f
887	addi	%r1,%r10,4096-CALLFRAMELEN
8881:
889	stwu	%r4,-FRAMELEN(%r1)
890	stw	%r4,FRAME_R1(%r1)
891	stmw	%r13,FRAME_R13(%r1)
892	mr	%r26,%r0
893	mfcr	%r27
894	mfxer	%r28
895	mfctr	%r29
896	mr	%r30,%r0
897	mr	%r31,%r3
898	stmw	%r26,FRAME_LR(%r1)
899	mr	%r31,%r1
900	mr	%r1,%r10
901	addi	%r4,%r1,FRAME_TF
902	li	%r3,EXC_PGM
903	stw	%r3,FRAME_EXC(%r1)
904	li	%r3,T_PROGRAM
905	bl	_C_LABEL(trap)
906	lmw	%r26,FRAME_LR(%r1)
907	mtlr	%r26
908	mtcr	%r27
909	mtxer	%r28
910	mtctr	%r29
911	mr	%r0,%r31
912	lmw	%r13,FRAME_R13(%r1)
913	lwz	%r1,FRAME_R1(%r1)
914	wrtee	%r0
915	blr
916#endif /* notyet */
917