]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/blackfin/kernel/traps.c
Blackfin arch: Fix bug - kernel build with config kernel debugging with remote gdb...
[linux-2.6-omap-h63xx.git] / arch / blackfin / kernel / traps.c
index ad922ab915438ef3d66820809285e1f9a8477deb..1a3c4daf557a8f10bc79051e68be1ab638a6b7d9 100644 (file)
 #include <linux/fs.h>
 #include <asm/traps.h>
 #include <asm/cacheflush.h>
+#include <asm/cplb.h>
 #include <asm/blackfin.h>
 #include <asm/irq_handler.h>
 #include <linux/irq.h>
 #include <asm/trace.h>
 #include <asm/fixed_code.h>
-#include <asm/dma.h>
 
 #ifdef CONFIG_KGDB
-# include <linux/debugger.h>
 # include <linux/kgdb.h>
 
 # define CHK_DEBUGGER_TRAP() \
        do { \
-               CHK_DEBUGGER(trapnr, sig, info.si_code, fp, ); \
+               kgdb_handle_exception(trapnr, sig, info.si_code, fp); \
        } while (0)
 # define CHK_DEBUGGER_TRAP_MAYBE() \
        do { \
@@ -67,7 +66,15 @@ void __init trap_init(void)
        CSYNC();
 }
 
-unsigned long saved_icplb_fault_addr, saved_dcplb_fault_addr;
+/*
+ * Used to save the RETX, SEQSTAT, I/D CPLB FAULT ADDR
+ * values across the transition from exception to IRQ5.
+ * We put these in L1, so they are going to be in a valid
+ * location during exception context
+ */
+__attribute__((l1_data))
+unsigned long saved_retx, saved_seqstat,
+       saved_icplb_fault_addr, saved_dcplb_fault_addr;
 
 static void decode_address(char *buf, unsigned long address)
 {
@@ -185,9 +192,27 @@ asmlinkage void double_fault_c(struct pt_regs *fp)
        console_verbose();
        oops_in_progress = 1;
        printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n");
-       dump_bfin_process(fp);
-       dump_bfin_mem(fp);
-       show_regs(fp);
+#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT
+       if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) == VEC_UNCOV) {
+               char buf[150];
+               decode_address(buf, saved_retx);
+               printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n",
+                       (int)saved_seqstat & SEQSTAT_EXCAUSE, buf);
+               decode_address(buf, saved_dcplb_fault_addr);
+               printk(KERN_NOTICE "   DCPLB_FAULT_ADDR: %s\n", buf);
+               decode_address(buf, saved_icplb_fault_addr);
+               printk(KERN_NOTICE "   ICPLB_FAULT_ADDR: %s\n", buf);
+
+               decode_address(buf, fp->retx);
+               printk(KERN_NOTICE "The instruction at %s caused a double exception\n",
+                       buf);
+       } else
+#endif
+       {
+               dump_bfin_process(fp);
+               dump_bfin_mem(fp);
+               show_regs(fp);
+       }
        panic("Double Fault - unrecoverable event\n");
 
 }
@@ -259,34 +284,42 @@ asmlinkage void trap_c(struct pt_regs *fp)
                        return;
                else
                        break;
-#ifdef CONFIG_KGDB
-       case VEC_EXCPT02 :               /* gdb connection */
-               info.si_code = TRAP_ILLTRAP;
-               sig = SIGTRAP;
-               CHK_DEBUGGER_TRAP();
-               return;
-#else
-       /* 0x02 - User Defined, Caught by default */
-#endif
        /* 0x03 - User Defined, userspace stack overflow */
        case VEC_EXCPT03:
                info.si_code = SEGV_STACKFLOW;
                sig = SIGSEGV;
                printk(KERN_NOTICE EXC_0x03(KERN_NOTICE));
+               CHK_DEBUGGER_TRAP_MAYBE();
+               break;
+       /* 0x02 - KGDB initial connection and break signal trap */
+       case VEC_EXCPT02:
+#ifdef CONFIG_KGDB
+               info.si_code = TRAP_ILLTRAP;
+               sig = SIGTRAP;
                CHK_DEBUGGER_TRAP();
