3f96960b6a9fc1f245a92401017b3378f9c67756
[openwrt/staging/florian.git] / 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
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"
59 };
60
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);
65
66 void __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
75 static 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
95 static 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
115 static 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
175 void 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
197 asmlinkage 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
230 void 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
262 int kstack_depth_to_print = 48;
263 void 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
290 void 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
305 asmlinkage 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
429 asmlinkage void set_esp0(unsigned long ssp)
430 {
431 current->thread.esp0 = ssp;
432 }
433
434 /*
435 * The architecture-independent backtrace generator
436 */
437 void dump_stack(void)
438 {
439 unsigned long stack;
440
441 show_stack(current, &stack);
442 }
443 EXPORT_SYMBOL(dump_stack);
444
445 #ifdef CONFIG_M68KFPU_EMU
446 asmlinkage 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