From: Matt Porter Adds general Book E debug exception support and PPC44x-specific debug exception implementation. --- 25-akpm/arch/ppc/kernel/entry.S | 44 ++++++--- 25-akpm/arch/ppc/kernel/head_44x.S | 165 +++++++++++++++++------------------- 25-akpm/include/asm-ppc/reg_booke.h | 1 3 files changed, 115 insertions(+), 95 deletions(-) diff -puN arch/ppc/kernel/entry.S~ppc32-add-book-e--ppc44x-specific-exception-support arch/ppc/kernel/entry.S --- 25/arch/ppc/kernel/entry.S~ppc32-add-book-e--ppc44x-specific-exception-support 2004-05-10 19:10:27.199599200 -0700 +++ 25-akpm/arch/ppc/kernel/entry.S 2004-05-10 19:10:27.206598136 -0700 @@ -44,13 +44,28 @@ #define LOAD_MSR_KERNEL(r, x) li r,(x) #endif -#ifdef CONFIG_4xx +#ifdef CONFIG_BOOKE +#define COR r8 +#define BOOKE_LOAD_COR lis COR,crit_save@ha +#define BOOKE_REST_COR mfspr COR,SPRG2 +#define BOOKE_SAVE_COR mtspr SPRG2,COR +#else +#define COR 0 +#define BOOKE_LOAD_COR +#define BOOKE_REST_COR +#define BOOKE_SAVE_COR +#endif + +#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) .globl crit_transfer_to_handler crit_transfer_to_handler: - lwz r0,crit_r10@l(0) + BOOKE_SAVE_COR + BOOKE_LOAD_COR + lwz r0,crit_r10@l(COR) stw r0,GPR10(r11) - lwz r0,crit_r11@l(0) + lwz r0,crit_r11@l(COR) stw r0,GPR11(r11) + BOOKE_REST_COR /* fall through */ #endif @@ -695,12 +710,14 @@ ret_from_crit_exc: mtlr r11 lwz r10,_CCR(r1) mtcrf 0xff,r10 +#ifdef CONFIG_40x /* avoid any possible TLB misses here by turning off MSR.DR, we * assume the instructions here are mapped by a pinned TLB entry */ li r10,MSR_IR mtmsr r10 isync tophys(r1, r1) +#endif lwz r9,_DEAR(r1) lwz r10,_ESR(r1) mtspr SPRN_DEAR,r9 @@ -711,27 +728,30 @@ ret_from_crit_exc: mtspr CSRR1,r12 lwz r9,GPR9(r1) lwz r12,GPR12(r1) - lwz r10,crit_sprg0@l(0) + BOOKE_SAVE_COR + BOOKE_LOAD_COR + lwz r10,crit_sprg0@l(COR) mtspr SPRN_SPRG0,r10 - lwz r10,crit_sprg1@l(0) + lwz r10,crit_sprg1@l(COR) mtspr SPRN_SPRG1,r10 - lwz r10,crit_sprg4@l(0) + lwz r10,crit_sprg4@l(COR) mtspr SPRN_SPRG4,r10 - lwz r10,crit_sprg5@l(0) + lwz r10,crit_sprg5@l(COR) mtspr SPRN_SPRG5,r10 - lwz r10,crit_sprg6@l(0) + lwz r10,crit_sprg6@l(COR) mtspr SPRN_SPRG6,r10 - lwz r10,crit_sprg7@l(0) + lwz r10,crit_sprg7@l(COR) mtspr SPRN_SPRG7,r10 - lwz r10,crit_srr0@l(0) + lwz r10,crit_srr0@l(COR) mtspr SRR0,r10 - lwz r10,crit_srr1@l(0) + lwz r10,crit_srr1@l(COR) mtspr SRR1,r10 - lwz r10,crit_pid@l(0) + lwz r10,crit_pid@l(COR) mtspr SPRN_PID,r10 lwz r10,GPR10(r1) lwz r11,GPR11(r1) lwz r1,GPR1(r1) + BOOKE_REST_COR PPC405_ERR77_SYNC rfci b . /* prevent prefetch past rfci */ diff -puN arch/ppc/kernel/head_44x.S~ppc32-add-book-e--ppc44x-specific-exception-support arch/ppc/kernel/head_44x.S --- 25/arch/ppc/kernel/head_44x.S~ppc32-add-book-e--ppc44x-specific-exception-support 2004-05-10 19:10:27.200599048 -0700 +++ 25-akpm/arch/ppc/kernel/head_44x.S 2004-05-10 19:10:27.208597832 -0700 @@ -313,7 +313,7 @@ skpinv: addi r4,r4,1 /* Increment */ #define NORMAL_EXCEPTION_PROLOG \ mtspr SPRN_SPRG0,r10; /* save two registers to work with */\ mtspr SPRN_SPRG1,r11; \ - mtspr SPRN_SPRG2,r1; \ + mtspr SPRN_SPRG4W,r1; \ mfcr r10; /* save CR in r10 for now */\ mfspr r11,SPRN_SRR1; /* check whether user or kernel */\ andi. r11,r11,MSR_PR; \ @@ -332,7 +332,7 @@ skpinv: addi r4,r4,1 /* Increment */ stw r12,GPR11(r11); \ mflr r10; \ stw r10,_LINK(r11); \ - mfspr r10,SPRG2; \ + mfspr r10,SPRG4R; \ mfspr r12,SRR0; \ stw r10,GPR1(r11); \ mfspr r9,SRR1; \ @@ -348,30 +348,36 @@ skpinv: addi r4,r4,1 /* Increment */ * can potentially occur at any point during normal exception processing. * Thus we cannot use the same SPRG registers as the normal prolog above. * Instead we use a couple of words of memory at low physical addresses. - * This is OK since we don't support SMP on these processors. + * This is OK since we don't support SMP on these processors. For Book E + * processors, we also have a reserved register (SPRG2) that is only used + * in critical exceptions so we can free up a GPR to use as the base for + * indirect access to the critical exception save area. This is necessary + * since the MMU is always on and the save area is offset from KERNELBASE. */ -/* XXX but we don't have RAM mapped at 0 in space 0 -- paulus. */ #define CRITICAL_EXCEPTION_PROLOG \ - stw r10,crit_r10@l(0); /* save two registers to work with */\ - stw r11,crit_r11@l(0); \ + mtspr SPRG2,r8; /* SPRG2 only used in criticals */ \ + lis r8,crit_save@ha; \ + stw r10,crit_r10@l(r8); \ + stw r11,crit_r11@l(r8); \ mfspr r10,SPRG0; \ - stw r10,crit_sprg0@l(0); \ + stw r10,crit_sprg0@l(r8); \ mfspr r10,SPRG1; \ - stw r10,crit_sprg1@l(0); \ + stw r10,crit_sprg1@l(r8); \ mfspr r10,SPRG4R; \ - stw r10,crit_sprg4@l(0); \ + stw r10,crit_sprg4@l(r8); \ mfspr r10,SPRG5R; \ - stw r10,crit_sprg5@l(0); \ + stw r10,crit_sprg5@l(r8); \ mfspr r10,SPRG6R; \ - stw r10,crit_sprg6@l(0); \ + stw r10,crit_sprg6@l(r8); \ mfspr r10,SPRG7R; \ - stw r10,crit_sprg7@l(0); \ + stw r10,crit_sprg7@l(r8); \ mfspr r10,SPRN_PID; \ - stw r10,crit_pid@l(0); \ + stw r10,crit_pid@l(r8); \ mfspr r10,SRR0; \ - stw r10,crit_srr0@l(0); \ + stw r10,crit_srr0@l(r8); \ mfspr r10,SRR1; \ - stw r10,crit_srr1@l(0); \ + stw r10,crit_srr1@l(r8); \ + mfspr r8,SPRG2; /* SPRG2 only used in criticals */ \ mfcr r10; /* save CR in r10 for now */\ mfspr r11,SPRN_CSRR1; /* check whether user or kernel */\ andi. r11,r11,MSR_PR; \ @@ -383,7 +389,6 @@ skpinv: addi r4,r4,1 /* Increment */ lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ addi r11,r11,THREAD_SIZE; \ 1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ - tophys(r11,r11); \ stw r10,_CCR(r11); /* save various registers */\ stw r12,GPR12(r11); \ stw r9,GPR9(r11); \ @@ -780,61 +785,50 @@ interrupt_base: * the MSR_DE bit set. */ /* Debug Interrupt */ - CRITICAL_EXCEPTION(0x2000, Debug, DebugException) -#if 0 START_EXCEPTION(Debug) - /* This first instruction was already executed by the exception - * handler and must be the first instruction of every exception - * handler. - */ - mtspr SPRN_SPRG0,r10 /* Save some working registers... */ - mtspr SPRN_SPRG1,r11 - mtspr SPRN_SPRG4W,r12 - mfcr r10 /* ..and the cr because we change it */ - - mfspr r11,SPRN_CSRR1 /* MSR at the time of fault */ - andi. r11,r11,MSR_PR - bne+ 2f /* trapped from problem state */ - - mfspr r11,SPRN_CSRR0 /* Faulting instruction address */ - lis r12, KERNELBASE@h - ori r12, r12, KERNELBASE@l - cmplw r11,r12 - blt+ 2f /* addr below exception vectors */ - - lis r12, Debug@h - ori r12, r12, Debug@l - cmplw r11,r12 - bgt+ 2f /* addr above TLB exception vectors */ - - lis r11,DBSR_IC@h /* Remove the trap status */ - mtspr SPRN_DBSR,r11 - - mfspr r11,SPRN_CSRR1 - rlwinm r11,r11,0,23,21 /* clear MSR_DE */ - mtspr SPRN_CSRR1, r11 /* restore MSR at rcfi without DE */ - - mtcrf 0xff,r10 /* restore registers */ - mfspr r12,SPRN_SPRG4R - mfspr r11,SPRN_SPRG1 - mfspr r10,SPRN_SPRG0 - - sync - rfci /* return to the exception handler */ - b . /* prevent prefetch past rfci */ + CRITICAL_EXCEPTION_PROLOG -2: - mtcrf 0xff,r10 /* restore registers */ - mfspr r12,SPRN_SPRG4R - mfspr r11,SPRN_SPRG1 - mfspr r10,SPRN_SPRG0 + /* + * If this is a single step or branch-taken exception in an + * exception entry sequence, it was probably meant to apply to + * the code where the exception occurred (since exception entry + * doesn't turn off DE automatically). We simulate the effect + * of turning off DE on entry to an exception handler by turning + * off DE in the CSRR1 value and clearing the debug status. + */ + mfspr r10,SPRN_DBSR /* check single-step/branch taken */ + andis. r10,r10,(DBSR_IC|DBSR_BT)@h + beq+ 1f + andi. r0,r9,MSR_PR /* check supervisor */ + beq 2f /* branch if we need to fix it up... */ - CRIT_EXCEPTION_PROLOG + /* continue normal handling for a critical exception... */ +1: mfspr r4,SPRN_DBSR addi r3,r1,STACK_FRAME_OVERHEAD - li r7,CRIT_EXC; - li r9,MSR_KERNEL - FINISH_EXCEPTION(DebugException) -#endif + EXC_XFER_TEMPLATE(DebugException, 0x2002, \ + (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ + NOCOPY, crit_transfer_to_handler, ret_from_crit_exc) + + /* here it looks like we got an inappropriate debug exception. */ +2: rlwinm r9,r9,0,~MSR_DE /* clear DE in the CSRR1 value */ + mtspr SPRN_DBSR,r10 /* clear the IC/BT debug intr status */ + /* restore state and get out */ + lwz r10,_CCR(r11) + lwz r0,GPR0(r11) + lwz r1,GPR1(r11) + mtcrf 0x80,r10 + mtspr CSRR0,r12 + mtspr CSRR1,r9 + lwz r9,GPR9(r11) + + mtspr SPRG2,r8; /* SPRG2 only used in criticals */ + lis r8,crit_save@ha; + lwz r10,crit_r10@l(r8) + lwz r11,crit_r11@l(r8) + mfspr r8,SPRG2 + + rfci + b . /* * Local functions @@ -993,24 +987,13 @@ critical_stack_top: .previous /* - * This space gets a copy of optional info passed to us by the bootstrap - * which is used to pass parameters into the kernel like root=/dev/sda1, etc. - */ -_GLOBAL(cmd_line) - .space 512 - -/* - * Room for two PTE pointers, usually the kernel and current user pointers - * to their respective root page table. - */ -abatron_pteptrs: - .space 8 - -/* * This area is used for temporarily saving registers during the - * critical exception prolog. + * critical exception prolog. It must always follow the page + * aligned allocations, so it starts on a page boundary, ensuring + * that all crit_save areas are in a single page. */ -crit_save: +_GLOBAL(crit_save) + .space 4 _GLOBAL(crit_r10) .space 4 _GLOBAL(crit_r11) @@ -1033,3 +1016,19 @@ _GLOBAL(crit_srr0) .space 4 _GLOBAL(crit_srr1) .space 4 + +/* + * This space gets a copy of optional info passed to us by the bootstrap + * which is used to pass parameters into the kernel like root=/dev/sda1, etc. + */ +_GLOBAL(cmd_line) + .space 512 + +/* + * Room for two PTE pointers, usually the kernel and current user pointers + * to their respective root page table. + */ +abatron_pteptrs: + .space 8 + + diff -puN include/asm-ppc/reg_booke.h~ppc32-add-book-e--ppc44x-specific-exception-support include/asm-ppc/reg_booke.h --- 25/include/asm-ppc/reg_booke.h~ppc32-add-book-e--ppc44x-specific-exception-support 2004-05-10 19:10:27.202598744 -0700 +++ 25-akpm/include/asm-ppc/reg_booke.h 2004-05-10 19:10:27.209597680 -0700 @@ -144,6 +144,7 @@ do { \ */ #ifdef CONFIG_BOOKE #define DBSR_IC 0x08000000 /* Instruction Completion */ +#define DBSR_BT 0x04000000 /* Branch Taken */ #define DBSR_TIE 0x01000000 /* Trap Instruction Event */ #endif #ifdef CONFIG_40x _