1 #ifndef __HEAD_BOOKE_H__
2 #define __HEAD_BOOKE_H__
4 #include <asm/ptrace.h> /* for STACK_FRAME_REGS_MARKER */
6 * Macros used for common Book-e exception handling
9 #define SET_IVOR(vector_number, vector_label) \
10 li r26,vector_label@l; \
11 mtspr SPRN_IVOR##vector_number,r26; \
14 #if (THREAD_SHIFT < 15)
15 #define ALLOC_STACK_FRAME(reg, val) \
18 #define ALLOC_STACK_FRAME(reg, val) \
19 addis reg,reg,val@ha; \
23 #define NORMAL_EXCEPTION_PROLOG \
24 mtspr SPRN_SPRG_WSCRATCH0,r10;/* save two registers to work with */\
25 mtspr SPRN_SPRG_WSCRATCH1,r11; \
26 mtspr SPRN_SPRG_WSCRATCH2,r1; \
27 mfcr r10; /* save CR in r10 for now */\
28 mfspr r11,SPRN_SRR1; /* check whether user or kernel */\
29 andi. r11,r11,MSR_PR; \
31 mfspr r1,SPRN_SPRG_THREAD; /* if from user, start at top of */\
32 lwz r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack */\
33 ALLOC_STACK_FRAME(r1, THREAD_SIZE); \
34 1: subi r1,r1,INT_FRAME_SIZE; /* Allocate an exception frame */\
36 stw r10,_CCR(r11); /* save various registers */\
39 mfspr r10,SPRN_SPRG_RSCRATCH0; \
41 mfspr r12,SPRN_SPRG_RSCRATCH1; \
45 mfspr r10,SPRN_SPRG_RSCRATCH2; \
46 mfspr r12,SPRN_SRR0; \
50 rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\
52 lis r10, STACK_FRAME_REGS_MARKER@ha;/* exception frame marker */ \
53 addi r10, r10, STACK_FRAME_REGS_MARKER@l; \
58 /* To handle the additional exception priority levels on 40x and Book-E
59 * processors we allocate a stack per additional priority level.
61 * On 40x critical is the only additional level
62 * On 44x/e500 we have critical and machine check
63 * On e200 we have critical and debug (machine check occurs via critical)
65 * Additionally we reserve a SPRG for each priority level so we can free up a
66 * GPR to use as the base for indirect access to the exception stacks. This
67 * is necessary since the MMU is always on, for Book-E parts, and the stacks
68 * are offset from KERNELBASE.
70 * There is some space optimization to be had here if desired. However
71 * to allow for a common kernel with support for debug exceptions either
72 * going to critical or their own debug level we aren't currently
73 * providing configurations that micro-optimize space usage.
76 #define MC_STACK_BASE mcheckirq_ctx
77 #define CRIT_STACK_BASE critirq_ctx
79 /* only on e500mc/e200 */
80 #define DBG_STACK_BASE dbgirq_ctx
82 #define EXC_LVL_FRAME_OVERHEAD (THREAD_SIZE - INT_FRAME_SIZE - EXC_LVL_SIZE)
85 #define BOOKE_LOAD_EXC_LEVEL_STACK(level) \
88 addis r8,r8,level##_STACK_BASE@ha; \
89 lwz r8,level##_STACK_BASE@l(r8); \
90 addi r8,r8,EXC_LVL_FRAME_OVERHEAD;
92 #define BOOKE_LOAD_EXC_LEVEL_STACK(level) \
93 lis r8,level##_STACK_BASE@ha; \
94 lwz r8,level##_STACK_BASE@l(r8); \
95 addi r8,r8,EXC_LVL_FRAME_OVERHEAD;
99 * Exception prolog for critical/machine check exceptions. This is a
100 * little different from the normal exception prolog above since a
101 * critical/machine check exception can potentially occur at any point
102 * during normal exception processing. Thus we cannot use the same SPRG
103 * registers as the normal prolog above. Instead we use a portion of the
104 * critical/machine check exception stack at low physical addresses.
106 #define EXC_LEVEL_EXCEPTION_PROLOG(exc_level, exc_level_srr0, exc_level_srr1) \
107 mtspr SPRN_SPRG_WSCRATCH_##exc_level,r8; \
108 BOOKE_LOAD_EXC_LEVEL_STACK(exc_level);/* r8 points to the exc_level stack*/ \
109 stw r9,GPR9(r8); /* save various registers */\
110 mfcr r9; /* save CR in r9 for now */\
113 stw r9,_CCR(r8); /* save CR on stack */\
114 mfspr r10,exc_level_srr1; /* check whether user or kernel */\
115 andi. r10,r10,MSR_PR; \
116 mfspr r11,SPRN_SPRG_THREAD; /* if from user, start at top of */\
117 lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
118 addi r11,r11,EXC_LVL_FRAME_OVERHEAD; /* allocate stack frame */\
120 /* COMING FROM USER MODE */ \
121 stw r9,_CCR(r11); /* save CR */\
122 lwz r10,GPR10(r8); /* copy regs from exception stack */\
124 stw r10,GPR10(r11); \
127 stw r10,GPR11(r11); \
129 /* COMING FROM PRIV MODE */ \
130 1: lwz r9,TI_FLAGS-EXC_LVL_FRAME_OVERHEAD(r11); \
131 lwz r10,TI_PREEMPT-EXC_LVL_FRAME_OVERHEAD(r11); \
132 stw r9,TI_FLAGS-EXC_LVL_FRAME_OVERHEAD(r8); \
133 stw r10,TI_PREEMPT-EXC_LVL_FRAME_OVERHEAD(r8); \
134 lwz r9,TI_TASK-EXC_LVL_FRAME_OVERHEAD(r11); \
135 stw r9,TI_TASK-EXC_LVL_FRAME_OVERHEAD(r8); \
137 2: mfspr r8,SPRN_SPRG_RSCRATCH_##exc_level; \
138 stw r12,GPR12(r11); /* save various registers */\
140 stw r10,_LINK(r11); \
141 mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\
142 stw r12,_DEAR(r11); /* since they may have had stuff */\
143 mfspr r9,SPRN_ESR; /* in them at the point where the */\
144 stw r9,_ESR(r11); /* exception was taken */\
145 mfspr r12,exc_level_srr0; \
147 mfspr r9,exc_level_srr1; \
150 rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\
152 SAVE_4GPRS(3, r11); \
155 #define CRITICAL_EXCEPTION_PROLOG \
156 EXC_LEVEL_EXCEPTION_PROLOG(CRIT, SPRN_CSRR0, SPRN_CSRR1)
157 #define DEBUG_EXCEPTION_PROLOG \
158 EXC_LEVEL_EXCEPTION_PROLOG(DBG, SPRN_DSRR0, SPRN_DSRR1)
159 #define MCHECK_EXCEPTION_PROLOG \
160 EXC_LEVEL_EXCEPTION_PROLOG(MC, SPRN_MCSRR0, SPRN_MCSRR1)
165 #define START_EXCEPTION(label) \
169 #define FINISH_EXCEPTION(func) \
170 bl transfer_to_handler_full; \
172 .long ret_from_except_full
174 #define EXCEPTION(n, label, hdlr, xfer) \
175 START_EXCEPTION(label); \
176 NORMAL_EXCEPTION_PROLOG; \
177 addi r3,r1,STACK_FRAME_OVERHEAD; \
180 #define CRITICAL_EXCEPTION(n, label, hdlr) \
181 START_EXCEPTION(label); \
182 CRITICAL_EXCEPTION_PROLOG; \
183 addi r3,r1,STACK_FRAME_OVERHEAD; \
184 EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
185 NOCOPY, crit_transfer_to_handler, \
188 #define MCHECK_EXCEPTION(n, label, hdlr) \
189 START_EXCEPTION(label); \
190 MCHECK_EXCEPTION_PROLOG; \
193 addi r3,r1,STACK_FRAME_OVERHEAD; \
194 EXC_XFER_TEMPLATE(hdlr, n+4, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
195 NOCOPY, mcheck_transfer_to_handler, \
198 #define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret) \
200 stw r10,_TRAP(r11); \
208 #define COPY_EE(d, s) rlwimi d,s,0,16,16
211 #define EXC_XFER_STD(n, hdlr) \
212 EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \
213 ret_from_except_full)
215 #define EXC_XFER_LITE(n, hdlr) \
216 EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \
219 #define EXC_XFER_EE(n, hdlr) \
220 EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \
221 ret_from_except_full)
223 #define EXC_XFER_EE_LITE(n, hdlr) \
224 EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \
227 /* Check for a single step debug exception while in an exception
228 * handler before state has been saved. This is to catch the case
229 * where an instruction that we are trying to single step causes
230 * an exception (eg ITLB/DTLB miss) and thus the first instruction of
231 * the exception handler generates a single step debug exception.
233 * If we get a debug trap on the first instruction of an exception handler,
234 * we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is
235 * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR).
236 * The exception handler was handling a non-critical interrupt, so it will
237 * save (and later restore) the MSR via SPRN_CSRR1, which will still have
238 * the MSR_DE bit set.
240 #define DEBUG_DEBUG_EXCEPTION \
241 START_EXCEPTION(DebugDebug); \
242 DEBUG_EXCEPTION_PROLOG; \
245 * If there is a single step or branch-taken exception in an \
246 * exception entry sequence, it was probably meant to apply to \
247 * the code where the exception occurred (since exception entry \
248 * doesn't turn off DE automatically). We simulate the effect \
249 * of turning off DE on entry to an exception handler by turning \
250 * off DE in the DSRR1 value and clearing the debug status. \
252 mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \
253 andis. r10,r10,(DBSR_IC|DBSR_BT)@h; \
256 lis r10,KERNELBASE@h; /* check if exception in vectors */ \
257 ori r10,r10,KERNELBASE@l; \
259 blt+ 2f; /* addr below exception vectors */ \
261 lis r10,DebugDebug@h; \
262 ori r10,r10,DebugDebug@l; \
264 bgt+ 2f; /* addr above exception vectors */ \
266 /* here it looks like we got an inappropriate debug exception. */ \
267 1: rlwinm r9,r9,0,~MSR_DE; /* clear DE in the CDRR1 value */ \
268 lis r10,(DBSR_IC|DBSR_BT)@h; /* clear the IC event */ \
269 mtspr SPRN_DBSR,r10; \
270 /* restore state and get out */ \
275 mtspr SPRN_DSRR0,r12; \
276 mtspr SPRN_DSRR1,r9; \
278 lwz r12,GPR12(r11); \
279 mtspr SPRN_SPRG_WSCRATCH_DBG,r8; \
280 BOOKE_LOAD_EXC_LEVEL_STACK(DBG); /* r8 points to the debug stack */ \
283 mfspr r8,SPRN_SPRG_RSCRATCH_DBG; \
288 /* continue normal handling for a debug exception... */ \
289 2: mfspr r4,SPRN_DBSR; \
290 addi r3,r1,STACK_FRAME_OVERHEAD; \
291 EXC_XFER_TEMPLATE(DebugException, 0x2008, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, debug_transfer_to_handler, ret_from_debug_exc)
293 #define DEBUG_CRIT_EXCEPTION \
294 START_EXCEPTION(DebugCrit); \
295 CRITICAL_EXCEPTION_PROLOG; \
298 * If there is a single step or branch-taken exception in an \
299 * exception entry sequence, it was probably meant to apply to \
300 * the code where the exception occurred (since exception entry \
301 * doesn't turn off DE automatically). We simulate the effect \
302 * of turning off DE on entry to an exception handler by turning \
303 * off DE in the CSRR1 value and clearing the debug status. \
305 mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \
306 andis. r10,r10,(DBSR_IC|DBSR_BT)@h; \
309 lis r10,KERNELBASE@h; /* check if exception in vectors */ \
310 ori r10,r10,KERNELBASE@l; \
312 blt+ 2f; /* addr below exception vectors */ \
314 lis r10,DebugCrit@h; \
315 ori r10,r10,DebugCrit@l; \
317 bgt+ 2f; /* addr above exception vectors */ \
319 /* here it looks like we got an inappropriate debug exception. */ \
320 1: rlwinm r9,r9,0,~MSR_DE; /* clear DE in the CSRR1 value */ \
321 lis r10,(DBSR_IC|DBSR_BT)@h; /* clear the IC event */ \
322 mtspr SPRN_DBSR,r10; \
323 /* restore state and get out */ \
328 mtspr SPRN_CSRR0,r12; \
329 mtspr SPRN_CSRR1,r9; \
331 lwz r12,GPR12(r11); \
332 mtspr SPRN_SPRG_WSCRATCH_CRIT,r8; \
333 BOOKE_LOAD_EXC_LEVEL_STACK(CRIT); /* r8 points to the debug stack */ \
336 mfspr r8,SPRN_SPRG_RSCRATCH_CRIT; \
341 /* continue normal handling for a critical exception... */ \
342 2: mfspr r4,SPRN_DBSR; \
343 addi r3,r1,STACK_FRAME_OVERHEAD; \
344 EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)
346 #define DATA_STORAGE_EXCEPTION \
347 START_EXCEPTION(DataStorage) \
348 NORMAL_EXCEPTION_PROLOG; \
349 mfspr r5,SPRN_ESR; /* Grab the ESR and save it */ \
351 mfspr r4,SPRN_DEAR; /* Grab the DEAR */ \
352 EXC_XFER_EE_LITE(0x0300, handle_page_fault)
354 #define INSTRUCTION_STORAGE_EXCEPTION \
355 START_EXCEPTION(InstructionStorage) \
356 NORMAL_EXCEPTION_PROLOG; \
357 mfspr r5,SPRN_ESR; /* Grab the ESR and save it */ \
359 mr r4,r12; /* Pass SRR0 as arg2 */ \
360 li r5,0; /* Pass zero as arg3 */ \
361 EXC_XFER_EE_LITE(0x0400, handle_page_fault)
363 #define ALIGNMENT_EXCEPTION \
364 START_EXCEPTION(Alignment) \
365 NORMAL_EXCEPTION_PROLOG; \
366 mfspr r4,SPRN_DEAR; /* Grab the DEAR and save it */ \
368 addi r3,r1,STACK_FRAME_OVERHEAD; \
369 EXC_XFER_EE(0x0600, alignment_exception)
371 #define PROGRAM_EXCEPTION \
372 START_EXCEPTION(Program) \
373 NORMAL_EXCEPTION_PROLOG; \
374 mfspr r4,SPRN_ESR; /* Grab the ESR and save it */ \
376 addi r3,r1,STACK_FRAME_OVERHEAD; \
377 EXC_XFER_STD(0x0700, program_check_exception)
379 #define DECREMENTER_EXCEPTION \
380 START_EXCEPTION(Decrementer) \
381 NORMAL_EXCEPTION_PROLOG; \
382 lis r0,TSR_DIS@h; /* Setup the DEC interrupt mask */ \
383 mtspr SPRN_TSR,r0; /* Clear the DEC interrupt */ \
384 addi r3,r1,STACK_FRAME_OVERHEAD; \
385 EXC_XFER_LITE(0x0900, timer_interrupt)
387 #define FP_UNAVAILABLE_EXCEPTION \
388 START_EXCEPTION(FloatingPointUnavailable) \
389 NORMAL_EXCEPTION_PROLOG; \
391 bl load_up_fpu; /* if from user, just load it up */ \
392 b fast_exception_return; \
393 1: addi r3,r1,STACK_FRAME_OVERHEAD; \
394 EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception)
397 struct exception_regs {
410 unsigned long saved_ksp_limit;
413 /* ensure this structure is always sized to a multiple of the stack alignment */
414 #define STACK_EXC_LVL_FRAME_SIZE _ALIGN_UP(sizeof (struct exception_regs), 16)
416 #endif /* __ASSEMBLY__ */
417 #endif /* __HEAD_BOOKE_H__ */