Root/target/linux/coldfire/files-2.6.31/arch/m68k/coldfire/common/traps.c

1/*
2 * linux/arch/m68knommu/kernel/traps.c
3 *
4 * Copyright Freescale Semiconductor, Inc. 2008-2009
5 * Jason Jin Jason.Jin@freescale.com
6 * Shrek Wu B16972@freescale.com
7 *
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
10 * for more details.
11 */
12
13/*
14 * Sets up all exception vectors
15 */
16#include <linux/sched.h>
17#include <linux/signal.h>
18#include <linux/kernel.h>
19#include <linux/mm.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>
29
30#include <asm/setup.h>
31#include <asm/fpu.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>
38
39static 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"
59};
60
61asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
62                 unsigned long error_code);
63asmlinkage void trap_c(struct frame *fp);
64extern void __init coldfire_trap_init(void);
65
66void __init trap_init(void)
67{
68    coldfire_trap_init();
69}
70
71/* The following table converts the FS encoding of a ColdFire
72   exception stack frame into the error_code value needed by
73   do_fault. */
74
75static const unsigned char fs_err_code[] = {
76    0, /* 0000 */
77    0, /* 0001 */
78    0, /* 0010 */
79    0, /* 0011 */
80    1, /* 0100 */
81    0, /* 0101 */
82    0, /* 0110 */
83    0, /* 0111 */
84    2, /* 1000 */
85    3, /* 1001 */
86    2, /* 1010 */
87    0, /* 1011 */
88    1, /* 1100 */
89    1, /* 1101 */
90    0, /* 1110 */
91    0 /* 1111 */
92};
93
94#ifdef DEBUG
95static const char *fs_err_msg[16] = {
96    "Normal",
97    "Reserved",
98    "Interrupt during debug service routine",
99    "Reserved",
100    "X Protection",
101    "TLB X miss (opword)",
102    "TLB X miss (ext. word)",
103    "IFP in emulator mode",
104    "W Protection",
105    "Write error",
106    "TLB W miss",
107    "Reserved",
108    "R Protection",
109    "R/RMW Protection",
110    "TLB R miss",
111    "OEP in emulator mode",
112};
113#endif
114
115static inline void access_errorCF(struct frame *fp)
116{
117    unsigned long int mmusr, complainingAddress;
118    unsigned int err_code, fs;
119    int need_page_fault;
120
121    mmusr = fp->ptregs.mmusr;
122    complainingAddress = fp->ptregs.mmuar;
123#ifdef DEBUG
124    printk(KERN_DEBUG "pc %#lx, mmusr %#lx, complainingAddress %#lx\n", \
125        fp->ptregs.pc, mmusr, complainingAddress);
126#endif
127
128    /*
129     * error_code:
130     * bit 0 == 0 means no page found, 1 means protection fault
131     * bit 1 == 0 means read, 1 means write
132     */
133
134    fs = (fp->ptregs.fs2 << 2) | fp->ptregs.fs1;
135    switch (fs) {
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;
139        break;
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);
143        break;
144    case 10: /* 1010 TLB W miss */
145        need_page_fault = cf_tlb_miss(&fp->ptregs, 1, 1, 0);
146        break;
147    case 14: /* 1110 TLB R miss */
148        need_page_fault = cf_tlb_miss(&fp->ptregs, 0, 1, 0);
149        break;
150    default:
151        /* 0000 Normal */
152        /* 0001 Reserved */
153        /* 0010 Interrupt during debug service routine */
154        /* 0011 Reserved */
155        /* 0100 X Protection */
156        /* 0111 IFP in emulator mode */
157        /* 1000 W Protection*/
158        /* 1001 Write error*/
159        /* 1011 Reserved*/
160        /* 1100 R Protection*/
161        /* 1101 R Protection*/
162        /* 1111 OEP in emulator mode*/
163        need_page_fault = 1;
164        break;
165    }
166
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);
172    }
173}
174
175void die_if_kernel(char *str, struct pt_regs *fp, int nr)
176{
177    if (!(fp->sr & PS_S))
178        return;
179
180    console_verbose();
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",
185           fp->sr, fp, fp->a2);
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);
190
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);
194    do_exit(SIGSEGV);
195}
196
197asmlinkage void buserr_c(struct frame *fp)
198{
199    unsigned int fs;
200
201    /* Only set esp0 if coming from user mode */
202    if (user_mode(&fp->ptregs))
203        current->thread.esp0 = (unsigned long) fp;
204
205    fs = (fp->ptregs.fs2 << 2) | fp->ptregs.fs1;
206#if defined(DEBUG)
207    printk(KERN_DEBUG "*** Bus Error *** (%x)%s\n", fs,
208        fs_err_msg[fs & 0xf]);
209#endif
210    switch (fs) {
211    case 0x5:
212    case 0x6:
213    case 0x7:
214    case 0x9:
215    case 0xa:
216    case 0xd:
217    case 0xe:
218    case 0xf:
219        access_errorCF(fp);
220        break;
221    default:
222        die_if_kernel("bad frame format", &fp->ptregs, 0);
223#if defined(DEBUG)
224        printk(KERN_DEBUG "Unknown SIGSEGV - 4\n");
225#endif
226        force_sig(SIGSEGV, current);
227    }
228}
229
230void show_trace(unsigned long *stack)
231{
232    unsigned long *endstack;
233    unsigned long addr;
234    int i;
235
236    printk("Call Trace:");
237    addr = (unsigned long)stack + THREAD_SIZE - 1;
238    endstack = (unsigned long *)(addr & -THREAD_SIZE);
239    i = 0;
240    while (stack + 1 <= endstack) {
241        addr = *stack++;
242        /*
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.
249         */
250        if (__kernel_text_address(addr)) {
251#ifndef CONFIG_KALLSYMS
252            if (i % 5 == 0)
253                printk("\n ");
254#endif
255            printk(" [<%08lx>] %pS\n", addr, (void *)addr);
256            i++;
257        }
258    }
259    printk("\n");
260}
261
262int kstack_depth_to_print = 48;
263void show_stack(struct task_struct *task, unsigned long *stack)
264{
265    unsigned long *p;
266    unsigned long *endstack;
267    int i;
268
269    if (!stack) {
270        if (task)
271            stack = (unsigned long *)task->thread.esp0;
272        else
273            stack = (unsigned long *)&stack;
274    }
275    endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) & -THREAD_SIZE);
276
277    printk("Stack from %08lx:", (unsigned long)stack);
278    p = stack;
279    for (i = 0; i < kstack_depth_to_print; i++) {
280        if (p + 1 > endstack)
281            break;
282        if (i % 8 == 0)
283            printk("\n ");
284        printk(" %08lx", *p++);
285    }
286    printk("\n");
287    show_trace(stack);
288}
289
290void bad_super_trap(struct frame *fp)
291{
292    console_verbose();
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],
296            fp->ptregs.format);
297    else
298        printk(KERN_WARNING "*** Exception %d *** FORMAT=%X\n",
299            fp->ptregs.vector,
300            fp->ptregs.format);
301    printk(KERN_WARNING "Current process id is %d\n", current->pid);
302    die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
303}
304
305asmlinkage void trap_c(struct frame *fp)
306{
307    int sig;
308    siginfo_t info;
309
310    if (fp->ptregs.sr & PS_S) {
311        if (fp->ptregs.vector == VEC_TRACE) {
312            /* traced a trapping instruction */
313            current->ptrace |= PT_DTRACE;
314        } else
315            bad_super_trap(fp);
316        return;
317    }
318
319    /* send the appropriate signal to the user program */
320    switch (fp->ptregs.vector) {
321    case VEC_ADDRERR:
322        info.si_code = BUS_ADRALN;
323        sig = SIGBUS;
324        break;
325    case VEC_ILLEGAL:
326    case VEC_LINE10:
327    case VEC_LINE11:
328        info.si_code = ILL_ILLOPC;
329        sig = SIGILL;
330        break;
331    case VEC_PRIV:
332        info.si_code = ILL_PRVOPC;
333        sig = SIGILL;
334        break;
335    case VEC_COPROC:
336        info.si_code = ILL_COPROC;
337        sig = SIGILL;
338        break;
339    case VEC_TRAP1: /* gdbserver breakpoint */
340        fp->ptregs.pc -= 2;
341        info.si_code = TRAP_TRACE;
342        sig = SIGTRAP;
343        break;
344    case VEC_TRAP2:
345    case VEC_TRAP3:
346    case VEC_TRAP4:
347    case VEC_TRAP5:
348    case VEC_TRAP6:
349    case VEC_TRAP7:
350    case VEC_TRAP8:
351    case VEC_TRAP9:
352    case VEC_TRAP10:
353    case VEC_TRAP11:
354    case VEC_TRAP12:
355    case VEC_TRAP13:
356    case VEC_TRAP14:
357        info.si_code = ILL_ILLTRP;
358        sig = SIGILL;
359        break;
360    case VEC_FPBRUC:
361    case VEC_FPOE:
362    case VEC_FPNAN:
363        info.si_code = FPE_FLTINV;
364        sig = SIGFPE;
365        break;
366    case VEC_FPIR:
367        info.si_code = FPE_FLTRES;
368        sig = SIGFPE;
369        break;
370    case VEC_FPDIVZ:
371        info.si_code = FPE_FLTDIV;
372        sig = SIGFPE;
373        break;
374    case VEC_FPUNDER:
375        info.si_code = FPE_FLTUND;
376        sig = SIGFPE;
377        break;
378    case VEC_FPOVER:
379        info.si_code = FPE_FLTOVF;
380        sig = SIGFPE;
381        break;
382    case VEC_ZERODIV:
383        info.si_code = FPE_INTDIV;
384        sig = SIGFPE;
385        break;
386    case VEC_CHK:
387    case VEC_TRAP:
388        info.si_code = FPE_INTOVF;
389        sig = SIGFPE;
390        break;
391    case VEC_TRACE: /* ptrace single step */
392        info.si_code = TRAP_TRACE;
393        sig = SIGTRAP;
394        break;
395    case VEC_TRAP15: /* breakpoint */
396        info.si_code = TRAP_BRKPT;
397        sig = SIGTRAP;
398        break;
399    default:
400        info.si_code = ILL_ILLOPC;
401        sig = SIGILL;
402        break;
403    }
404    info.si_signo = sig;
405    info.si_errno = 0;
406    switch (fp->ptregs.format) {
407    default:
408        info.si_addr = (void *) fp->ptregs.pc;
409        break;
410    case 2:
411        info.si_addr = (void *) fp->un.fmt2.iaddr;
412        break;
413    case 7:
414        info.si_addr = (void *) fp->un.fmt7.effaddr;
415        break;
416    case 9:
417        info.si_addr = (void *) fp->un.fmt9.iaddr;
418        break;
419    case 10:
420        info.si_addr = (void *) fp->un.fmta.daddr;
421        break;
422    case 11:
423        info.si_addr = (void *) fp->un.fmtb.daddr;
424        break;
425    }
426    force_sig_info(sig, &info, current);
427}
428
429asmlinkage void set_esp0(unsigned long ssp)
430{
431    current->thread.esp0 = ssp;
432}
433
434/*
435 * The architecture-independent backtrace generator
436 */
437void dump_stack(void)
438{
439    unsigned long stack;
440
441    show_stack(current, &stack);
442}
443EXPORT_SYMBOL(dump_stack);
444
445#ifdef CONFIG_M68KFPU_EMU
446asmlinkage void fpemu_signal(int signal, int code, void *addr)
447{
448    siginfo_t info;
449
450    info.si_signo = signal;
451    info.si_errno = 0;
452    info.si_code = code;
453    info.si_addr = addr;
454    force_sig_info(signal, &info, current);
455}
456#endif
457

Archive Download this file



interactive