This patch updates the 40x and Book E Debug exception handling paths
to handle kernel space debug events. It also fixes up the in-kernel
ppc32 kgdb stub to work properly.

Signed-off-by: Matt Porter <mporter at kernel.crashing.org>

diff -Nru a/arch/ppc/kernel/head_44x.S b/arch/ppc/kernel/head_44x.S
--- a/arch/ppc/kernel/head_44x.S        2004-10-29 17:13:29 -07:00
+++ b/arch/ppc/kernel/head_44x.S        2004-10-29 17:13:29 -07:00
@@ -599,64 +599,8 @@
        mfspr   r10, SPRG0
        b       InstructionStorage
 
-/* Check for a single step debug exception while in an exception
- * handler before state has been saved.  This is to catch the case
- * where an instruction that we are trying to single step causes
- * an exception (eg ITLB/DTLB miss) and thus the first instruction of
- * the exception handler generates a single step debug exception.
- *
- * If we get a debug trap on the first instruction of an exception handler,
- * we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is
- * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR).
- * The exception handler was handling a non-critical interrupt, so it will
- * save (and later restore) the MSR via SPRN_SRR1, which will still have
- * the MSR_DE bit set.
- */
        /* Debug Interrupt */
-       START_EXCEPTION(Debug)
-       CRITICAL_EXCEPTION_PROLOG
-
-       /*
-        * 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... */
-
-       /* continue normal handling for a critical exception... */
-1:     mfspr   r4,SPRN_DBSR
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       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 at ha;
-       lwz     r10,crit_r10 at l(r8)
-       lwz     r11,crit_r11 at l(r8)
-       mfspr   r8,SPRG2
-
-       rfci
-       b       .
+       DEBUG_EXCEPTION
 
 /*
  * Local functions
diff -Nru a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S
--- a/arch/ppc/kernel/head_4xx.S        2004-10-29 17:13:29 -07:00
+++ b/arch/ppc/kernel/head_4xx.S        2004-10-29 17:13:29 -07:00
@@ -709,8 +709,20 @@
        EXCEPTION(0x1E00, Trap_1E, UnknownException, EXC_XFER_EE)
        EXCEPTION(0x1F00, Trap_1F, UnknownException, EXC_XFER_EE)
 
-/* 0x2000 - Debug Exception
-*/
+/* Check for a single step debug exception while in an exception
+ * handler before state has been saved.  This is to catch the case
+ * where an instruction that we are trying to single step causes
+ * an exception (eg ITLB/DTLB miss) and thus the first instruction of
+ * the exception handler generates a single step debug exception.
+ *
+ * If we get a debug trap on the first instruction of an exception handler,
+ * we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is
+ * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR).
+ * The exception handler was handling a non-critical interrupt, so it will
+ * save (and later restore) the MSR via SPRN_SRR1, which will still have
+ * the MSR_DE bit set.
+ */
+       /* 0x2000 - Debug Exception */
        START_EXCEPTION(0x2000, DebugTrap)
        CRITICAL_EXCEPTION_PROLOG
 
@@ -723,21 +735,20 @@
         * off DE in the SRR3 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_IR|MSR_PR     /* check supervisor + MMU off */
-       beq     2f                      /* branch if we need to fix it up... */
+       andis.  r10,r10,DBSR_IC at h
+       beq+    2f
 
