Merge git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus
[pandora-kernel.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 int kstack_depth_to_print = 48;
107
108 static void __show_stack(struct task_struct *task, unsigned long *stack)
109 {
110         unsigned long *endstack, addr;
111         unsigned long *last_stack;
112         int i;
113
114         if (!stack)
115                 stack = (unsigned long *)task->thread.ksp;
116
117         addr = (unsigned long) stack;
118         endstack = (unsigned long *) PAGE_ALIGN(addr);
119
120         printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
121         for (i = 0; i < kstack_depth_to_print; i++) {
122                 if (stack + 1 + i > endstack)
123                         break;
124                 if (i % 8 == 0)
125                         printk("\n" KERN_EMERG "       ");
126                 printk(" %08lx", *(stack + i));
127         }
128         printk("\n");
129
130 #ifdef CONFIG_FRAME_POINTER
131         printk(KERN_EMERG "Call Trace:\n");
132
133         last_stack = stack - 1;
134         while (stack <= endstack && stack > last_stack) {
135
136                 addr = *(stack + 1);
137                 printk(KERN_EMERG " [%08lx] ", addr);
138                 print_symbol(KERN_CONT "%s\n", addr);
139
140                 last_stack = stack;
141                 stack = (unsigned long *)*stack;
142         }
143         printk("\n");
144 #else
145         printk(KERN_EMERG "CONFIG_FRAME_POINTER disabled, no symbolic call trace\n");
146 #endif
147 }
148
149 void bad_super_trap(struct frame *fp)
150 {
151         console_verbose();
152         if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
153                 printk (KERN_WARNING "*** %s ***   FORMAT=%X\n",
154                         vec_names[(fp->ptregs.vector) >> 2],
155                         fp->ptregs.format);
156         else
157                 printk (KERN_WARNING "*** Exception %d ***   FORMAT=%X\n",
158                         (fp->ptregs.vector) >> 2, 
159                         fp->ptregs.format);
160         printk (KERN_WARNING "Current process id is %d\n", current->pid);
161         die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
162 }
163
164 asmlinkage void trap_c(struct frame *fp)
165 {
166         int sig;
167         siginfo_t info;
168
169         if (fp->ptregs.sr & PS_S) {
170                 if ((fp->ptregs.vector >> 2) == VEC_TRACE) {
171                         /* traced a trapping instruction */
172                         current->ptrace |= PT_DTRACE;
173                 } else
174                         bad_super_trap(fp);
175                 return;
176         }
177
178         /* send the appropriate signal to the user program */
179         switch ((fp->ptregs.vector) >> 2) {
180             case VEC_ADDRERR:
181                 info.si_code = BUS_ADRALN;
182                 sig = SIGBUS;
183                 break;
184             case VEC_ILLEGAL:
185             case VEC_LINE10:
186             case VEC_LINE11:
187                 info.si_code = ILL_ILLOPC;
188                 sig = SIGILL;
189                 break;
190             case VEC_PRIV:
191                 info.si_code = ILL_PRVOPC;
192                 sig = SIGILL;
193                 break;
194             case VEC_COPROC:
195                 info.si_code = ILL_COPROC;
196                 sig = SIGILL;
197                 break;
198             case VEC_TRAP1: /* gdbserver breakpoint */
199                 fp->ptregs.pc -= 2;
200                 info.si_code = TRAP_TRACE;
201                 sig = SIGTRAP;
202                 break;
203             case VEC_TRAP2:
204             case VEC_TRAP3:
205             case VEC_TRAP4:
206             case VEC_TRAP5:
207             case VEC_TRAP6:
208             case VEC_TRAP7:
209             case VEC_TRAP8:
210             case VEC_TRAP9:
211             case VEC_TRAP10:
212             case VEC_TRAP11:
213             case VEC_TRAP12:
214             case VEC_TRAP13:
215             case VEC_TRAP14:
216                 info.si_code = ILL_ILLTRP;
217                 sig = SIGILL;
218                 break;
219             case VEC_FPBRUC:
220             case VEC_FPOE:
221             case VEC_FPNAN:
222                 info.si_code = FPE_FLTINV;
223                 sig = SIGFPE;
224                 break;
225             case VEC_FPIR:
226                 info.si_code = FPE_FLTRES;
227                 sig = SIGFPE;
228                 break;
229             case VEC_FPDIVZ:
230                 info.si_code = FPE_FLTDIV;
231                 sig = SIGFPE;
232                 break;
233             case VEC_FPUNDER:
234                 info.si_code = FPE_FLTUND;
235                 sig = SIGFPE;
236                 break;
237             case VEC_FPOVER:
238                 info.si_code = FPE_FLTOVF;
239                 sig = SIGFPE;
240                 break;
241             case VEC_ZERODIV:
242                 info.si_code = FPE_INTDIV;
243                 sig = SIGFPE;
244                 break;
245             case VEC_CHK:
246             case VEC_TRAP:
247                 info.si_code = FPE_INTOVF;
248                 sig = SIGFPE;
249                 break;
250             case VEC_TRACE:             /* ptrace single step */
251                 info.si_code = TRAP_TRACE;
252                 sig = SIGTRAP;
253                 break;
254             case VEC_TRAP15:            /* breakpoint */
255                 info.si_code = TRAP_BRKPT;
256                 sig = SIGTRAP;
257                 break;
258             default:
259                 info.si_code = ILL_ILLOPC;
260                 sig = SIGILL;
261                 break;
262         }
263         info.si_signo = sig;
264         info.si_errno = 0;
265         switch (fp->ptregs.format) {
266             default:
267                 info.si_addr = (void *) fp->ptregs.pc;
268                 break;
269             case 2:
270                 info.si_addr = (void *) fp->un.fmt2.iaddr;
271                 break;
272             case 7:
273                 info.si_addr = (void *) fp->un.fmt7.effaddr;
274                 break;
275             case 9:
276                 info.si_addr = (void *) fp->un.fmt9.iaddr;
277                 break;
278             case 10:
279                 info.si_addr = (void *) fp->un.fmta.daddr;
280                 break;
281             case 11:
282                 info.si_addr = (void *) fp->un.fmtb.daddr;
283                 break;
284         }
285         force_sig_info (sig, &info, current);
286 }
287
288 asmlinkage void set_esp0(unsigned long ssp)
289 {
290         current->thread.esp0 = ssp;
291 }
292
293 /*
294  * The architecture-independent backtrace generator
295  */
296 void dump_stack(void)
297 {
298         /*
299          * We need frame pointers for this little trick, which works as follows:
300          *
301          * +------------+ 0x00
302          * | Next SP    |       -> 0x0c
303          * +------------+ 0x04
304          * | Caller     |
305          * +------------+ 0x08
306          * | Local vars |       -> our stack var
307          * +------------+ 0x0c
308          * | Next SP    |       -> 0x18, that is what we pass to show_stack()
309          * +------------+ 0x10
310          * | Caller     |
311          * +------------+ 0x14
312          * | Local vars |
313          * +------------+ 0x18
314          * | ...        |
315          * +------------+
316          */
317
318         unsigned long *stack;
319
320         stack = (unsigned long *)&stack;
321         stack++;
322         __show_stack(current, stack);
323 }
324 EXPORT_SYMBOL(dump_stack);
325
326 void show_stack(struct task_struct *task, unsigned long *stack)
327 {
328         if (!stack && !task)
329                 dump_stack();
330         else
331                 __show_stack(task, stack);
332 }
333
334 #ifdef CONFIG_M68KFPU_EMU
335 asmlinkage void fpemu_signal(int signal, int code, void *addr)
336 {
337         siginfo_t info;
338
339         info.si_signo = signal;
340         info.si_errno = 0;
341         info.si_code = code;
342         info.si_addr = addr;
343         force_sig_info(signal, &info, current);
344 }
345 #endif