Path: blob/master/arch/powerpc/kernel/head_booke.h
10817 views
#ifndef __HEAD_BOOKE_H__1#define __HEAD_BOOKE_H__23#include <asm/ptrace.h> /* for STACK_FRAME_REGS_MARKER */4/*5* Macros used for common Book-e exception handling6*/78#define SET_IVOR(vector_number, vector_label) \9li r26,vector_label@l; \10mtspr SPRN_IVOR##vector_number,r26; \11sync1213#if (THREAD_SHIFT < 15)14#define ALLOC_STACK_FRAME(reg, val) \15addi reg,reg,val16#else17#define ALLOC_STACK_FRAME(reg, val) \18addis reg,reg,val@ha; \19addi reg,reg,val@l20#endif2122#define NORMAL_EXCEPTION_PROLOG \23mtspr SPRN_SPRG_WSCRATCH0,r10;/* save two registers to work with */\24mtspr SPRN_SPRG_WSCRATCH1,r11; \25mtspr SPRN_SPRG_WSCRATCH2,r1; \26mfcr r10; /* save CR in r10 for now */\27mfspr r11,SPRN_SRR1; /* check whether user or kernel */\28andi. r11,r11,MSR_PR; \29beq 1f; \30mfspr r1,SPRN_SPRG_THREAD; /* if from user, start at top of */\31lwz r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack */\32ALLOC_STACK_FRAME(r1, THREAD_SIZE); \331: subi r1,r1,INT_FRAME_SIZE; /* Allocate an exception frame */\34mr r11,r1; \35stw r10,_CCR(r11); /* save various registers */\36stw r12,GPR12(r11); \37stw r9,GPR9(r11); \38mfspr r10,SPRN_SPRG_RSCRATCH0; \39stw r10,GPR10(r11); \40mfspr r12,SPRN_SPRG_RSCRATCH1; \41stw r12,GPR11(r11); \42mflr r10; \43stw r10,_LINK(r11); \44mfspr r10,SPRN_SPRG_RSCRATCH2; \45mfspr r12,SPRN_SRR0; \46stw r10,GPR1(r11); \47mfspr r9,SPRN_SRR1; \48stw r10,0(r11); \49rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\50stw r0,GPR0(r11); \51lis r10, STACK_FRAME_REGS_MARKER@ha;/* exception frame marker */ \52addi r10, r10, STACK_FRAME_REGS_MARKER@l; \53stw r10, 8(r11); \54SAVE_4GPRS(3, r11); \55SAVE_2GPRS(7, r11)5657/* To handle the additional exception priority levels on 40x and Book-E58* processors we allocate a stack per additional priority level.59*60* On 40x critical is the only additional level61* On 44x/e500 we have critical and machine check62* On e200 we have critical and debug (machine check occurs via critical)63*64* Additionally we reserve a SPRG for each priority level so we can free up a65* GPR to use as the base for indirect access to the exception stacks. This66* is necessary since the MMU is always on, for Book-E parts, and the stacks67* are offset from KERNELBASE.68*69* There is some space optimization to be had here if desired. However70* to allow for a common kernel with support for debug exceptions either71* going to critical or their own debug level we aren't currently72* providing configurations that micro-optimize space usage.73*/7475#define MC_STACK_BASE mcheckirq_ctx76#define CRIT_STACK_BASE critirq_ctx7778/* only on e500mc/e200 */79#define DBG_STACK_BASE dbgirq_ctx8081#define EXC_LVL_FRAME_OVERHEAD (THREAD_SIZE - INT_FRAME_SIZE - EXC_LVL_SIZE)8283#ifdef CONFIG_SMP84#define BOOKE_LOAD_EXC_LEVEL_STACK(level) \85mfspr r8,SPRN_PIR; \86slwi r8,r8,2; \87addis r8,r8,level##_STACK_BASE@ha; \88lwz r8,level##_STACK_BASE@l(r8); \89addi r8,r8,EXC_LVL_FRAME_OVERHEAD;90#else91#define BOOKE_LOAD_EXC_LEVEL_STACK(level) \92lis r8,level##_STACK_BASE@ha; \93lwz r8,level##_STACK_BASE@l(r8); \94addi r8,r8,EXC_LVL_FRAME_OVERHEAD;95#endif9697/*98* Exception prolog for critical/machine check exceptions. This is a99* little different from the normal exception prolog above since a100* critical/machine check exception can potentially occur at any point101* during normal exception processing. Thus we cannot use the same SPRG102* registers as the normal prolog above. Instead we use a portion of the103* critical/machine check exception stack at low physical addresses.104*/105#define EXC_LEVEL_EXCEPTION_PROLOG(exc_level, exc_level_srr0, exc_level_srr1) \106mtspr SPRN_SPRG_WSCRATCH_##exc_level,r8; \107BOOKE_LOAD_EXC_LEVEL_STACK(exc_level);/* r8 points to the exc_level stack*/ \108stw r9,GPR9(r8); /* save various registers */\109mfcr r9; /* save CR in r9 for now */\110stw r10,GPR10(r8); \111stw r11,GPR11(r8); \112stw r9,_CCR(r8); /* save CR on stack */\113mfspr r10,exc_level_srr1; /* check whether user or kernel */\114andi. r10,r10,MSR_PR; \115mfspr r11,SPRN_SPRG_THREAD; /* if from user, start at top of */\116lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\117addi r11,r11,EXC_LVL_FRAME_OVERHEAD; /* allocate stack frame */\118beq 1f; \119/* COMING FROM USER MODE */ \120stw r9,_CCR(r11); /* save CR */\121lwz r10,GPR10(r8); /* copy regs from exception stack */\122lwz r9,GPR9(r8); \123stw r10,GPR10(r11); \124lwz r10,GPR11(r8); \125stw r9,GPR9(r11); \126stw r10,GPR11(r11); \127b 2f; \128/* COMING FROM PRIV MODE */ \1291: lwz r9,TI_FLAGS-EXC_LVL_FRAME_OVERHEAD(r11); \130lwz r10,TI_PREEMPT-EXC_LVL_FRAME_OVERHEAD(r11); \131stw r9,TI_FLAGS-EXC_LVL_FRAME_OVERHEAD(r8); \132stw r10,TI_PREEMPT-EXC_LVL_FRAME_OVERHEAD(r8); \133lwz r9,TI_TASK-EXC_LVL_FRAME_OVERHEAD(r11); \134stw r9,TI_TASK-EXC_LVL_FRAME_OVERHEAD(r8); \135mr r11,r8; \1362: mfspr r8,SPRN_SPRG_RSCRATCH_##exc_level; \137stw r12,GPR12(r11); /* save various registers */\138mflr r10; \139stw r10,_LINK(r11); \140mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\141stw r12,_DEAR(r11); /* since they may have had stuff */\142mfspr r9,SPRN_ESR; /* in them at the point where the */\143stw r9,_ESR(r11); /* exception was taken */\144mfspr r12,exc_level_srr0; \145stw r1,GPR1(r11); \146mfspr r9,exc_level_srr1; \147stw r1,0(r11); \148mr r1,r11; \149rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\150stw r0,GPR0(r11); \151SAVE_4GPRS(3, r11); \152SAVE_2GPRS(7, r11)153154#define CRITICAL_EXCEPTION_PROLOG \155EXC_LEVEL_EXCEPTION_PROLOG(CRIT, SPRN_CSRR0, SPRN_CSRR1)156#define DEBUG_EXCEPTION_PROLOG \157EXC_LEVEL_EXCEPTION_PROLOG(DBG, SPRN_DSRR0, SPRN_DSRR1)158#define MCHECK_EXCEPTION_PROLOG \159EXC_LEVEL_EXCEPTION_PROLOG(MC, SPRN_MCSRR0, SPRN_MCSRR1)160161/*162* Exception vectors.163*/164#define START_EXCEPTION(label) \165.align 5; \166label:167168#define FINISH_EXCEPTION(func) \169bl transfer_to_handler_full; \170.long func; \171.long ret_from_except_full172173#define EXCEPTION(n, label, hdlr, xfer) \174START_EXCEPTION(label); \175NORMAL_EXCEPTION_PROLOG; \176addi r3,r1,STACK_FRAME_OVERHEAD; \177xfer(n, hdlr)178179#define CRITICAL_EXCEPTION(n, label, hdlr) \180START_EXCEPTION(label); \181CRITICAL_EXCEPTION_PROLOG; \182addi r3,r1,STACK_FRAME_OVERHEAD; \183EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \184NOCOPY, crit_transfer_to_handler, \185ret_from_crit_exc)186187#define MCHECK_EXCEPTION(n, label, hdlr) \188START_EXCEPTION(label); \189MCHECK_EXCEPTION_PROLOG; \190mfspr r5,SPRN_ESR; \191stw r5,_ESR(r11); \192addi r3,r1,STACK_FRAME_OVERHEAD; \193EXC_XFER_TEMPLATE(hdlr, n+4, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \194NOCOPY, mcheck_transfer_to_handler, \195ret_from_mcheck_exc)196197#define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret) \198li r10,trap; \199stw r10,_TRAP(r11); \200lis r10,msr@h; \201ori r10,r10,msr@l; \202copyee(r10, r9); \203bl tfer; \204.long hdlr; \205.long ret206207#define COPY_EE(d, s) rlwimi d,s,0,16,16208#define NOCOPY(d, s)209210#define EXC_XFER_STD(n, hdlr) \211EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \212ret_from_except_full)213214#define EXC_XFER_LITE(n, hdlr) \215EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \216ret_from_except)217218#define EXC_XFER_EE(n, hdlr) \219EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \220ret_from_except_full)221222#define EXC_XFER_EE_LITE(n, hdlr) \223EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \224ret_from_except)225226/* Check for a single step debug exception while in an exception227* handler before state has been saved. This is to catch the case228* where an instruction that we are trying to single step causes229* an exception (eg ITLB/DTLB miss) and thus the first instruction of230* the exception handler generates a single step debug exception.231*232* If we get a debug trap on the first instruction of an exception handler,233* we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is234* a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR).235* The exception handler was handling a non-critical interrupt, so it will236* save (and later restore) the MSR via SPRN_CSRR1, which will still have237* the MSR_DE bit set.238*/239#define DEBUG_DEBUG_EXCEPTION \240START_EXCEPTION(DebugDebug); \241DEBUG_EXCEPTION_PROLOG; \242\243/* \244* If there is a single step or branch-taken exception in an \245* exception entry sequence, it was probably meant to apply to \246* the code where the exception occurred (since exception entry \247* doesn't turn off DE automatically). We simulate the effect \248* of turning off DE on entry to an exception handler by turning \249* off DE in the DSRR1 value and clearing the debug status. \250*/ \251mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \252andis. r10,r10,(DBSR_IC|DBSR_BT)@h; \253beq+ 2f; \254\255lis r10,KERNELBASE@h; /* check if exception in vectors */ \256ori r10,r10,KERNELBASE@l; \257cmplw r12,r10; \258blt+ 2f; /* addr below exception vectors */ \259\260lis r10,DebugDebug@h; \261ori r10,r10,DebugDebug@l; \262cmplw r12,r10; \263bgt+ 2f; /* addr above exception vectors */ \264\265/* here it looks like we got an inappropriate debug exception. */ \2661: rlwinm r9,r9,0,~MSR_DE; /* clear DE in the CDRR1 value */ \267lis r10,(DBSR_IC|DBSR_BT)@h; /* clear the IC event */ \268mtspr SPRN_DBSR,r10; \269/* restore state and get out */ \270lwz r10,_CCR(r11); \271lwz r0,GPR0(r11); \272lwz r1,GPR1(r11); \273mtcrf 0x80,r10; \274mtspr SPRN_DSRR0,r12; \275mtspr SPRN_DSRR1,r9; \276lwz r9,GPR9(r11); \277lwz r12,GPR12(r11); \278mtspr SPRN_SPRG_WSCRATCH_DBG,r8; \279BOOKE_LOAD_EXC_LEVEL_STACK(DBG); /* r8 points to the debug stack */ \280lwz r10,GPR10(r8); \281lwz r11,GPR11(r8); \282mfspr r8,SPRN_SPRG_RSCRATCH_DBG; \283\284PPC_RFDI; \285b .; \286\287/* continue normal handling for a debug exception... */ \2882: mfspr r4,SPRN_DBSR; \289addi r3,r1,STACK_FRAME_OVERHEAD; \290EXC_XFER_TEMPLATE(DebugException, 0x2008, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, debug_transfer_to_handler, ret_from_debug_exc)291292#define DEBUG_CRIT_EXCEPTION \293START_EXCEPTION(DebugCrit); \294CRITICAL_EXCEPTION_PROLOG; \295\296/* \297* If there is a single step or branch-taken exception in an \298* exception entry sequence, it was probably meant to apply to \299* the code where the exception occurred (since exception entry \300* doesn't turn off DE automatically). We simulate the effect \301* of turning off DE on entry to an exception handler by turning \302* off DE in the CSRR1 value and clearing the debug status. \303*/ \304mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \305andis. r10,r10,(DBSR_IC|DBSR_BT)@h; \306beq+ 2f; \307\308lis r10,KERNELBASE@h; /* check if exception in vectors */ \309ori r10,r10,KERNELBASE@l; \310cmplw r12,r10; \311blt+ 2f; /* addr below exception vectors */ \312\313lis r10,DebugCrit@h; \314ori r10,r10,DebugCrit@l; \315cmplw r12,r10; \316bgt+ 2f; /* addr above exception vectors */ \317\318/* here it looks like we got an inappropriate debug exception. */ \3191: rlwinm r9,r9,0,~MSR_DE; /* clear DE in the CSRR1 value */ \320lis r10,(DBSR_IC|DBSR_BT)@h; /* clear the IC event */ \321mtspr SPRN_DBSR,r10; \322/* restore state and get out */ \323lwz r10,_CCR(r11); \324lwz r0,GPR0(r11); \325lwz r1,GPR1(r11); \326mtcrf 0x80,r10; \327mtspr SPRN_CSRR0,r12; \328mtspr SPRN_CSRR1,r9; \329lwz r9,GPR9(r11); \330lwz r12,GPR12(r11); \331mtspr SPRN_SPRG_WSCRATCH_CRIT,r8; \332BOOKE_LOAD_EXC_LEVEL_STACK(CRIT); /* r8 points to the debug stack */ \333lwz r10,GPR10(r8); \334lwz r11,GPR11(r8); \335mfspr r8,SPRN_SPRG_RSCRATCH_CRIT; \336\337rfci; \338b .; \339\340/* continue normal handling for a critical exception... */ \3412: mfspr r4,SPRN_DBSR; \342addi r3,r1,STACK_FRAME_OVERHEAD; \343EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)344345#define DATA_STORAGE_EXCEPTION \346START_EXCEPTION(DataStorage) \347NORMAL_EXCEPTION_PROLOG; \348mfspr r5,SPRN_ESR; /* Grab the ESR and save it */ \349stw r5,_ESR(r11); \350mfspr r4,SPRN_DEAR; /* Grab the DEAR */ \351EXC_XFER_EE_LITE(0x0300, handle_page_fault)352353#define INSTRUCTION_STORAGE_EXCEPTION \354START_EXCEPTION(InstructionStorage) \355NORMAL_EXCEPTION_PROLOG; \356mfspr r5,SPRN_ESR; /* Grab the ESR and save it */ \357stw r5,_ESR(r11); \358mr r4,r12; /* Pass SRR0 as arg2 */ \359li r5,0; /* Pass zero as arg3 */ \360EXC_XFER_EE_LITE(0x0400, handle_page_fault)361362#define ALIGNMENT_EXCEPTION \363START_EXCEPTION(Alignment) \364NORMAL_EXCEPTION_PROLOG; \365mfspr r4,SPRN_DEAR; /* Grab the DEAR and save it */ \366stw r4,_DEAR(r11); \367addi r3,r1,STACK_FRAME_OVERHEAD; \368EXC_XFER_EE(0x0600, alignment_exception)369370#define PROGRAM_EXCEPTION \371START_EXCEPTION(Program) \372NORMAL_EXCEPTION_PROLOG; \373mfspr r4,SPRN_ESR; /* Grab the ESR and save it */ \374stw r4,_ESR(r11); \375addi r3,r1,STACK_FRAME_OVERHEAD; \376EXC_XFER_STD(0x0700, program_check_exception)377378#define DECREMENTER_EXCEPTION \379START_EXCEPTION(Decrementer) \380NORMAL_EXCEPTION_PROLOG; \381lis r0,TSR_DIS@h; /* Setup the DEC interrupt mask */ \382mtspr SPRN_TSR,r0; /* Clear the DEC interrupt */ \383addi r3,r1,STACK_FRAME_OVERHEAD; \384EXC_XFER_LITE(0x0900, timer_interrupt)385386#define FP_UNAVAILABLE_EXCEPTION \387START_EXCEPTION(FloatingPointUnavailable) \388NORMAL_EXCEPTION_PROLOG; \389beq 1f; \390bl load_up_fpu; /* if from user, just load it up */ \391b fast_exception_return; \3921: addi r3,r1,STACK_FRAME_OVERHEAD; \393EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception)394395#ifndef __ASSEMBLY__396struct exception_regs {397unsigned long mas0;398unsigned long mas1;399unsigned long mas2;400unsigned long mas3;401unsigned long mas6;402unsigned long mas7;403unsigned long srr0;404unsigned long srr1;405unsigned long csrr0;406unsigned long csrr1;407unsigned long dsrr0;408unsigned long dsrr1;409unsigned long saved_ksp_limit;410};411412/* ensure this structure is always sized to a multiple of the stack alignment */413#define STACK_EXC_LVL_FRAME_SIZE _ALIGN_UP(sizeof (struct exception_regs), 16)414415#endif /* __ASSEMBLY__ */416#endif /* __HEAD_BOOKE_H__ */417418419