-       /* continue normal handling for a critical exception... */
-1:     mfspr   r4,SPRN_DBSR
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       EXC_XFER_TEMPLATE(DebugException, 0x2002, \
-               (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
-               NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)
+       andi.   r10,r9,MSR_IR|MSR_PR    /* check supervisor + MMU off */
+       beq     1f                      /* branch and fix it up */
+
+       mfspr   r10,SPRN_SRR2           /* Faulting instruction address */
+       cmplwi  r10,0x2100
+       bgt+    2f                      /* address above exception vectors */
 
        /* here it looks like we got an inappropriate debug exception. */
-2:     rlwinm  r9,r9,0,~MSR_DE         /* clear DE in the SRR3 value */
-       mtspr   SPRN_DBSR,r10           /* clear the IC/BT debug intr status */
+1:     rlwinm  r9,r9,0,~MSR_DE         /* clear DE in the SRR3 value */
+       lis     r10,DBSR_IC at h                /* clear the IC event */
+       mtspr   SPRN_DBSR,r10
        /* restore state and get out */
        lwz     r10,_CCR(r11)
        lwz     r0,GPR0(r11)
@@ -752,6 +763,13 @@
        PPC405_ERR77_SYNC
        rfci
        b       .
+
+       /* continue normal handling for a critical exception... */
+2:     mfspr   r4,SPRN_DBSR
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       EXC_XFER_TEMPLATE(DebugException, 0x2002, \
+               (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
+               NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)
 
 /*
  * The other Data TLB exceptions bail out to this point
diff -Nru a/arch/ppc/kernel/head_booke.h b/arch/ppc/kernel/head_booke.h
--- a/arch/ppc/kernel/head_booke.h      2004-10-29 17:13:29 -07:00
+++ b/arch/ppc/kernel/head_booke.h      2004-10-29 17:13:29 -07:00
@@ -237,4 +237,70 @@
                          ret_from_except)
 
 
+/* Check for a single step debug exception while in an exception
+ * handler before state has been saved.  This is to catch the case
+ * where an instruction that we are trying to single step causes
+ * an exception (eg ITLB/DTLB miss) and thus the first instruction of
+ * the exception handler generates a single step debug exception.
+ *
+ * If we get a debug trap on the first instruction of an exception handler,
+ * we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is
+ * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR).
+ * The exception handler was handling a non-critical interrupt, so it will
+ * save (and later restore) the MSR via SPRN_CSRR1, which will still have
+ * the MSR_DE bit set.
+ */
+#define DEBUG_EXCEPTION                                                        
      \
+       START_EXCEPTION(Debug);                                               \
+       CRITICAL_EXCEPTION_PROLOG;                                            \
+                                                                             \
+       /*                                                                    \
+        * 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 CSRR1 value and clearing the debug status.           \
+        */                                                                   \
+       mfspr   r10,SPRN_DBSR;          /* check single-step/branch taken */  \
+       andis.  r10,r10,DBSR_IC at h;                                         \
+       beq+    2f;                                                           \
+                                                                             \
+       lis     r10,KERNELBASE at h;    /* check if exception in vectors */   \
+       ori     r10,r10,KERNELBASE at l;                                        
      \
+       cmplw   r12,r10;                                                      \
+       blt+    2f;                     /* addr below exception vectors */    \
+                                                                             \
+       lis     r10,Debug at h;                                               \
+       ori     r10,r10,Debug at l;                                           \
+       cmplw   r12,r10;                                                      \
+       bgt+    2f;                     /* addr above exception vectors */    \
+                                                                             \
+       /* here it looks like we got an inappropriate debug exception. */     \
+1:     rlwinm  r9,r9,0,~MSR_DE;        /* clear DE in the CSRR1 value */     \
+       lis     r10,DBSR_IC at h;               /* clear the IC event */        
      \
+       mtspr   SPRN_DBSR,r10;                                                \
+       /* 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);                                                 \
+       lwz     r12,GPR12(r11);                                               \
+       mtspr   SPRG2,r8;               /* SPRG2 only used in criticals */    \
+       lis     r8,crit_save at ha;                                           \
+       lwz     r10,crit_r10 at l(r8);                                        \
+       lwz     r11,crit_r11 at l(r8);                                        \
+       mfspr   r8,SPRG2;                                                     \
+                                                                             \
+       rfci;                                                                 \
+       b       .;                                                            \
+                                                                             \
+       /* continue normal handling for a critical exception... */            \
+2:     mfspr   r4,SPRN_DBSR;                                                 \
+       addi    r3,r1,STACK_FRAME_OVERHEAD;                                   \
+       EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & 
~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)
+
 #endif /* __HEAD_BOOKE_H__ */
diff -Nru a/arch/ppc/kernel/head_e500.S b/arch/ppc/kernel/head_e500.S
--- a/arch/ppc/kernel/head_e500.S       2004-10-29 17:13:29 -07:00
+++ b/arch/ppc/kernel/head_e500.S       2004-10-29 17:13:29 -07:00
@@ -668,64 +668,8 @@
        /* Performance Monitor */
        EXCEPTION(0x2060, PerformanceMonitor, UnknownException, EXC_XFER_EE)
 
-/* Check for a single step debug exception while in an exception
- * handler before state has been saved.  This is to catch the case
- * where an instruction that we are trying to single step causes
- * an exception (eg ITLB/DTLB miss) and thus the first instruction of
- * the exception handler generates a single step debug exception.
- *
- * If we get a debug trap on the first instruction of an exception handler,
- * we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is
- * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR).
- * The exception handler was handling a non-critical interrupt, so it will
- * save (and later restore) the MSR via SPRN_SRR1, which will still have
- * the MSR_DE bit set.
- */
        /* Debug Interrupt */
-       START_EXCEPTION(Debug)
-       CRITICAL_EXCEPTION_PROLOG
-
-       /*
-        * 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... */
-
-       /* continue normal handling for a critical exception... */
-1:     mfspr   r4,SPRN_DBSR
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       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 at ha;
-       lwz     r10,crit_r10 at l(r8)
-       lwz     r11,crit_r11 at l(r8)
-       mfspr   r8,SPRG2
-
-       rfci
-       b       .
+       DEBUG_EXCEPTION
 
 /*
  * Local functions
diff -Nru a/arch/ppc/kernel/ppc-stub.c b/arch/ppc/kernel/ppc-stub.c
--- a/arch/ppc/kernel/ppc-stub.c        2004-10-29 17:13:29 -07:00
+++ b/arch/ppc/kernel/ppc-stub.c        2004-10-29 17:13:29 -07:00
@@ -498,7 +498,7 @@
        unsigned int tt;                /* Trap type code for powerpc */
        unsigned char signo;            /* Signal that we map this trap into */
 } hard_trap_info[] = {
-#if defined(CONFIG_40x)
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
        { 0x100, SIGINT  },             /* critical input interrupt */
        { 0x200, SIGSEGV },             /* machine check */
        { 0x300, SIGSEGV },             /* data storage */
@@ -521,7 +521,7 @@
        ** 0x1100  data TLB miss
        ** 0x1200  instruction TLB miss
        */
-       { 0x2000, SIGTRAP},             /* debug */
+       { 0x2002, SIGTRAP},             /* debug */
 #else
        { 0x200, SIGSEGV },             /* machine check */
        { 0x300, SIGSEGV },             /* address error (store) */
@@ -602,11 +602,6 @@
        sigval = computeSignal(regs->trap);
        ptr = remcomOutBuffer;
 
-#if defined(CONFIG_40x)
-       *ptr++ = 'S';
-       *ptr++ = hexchars[sigval >> 4];
-       *ptr++ = hexchars[sigval & 0xf];
-#else
        *ptr++ = 'T';
        *ptr++ = hexchars[sigval >> 4];
        *ptr++ = hexchars[sigval & 0xf];
@@ -620,8 +615,6 @@
        *ptr++ = ':';
        ptr = mem2hex(((char *)regs) + SP_REGNUM*4, ptr, 4);
        *ptr++ = ';';
-#endif
-
        *ptr++ = 0;
 
        putpacket(remcomOutBuffer);
@@ -774,10 +767,6 @@
  * some location may have changed something that is in the instruction cache.
  */
                        kgdb_flush_cache_all();
-#if defined(CONFIG_40x)
-                       strcpy(remcomOutBuffer, "OK");
-                       putpacket(remcomOutBuffer);
-#endif
                        mtmsr(msr);
 
                        kgdb_interruptible(1);
@@ -791,10 +780,9 @@
 
                case 's':
                        kgdb_flush_cache_all();
-#if defined(CONFIG_40x)
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+                       mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC);
                        regs->msr |= MSR_DE;
