Blackfin arch: Fix bug - skip single step in high priority interrupt handler instead...
authorSonic Zhang <sonic.zhang@analog.com>
Sat, 26 Jul 2008 10:54:38 +0000 (18:54 +0800)
committerBryan Wu <cooloney@kernel.org>
Sat, 26 Jul 2008 10:54:38 +0000 (18:54 +0800)
Skip single step if event priority of current instruction is higher than
that of the first instruction, from which gdb starts single step.

Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
Signed-off-by: Bryan Wu <cooloney@kernel.org>
arch/blackfin/kernel/kgdb.c
arch/blackfin/mach-common/entry.S

index a9c15515bfd7347dd62fcc536c8b2194fe5a4c25..a1f9641a6425d6158ebf21f4a71f4df867fd44ea 100644 (file)
@@ -203,6 +203,8 @@ struct hw_breakpoint {
 
 int kgdb_arch_init(void)
 {
+       debugger_step = 0;
+
        kgdb_remove_all_hw_break();
        return 0;
 }
@@ -368,6 +370,7 @@ int kgdb_arch_handle_exception(int exceptionVector, int signo,
        char *ptr;
        int newPC;
        int wp_status;
+       int i;
 
        switch (remcom_in_buffer[0]) {
        case 'c':
@@ -392,7 +395,18 @@ int kgdb_arch_handle_exception(int exceptionVector, int signo,
                /* set the trace bit if we're stepping */
                if (remcom_in_buffer[0] == 's') {
                        linux_regs->syscfg |= 0x1;
-                       debugger_step = 1;
+                       debugger_step = linux_regs->ipend;
+                       debugger_step >>= 6;
+                       for (i = 10; i > 0; i--, debugger_step >>= 1)
+                               if (debugger_step & 1)
+                                       break;
+                       /* i indicate event priority of current stopped instruction
+                        * user space instruction is 0, IVG15 is 1, IVTMR is 10.
+                        * debugger_step > 0 means in single step mode
+                        */
+                       debugger_step = i + 1;
+               } else {
+                       debugger_step = 0;
                }
 
                wp_status = bfin_read_WPSTAT();
index 038f70e0be65cb4adcb1ada19b07f6d75eba7d8b..eceb484d90f9da1144a1c1afca1e019f29a3f672 100644 (file)
@@ -158,23 +158,45 @@ ENTRY(_ex_single_step)
        cc = r7 == r6;
        if cc jump _bfin_return_from_exception;
 
+       /* Don't do single step in hardware exception handler */
+        p5.l = lo(IPEND);
+        p5.h = hi(IPEND);
+       r6 = [p5];
+       cc = bittst(r6, 5);
+       if cc jump _bfin_return_from_exception;
+
+#ifdef CONFIG_KGDB
+       /* skip single step if current interrupt priority is higher than
+        * that of the first instruction, from which gdb starts single step */
+       r6 >>= 6;
+       r7 = 10;
+.Lfind_priority_start:
+       cc = bittst(r6, 0);
+       if cc jump .Lfind_priority_done;
+       r6 >>= 1;
+       r7 += -1;
+       cc = r7 == 0;
+       if cc jump .Lfind_priority_done;
+       jump.s .Lfind_priority_start;
+.Lfind_priority_done:
+       p4.l = _debugger_step;
+       p4.h = _debugger_step;
+       r6 = [p4];
+       cc = r6 == 0;
+       if cc jump .Ldo_single_step;
+       r6 += -1;
+       cc = r6 < r7;
+       if cc jump _bfin_return_from_exception;
+.Ldo_single_step:
+#endif
+
        /* If we were in user mode, do the single step normally.  */
-       p5.l = lo(IPEND);
-       p5.h = hi(IPEND);
        r6 = [p5];
        r7 = 0xffe0 (z);
        r7 = r7 & r6;
        cc = r7 == 0;
-       if !cc jump 1f;
-
-       /* Single stepping only a single instruction, so clear the trace
-        * bit here.  */
-       r7 = syscfg;
-       bitclr (r7, 0);
-       syscfg = R7;
-       jump _ex_trap_c;
+       if cc jump 1f;
 
-1:
        /*
         * We were in an interrupt handler.  By convention, all of them save
         * SYSCFG with their first instruction, so by checking whether our
@@ -202,11 +224,15 @@ ENTRY(_ex_single_step)
        cc = R7 == R6;
        if !cc jump _bfin_return_from_exception;
 
+1:
+       /* Single stepping only a single instruction, so clear the trace
+        * bit here.  */
        r7 = syscfg;
        bitclr (r7, 0);
        syscfg = R7;
 
-       /* Fall through to _bfin_return_from_exception.  */
+       jump _ex_trap_c;
+
 ENDPROC(_ex_single_step)
 
 ENTRY(_bfin_return_from_exception)