+               return;
+#endif
+       /* 0x04 - User Defined */
+       /* 0x05 - User Defined */
+       /* 0x06 - User Defined */
+       /* 0x07 - User Defined */
+       /* 0x08 - User Defined */
+       /* 0x09 - User Defined */
+       /* 0x0A - User Defined */
+       /* 0x0B - User Defined */
+       /* 0x0C - User Defined */
+       /* 0x0D - User Defined */
+       /* 0x0E - User Defined */
+       /* 0x0F - User Defined */
+       /* If we got here, it is most likely that someone was trying to use a
+        * custom exception handler, and it is not actually installed properly
+        */
+       case VEC_EXCPT04 ... VEC_EXCPT15:
+               info.si_code = ILL_ILLPARAOP;
+               sig = SIGILL;
+               printk(KERN_NOTICE EXC_0x04(KERN_NOTICE));
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
-       /* 0x04 - User Defined, Caught by default */
-       /* 0x05 - User Defined, Caught by default */
-       /* 0x06 - User Defined, Caught by default */
-       /* 0x07 - User Defined, Caught by default */
-       /* 0x08 - User Defined, Caught by default */
-       /* 0x09 - User Defined, Caught by default */
-       /* 0x0A - User Defined, Caught by default */
-       /* 0x0B - User Defined, Caught by default */
-       /* 0x0C - User Defined, Caught by default */
-       /* 0x0D - User Defined, Caught by default */
-       /* 0x0E - User Defined, Caught by default */
-       /* 0x0F - User Defined, Caught by default */
        /* 0x10 HW Single step, handled here */
        case VEC_STEP:
                info.si_code = TRAP_STEP;