-                       regs->dbcr0 |= (DBCR0_IDM | DBCR0_IC);
-                       mtmsr(msr);
 #else
                        regs->msr |= MSR_SE;
 #endif
diff -Nru a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c
--- a/arch/ppc/kernel/ptrace.c  2004-10-29 17:13:29 -07:00
+++ b/arch/ppc/kernel/ptrace.c  2004-10-29 17:13:29 -07:00
@@ -35,7 +35,7 @@
 /*
  * Set of msr bits that gdb can change on behalf of a process.
  */
-#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
 #define MSR_DEBUGCHANGE        0
 #else
 #define MSR_DEBUGCHANGE        (MSR_SE | MSR_BE)
@@ -201,9 +201,9 @@
        struct pt_regs *regs = task->thread.regs;
 
        if (regs != NULL) {
-#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
                task->thread.dbcr0 = DBCR0_IDM | DBCR0_IC;
-               /* MSR.DE should already be set */
+               regs->msr |= MSR_DE;
 #else
                regs->msr |= MSR_SE;
 #endif
@@ -216,8 +216,9 @@
        struct pt_regs *regs = task->thread.regs;
 
        if (regs != NULL) {
-#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
                task->thread.dbcr0 = 0;
+               regs->msr &= ~MSR_DE;
 #else
                regs->msr &= ~MSR_SE;
 #endif
diff -Nru a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
--- a/arch/ppc/kernel/traps.c   2004-10-29 17:13:29 -07:00
+++ b/arch/ppc/kernel/traps.c   2004-10-29 17:13:29 -07:00
@@ -647,22 +647,22 @@
 }
 #endif /* CONFIG_8xx */
 
-#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
 
 void DebugException(struct pt_regs *regs, unsigned long debug_status)
 {
-#if 0
-       if (debug_status & DBSR_TIE) {          /* trap instruction*/
-               if (!user_mode(regs) && debugger_bpt(regs))
-                       return;
-               _exception(SIGTRAP, regs, 0, 0);
-
-       }
-#endif
        if (debug_status & DBSR_IC) {   /* instruction completion */
-               if (!user_mode(regs) && debugger_sstep(regs))
-                       return;
-               current->thread.dbcr0 &= ~DBCR0_IC;
+               regs->msr &= ~MSR_DE;
+               if (user_mode(regs)) {
+                       current->thread.dbcr0 &= ~DBCR0_IC;
+               } else {
+                       /* Disable instruction completion */
+                       mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~DBCR0_IC);
+                       /* Clear the instruction completion event */
+                       mtspr(SPRN_DBSR, DBSR_IC);
+                       if (debugger_sstep(regs))
+                               return;
+               }
                _exception(SIGTRAP, regs, TRAP_TRACE, 0);
        }
 }
diff -Nru a/include/asm-ppc/reg_booke.h b/include/asm-ppc/reg_booke.h
--- a/include/asm-ppc/reg_booke.h       2004-10-29 17:13:29 -07:00
+++ b/include/asm-ppc/reg_booke.h       2004-10-29 17:13:29 -07:00
@@ -63,9 +63,9 @@
 
 /* Default MSR for kernel mode. */
 #if defined (CONFIG_40x)
-#define MSR_KERNEL     (MSR_ME|MSR_RI|MSR_IR|MSR_DR|MSR_CE|MSR_DE)
+#define MSR_KERNEL     (MSR_ME|MSR_RI|MSR_IR|MSR_DR|MSR_CE)
 #elif defined(CONFIG_BOOKE)
-#define MSR_KERNEL     (MSR_ME|MSR_RI|MSR_CE|MSR_DE)
+#define MSR_KERNEL     (MSR_ME|MSR_RI|MSR_CE)
 #endif
 
 /* Special Purpose Registers (SPRNs)*/

Reply via email to