2 * linux/arch/m68knommu/kernel/traps.c
4 * Copyright Freescale Semiconductor, Inc. 2008-2009
5 * Jason Jin Jason.Jin@freescale.com
6 * Shrek Wu B16972@freescale.com
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file COPYING in the main directory of this archive
14 * Sets up all exception vectors
16 #include <linux/sched.h>
17 #include <linux/signal.h>
18 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/types.h>
22 #include <linux/a.out.h>
23 #include <linux/user.h>
24 #include <linux/string.h>
25 #include <linux/linkage.h>
26 #include <linux/init.h>
27 #include <linux/ptrace.h>
28 #include <linux/kallsyms.h>
30 #include <asm/setup.h>
32 #include <asm/system.h>
33 #include <asm/uaccess.h>
34 #include <asm/traps.h>
35 #include <asm/pgtable.h>
36 #include <asm/machdep.h>
37 #include <asm/siginfo.h>
39 static char const * const vec_names[] = {
40 "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR",
41 "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc",
42 "PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111",
43 "UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION",
44 "FORMAT ERROR", "UNINITIALIZED INTERRUPT",
45 "UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17",
46 "UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19",
47 "UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21",
48 "UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23",
49 "SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT",
50 "LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT",
51 "SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3",
52 "TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7",
53 "TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11",
54 "TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15",
55 "FPCP BSUN", "FPCP INEXACT", "FPCP DIV BY 0", "FPCP UNDERFLOW",
56 "FPCP OPERAND ERROR", "FPCP OVERFLOW", "FPCP SNAN",
57 "FPCP UNSUPPORTED OPERATION",
58 "MMU CONFIGURATION ERROR"
61 asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
62 unsigned long error_code);
63 asmlinkage void trap_c(struct frame *fp);
64 extern void __init coldfire_trap_init(void);
66 void __init trap_init(void)
71 /* The following table converts the FS encoding of a ColdFire
72 exception stack frame into the error_code value needed by
75 static const unsigned char fs_err_code[] = {
95 static const char *fs_err_msg[16] = {
98 "Interrupt during debug service routine",
101 "TLB X miss (opword)",
102 "TLB X miss (ext. word)",
103 "IFP in emulator mode",
111 "OEP in emulator mode",
115 static inline void access_errorCF(struct frame *fp)
117 unsigned long int mmusr, complainingAddress;
118 unsigned int err_code, fs;
121 mmusr = fp->ptregs.mmusr;
122 complainingAddress = fp->ptregs.mmuar;
124 printk(KERN_DEBUG "pc %#lx, mmusr %#lx, complainingAddress %#lx\n", \
125 fp->ptregs.pc, mmusr, complainingAddress);
130 * bit 0 == 0 means no page found, 1 means protection fault
131 * bit 1 == 0 means read, 1 means write
134 fs = (fp->ptregs.fs2 << 2) | fp->ptregs.fs1;
136 case 5: /* 0101 TLB opword X miss */
137 need_page_fault = cf_tlb_miss(&fp->ptregs, 0, 0, 0);
138 complainingAddress = fp->ptregs.pc;
140 case 6: /* 0110 TLB extension word X miss */
141 need_page_fault = cf_tlb_miss(&fp->ptregs, 0, 0, 1);
142 complainingAddress = fp->ptregs.pc + sizeof(long);
144 case 10: /* 1010 TLB W miss */
145 need_page_fault = cf_tlb_miss(&fp->ptregs, 1, 1, 0);
147 case 14: /* 1110 TLB R miss */
148 need_page_fault = cf_tlb_miss(&fp->ptregs, 0, 1, 0);
153 /* 0010 Interrupt during debug service routine */
155 /* 0100 X Protection */
156 /* 0111 IFP in emulator mode */
157 /* 1000 W Protection*/
158 /* 1001 Write error*/
160 /* 1100 R Protection*/
161 /* 1101 R Protection*/
162 /* 1111 OEP in emulator mode*/
167 if (need_page_fault) {
168 err_code = fs_err_code[fs];
169 if ((fs == 13) && (mmusr & MMUSR_WF)) /* rd-mod-wr access */
170 err_code |= 2; /* bit1 - write, bit0 - protection */
171 do_page_fault(&fp->ptregs, complainingAddress, err_code);
175 void die_if_kernel(char *str, struct pt_regs *fp, int nr)
177 if (!(fp->sr & PS_S))
181 printk(KERN_EMERG "%s: %08x\n", str, nr);
182 printk(KERN_EMERG "PC: [<%08lx>]", fp->pc);
183 print_symbol(" %s", fp->pc);
184 printk(KERN_EMERG "\nSR: %04x SP: %p a2: %08lx\n",
186 printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
187 fp->d0, fp->d1, fp->d2, fp->d3);
188 printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
189 fp->d4, fp->d5, fp->a0, fp->a1);
191 printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n",
192 current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
193 show_stack(NULL, (unsigned long *)fp);
197 asmlinkage void buserr_c(struct frame *fp)
201 /* Only set esp0 if coming from user mode */
202 if (user_mode(&fp->ptregs))
203 current->thread.esp0 = (unsigned long) fp;
205 fs = (fp->ptregs.fs2 << 2) | fp->ptregs.fs1;
207 printk(KERN_DEBUG "*** Bus Error *** (%x)%s\n", fs,
208 fs_err_msg[fs & 0xf]);
222 die_if_kernel("bad frame format", &fp->ptregs, 0);
224 printk(KERN_DEBUG "Unknown SIGSEGV - 4\n");
226 force_sig(SIGSEGV, current);
230 void show_trace(unsigned long *stack)
232 unsigned long *endstack;
236 printk("Call Trace:");
237 addr = (unsigned long)stack + THREAD_SIZE - 1;
238 endstack = (unsigned long *)(addr & -THREAD_SIZE);
240 while (stack + 1 <= endstack) {
243 * If the address is either in the text segment of the
244 * kernel, or in the region which contains vmalloc'ed
245 * memory, it *may* be the address of a calling
246 * routine; if so, print it so that someone tracing
247 * down the cause of the crash will be able to figure
248 * out the call path that was taken.
250 if (__kernel_text_address(addr)) {
251 #ifndef CONFIG_KALLSYMS
255 printk(" [<%08lx>] %pS\n", addr, (void *)addr);
262 int kstack_depth_to_print = 48;
263 void show_stack(struct task_struct *task, unsigned long *stack)
266 unsigned long *endstack;
271 stack = (unsigned long *)task->thread.esp0;
273 stack = (unsigned long *)&stack;
275 endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) & -THREAD_SIZE);
277 printk("Stack from %08lx:", (unsigned long)stack);
279 for (i = 0; i < kstack_depth_to_print; i++) {
280 if (p + 1 > endstack)
284 printk(" %08lx", *p++);
290 void bad_super_trap(struct frame *fp)
293 if (fp->ptregs.vector < sizeof(vec_names)/sizeof(vec_names[0]))
294 printk(KERN_WARNING "*** %s *** FORMAT=%X\n",
295 vec_names[fp->ptregs.vector],
298 printk(KERN_WARNING "*** Exception %d *** FORMAT=%X\n",
301 printk(KERN_WARNING "Current process id is %d\n", current->pid);
302 die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
305 asmlinkage void trap_c(struct frame *fp)
310 if (fp->ptregs.sr & PS_S) {
311 if (fp->ptregs.vector == VEC_TRACE) {
312 /* traced a trapping instruction */
313 current->ptrace |= PT_DTRACE;
319 /* send the appropriate signal to the user program */
320 switch (fp->ptregs.vector) {
322 info.si_code = BUS_ADRALN;
328 info.si_code = ILL_ILLOPC;
332 info.si_code = ILL_PRVOPC;
336 info.si_code = ILL_COPROC;
339 case VEC_TRAP1: /* gdbserver breakpoint */
341 info.si_code = TRAP_TRACE;
357 info.si_code = ILL_ILLTRP;
363 info.si_code = FPE_FLTINV;
367 info.si_code = FPE_FLTRES;
371 info.si_code = FPE_FLTDIV;
375 info.si_code = FPE_FLTUND;
379 info.si_code = FPE_FLTOVF;
383 info.si_code = FPE_INTDIV;
388 info.si_code = FPE_INTOVF;
391 case VEC_TRACE: /* ptrace single step */
392 info.si_code = TRAP_TRACE;
395 case VEC_TRAP15: /* breakpoint */
396 info.si_code = TRAP_BRKPT;
400 info.si_code = ILL_ILLOPC;
406 switch (fp->ptregs.format) {
408 info.si_addr = (void *) fp->ptregs.pc;
411 info.si_addr = (void *) fp->un.fmt2.iaddr;
414 info.si_addr = (void *) fp->un.fmt7.effaddr;
417 info.si_addr = (void *) fp->un.fmt9.iaddr;
420 info.si_addr = (void *) fp->un.fmta.daddr;
423 info.si_addr = (void *) fp->un.fmtb.daddr;
426 force_sig_info(sig, &info, current);
429 asmlinkage void set_esp0(unsigned long ssp)
431 current->thread.esp0 = ssp;
435 * The architecture-independent backtrace generator
437 void dump_stack(void)
441 show_stack(current, &stack);
443 EXPORT_SYMBOL(dump_stack);
445 #ifdef CONFIG_M68KFPU_EMU
446 asmlinkage void fpemu_signal(int signal, int code, void *addr)
450 info.si_signo = signal;
454 force_sig_info(signal, &info, current);