aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/coldfire/files-2.6.31/arch/m68k/coldfire/common/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/coldfire/files-2.6.31/arch/m68k/coldfire/common/traps.c')
-rw-r--r--target/linux/coldfire/files-2.6.31/arch/m68k/coldfire/common/traps.c456
1 files changed, 456 insertions, 0 deletions
diff --git a/target/linux/coldfire/files-2.6.31/arch/m68k/coldfire/common/traps.c b/target/linux/coldfire/files-2.6.31/arch/m68k/coldfire/common/traps.c
new file mode 100644
index 0000000000..3f96960b6a
--- /dev/null
+++ b/target/linux/coldfire/files-2.6.31/arch/m68k/coldfire/common/traps.c
@@ -0,0 +1,456 @@
+/*
+ * linux/arch/m68knommu/kernel/traps.c
+ *
+ * Copyright Freescale Semiconductor, Inc. 2008-2009
+ * Jason Jin Jason.Jin@freescale.com
+ * Shrek Wu B16972@freescale.com
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * Sets up all exception vectors
+ */
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/a.out.h>
+#include <linux/user.h>
+#include <linux/string.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/ptrace.h>
+#include <linux/kallsyms.h>
+
+#include <asm/setup.h>
+#include <asm/fpu.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/traps.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/siginfo.h>
+
+static char const * const vec_names[] = {
+ "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR",
+ "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc",
+ "PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111",
+ "UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION",
+ "FORMAT ERROR", "UNINITIALIZED INTERRUPT",
+ "UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17",
+ "UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19",
+ "UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21",
+ "UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23",
+ "SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT",
+ "LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT",
+ "SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3",
+ "TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7",
+ "TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11",
+ "TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15",
+ "FPCP BSUN", "FPCP INEXACT", "FPCP DIV BY 0", "FPCP UNDERFLOW",
+ "FPCP OPERAND ERROR", "FPCP OVERFLOW", "FPCP SNAN",
+ "FPCP UNSUPPORTED OPERATION",
+ "MMU CONFIGURATION ERROR"
+};
+
+asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
+ unsigned long error_code);
+asmlinkage void trap_c(struct frame *fp);
+extern void __init coldfire_trap_init(void);
+
+void __init trap_init(void)
+{
+ coldfire_trap_init();
+}
+
+/* The following table converts the FS encoding of a ColdFire
+ exception stack frame into the error_code value needed by
+ do_fault. */
+
+static const unsigned char fs_err_code[] = {
+ 0, /* 0000 */
+ 0, /* 0001 */
+ 0, /* 0010 */
+ 0, /* 0011 */
+ 1, /* 0100 */
+ 0, /* 0101 */
+ 0, /* 0110 */
+ 0, /* 0111 */
+ 2, /* 1000 */
+ 3, /* 1001 */
+ 2, /* 1010 */
+ 0, /* 1011 */
+ 1, /* 1100 */
+ 1, /* 1101 */
+ 0, /* 1110 */
+ 0 /* 1111 */
+};
+
+#ifdef DEBUG
+static const char *fs_err_msg[16] = {
+ "Normal",
+ "Reserved",
+ "Interrupt during debug service routine",
+ "Reserved",
+ "X Protection",
+ "TLB X miss (opword)",
+ "TLB X miss (ext. word)",
+ "IFP in emulator mode",
+ "W Protection",
+ "Write error",
+ "TLB W miss",
+ "Reserved",
+ "R Protection",
+ "R/RMW Protection",
+ "TLB R miss",
+ "OEP in emulator mode",
+};
+#endif
+
+static inline void access_errorCF(struct frame *fp)
+{
+ unsigned long int mmusr, complainingAddress;
+ unsigned int err_code, fs;
+ int need_page_fault;
+
+ mmusr = fp->ptregs.mmusr;
+ complainingAddress = fp->ptregs.mmuar;
+#ifdef DEBUG
+ printk(KERN_DEBUG "pc %#lx, mmusr %#lx, complainingAddress %#lx\n", \
+ fp->ptregs.pc, mmusr, complainingAddress);
+#endif
+
+ /*
+ * error_code:
+ * bit 0 == 0 means no page found, 1 means protection fault
+ * bit 1 == 0 means read, 1 means write
+ */
+
+ fs = (fp->ptregs.fs2 << 2) | fp->ptregs.fs1;
+ switch (fs) {
+ case 5: /* 0101 TLB opword X miss */
+ need_page_fault = cf_tlb_miss(&fp->ptregs, 0, 0, 0);
+ complainingAddress = fp->ptregs.pc;
+ break;
+ case 6: /* 0110 TLB extension word X miss */
+ need_page_fault = cf_tlb_miss(&fp->ptregs, 0, 0, 1);
+ complainingAddress = fp->ptregs.pc + sizeof(long);
+ break;
+ case 10: /* 1010 TLB W miss */
+ need_page_fault = cf_tlb_miss(&fp->ptregs, 1, 1, 0);
+ break;
+ case 14: /* 1110 TLB R miss */
+ need_page_fault = cf_tlb_miss(&fp->ptregs, 0, 1, 0);
+ break;
+ default:
+ /* 0000 Normal */
+ /* 0001 Reserved */
+ /* 0010 Interrupt during debug service routine */
+ /* 0011 Reserved */
+ /* 0100 X Protection */
+ /* 0111 IFP in emulator mode */
+ /* 1000 W Protection*/
+ /* 1001 Write error*/
+ /* 1011 Reserved*/
+ /* 1100 R Protection*/
+ /* 1101 R Protection*/
+ /* 1111 OEP in emulator mode*/
+ need_page_fault = 1;
+ break;
+ }
+
+ if (need_page_fault) {
+ err_code = fs_err_code[fs];
+ if ((fs == 13) && (mmusr & MMUSR_WF)) /* rd-mod-wr access */
+ err_code |= 2; /* bit1 - write, bit0 - protection */
+ do_page_fault(&fp->ptregs, complainingAddress, err_code);
+ }
+}
+
+void die_if_kernel(char *str, struct pt_regs *fp, int nr)
+{
+ if (!(fp->sr & PS_S))
+ return;
+
+ console_verbose();
+ printk(KERN_EMERG "%s: %08x\n", str, nr);
+ printk(KERN_EMERG "PC: [<%08lx>]", fp->pc);
+ print_symbol(" %s", fp->pc);
+ printk(KERN_EMERG "\nSR: %04x SP: %p a2: %08lx\n",
+ fp->sr, fp, fp->a2);
+ printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
+ fp->d0, fp->d1, fp->d2, fp->d3);
+ printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
+ fp->d4, fp->d5, fp->a0, fp->a1);
+
+ printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n",
+ current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
+ show_stack(NULL, (unsigned long *)fp);
+ do_exit(SIGSEGV);
+}
+
+asmlinkage void buserr_c(struct frame *fp)
+{
+ unsigned int fs;
+
+ /* Only set esp0 if coming from user mode */
+ if (user_mode(&fp->ptregs))
+ current->thread.esp0 = (unsigned long) fp;
+
+ fs = (fp->ptregs.fs2 << 2) | fp->ptregs.fs1;
+#if defined(DEBUG)
+ printk(KERN_DEBUG "*** Bus Error *** (%x)%s\n", fs,
+ fs_err_msg[fs & 0xf]);
+#endif
+ switch (fs) {
+ case 0x5:
+ case 0x6:
+ case 0x7:
+ case 0x9:
+ case 0xa:
+ case 0xd:
+ case 0xe:
+ case 0xf:
+ access_errorCF(fp);
+ break;
+ default:
+ die_if_kernel("bad frame format", &fp->ptregs, 0);
+#if defined(DEBUG)
+ printk(KERN_DEBUG "Unknown SIGSEGV - 4\n");
+#endif
+ force_sig(SIGSEGV, current);
+ }
+}
+
+void show_trace(unsigned long *stack)
+{
+ unsigned long *endstack;
+ unsigned long addr;
+ int i;
+
+ printk("Call Trace:");
+ addr = (unsigned long)stack + THREAD_SIZE - 1;
+ endstack = (unsigned long *)(addr & -THREAD_SIZE);
+ i = 0;
+ while (stack + 1 <= endstack) {
+ addr = *stack++;
+ /*
+ * If the address is either in the text segment of the
+ * kernel, or in the region which contains vmalloc'ed
+ * memory, it *may* be the address of a calling
+ * routine; if so, print it so that someone tracing
+ * down the cause of the crash will be able to figure
+ * out the call path that was taken.
+ */
+ if (__kernel_text_address(addr)) {
+#ifndef CONFIG_KALLSYMS
+ if (i % 5 == 0)
+ printk("\n ");
+#endif
+ printk(" [<%08lx>] %pS\n", addr, (void *)addr);
+ i++;
+ }
+ }
+ printk("\n");
+}
+
+int kstack_depth_to_print = 48;
+void show_stack(struct task_struct *task, unsigned long *stack)
+{
+ unsigned long *p;
+ unsigned long *endstack;
+ int i;
+
+ if (!stack) {
+ if (task)
+ stack = (unsigned long *)task->thread.esp0;
+ else
+ stack = (unsigned long *)&stack;
+ }
+ endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) & -THREAD_SIZE);
+
+ printk("Stack from %08lx:", (unsigned long)stack);
+ p = stack;
+ for (i = 0; i < kstack_depth_to_print; i++) {
+ if (p + 1 > endstack)
+ break;
+ if (i % 8 == 0)
+ printk("\n ");
+ printk(" %08lx", *p++);
+ }
+ printk("\n");
+ show_trace(stack);
+}
+
+void bad_super_trap(struct frame *fp)
+{
+ console_verbose();
+ if (fp->ptregs.vector < sizeof(vec_names)/sizeof(vec_names[0]))
+ printk(KERN_WARNING "*** %s *** FORMAT=%X\n",
+ vec_names[fp->ptregs.vector],
+ fp->ptregs.format);
+ else
+ printk(KERN_WARNING "*** Exception %d *** FORMAT=%X\n",
+ fp->ptregs.vector,
+ fp->ptregs.format);
+ printk(KERN_WARNING "Current process id is %d\n", current->pid);
+ die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
+}
+
+asmlinkage void trap_c(struct frame *fp)
+{
+ int sig;
+ siginfo_t info;
+
+ if (fp->ptregs.sr & PS_S) {
+ if (fp->ptregs.vector == VEC_TRACE) {
+ /* traced a trapping instruction */
+ current->ptrace |= PT_DTRACE;
+ } else
+ bad_super_trap(fp);
+ return;
+ }
+
+ /* send the appropriate signal to the user program */
+ switch (fp->ptregs.vector) {
+ case VEC_ADDRERR:
+ info.si_code = BUS_ADRALN;
+ sig = SIGBUS;
+ break;
+ case VEC_ILLEGAL:
+ case VEC_LINE10:
+ case VEC_LINE11:
+ info.si_code = ILL_ILLOPC;
+ sig = SIGILL;
+ break;
+ case VEC_PRIV:
+ info.si_code = ILL_PRVOPC;
+ sig = SIGILL;
+ break;
+ case VEC_COPROC:
+ info.si_code = ILL_COPROC;
+ sig = SIGILL;
+ break;
+ case VEC_TRAP1: /* gdbserver breakpoint */
+ fp->ptregs.pc -= 2;
+ info.si_code = TRAP_TRACE;
+ sig = SIGTRAP;
+ break;
+ case VEC_TRAP2:
+ case VEC_TRAP3:
+ case VEC_TRAP4:
+ case VEC_TRAP5:
+ case VEC_TRAP6:
+ case VEC_TRAP7:
+ case VEC_TRAP8:
+ case VEC_TRAP9:
+ case VEC_TRAP10:
+ case VEC_TRAP11:
+ case VEC_TRAP12:
+ case VEC_TRAP13:
+ case VEC_TRAP14:
+ info.si_code = ILL_ILLTRP;
+ sig = SIGILL;
+ break;
+ case VEC_FPBRUC:
+ case VEC_FPOE:
+ case VEC_FPNAN:
+ info.si_code = FPE_FLTINV;
+ sig = SIGFPE;
+ break;
+ case VEC_FPIR:
+ info.si_code = FPE_FLTRES;
+ sig = SIGFPE;
+ break;
+ case VEC_FPDIVZ:
+ info.si_code = FPE_FLTDIV;
+ sig = SIGFPE;
+ break;
+ case VEC_FPUNDER:
+ info.si_code = FPE_FLTUND;
+ sig = SIGFPE;
+ break;
+ case VEC_FPOVER:
+ info.si_code = FPE_FLTOVF;
+ sig = SIGFPE;
+ break;
+ case VEC_ZERODIV:
+ info.si_code = FPE_INTDIV;
+ sig = SIGFPE;
+ break;
+ case VEC_CHK:
+ case VEC_TRAP:
+ info.si_code = FPE_INTOVF;
+ sig = SIGFPE;
+ break;
+ case VEC_TRACE: /* ptrace single step */
+ info.si_code = TRAP_TRACE;
+ sig = SIGTRAP;
+ break;
+ case VEC_TRAP15: /* breakpoint */
+ info.si_code = TRAP_BRKPT;
+ sig = SIGTRAP;
+ break;
+ default:
+ info.si_code = ILL_ILLOPC;
+ sig = SIGILL;
+ break;
+ }
+ info.si_signo = sig;
+ info.si_errno = 0;
+ switch (fp->ptregs.format) {
+ default:
+ info.si_addr = (void *) fp->ptregs.pc;
+ break;
+ case 2:
+ info.si_addr = (void *) fp->un.fmt2.iaddr;
+ break;
+ case 7:
+ info.si_addr = (void *) fp->un.fmt7.effaddr;
+ break;
+ case 9:
+ info.si_addr = (void *) fp->un.fmt9.iaddr;
+ break;
+ case 10:
+ info.si_addr = (void *) fp->un.fmta.daddr;
+ break;
+ case 11:
+ info.si_addr = (void *) fp->un.fmtb.daddr;
+ break;
+ }
+ force_sig_info(sig, &info, current);
+}
+
+asmlinkage void set_esp0(unsigned long ssp)
+{
+ current->thread.esp0 = ssp;
+}
+
+/*
+ * The architecture-independent backtrace generator
+ */
+void dump_stack(void)
+{
+ unsigned long stack;
+
+ show_stack(current, &stack);
+}
+EXPORT_SYMBOL(dump_stack);
+
+#ifdef CONFIG_M68KFPU_EMU
+asmlinkage void fpemu_signal(int signal, int code, void *addr)
+{
+ siginfo_t info;
+
+ info.si_signo = signal;
+ info.si_errno = 0;
+ info.si_code = code;
+ info.si_addr = addr;
+ force_sig_info(signal, &info, current);
+}
+#endif