diff options
Diffstat (limited to 'arch/powerpc/kernel/head_booke.h')
-rw-r--r-- | arch/powerpc/kernel/head_booke.h | 126 |
1 files changed, 85 insertions, 41 deletions
diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h index aefafc6330c9..fce2df988504 100644 --- a/arch/powerpc/kernel/head_booke.h +++ b/arch/powerpc/kernel/head_booke.h | |||
@@ -43,9 +43,7 @@ | |||
43 | SAVE_2GPRS(7, r11) | 43 | SAVE_2GPRS(7, r11) |
44 | 44 | ||
45 | /* To handle the additional exception priority levels on 40x and Book-E | 45 | /* To handle the additional exception priority levels on 40x and Book-E |
46 | * processors we allocate a 4k stack per additional priority level. The various | 46 | * processors we allocate a stack per additional priority level. |
47 | * head_xxx.S files allocate space (exception_stack_top) for each priority's | ||
48 | * stack times the number of CPUs | ||
49 | * | 47 | * |
50 | * On 40x critical is the only additional level | 48 | * On 40x critical is the only additional level |
51 | * On 44x/e500 we have critical and machine check | 49 | * On 44x/e500 we have critical and machine check |
@@ -61,36 +59,37 @@ | |||
61 | * going to critical or their own debug level we aren't currently | 59 | * going to critical or their own debug level we aren't currently |
62 | * providing configurations that micro-optimize space usage. | 60 | * providing configurations that micro-optimize space usage. |
63 | */ | 61 | */ |
64 | #ifdef CONFIG_44x | ||
65 | #define NUM_EXCEPTION_LVLS 2 | ||
66 | #else | ||
67 | #define NUM_EXCEPTION_LVLS 3 | ||
68 | #endif | ||
69 | #define BOOKE_EXCEPTION_STACK_SIZE (4096 * NUM_EXCEPTION_LVLS) | ||
70 | 62 | ||
71 | /* CRIT_SPRG only used in critical exception handling */ | 63 | /* CRIT_SPRG only used in critical exception handling */ |
72 | #define CRIT_SPRG SPRN_SPRG2 | 64 | #define CRIT_SPRG SPRN_SPRG2 |
73 | /* MCHECK_SPRG only used in machine check exception handling */ | 65 | /* MCHECK_SPRG only used in machine check exception handling */ |
74 | #define MCHECK_SPRG SPRN_SPRG6W | 66 | #define MCHECK_SPRG SPRN_SPRG6W |
75 | 67 | ||
76 | #define MCHECK_STACK_TOP (exception_stack_top - 4096) | 68 | #define MCHECK_STACK_BASE mcheckirq_ctx |
77 | #define CRIT_STACK_TOP (exception_stack_top) | 69 | #define CRIT_STACK_BASE critirq_ctx |
78 | 70 | ||
79 | /* only on e200 for now */ | 71 | /* only on e500mc/e200 */ |
80 | #define DEBUG_STACK_TOP (exception_stack_top - 8192) | 72 | #define DEBUG_STACK_BASE dbgirq_ctx |
73 | #ifdef CONFIG_PPC_E500MC | ||
74 | #define DEBUG_SPRG SPRN_SPRG9 | ||
75 | #else | ||
81 | #define DEBUG_SPRG SPRN_SPRG6W | 76 | #define DEBUG_SPRG SPRN_SPRG6W |
77 | #endif | ||
78 | |||
79 | #define EXC_LVL_FRAME_OVERHEAD (THREAD_SIZE - INT_FRAME_SIZE - EXC_LVL_SIZE) | ||
82 | 80 | ||
83 | #ifdef CONFIG_SMP | 81 | #ifdef CONFIG_SMP |
84 | #define BOOKE_LOAD_EXC_LEVEL_STACK(level) \ | 82 | #define BOOKE_LOAD_EXC_LEVEL_STACK(level) \ |
85 | mfspr r8,SPRN_PIR; \ | 83 | mfspr r8,SPRN_PIR; \ |
86 | mulli r8,r8,BOOKE_EXCEPTION_STACK_SIZE; \ | 84 | slwi r8,r8,2; \ |
87 | neg r8,r8; \ | 85 | addis r8,r8,level##_STACK_BASE@ha; \ |
88 | addis r8,r8,level##_STACK_TOP@ha; \ | 86 | lwz r8,level##_STACK_BASE@l(r8); \ |
89 | addi r8,r8,level##_STACK_TOP@l | 87 | addi r8,r8,EXC_LVL_FRAME_OVERHEAD; |
90 | #else | 88 | #else |
91 | #define BOOKE_LOAD_EXC_LEVEL_STACK(level) \ | 89 | #define BOOKE_LOAD_EXC_LEVEL_STACK(level) \ |
92 | lis r8,level##_STACK_TOP@h; \ | 90 | lis r8,level##_STACK_BASE@ha; \ |
93 | ori r8,r8,level##_STACK_TOP@l | 91 | lwz r8,level##_STACK_BASE@l(r8); \ |
92 | addi r8,r8,EXC_LVL_FRAME_OVERHEAD; | ||
94 | #endif | 93 | #endif |
95 | 94 | ||
96 | /* | 95 | /* |
@@ -104,22 +103,36 @@ | |||
104 | #define EXC_LEVEL_EXCEPTION_PROLOG(exc_level, exc_level_srr0, exc_level_srr1) \ | 103 | #define EXC_LEVEL_EXCEPTION_PROLOG(exc_level, exc_level_srr0, exc_level_srr1) \ |
105 | mtspr exc_level##_SPRG,r8; \ | 104 | mtspr exc_level##_SPRG,r8; \ |
106 | BOOKE_LOAD_EXC_LEVEL_STACK(exc_level);/* r8 points to the exc_level stack*/ \ | 105 | BOOKE_LOAD_EXC_LEVEL_STACK(exc_level);/* r8 points to the exc_level stack*/ \ |
107 | stw r10,GPR10-INT_FRAME_SIZE(r8); \ | 106 | stw r9,GPR9(r8); /* save various registers */\ |
108 | stw r11,GPR11-INT_FRAME_SIZE(r8); \ | 107 | mfcr r9; /* save CR in r9 for now */\ |
109 | mfcr r10; /* save CR in r10 for now */\ | 108 | stw r10,GPR10(r8); \ |
110 | mfspr r11,exc_level_srr1; /* check whether user or kernel */\ | 109 | stw r11,GPR11(r8); \ |
111 | andi. r11,r11,MSR_PR; \ | 110 | stw r9,_CCR(r8); /* save CR on stack */\ |
112 | mr r11,r8; \ | 111 | mfspr r10,exc_level_srr1; /* check whether user or kernel */\ |
113 | mfspr r8,exc_level##_SPRG; \ | 112 | andi. r10,r10,MSR_PR; \ |
114 | beq 1f; \ | ||
115 | /* COMING FROM USER MODE */ \ | ||
116 | mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\ | 113 | mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\ |
117 | lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ | 114 | lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ |
118 | addi r11,r11,THREAD_SIZE; \ | 115 | addi r11,r11,EXC_LVL_FRAME_OVERHEAD; /* allocate stack frame */\ |
119 | 1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ | 116 | beq 1f; \ |
120 | stw r10,_CCR(r11); /* save various registers */\ | 117 | /* COMING FROM USER MODE */ \ |
121 | stw r12,GPR12(r11); \ | 118 | stw r9,_CCR(r11); /* save CR */\ |
119 | lwz r10,GPR10(r8); /* copy regs from exception stack */\ | ||
120 | lwz r9,GPR9(r8); \ | ||
121 | stw r10,GPR10(r11); \ | ||
122 | lwz r10,GPR11(r8); \ | ||
122 | stw r9,GPR9(r11); \ | 123 | stw r9,GPR9(r11); \ |
124 | stw r10,GPR11(r11); \ | ||
125 | b 2f; \ | ||
126 | /* COMING FROM PRIV MODE */ \ | ||
127 | 1: lwz r9,TI_FLAGS-EXC_LVL_FRAME_OVERHEAD(r11); \ | ||
128 | lwz r10,TI_PREEMPT-EXC_LVL_FRAME_OVERHEAD(r11); \ | ||
129 | stw r9,TI_FLAGS-EXC_LVL_FRAME_OVERHEAD(r8); \ | ||
130 | stw r10,TI_PREEMPT-EXC_LVL_FRAME_OVERHEAD(r8); \ | ||
131 | lwz r9,TI_TASK-EXC_LVL_FRAME_OVERHEAD(r11); \ | ||
132 | stw r9,TI_TASK-EXC_LVL_FRAME_OVERHEAD(r8); \ | ||
133 | mr r11,r8; \ | ||
134 | 2: mfspr r8,exc_level##_SPRG; \ | ||
135 | stw r12,GPR12(r11); /* save various registers */\ | ||
123 | mflr r10; \ | 136 | mflr r10; \ |
124 | stw r10,_LINK(r11); \ | 137 | stw r10,_LINK(r11); \ |
125 | mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ | 138 | mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ |
@@ -231,7 +244,7 @@ label: | |||
231 | * the code where the exception occurred (since exception entry \ | 244 | * the code where the exception occurred (since exception entry \ |
232 | * doesn't turn off DE automatically). We simulate the effect \ | 245 | * doesn't turn off DE automatically). We simulate the effect \ |
233 | * of turning off DE on entry to an exception handler by turning \ | 246 | * of turning off DE on entry to an exception handler by turning \ |
234 | * off DE in the CSRR1 value and clearing the debug status. \ | 247 | * off DE in the DSRR1 value and clearing the debug status. \ |
235 | */ \ | 248 | */ \ |
236 | mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \ | 249 | mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \ |
237 | andis. r10,r10,DBSR_IC@h; \ | 250 | andis. r10,r10,DBSR_IC@h; \ |
@@ -262,17 +275,17 @@ label: | |||
262 | lwz r12,GPR12(r11); \ | 275 | lwz r12,GPR12(r11); \ |
263 | mtspr DEBUG_SPRG,r8; \ | 276 | mtspr DEBUG_SPRG,r8; \ |
264 | BOOKE_LOAD_EXC_LEVEL_STACK(DEBUG); /* r8 points to the debug stack */ \ | 277 | BOOKE_LOAD_EXC_LEVEL_STACK(DEBUG); /* r8 points to the debug stack */ \ |
265 | lwz r10,GPR10-INT_FRAME_SIZE(r8); \ | 278 | lwz r10,GPR10(r8); \ |
266 | lwz r11,GPR11-INT_FRAME_SIZE(r8); \ | 279 | lwz r11,GPR11(r8); \ |
267 | mfspr r8,DEBUG_SPRG; \ | 280 | mfspr r8,DEBUG_SPRG; \ |
268 | \ | 281 | \ |
269 | RFDI; \ | 282 | RFDI; \ |
270 | b .; \ | 283 | b .; \ |
271 | \ | 284 | \ |
272 | /* continue normal handling for a critical exception... */ \ | 285 | /* continue normal handling for a debug exception... */ \ |
273 | 2: mfspr r4,SPRN_DBSR; \ | 286 | 2: mfspr r4,SPRN_DBSR; \ |
274 | addi r3,r1,STACK_FRAME_OVERHEAD; \ | 287 | addi r3,r1,STACK_FRAME_OVERHEAD; \ |
275 | EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, debug_transfer_to_handler, ret_from_debug_exc) | 288 | EXC_XFER_TEMPLATE(DebugException, 0x2008, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, debug_transfer_to_handler, ret_from_debug_exc) |
276 | 289 | ||
277 | #define DEBUG_CRIT_EXCEPTION \ | 290 | #define DEBUG_CRIT_EXCEPTION \ |
278 | START_EXCEPTION(DebugCrit); \ | 291 | START_EXCEPTION(DebugCrit); \ |
@@ -315,8 +328,8 @@ label: | |||
315 | lwz r12,GPR12(r11); \ | 328 | lwz r12,GPR12(r11); \ |
316 | mtspr CRIT_SPRG,r8; \ | 329 | mtspr CRIT_SPRG,r8; \ |
317 | BOOKE_LOAD_EXC_LEVEL_STACK(CRIT); /* r8 points to the debug stack */ \ | 330 | BOOKE_LOAD_EXC_LEVEL_STACK(CRIT); /* r8 points to the debug stack */ \ |
318 | lwz r10,GPR10-INT_FRAME_SIZE(r8); \ | 331 | lwz r10,GPR10(r8); \ |
319 | lwz r11,GPR11-INT_FRAME_SIZE(r8); \ | 332 | lwz r11,GPR11(r8); \ |
320 | mfspr r8,CRIT_SPRG; \ | 333 | mfspr r8,CRIT_SPRG; \ |
321 | \ | 334 | \ |
322 | rfci; \ | 335 | rfci; \ |
@@ -327,6 +340,14 @@ label: | |||
327 | addi r3,r1,STACK_FRAME_OVERHEAD; \ | 340 | addi r3,r1,STACK_FRAME_OVERHEAD; \ |
328 | EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, crit_transfer_to_handler, ret_from_crit_exc) | 341 | EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, crit_transfer_to_handler, ret_from_crit_exc) |
329 | 342 | ||
343 | #define DATA_STORAGE_EXCEPTION \ | ||
344 | START_EXCEPTION(DataStorage) \ | ||
345 | NORMAL_EXCEPTION_PROLOG; \ | ||
346 | mfspr r5,SPRN_ESR; /* Grab the ESR and save it */ \ | ||
347 | stw r5,_ESR(r11); \ | ||
348 | mfspr r4,SPRN_DEAR; /* Grab the DEAR */ \ | ||
349 | EXC_XFER_EE_LITE(0x0300, handle_page_fault) | ||
350 | |||
330 | #define INSTRUCTION_STORAGE_EXCEPTION \ | 351 | #define INSTRUCTION_STORAGE_EXCEPTION \ |
331 | START_EXCEPTION(InstructionStorage) \ | 352 | START_EXCEPTION(InstructionStorage) \ |
332 | NORMAL_EXCEPTION_PROLOG; \ | 353 | NORMAL_EXCEPTION_PROLOG; \ |
@@ -363,8 +384,31 @@ label: | |||
363 | #define FP_UNAVAILABLE_EXCEPTION \ | 384 | #define FP_UNAVAILABLE_EXCEPTION \ |
364 | START_EXCEPTION(FloatingPointUnavailable) \ | 385 | START_EXCEPTION(FloatingPointUnavailable) \ |
365 | NORMAL_EXCEPTION_PROLOG; \ | 386 | NORMAL_EXCEPTION_PROLOG; \ |
366 | bne load_up_fpu; /* if from user, just load it up */ \ | 387 | beq 1f; \ |
367 | addi r3,r1,STACK_FRAME_OVERHEAD; \ | 388 | bl load_up_fpu; /* if from user, just load it up */ \ |
389 | b fast_exception_return; \ | ||
390 | 1: addi r3,r1,STACK_FRAME_OVERHEAD; \ | ||
368 | EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception) | 391 | EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception) |
369 | 392 | ||
393 | #ifndef __ASSEMBLY__ | ||
394 | struct exception_regs { | ||
395 | unsigned long mas0; | ||
396 | unsigned long mas1; | ||
397 | unsigned long mas2; | ||
398 | unsigned long mas3; | ||
399 | unsigned long mas6; | ||
400 | unsigned long mas7; | ||
401 | unsigned long srr0; | ||
402 | unsigned long srr1; | ||
403 | unsigned long csrr0; | ||
404 | unsigned long csrr1; | ||
405 | unsigned long dsrr0; | ||
406 | unsigned long dsrr1; | ||
407 | unsigned long saved_ksp_limit; | ||
408 | }; | ||
409 | |||
410 | /* ensure this structure is always sized to a multiple of the stack alignment */ | ||
411 | #define STACK_EXC_LVL_FRAME_SIZE _ALIGN_UP(sizeof (struct exception_regs), 16) | ||
412 | |||
413 | #endif /* __ASSEMBLY__ */ | ||
370 | #endif /* __HEAD_BOOKE_H__ */ | 414 | #endif /* __HEAD_BOOKE_H__ */ |