trap_subr.S revision 1.8 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
37 RCSID("$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 */ \
187 1: \
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 */ \
265 1:
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 */
382 trapenter:
383 trapagain:
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 */
401 trapdone:
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 */
437 intrexit:
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
651 pte_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 */
715 e500_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 */
721 1:
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 */
729 2:
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
888 1:
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