powerpc/fsl-booke64: Add support for Debug Level exception handler
authorKumar Gala <galak@kernel.crashing.org>
Wed, 6 Apr 2011 05:18:48 +0000 (00:18 -0500)
committerKumar Gala <galak@kernel.crashing.org>
Thu, 19 May 2011 05:36:42 +0000 (00:36 -0500)
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
arch/powerpc/include/asm/cputable.h
arch/powerpc/kernel/exceptions-64e.S
arch/powerpc/kernel/setup_64.c

index 4efbfb3f325463ba53c80add9975f8c77ddcb8bf..c0d842cfd012c7cf8f2469c2548ee6dca22e3469 100644 (file)
@@ -157,6 +157,7 @@ extern const char *powerpc_base_platform;
 #define CPU_FTR_476_DD2                        ASM_CONST(0x0000000000010000)
 #define CPU_FTR_NEED_COHERENT          ASM_CONST(0x0000000000020000)
 #define CPU_FTR_NO_BTIC                        ASM_CONST(0x0000000000040000)
+#define CPU_FTR_DEBUG_LVL_EXC          ASM_CONST(0x0000000000080000)
 #define CPU_FTR_NODSISRALIGN           ASM_CONST(0x0000000000100000)
 #define CPU_FTR_PPC_LE                 ASM_CONST(0x0000000000200000)
 #define CPU_FTR_REAL_LE                        ASM_CONST(0x0000000000400000)
@@ -385,7 +386,8 @@ extern const char *powerpc_base_platform;
            CPU_FTR_DBELL)
 #define CPU_FTRS_E5500 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \
            CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \
-           CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD)
+           CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
+           CPU_FTR_DEBUG_LVL_EXC)
 #define CPU_FTRS_GENERIC_32    (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN)
 
 /* 64-bit CPUs */
index 4d0abb4930a1411521544407af481279bbafff40..cf27a8fa0d29d8f7f69557468ae52971505496f8 100644 (file)
@@ -253,9 +253,6 @@ exception_marker:
        .balign 0x1000
        .globl interrupt_base_book3e
 interrupt_base_book3e:                                 /* fake trap */
-       /* Note: If real debug exceptions are supported by the HW, the vector
-        * below will have to be patched up to point to an appropriate handler
-        */
        EXCEPTION_STUB(0x000, machine_check)            /* 0x0200 */
        EXCEPTION_STUB(0x020, critical_input)           /* 0x0580 */
        EXCEPTION_STUB(0x040, debug_crit)               /* 0x0d00 */
@@ -455,6 +452,68 @@ interrupt_end_book3e:
 kernel_dbg_exc:
        b       .       /* NYI */
 
+/* Debug exception as a debug interrupt*/
+       START_EXCEPTION(debug_debug);
+       DBG_EXCEPTION_PROLOG(0xd00, PROLOG_ADDITION_2REGS)
+
+       /*
+        * If there 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 DSRR1 value and clearing the debug status.
+        */
+
+       mfspr   r14,SPRN_DBSR           /* check single-step/branch taken */
+       andis.  r15,r14,DBSR_IC@h
+       beq+    1f
+
+       LOAD_REG_IMMEDIATE(r14,interrupt_base_book3e)
+       LOAD_REG_IMMEDIATE(r15,interrupt_end_book3e)
+       cmpld   cr0,r10,r14
+       cmpld   cr1,r10,r15
+       blt+    cr0,1f
+       bge+    cr1,1f
+
+       /* here it looks like we got an inappropriate debug exception. */
+       lis     r14,DBSR_IC@h           /* clear the IC event */
+       rlwinm  r11,r11,0,~MSR_DE       /* clear DE in the DSRR1 value */
+       mtspr   SPRN_DBSR,r14
+       mtspr   SPRN_DSRR1,r11
+       lwz     r10,PACA_EXDBG+EX_CR(r13)       /* restore registers */
+       ld      r1,PACA_EXDBG+EX_R1(r13)
+       ld      r14,PACA_EXDBG+EX_R14(r13)
+       ld      r15,PACA_EXDBG+EX_R15(r13)
+       mtcr    r10
+       ld      r10,PACA_EXDBG+EX_R10(r13)      /* restore registers */
+       ld      r11,PACA_EXDBG+EX_R11(r13)
+       mfspr   r13,SPRN_SPRG_DBG_SCRATCH
+       rfdi
+
+       /* Normal debug exception */
+       /* XXX We only handle coming from userspace for now since we can't
+        *     quite save properly an interrupted kernel state yet
+        */
+1:     andi.   r14,r11,MSR_PR;         /* check for userspace again */
+       beq     kernel_dbg_exc;         /* if from kernel mode */
+
+       /* Now we mash up things to make it look like we are coming on a
+        * normal exception
+        */
+       mfspr   r15,SPRN_SPRG_DBG_SCRATCH
+       mtspr   SPRN_SPRG_GEN_SCRATCH,r15
+       mfspr   r14,SPRN_DBSR
+       EXCEPTION_COMMON(0xd00, PACA_EXDBG, INTS_DISABLE_ALL)
+       std     r14,_DSISR(r1)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       mr      r4,r14
+       ld      r14,PACA_EXDBG+EX_R14(r13)
+       ld      r15,PACA_EXDBG+EX_R15(r13)
+       bl      .save_nvgprs
+       bl      .DebugException
+       b       .ret_from_except
+
 /* Doorbell interrupt */
        MASKABLE_EXCEPTION(0x2070, doorbell, .doorbell_exception, ACK_NONE)
 
index c2ec0a12e14f868166fa45c9d0934258678aa13c..a88bf2713d4175a5845ff33b37fe340a4b20518a 100644 (file)
@@ -62,6 +62,7 @@
 #include <asm/udbg.h>
 #include <asm/kexec.h>
 #include <asm/mmu_context.h>
+#include <asm/code-patching.h>
 
 #include "setup.h"
 
@@ -477,6 +478,9 @@ static void __init irqstack_early_init(void)
 #ifdef CONFIG_PPC_BOOK3E
 static void __init exc_lvl_early_init(void)
 {
+       extern unsigned int interrupt_base_book3e;
+       extern unsigned int exc_debug_debug_book3e;
+
        unsigned int i;
 
        for_each_possible_cpu(i) {
@@ -487,6 +491,10 @@ static void __init exc_lvl_early_init(void)
                mcheckirq_ctx[i] = (struct thread_info *)
                        __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
        }
+
+       if (cpu_has_feature(CPU_FTR_DEBUG_LVL_EXC))
+               patch_branch(&interrupt_base_book3e + (0x040 / 4) + 1,
+                            (unsigned long)&exc_debug_debug_book3e, 0);
 }
 #else
 #define exc_lvl_early_init()