|
@@ -0,0 +1,136 @@
|
|
|
+/*
|
|
|
+ * Main exception handling logic.
|
|
|
+ *
|
|
|
+ * Copyright 2004-2010 Analog Devices Inc.
|
|
|
+ *
|
|
|
+ * Licensed under the GPL-2 or later
|
|
|
+ */
|
|
|
+
|
|
|
+#include <linux/bug.h>
|
|
|
+#include <linux/uaccess.h>
|
|
|
+#include <linux/module.h>
|
|
|
+#include <asm/traps.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/pseudo_instructions.h>
|
|
|
+#include <asm/pda.h>
|
|
|
+
|
|
|
+#ifdef CONFIG_KGDB
|
|
|
+# include <linux/kgdb.h>
|
|
|
+
|
|
|
+# define CHK_DEBUGGER_TRAP() \
|
|
|
+ do { \
|
|
|
+ kgdb_handle_exception(trapnr, sig, info.si_code, fp); \
|
|
|
+ } while (0)
|
|
|
+# define CHK_DEBUGGER_TRAP_MAYBE() \
|
|
|
+ do { \
|
|
|
+ if (kgdb_connected) \
|
|
|
+ CHK_DEBUGGER_TRAP(); \
|
|
|
+ } while (0)
|
|
|
+#else
|
|
|
+# define CHK_DEBUGGER_TRAP() do { } while (0)
|
|
|
+# define CHK_DEBUGGER_TRAP_MAYBE() do { } while (0)
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+#ifdef CONFIG_DEBUG_VERBOSE
|
|
|
+#define verbose_printk(fmt, arg...) \
|
|
|
+ printk(fmt, ##arg)
|
|
|
+#else
|
|
|
+#define verbose_printk(fmt, arg...) \
|
|
|
+ ({ if (0) printk(fmt, ##arg); 0; })
|
|
|
+#endif
|
|
|
+
|
|
|
+#if defined(CONFIG_DEBUG_MMRS) || defined(CONFIG_DEBUG_MMRS_MODULE)
|
|
|
+u32 last_seqstat;
|
|
|
+#ifdef CONFIG_DEBUG_MMRS_MODULE
|
|
|
+EXPORT_SYMBOL(last_seqstat);
|
|
|
+#endif
|
|
|
+#endif
|
|
|
+
|
|
|
+/* Initiate the event table handler */
|
|
|
+void __init trap_init(void)
|
|
|
+{
|
|
|
+ CSYNC();
|
|
|
+ bfin_write_EVT3(trap);
|
|
|
+ CSYNC();
|
|
|
+}
|
|
|
+
|
|
|
+static int kernel_mode_regs(struct pt_regs *regs)
|
|
|
+{
|
|
|
+ return regs->ipend & 0xffc0;
|
|
|
+}
|
|
|
+
|
|
|
+asmlinkage notrace void trap_c(struct pt_regs *fp)
|
|
|
+{
|
|
|
+#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
|
|
|
+ int j;
|
|
|
+#endif
|
|
|
+#ifdef CONFIG_BFIN_PSEUDODBG_INSNS
|
|
|
+ int opcode;
|
|
|
+#endif
|
|
|
+ unsigned int cpu = raw_smp_processor_id();
|
|
|
+ const char *strerror = NULL;
|
|
|
+ int sig = 0;
|
|
|
+ siginfo_t info;
|
|
|
+ unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE;
|
|
|
+
|
|
|
+ trace_buffer_save(j);
|
|
|
+#if defined(CONFIG_DEBUG_MMRS) || defined(CONFIG_DEBUG_MMRS_MODULE)
|
|
|
+ last_seqstat = (u32)fp->seqstat;
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Important - be very careful dereferncing pointers - will lead to
|
|
|
+ * double faults if the stack has become corrupt
|
|
|
+ */
|
|
|
+
|
|
|
+ /* trap_c() will be called for exceptions. During exceptions
|
|
|
+ * processing, the pc value should be set with retx value.
|
|
|
+ * With this change we can cleanup some code in signal.c- TODO
|
|
|
+ */
|
|
|
+ fp->orig_pc = fp->retx;
|
|
|
+ /* printk("exception: 0x%x, ipend=%x, reti=%x, retx=%x\n",
|
|
|
+ trapnr, fp->ipend, fp->pc, fp->retx); */
|
|
|
+
|
|
|
+ /* send the appropriate signal to the user program */
|
|
|
+ switch (trapnr) {
|
|
|
+
|
|
|
+ /* This table works in conjunction with the one in ./mach-common/entry.S
|
|
|
+ * Some exceptions are handled there (in assembly, in exception space)
|
|
|
+ * Some are handled here, (in C, in interrupt space)
|
|
|
+ * Some, like CPLB, are handled in both, where the normal path is
|
|
|
+ * handled in assembly/exception space, and the error path is handled
|
|
|
+ * here
|
|
|
+ */
|
|
|
+
|
|
|
+ /* 0x00 - Linux Syscall, getting here is an error */
|
|
|
+ /* 0x01 - userspace gdb breakpoint, handled here */
|
|
|
+ case VEC_EXCPT01:
|
|
|
+ info.si_code = TRAP_ILLTRAP;
|
|
|
+ sig = SIGTRAP;
|
|
|
+ CHK_DEBUGGER_TRAP_MAYBE();
|
|
|
+ /* Check if this is a breakpoint in kernel space */
|
|
|
+ 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;
|
|
|
+ strerror = 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();
|
|
|
+ goto traps_done;
|
|
|
+#endif
|
|
|
+ /* 0x04 - User Defined */
|