@@ -302,7 +335,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
                info.si_code = TRAP_TRACEFLOW;
                sig = SIGTRAP;
                printk(KERN_NOTICE EXC_0x11(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x12 - Reserved, Caught by default */
        /* 0x13 - Reserved, Caught by default */
@@ -324,35 +357,35 @@ asmlinkage void trap_c(struct pt_regs *fp)
                info.si_code = ILL_ILLOPC;
                sig = SIGILL;
                printk(KERN_NOTICE EXC_0x21(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x22 - Illegal Instruction Combination, handled here */
        case VEC_ILGAL_I:
                info.si_code = ILL_ILLPARAOP;
                sig = SIGILL;
                printk(KERN_NOTICE EXC_0x22(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x23 - Data CPLB protection violation, handled here */
        case VEC_CPLB_VL:
                info.si_code = ILL_CPLB_VI;
                sig = SIGBUS;
                printk(KERN_NOTICE EXC_0x23(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x24 - Data access misaligned, handled here */
        case VEC_MISALI_D:
                info.si_code = BUS_ADRALN;
                sig = SIGBUS;
                printk(KERN_NOTICE EXC_0x24(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x25 - Unrecoverable Event, handled here */
        case VEC_UNCOV:
                info.si_code = ILL_ILLEXCPT;
                sig = SIGILL;
                printk(KERN_NOTICE EXC_0x25(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr,
                error case is handled here */
@@ -360,7 +393,6 @@ asmlinkage void trap_c(struct pt_regs *fp)
                info.si_code = BUS_ADRALN;
                sig = SIGBUS;
                printk(KERN_NOTICE EXC_0x26(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
                break;
        /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */
        case VEC_CPLB_MHIT:
@@ -372,7 +404,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
                else
 #endif
                        printk(KERN_NOTICE EXC_0x27(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x28 - Emulation Watchpoint, handled here */
        case VEC_WATCH:
@@ -391,7 +423,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
                info.si_code = BUS_OPFETCH;
                sig = SIGBUS;
                printk(KERN_NOTICE "BF535: VEC_ISTRU_VL\n");
-               CHK_DEBUGGER_TRAP();
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
 #else
        /* 0x29 - Reserved, Caught by default */
@@ -401,21 +433,20 @@ asmlinkage void trap_c(struct pt_regs *fp)
                info.si_code = BUS_ADRALN;
                sig = SIGBUS;
                printk(KERN_NOTICE EXC_0x2A(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2B - Instruction CPLB protection violation, handled here */
        case VEC_CPLB_I_VL:
                info.si_code = ILL_CPLB_VI;
                sig = SIGBUS;
                printk(KERN_NOTICE EXC_0x2B(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */
        case VEC_CPLB_I_M:
                info.si_code = ILL_CPLB_MISS;
                sig = SIGBUS;
                printk(KERN_NOTICE EXC_0x2C(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
                break;
        /* 0x2D - Instruction CPLB Multiple Hits, handled here */
        case VEC_CPLB_I_MHIT:
@@ -427,14 +458,14 @@ asmlinkage void trap_c(struct pt_regs *fp)
                else
 #endif
                        printk(KERN_NOTICE EXC_0x2D(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2E - Illegal use of Supervisor Resource, handled here */
        case VEC_ILL_RES:
                info.si_code = ILL_PRVOPC;
                sig = SIGILL;
                printk(KERN_NOTICE EXC_0x2E(KERN_NOTICE));
-               CHK_DEBUGGER_TRAP();
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2F - Reserved, Caught by default */
        /* 0x30 - Reserved, Caught by default */
@@ -481,14 +512,19 @@ asmlinkage void trap_c(struct pt_regs *fp)
                        printk(KERN_NOTICE HWC_default(KERN_NOTICE));
                        break;
                }
-               CHK_DEBUGGER_TRAP();
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
+       /*
+        * We should be handling all known exception types above,
+        * if we get here we hit a reserved one, so panic
+        */
        default:
-               info.si_code = TRAP_ILLTRAP;
-               sig = SIGTRAP;
+               oops_in_progress = 1;
+               info.si_code = ILL_ILLPARAOP;
+               sig = SIGILL;
                printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n",
                        (fp->seqstat & SEQSTAT_EXCAUSE));
-               CHK_DEBUGGER_TRAP();
+               CHK_DEBUGGER_TRAP_MAYBE();
                break;
        }
 
@@ -567,7 +603,7 @@ bool get_instruction(unsigned short *val, unsigned short *address)
         * we don't read something in the async space that can hang forever
         */
        if ((addr >= FIXED_CODE_START && (addr + 2) <= physical_mem_end) ||
-#ifdef L2_START
+#if L2_LENGTH != 0
            (addr >= L2_START && (addr + 2) <= (L2_START + L2_LENGTH)) ||
 #endif
            (addr >= BOOT_ROM_START && (addr + 2) <= (BOOT_ROM_START + BOOT_ROM_LENGTH)) ||
@@ -592,7 +628,7 @@ bool get_instruction(unsigned short *val, unsigned short *address)
 
 #if L1_CODE_LENGTH != 0
        if (addr >= L1_CODE_START && (addr + 2) <= (L1_CODE_START + L1_CODE_LENGTH)) {
-               dma_memcpy(val, address, 2);
+               isram_memcpy(val, address, 2);
                return true;
        }
 #endif
@@ -601,12 +637,55 @@ bool get_instruction(unsigned short *val, unsigned short *address)
        return false;
 }
 
+/* 
+ * decode the instruction if we are printing out the trace, as it
+ * makes things easier to follow, without running it through objdump
+ * These are the normal instructions which cause change of flow, which
+ * would be at the source of the trace buffer
+ */
+void decode_instruction(unsigned short *address)
+{
+       unsigned short opcode;
+
+       if (get_instruction(&opcode, address)) {
+               if (opcode == 0x0010)
+                       printk("RTS");
+               else if (opcode == 0x0011)
+                       printk("RTI");
+               else if (opcode == 0x0012)
+                       printk("RTX");
+               else if (opcode >= 0x0050 && opcode <= 0x0057)
+                       printk("JUMP (P%i)", opcode & 7);
+               else if (opcode >= 0x0060 && opcode <= 0x0067)
+                       printk("CALL (P%i)", opcode & 7);
+               else if (opcode >= 0x0070 && opcode <= 0x0077)
+                       printk("CALL (PC+P%i)", opcode & 7);
+               else if (opcode >= 0x0080 && opcode <= 0x0087)
+                       printk("JUMP (PC+P%i)", opcode & 7);
+               else if ((opcode >= 0x1000 && opcode <= 0x13FF) || (opcode >= 0x1800 && opcode <= 0x1BFF))
+                       printk("IF !CC JUMP");
+               else if ((opcode >= 0x1400 && opcode <= 0x17ff) || (opcode >= 0x1c00 && opcode <= 0x1fff))
+                       printk("IF CC JUMP");
+               else if (opcode >= 0x2000 && opcode <= 0x2fff)
+                       printk("JUMP.S");
+               else if (opcode >= 0xe080 && opcode <= 0xe0ff)
+                       printk("LSETUP");
+               else if (opcode >= 0xe200 && opcode <= 0xe2ff)
+                       printk("JUMP.L");
+               else if (opcode >= 0xe300 && opcode <= 0xe3ff)
+                       printk("CALL pcrel");
+               else
+                       printk("0x%04x", opcode);
+       }
+
+}
+
 void dump_bfin_trace_buffer(void)
 {
 #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
        int tflags, i = 0;
        char buf[150];
-       unsigned short val = 0, *addr;
+       unsigned short *addr;
 #ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
        int j, index;
 #endif
@@ -615,6 +694,10 @@ void dump_bfin_trace_buffer(void)
 
        printk(KERN_NOTICE "Hardware Trace:\n");
 
+#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
+       printk(KERN_NOTICE "WARNING: Expanded trace turned on - can not trace exceptions\n");
+#endif
+
        if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) {
                for (; bfin_read_TBUFSTAT() & TBUFCNT; i++) {
                        decode_address(buf, (unsigned long)bfin_read_TBUF());
@@ -622,45 +705,14 @@ void dump_bfin_trace_buffer(void)
                        addr = (unsigned short *)bfin_read_TBUF();
                        decode_address(buf, (unsigned long)addr);
                        printk(KERN_NOTICE "     Source : %s ", buf);
-                       if (get_instruction(&val, addr)) {
-                               if (val == 0x0010)
-                                       printk("RTS");
-                               else if (val == 0x0011)
-                                       printk("RTI");
-                               else if (val == 0x0012)
-                                       printk("RTX");
-                               else if (val >= 0x0050 && val <= 0x0057)
-                                       printk("JUMP (P%i)", val & 7);
-                               else if (val >= 0x0060 && val <= 0x0067)
-                                       printk("CALL (P%i)", val & 7);
-                               else if (val >= 0x0070 && val <= 0x0077)
-                                       printk("CALL (PC+P%i)", val & 7);
-                               else if (val >= 0x0080 && val <= 0x0087)
-                                       printk("JUMP (PC+P%i)", val & 7);
-                               else if ((val >= 0x1000 && val <= 0x13FF) ||
-                                   (val >= 0x1800 && val <= 0x1BFF))
-                                       printk("IF !CC JUMP");
-                               else if ((val >= 0x1400 && val <= 0x17ff) ||
-                                   (val >= 0x1c00 && val <= 0x1fff))
-                                       printk("IF CC JUMP");
-                               else if (val >= 0x2000 && val <= 0x2fff)
-                                       printk("JUMP.S");
-                               else if (val >= 0xe080 && val <= 0xe0ff)
-                                       printk("LSETUP");
-                               else if (val >= 0xe200 && val <= 0xe2ff)
-                                       printk("JUMP.L");
-                               else if (val >= 0xe300 && val <= 0xe3ff)
-                                       printk("CALL pcrel");
-                               else
-                                       printk("0x%04x", val);
-                       }
+                       decode_instruction(addr);
                        printk("\n");
                }
        }
 
 #ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
        if (trace_buff_offset)
-               index = trace_buff_offset/4 - 1;
+               index = trace_buff_offset / 4;
        else
                index = EXPAND_LEN;
 
@@ -672,7 +724,9 @@ void dump_bfin_trace_buffer(void)
                if (index < 0 )
                        index = EXPAND_LEN;
                decode_address(buf, software_trace_buff[index]);
-               printk(KERN_NOTICE "     Source : %s\n", buf);
+               printk(KERN_NOTICE "     Source : %s ", buf);
+               decode_instruction((unsigned short *)software_trace_buff[index]);
+               printk("\n");
                index -= 1;
                if (index < 0)
                        index = EXPAND_LEN;
@@ -911,7 +965,7 @@ void dump_bfin_mem(struct pt_regs *fp)
                if (!((unsigned long)addr & 0xF))
                        printk("\n" KERN_NOTICE "0x%p: ", addr);
 
-               if (get_instruction(&val, addr)) {
+               if (!get_instruction(&val, addr)) {
                                val = 0;
                                sprintf(buf, "????");
                } else