|
@@ -27,6 +27,7 @@
|
|
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
*/
|
|
|
|
|
|
+#include <linux/bug.h>
|
|
|
#include <linux/uaccess.h>
|
|
|
#include <linux/interrupt.h>
|
|
|
#include <linux/module.h>
|
|
@@ -238,6 +239,11 @@ asmlinkage void double_fault_c(struct pt_regs *fp)
|
|
|
|
|
|
}
|
|
|
|
|
|
+static int kernel_mode_regs(struct pt_regs *regs)
|
|
|
+{
|
|
|
+ return regs->ipend & 0xffc0;
|
|
|
+}
|
|
|
+
|
|
|
asmlinkage void trap_c(struct pt_regs *fp)
|
|
|
{
|
|
|
#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
|
|
@@ -246,6 +252,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
|
|
|
#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
|
|
|
unsigned int cpu = smp_processor_id();
|
|
|
#endif
|
|
|
+ const char *strerror = NULL;
|
|
|
int sig = 0;
|
|
|
siginfo_t info;
|
|
|
unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE;
|
|
@@ -259,27 +266,10 @@ asmlinkage void trap_c(struct pt_regs *fp)
|
|
|
* double faults if the stack has become corrupt
|
|
|
*/
|
|
|
|
|
|
- /* If the fault was caused by a kernel thread, or interrupt handler
|
|
|
- * we will kernel panic, so the system reboots.
|
|
|
- * If KGDB is enabled, don't set this for kernel breakpoints
|
|
|
- */
|
|
|
-
|
|
|
- /* TODO: check to see if we are in some sort of deferred HWERR
|
|
|
- * that we should be able to recover from, not kernel panic
|
|
|
- */
|
|
|
- if ((bfin_read_IPEND() & 0xFFC0) && (trapnr != VEC_STEP)
|
|
|
-#ifdef CONFIG_KGDB
|
|
|
- && (trapnr != VEC_EXCPT02)
|
|
|
+#ifndef CONFIG_KGDB
|
|
|
+ /* IPEND is skipped if KGDB isn't enabled (see entry code) */
|
|
|
+ fp->ipend = bfin_read_IPEND();
|
|
|
#endif
|
|
|
- ){
|
|
|
- console_verbose();
|
|
|
- oops_in_progress = 1;
|
|
|
- } else if (current) {
|
|
|
- if (current->mm == NULL) {
|
|
|
- console_verbose();
|
|
|
- oops_in_progress = 1;
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
/* trap_c() will be called for exceptions. During exceptions
|
|
|
* processing, the pc value should be set with retx value.
|
|
@@ -307,15 +297,15 @@ asmlinkage void trap_c(struct pt_regs *fp)
|
|
|
sig = SIGTRAP;
|
|
|
CHK_DEBUGGER_TRAP_MAYBE();
|
|
|
/* Check if this is a breakpoint in kernel space */
|
|
|
- if (fp->ipend & 0xffc0)
|
|
|
- return;
|
|
|
+ if (kernel_mode_regs(fp))
|
|
|
+ goto traps_done;
|
|
|
else
|
|
|
break;
|
|
|
/* 0x03 - User Defined, userspace stack overflow */
|
|
|
case VEC_EXCPT03:
|
|
|
info.si_code = SEGV_STACKFLOW;
|
|
|
sig = SIGSEGV;
|
|
|
- verbose_printk(KERN_NOTICE EXC_0x03(KERN_NOTICE));
|
|
|
+ strerror = KERN_NOTICE EXC_0x03(KERN_NOTICE);
|
|
|
CHK_DEBUGGER_TRAP_MAYBE();
|
|
|
break;
|
|
|
/* 0x02 - KGDB initial connection and break signal trap */
|
|
@@ -324,7 +314,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
|
|
|
info.si_code = TRAP_ILLTRAP;
|
|
|
sig = SIGTRAP;
|
|
|
CHK_DEBUGGER_TRAP();
|
|
|
- return;
|
|
|
+ goto traps_done;
|
|
|
#endif
|
|
|
/* 0x04 - User Defined */
|
|
|
/* 0x05 - User Defined */
|
|
@@ -344,7 +334,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
|
|
|
case VEC_EXCPT04 ... VEC_EXCPT15:
|
|
|
info.si_code = ILL_ILLPARAOP;
|
|
|
sig = SIGILL;
|
|
|
- verbose_printk(KERN_NOTICE EXC_0x04(KERN_NOTICE));
|
|
|
+ strerror = KERN_NOTICE EXC_0x04(KERN_NOTICE);
|
|
|
CHK_DEBUGGER_TRAP_MAYBE();
|
|
|
break;
|
|
|
/* 0x10 HW Single step, handled here */
|
|
@@ -353,15 +343,15 @@ asmlinkage void trap_c(struct pt_regs *fp)
|
|
|
sig = SIGTRAP;
|
|
|
CHK_DEBUGGER_TRAP_MAYBE();
|
|
|
/* Check if this is a single step in kernel space */
|
|
|
- if (fp->ipend & 0xffc0)
|
|
|
- return;
|
|
|
+ if (kernel_mode_regs(fp))
|
|
|
+ goto traps_done;
|
|
|
else
|
|
|
break;
|
|
|
/* 0x11 - Trace Buffer Full, handled here */
|
|
|
case VEC_OVFLOW:
|
|
|
info.si_code = TRAP_TRACEFLOW;
|
|
|
sig = SIGTRAP;
|
|
|
- verbose_printk(KERN_NOTICE EXC_0x11(KERN_NOTICE));
|
|
|
+ strerror = KERN_NOTICE EXC_0x11(KERN_NOTICE);
|
|
|
CHK_DEBUGGER_TRAP_MAYBE();
|
|
|
break;
|
|
|
/* 0x12 - Reserved, Caught by default */
|
|
@@ -381,37 +371,54 @@ asmlinkage void trap_c(struct pt_regs *fp)
|
|
|
/* 0x20 - Reserved, Caught by default */
|
|
|
/* 0x21 - Undefined Instruction, handled here */
|
|
|
case VEC_UNDEF_I:
|
|
|
+#ifdef CONFIG_BUG
|
|
|
+ if (kernel_mode_regs(fp)) {
|
|
|
+ switch (report_bug(fp->pc, fp)) {
|
|
|
+ case BUG_TRAP_TYPE_NONE:
|
|
|
+ break;
|
|
|
+ case BUG_TRAP_TYPE_WARN:
|
|
|
+ dump_bfin_trace_buffer();
|
|
|
+ fp->pc += 2;
|
|
|
+ goto traps_done;
|
|
|
+ case BUG_TRAP_TYPE_BUG:
|
|
|
+ /* call to panic() will dump trace, and it is
|
|
|
+ * off at this point, so it won't be clobbered
|
|
|
+ */
|
|
|
+ panic("BUG()");
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
info.si_code = ILL_ILLOPC;
|
|
|
sig = SIGILL;
|
|
|
- verbose_printk(KERN_NOTICE EXC_0x21(KERN_NOTICE));
|
|
|
+ strerror = KERN_NOTICE EXC_0x21(KERN_NOTICE);
|
|
|
CHK_DEBUGGER_TRAP_MAYBE();
|
|
|
break;
|
|
|
/* 0x22 - Illegal Instruction Combination, handled here */
|
|
|
case VEC_ILGAL_I:
|
|
|
info.si_code = ILL_ILLPARAOP;
|
|
|
sig = SIGILL;
|
|
|
- verbose_printk(KERN_NOTICE EXC_0x22(KERN_NOTICE));
|
|
|
+ strerror = KERN_NOTICE EXC_0x22(KERN_NOTICE);
|
|
|
CHK_DEBUGGER_TRAP_MAYBE();
|
|
|
break;
|
|
|
/* 0x23 - Data CPLB protection violation, handled here */
|
|
|
case VEC_CPLB_VL:
|
|
|
info.si_code = ILL_CPLB_VI;
|
|
|
sig = SIGBUS;
|
|
|
- verbose_printk(KERN_NOTICE EXC_0x23(KERN_NOTICE));
|
|
|
+ strerror = KERN_NOTICE EXC_0x23(KERN_NOTICE);
|
|
|
CHK_DEBUGGER_TRAP_MAYBE();
|
|
|
break;
|
|
|
/* 0x24 - Data access misaligned, handled here */
|
|
|
case VEC_MISALI_D:
|
|
|
info.si_code = BUS_ADRALN;
|
|
|
sig = SIGBUS;
|
|
|
- verbose_printk(KERN_NOTICE EXC_0x24(KERN_NOTICE));
|
|
|
+ strerror = KERN_NOTICE EXC_0x24(KERN_NOTICE);
|
|
|
CHK_DEBUGGER_TRAP_MAYBE();
|
|
|
break;
|
|
|
/* 0x25 - Unrecoverable Event, handled here */
|
|
|
case VEC_UNCOV:
|
|
|
info.si_code = ILL_ILLEXCPT;
|
|
|
sig = SIGILL;
|
|
|
- verbose_printk(KERN_NOTICE EXC_0x25(KERN_NOTICE));
|
|
|
+ strerror = KERN_NOTICE EXC_0x25(KERN_NOTICE);
|
|
|
CHK_DEBUGGER_TRAP_MAYBE();
|
|
|
break;
|
|
|
/* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr,
|
|
@@ -419,7 +426,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
|
|
|
case VEC_CPLB_M:
|
|
|
info.si_code = BUS_ADRALN;
|
|
|
sig = SIGBUS;
|
|
|
- verbose_printk(KERN_NOTICE EXC_0x26(KERN_NOTICE));
|
|
|
+ strerror = KERN_NOTICE EXC_0x26(KERN_NOTICE);
|
|
|
break;
|
|
|
/* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */
|
|
|
case VEC_CPLB_MHIT:
|
|
@@ -427,10 +434,10 @@ asmlinkage void trap_c(struct pt_regs *fp)
|
|
|
sig = SIGSEGV;
|
|
|
#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
|
|
|
if (cpu_pda[cpu].dcplb_fault_addr < FIXED_CODE_START)
|
|
|
- verbose_printk(KERN_NOTICE "NULL pointer access\n");
|
|
|
+ strerror = KERN_NOTICE "NULL pointer access\n";
|
|
|
else
|
|
|
#endif
|
|
|
- verbose_printk(KERN_NOTICE EXC_0x27(KERN_NOTICE));
|
|
|
+ strerror = KERN_NOTICE EXC_0x27(KERN_NOTICE);
|
|
|
CHK_DEBUGGER_TRAP_MAYBE();
|
|
|
break;
|
|
|
/* 0x28 - Emulation Watchpoint, handled here */
|
|
@@ -440,8 +447,8 @@ asmlinkage void trap_c(struct pt_regs *fp)
|
|
|
pr_debug(EXC_0x28(KERN_DEBUG));
|
|
|
CHK_DEBUGGER_TRAP_MAYBE();
|
|
|
/* Check if this is a watchpoint in kernel space */
|
|
|
- if (fp->ipend & 0xffc0)
|
|
|
- return;
|
|
|
+ if (kernel_mode_regs(fp))
|
|
|
+ goto traps_done;
|
|
|
else
|
|
|
break;
|
|
|
#ifdef CONFIG_BF535
|
|
@@ -449,7 +456,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
|
|
|
case VEC_ISTRU_VL: /* ADSP-BF535 only (MH) */
|
|
|
info.si_code = BUS_OPFETCH;
|
|
|
sig = SIGBUS;
|
|
|
- verbose_printk(KERN_NOTICE "BF535: VEC_ISTRU_VL\n");
|
|
|
+ strerror = KERN_NOTICE "BF535: VEC_ISTRU_VL\n";
|
|
|
CHK_DEBUGGER_TRAP_MAYBE();
|
|
|
break;
|
|
|
#else
|
|
@@ -459,21 +466,21 @@ asmlinkage void trap_c(struct pt_regs *fp)
|
|
|
case VEC_MISALI_I:
|
|
|
info.si_code = BUS_ADRALN;
|
|
|
sig = SIGBUS;
|
|
|
- verbose_printk(KERN_NOTICE EXC_0x2A(KERN_NOTICE));
|
|
|
+ strerror = KERN_NOTICE EXC_0x2A(KERN_NOTICE);
|
|
|
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;
|
|
|
- verbose_printk(KERN_NOTICE EXC_0x2B(KERN_NOTICE));
|
|
|
+ strerror = KERN_NOTICE EXC_0x2B(KERN_NOTICE);
|
|
|
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;
|
|
|
- verbose_printk(KERN_NOTICE EXC_0x2C(KERN_NOTICE));
|
|
|
+ strerror = KERN_NOTICE EXC_0x2C(KERN_NOTICE);
|
|
|
break;
|
|
|
/* 0x2D - Instruction CPLB Multiple Hits, handled here */
|
|
|
case VEC_CPLB_I_MHIT:
|
|
@@ -481,17 +488,17 @@ asmlinkage void trap_c(struct pt_regs *fp)
|
|
|
sig = SIGSEGV;
|
|
|
#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
|
|
|
if (cpu_pda[cpu].icplb_fault_addr < FIXED_CODE_START)
|
|
|
- verbose_printk(KERN_NOTICE "Jump to NULL address\n");
|
|
|
+ strerror = KERN_NOTICE "Jump to NULL address\n";
|
|
|
else
|
|
|
#endif
|
|
|
- verbose_printk(KERN_NOTICE EXC_0x2D(KERN_NOTICE));
|
|
|
+ strerror = KERN_NOTICE EXC_0x2D(KERN_NOTICE);
|
|
|
CHK_DEBUGGER_TRAP_MAYBE();
|
|
|
break;
|
|
|
/* 0x2E - Illegal use of Supervisor Resource, handled here */
|
|
|
case VEC_ILL_RES:
|
|
|
info.si_code = ILL_PRVOPC;
|
|
|
sig = SIGILL;
|
|
|
- verbose_printk(KERN_NOTICE EXC_0x2E(KERN_NOTICE));
|
|
|
+ strerror = KERN_NOTICE EXC_0x2E(KERN_NOTICE);
|
|
|
CHK_DEBUGGER_TRAP_MAYBE();
|
|
|
break;
|
|
|
/* 0x2F - Reserved, Caught by default */
|
|
@@ -519,17 +526,17 @@ asmlinkage void trap_c(struct pt_regs *fp)
|
|
|
case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR):
|
|
|
info.si_code = BUS_ADRALN;
|
|
|
sig = SIGBUS;
|
|
|
- verbose_printk(KERN_NOTICE HWC_x2(KERN_NOTICE));
|
|
|
+ strerror = KERN_NOTICE HWC_x2(KERN_NOTICE);
|
|
|
break;
|
|
|
/* External Memory Addressing Error */
|
|
|
case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR):
|
|
|
info.si_code = BUS_ADRERR;
|
|
|
sig = SIGBUS;
|
|
|
- verbose_printk(KERN_NOTICE HWC_x3(KERN_NOTICE));
|
|
|
+ strerror = KERN_NOTICE HWC_x3(KERN_NOTICE);
|
|
|
break;
|
|
|
/* Performance Monitor Overflow */
|
|
|
case (SEQSTAT_HWERRCAUSE_PERF_FLOW):
|
|
|
- verbose_printk(KERN_NOTICE HWC_x12(KERN_NOTICE));
|
|
|
+ strerror = KERN_NOTICE HWC_x12(KERN_NOTICE);
|
|
|
break;
|
|
|
/* RAISE 5 instruction */
|
|
|
case (SEQSTAT_HWERRCAUSE_RAISE_5):
|
|
@@ -546,7 +553,6 @@ asmlinkage void trap_c(struct pt_regs *fp)
|
|
|
* if we get here we hit a reserved one, so panic
|
|
|
*/
|
|
|
default:
|
|
|
- oops_in_progress = 1;
|
|
|
info.si_code = ILL_ILLPARAOP;
|
|
|
sig = SIGILL;
|
|
|
verbose_printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n",
|
|
@@ -557,6 +563,16 @@ asmlinkage void trap_c(struct pt_regs *fp)
|
|
|
|
|
|
BUG_ON(sig == 0);
|
|
|
|
|
|
+ /* If the fault was caused by a kernel thread, or interrupt handler
|
|
|
+ * we will kernel panic, so the system reboots.
|
|
|
+ */
|
|
|
+ if (kernel_mode_regs(fp) || (current && !current->mm)) {
|
|
|
+ console_verbose();
|
|
|
+ oops_in_progress = 1;
|
|
|
+ if (strerror)
|
|
|
+ verbose_printk(strerror);
|
|
|
+ }
|
|
|
+
|
|
|
if (sig != SIGTRAP) {
|
|
|
dump_bfin_process(fp);
|
|
|
dump_bfin_mem(fp);
|
|
@@ -606,8 +622,8 @@ asmlinkage void trap_c(struct pt_regs *fp)
|
|
|
if (ANOMALY_05000461 && trapnr == VEC_HWERR && !access_ok(VERIFY_READ, fp->pc, 8))
|
|
|
fp->pc = SAFE_USER_INSTRUCTION;
|
|
|
|
|
|
+ traps_done:
|
|
|
trace_buffer_restore(j);
|
|
|
- return;
|
|
|
}
|
|
|
|
|
|
/* Typical exception handling routines */
|
|
@@ -792,6 +808,18 @@ void dump_bfin_trace_buffer(void)
|
|
|
}
|
|
|
EXPORT_SYMBOL(dump_bfin_trace_buffer);
|
|
|
|
|
|
+#ifdef CONFIG_BUG
|
|
|
+int is_valid_bugaddr(unsigned long addr)
|
|
|
+{
|
|
|
+ unsigned short opcode;
|
|
|
+
|
|
|
+ if (!get_instruction(&opcode, (unsigned short *)addr))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ return opcode == BFIN_BUG_OPCODE;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
/*
|
|
|
* Checks to see if the address pointed to is either a
|
|
|
* 16-bit CALL instruction, or a 32-bit CALL instruction
|