46f8f9d0c4089085c2c3888e0c63afa2cbbb0e09
[linux-3.10.git] / arch / m68knommu / kernel / traps.c
1 /*
2  *  linux/arch/m68knommu/kernel/traps.c
3  *
4  *  Copyright (C) 1993, 1994 by Hamish Macdonald
5  *
6  *  68040 fixes by Michael Rausch
7  *  68040 fixes by Martin Apel
8  *  68060 fixes by Roman Hodek
9  *  68060 fixes by Jesper Skov
10  *
11  * This file is subject to the terms and conditions of the GNU General Public
12  * License.  See the file COPYING in the main directory of this archive
13  * for more details.
14  */
15
16 /*
17  * Sets up all exception vectors
18  */
19 #include <linux/sched.h>
20 #include <linux/signal.h>
21 #include <linux/kernel.h>
22 #include <linux/mm.h>
23 #include <linux/module.h>
24 #include <linux/types.h>
25 #include <linux/a.out.h>
26 #include <linux/user.h>
27 #include <linux/string.h>
28 #include <linux/linkage.h>
29 #include <linux/init.h>
30 #include <linux/ptrace.h>
31 #include <linux/kallsyms.h>
32
33 #include <asm/setup.h>
34 #include <asm/fpu.h>
35 #include <asm/system.h>
36 #include <asm/uaccess.h>
37 #include <asm/traps.h>
38 #include <asm/pgtable.h>
39 #include <asm/machdep.h>
40 #include <asm/siginfo.h>
41
42 static char const * const vec_names[] = {
43         "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR",
44         "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc",
45         "PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111",
46         "UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION",
47         "FORMAT ERROR", "UNINITIALIZED INTERRUPT",
48         "UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17",
49         "UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19",
50         "UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21",
51         "UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23",
52         "SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT",
53         "LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT",
54         "SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3",
55         "TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7",
56         "TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11",
57         "TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15",
58         "FPCP BSUN", "FPCP INEXACT", "FPCP DIV BY 0", "FPCP UNDERFLOW",
59         "FPCP OPERAND ERROR", "FPCP OVERFLOW", "FPCP SNAN",
60         "FPCP UNSUPPORTED OPERATION",
61         "MMU CONFIGURATION ERROR"
62 };
63
64 void __init trap_init(void)
65 {
66 }
67
68 void die_if_kernel(char *str, struct pt_regs *fp, int nr)
69 {
70         if (!(fp->sr & PS_S))
71                 return;
72
73         console_verbose();
74         printk(KERN_EMERG "%s: %08x\n",str,nr);
75         printk(KERN_EMERG "PC: [<%08lx>]\nSR: %04x  SP: %p  a2: %08lx\n",
76                fp->pc, fp->sr, fp, fp->a2);
77         printk(KERN_EMERG "d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
78                fp->d0, fp->d1, fp->d2, fp->d3);
79         printk(KERN_EMERG "d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
80                fp->d4, fp->d5, fp->a0, fp->a1);
81
82         printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n",
83                 current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
84         show_stack(NULL, (unsigned long *)(fp + 1));
85         add_taint(TAINT_DIE);
86         do_exit(SIGSEGV);
87 }
88
89 asmlinkage void buserr_c(struct frame *fp)
90 {
91         /* Only set esp0 if coming from user mode */
92         if (user_mode(&fp->ptregs))
93                 current->thread.esp0 = (unsigned long) fp;
94
95 #if defined(DEBUG)
96         printk (KERN_DEBUG "*** Bus Error *** Format is %x\n", fp->ptregs.format);
97 #endif
98
99         die_if_kernel("bad frame format",&fp->ptregs,0);
100 #if defined(DEBUG)
101         printk(KERN_DEBUG "Unknown SIGSEGV - 4\n");
102 #endif
103         force_sig(SIGSEGV, current);
104 }
105
106 static void print_this_address(unsigned long addr, int i)
107 {
108 #ifdef CONFIG_KALLSYMS
109         printk(KERN_EMERG " [%08lx] ", addr);
110         print_symbol(KERN_CONT "%s\n", addr);
111 #else
112         if (i % 5)
113                 printk(KERN_CONT " [%08lx] ", addr);
114         else
115                 printk(KERN_CONT "\n" KERN_EMERG " [%08lx] ", addr);
116         i++;
117 #endif
118 }
119
120 int kstack_depth_to_print = 48;
121
122 static void __show_stack(struct task_struct *task, unsigned long *stack)
123 {
124         unsigned long *endstack, addr;
125 #ifdef CONFIG_FRAME_POINTER
126         unsigned long *last_stack;
127 #endif
128         int i;
129
130         if (!stack)
131                 stack = (unsigned long *)task->thread.ksp;
132
133         addr = (unsigned long) stack;
134         endstack = (unsigned long *) PAGE_ALIGN(addr);
135
136         printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
137         for (i = 0; i < kstack_depth_to_print; i++) {
138                 if (stack + 1 + i > endstack)
139                         break;
140                 if (i % 8 == 0)
141                         printk("\n" KERN_EMERG "       ");
142                 printk(" %08lx", *(stack + i));
143         }
144         printk("\n");
145         i = 0;
146
147 #ifdef CONFIG_FRAME_POINTER
148         printk(KERN_EMERG "Call Trace:\n");
149
150         last_stack = stack - 1;
151         while (stack <= endstack && stack > last_stack) {
152
153                 addr = *(stack + 1);
154                 print_this_address(addr, i);
155                 i++;
156
157                 last_stack = stack;
158                 stack = (unsigned long *)*stack;
159         }
160         printk("\n");
161 #else
162         printk(KERN_EMERG "Call Trace with CONFIG_FRAME_POINTER disabled:\n");
163         while (stack <= endstack) {
164                 addr = *stack++;
165                 /*
166                  * If the address is either in the text segment of the kernel,
167                  * or in a region which is occupied by a module then it *may*
168                  * be the address of a calling routine; if so, print it so that
169                  * someone tracing down the cause of the crash will be able to
170                  * figure out the call path that was taken.
171                  */
172                 if (__kernel_text_address(addr)) {
173                         print_this_address(addr, i);
174                         i++;
175                 }
176         }
177         printk(KERN_CONT "\n");
178 #endif
179 }
180
181 void bad_super_trap(struct frame *fp)
182 {
183         console_verbose();
184         if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
185                 printk (KERN_WARNING "*** %s ***   FORMAT=%X\n",
186                         vec_names[(fp->ptregs.vector) >> 2],
187                         fp->ptregs.format);
188         else
189                 printk (KERN_WARNING "*** Exception %d ***   FORMAT=%X\n",
190                         (fp->ptregs.vector) >> 2, 
191                         fp->ptregs.format);
192         printk (KERN_WARNING "Current process id is %d\n", current->pid);
193         die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
194 }
195
196 asmlinkage void trap_c(struct frame *fp)
197 {
198         int sig;
199         siginfo_t info;
200
201         if (fp->ptregs.sr & PS_S) {
202                 if ((fp->ptregs.vector >> 2) == VEC_TRACE) {
203                         /* traced a trapping instruction */
204                         current->ptrace |= PT_DTRACE;
205                 } else
206                         bad_super_trap(fp);
207                 return;
208         }
209
210         /* send the appropriate signal to the user program */
211         switch ((fp->ptregs.vector) >> 2) {
212             case VEC_ADDRERR:
213                 info.si_code = BUS_ADRALN;
214                 sig = SIGBUS;
215                 break;
216             case VEC_ILLEGAL:
217             case VEC_LINE10:
218             case VEC_LINE11:
219                 info.si_code = ILL_ILLOPC;
220                 sig = SIGILL;
221                 break;
222             case VEC_PRIV:
223                 info.si_code = ILL_PRVOPC;
224                 sig = SIGILL;
225                 break;
226             case VEC_COPROC:
227                 info.si_code = ILL_COPROC;
228                 sig = SIGILL;
229                 break;
230             case VEC_TRAP1: /* gdbserver breakpoint */
231                 fp->ptregs.pc -= 2;
232                 info.si_code = TRAP_TRACE;
233                 sig = SIGTRAP;
234                 break;
235             case VEC_TRAP2:
236             case VEC_TRAP3:
237             case VEC_TRAP4:
238             case VEC_TRAP5:
239             case VEC_TRAP6:
240             case VEC_TRAP7:
241             case VEC_TRAP8:
242             case VEC_TRAP9:
243             case VEC_TRAP10:
244             case VEC_TRAP11:
245             case VEC_TRAP12:
246             case VEC_TRAP13:
247             case VEC_TRAP14:
248                 info.si_code = ILL_ILLTRP;
249                 sig = SIGILL;
250                 break;
251             case VEC_FPBRUC:
252             case VEC_FPOE:
253             case VEC_FPNAN:
254                 info.si_code = FPE_FLTINV;
255                 sig = SIGFPE;
256                 break;
257             case VEC_FPIR:
258                 info.si_code = FPE_FLTRES;
259                 sig = SIGFPE;
260                 break;
261             case VEC_FPDIVZ:
262                 info.si_code = FPE_FLTDIV;
263                 sig = SIGFPE;
264                 break;
265             case VEC_FPUNDER:
266                 info.si_code = FPE_FLTUND;
267                 sig = SIGFPE;
268                 break;
269             case VEC_FPOVER:
270                 info.si_code = FPE_FLTOVF;
271                 sig = SIGFPE;
272                 break;
273             case VEC_ZERODIV:
274                 info.si_code = FPE_INTDIV;
275                 sig = SIGFPE;
276                 break;
277             case VEC_CHK:
278             case VEC_TRAP:
279                 info.si_code = FPE_INTOVF;
280                 sig = SIGFPE;
281                 break;
282             case VEC_TRACE:             /* ptrace single step */
283                 info.si_code = TRAP_TRACE;
284                 sig = SIGTRAP;
285                 break;
286             case VEC_TRAP15:            /* breakpoint */
287                 info.si_code = TRAP_BRKPT;
288                 sig = SIGTRAP;
289                 break;
290             default:
291                 info.si_code = ILL_ILLOPC;
292                 sig = SIGILL;
293                 break;
294         }
295         info.si_signo = sig;
296         info.si_errno = 0;
297         switch (fp->ptregs.format) {
298             default:
299                 info.si_addr = (void *) fp->ptregs.pc;
300                 break;
301             case 2:
302                 info.si_addr = (void *) fp->un.fmt2.iaddr;
303                 break;
304             case 7:
305                 info.si_addr = (void *) fp->un.fmt7.effaddr;
306                 break;
307             case 9:
308                 info.si_addr = (void *) fp->un.fmt9.iaddr;
309                 break;
310             case 10:
311                 info.si_addr = (void *) fp->un.fmta.daddr;
312                 break;
313             case 11:
314                 info.si_addr = (void *) fp->un.fmtb.daddr;
315                 break;
316         }
317         force_sig_info (sig, &info, current);
318 }
319
320 asmlinkage void set_esp0(unsigned long ssp)
321 {
322         current->thread.esp0 = ssp;
323 }
324
325 /*
326  * The architecture-independent backtrace generator
327  */
328 void dump_stack(void)
329 {
330         /*
331          * We need frame pointers for this little trick, which works as follows:
332          *
333          * +------------+ 0x00
334          * | Next SP    |       -> 0x0c
335          * +------------+ 0x04
336          * | Caller     |
337          * +------------+ 0x08
338          * | Local vars |       -> our stack var
339          * +------------+ 0x0c
340          * | Next SP    |       -> 0x18, that is what we pass to show_stack()
341          * +------------+ 0x10
342          * | Caller     |
343          * +------------+ 0x14
344          * | Local vars |
345          * +------------+ 0x18
346          * | ...        |
347          * +------------+
348          */
349
350         unsigned long *stack;
351
352         stack = (unsigned long *)&stack;
353         stack++;
354         __show_stack(current, stack);
355 }
356 EXPORT_SYMBOL(dump_stack);
357
358 void show_stack(struct task_struct *task, unsigned long *stack)
359 {
360         if (!stack && !task)
361                 dump_stack();
362         else
363                 __show_stack(task, stack);
364 }
365
366 #ifdef CONFIG_M68KFPU_EMU
367 asmlinkage void fpemu_signal(int signal, int code, void *addr)
368 {
369         siginfo_t info;
370
371         info.si_signo = signal;
372         info.si_errno = 0;
373         info.si_code = code;
374         info.si_addr = addr;
375         force_sig_info(signal, &info, current);
376 }
377 #endif