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