Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
[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/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
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         if (mach_trap_init)
66                 mach_trap_init();
67 }
68
69 void die_if_kernel(char *str, struct pt_regs *fp, int nr)
70 {
71         if (!(fp->sr & PS_S))
72                 return;
73
74         console_verbose();
75         printk(KERN_EMERG "%s: %08x\n",str,nr);
76         printk(KERN_EMERG "PC: [<%08lx>]\nSR: %04x  SP: %p  a2: %08lx\n",
77                fp->pc, fp->sr, fp, fp->a2);
78         printk(KERN_EMERG "d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
79                fp->d0, fp->d1, fp->d2, fp->d3);
80         printk(KERN_EMERG "d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
81                fp->d4, fp->d5, fp->a0, fp->a1);
82
83         printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n",
84                 current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
85         show_stack(NULL, (unsigned long *)fp);
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
107 int kstack_depth_to_print = 48;
108
109 void show_stack(struct task_struct *task, unsigned long *stack)
110 {
111         unsigned long *endstack, addr;
112         extern char _start, _etext;
113         int i;
114
115         if (!stack) {
116                 if (task)
117                         stack = (unsigned long *)task->thread.ksp;
118                 else
119                         stack = (unsigned long *)&stack;
120         }
121
122         addr = (unsigned long) stack;
123         endstack = (unsigned long *) PAGE_ALIGN(addr);
124
125         printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
126         for (i = 0; i < kstack_depth_to_print; i++) {
127                 if (stack + 1 > endstack)
128                         break;
129                 if (i % 8 == 0)
130                         printk("\n" KERN_EMERG "       ");
131                 printk(" %08lx", *stack++);
132         }
133         printk("\n");
134
135         printk(KERN_EMERG "Call Trace:");
136         i = 0;
137         while (stack + 1 <= endstack) {
138                 addr = *stack++;
139                 /*
140                  * If the address is either in the text segment of the
141                  * kernel, or in the region which contains vmalloc'ed
142                  * memory, it *may* be the address of a calling
143                  * routine; if so, print it so that someone tracing
144                  * down the cause of the crash will be able to figure
145                  * out the call path that was taken.
146                  */
147                 if (((addr >= (unsigned long) &_start) &&
148                      (addr <= (unsigned long) &_etext))) {
149                         if (i % 4 == 0)
150                                 printk("\n" KERN_EMERG "       ");
151                         printk(" [<%08lx>]", addr);
152                         i++;
153                 }
154         }
155         printk("\n");
156 }
157
158 void bad_super_trap(struct frame *fp)
159 {
160         console_verbose();
161         if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
162                 printk (KERN_WARNING "*** %s ***   FORMAT=%X\n",
163                         vec_names[(fp->ptregs.vector) >> 2],
164                         fp->ptregs.format);
165         else
166                 printk (KERN_WARNING "*** Exception %d ***   FORMAT=%X\n",
167                         (fp->ptregs.vector) >> 2, 
168                         fp->ptregs.format);
169         printk (KERN_WARNING "Current process id is %d\n", current->pid);
170         die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
171 }
172
173 asmlinkage void trap_c(struct frame *fp)
174 {
175         int sig;
176         siginfo_t info;
177
178         if (fp->ptregs.sr & PS_S) {
179                 if ((fp->ptregs.vector >> 2) == VEC_TRACE) {
180                         /* traced a trapping instruction */
181                         current->ptrace |= PT_DTRACE;
182                 } else
183                         bad_super_trap(fp);
184                 return;
185         }
186
187         /* send the appropriate signal to the user program */
188         switch ((fp->ptregs.vector) >> 2) {
189             case VEC_ADDRERR:
190                 info.si_code = BUS_ADRALN;
191                 sig = SIGBUS;
192                 break;
193             case VEC_ILLEGAL:
194             case VEC_LINE10:
195             case VEC_LINE11:
196                 info.si_code = ILL_ILLOPC;
197                 sig = SIGILL;
198                 break;
199             case VEC_PRIV:
200                 info.si_code = ILL_PRVOPC;
201                 sig = SIGILL;
202                 break;
203             case VEC_COPROC:
204                 info.si_code = ILL_COPROC;
205                 sig = SIGILL;
206                 break;
207             case VEC_TRAP1: /* gdbserver breakpoint */
208                 fp->ptregs.pc -= 2;
209                 info.si_code = TRAP_TRACE;
210                 sig = SIGTRAP;
211                 break;
212             case VEC_TRAP2:
213             case VEC_TRAP3:
214             case VEC_TRAP4:
215             case VEC_TRAP5:
216             case VEC_TRAP6:
217             case VEC_TRAP7:
218             case VEC_TRAP8:
219             case VEC_TRAP9:
220             case VEC_TRAP10:
221             case VEC_TRAP11:
222             case VEC_TRAP12:
223             case VEC_TRAP13:
224             case VEC_TRAP14:
225                 info.si_code = ILL_ILLTRP;
226                 sig = SIGILL;
227                 break;
228             case VEC_FPBRUC:
229             case VEC_FPOE:
230             case VEC_FPNAN:
231                 info.si_code = FPE_FLTINV;
232                 sig = SIGFPE;
233                 break;
234             case VEC_FPIR:
235                 info.si_code = FPE_FLTRES;
236                 sig = SIGFPE;
237                 break;
238             case VEC_FPDIVZ:
239                 info.si_code = FPE_FLTDIV;
240                 sig = SIGFPE;
241                 break;
242             case VEC_FPUNDER:
243                 info.si_code = FPE_FLTUND;
244                 sig = SIGFPE;
245                 break;
246             case VEC_FPOVER:
247                 info.si_code = FPE_FLTOVF;
248                 sig = SIGFPE;
249                 break;
250             case VEC_ZERODIV:
251                 info.si_code = FPE_INTDIV;
252                 sig = SIGFPE;
253                 break;
254             case VEC_CHK:
255             case VEC_TRAP:
256                 info.si_code = FPE_INTOVF;
257                 sig = SIGFPE;
258                 break;
259             case VEC_TRACE:             /* ptrace single step */
260                 info.si_code = TRAP_TRACE;
261                 sig = SIGTRAP;
262                 break;
263             case VEC_TRAP15:            /* breakpoint */
264                 info.si_code = TRAP_BRKPT;
265                 sig = SIGTRAP;
266                 break;
267             default:
268                 info.si_code = ILL_ILLOPC;
269                 sig = SIGILL;
270                 break;
271         }
272         info.si_signo = sig;
273         info.si_errno = 0;
274         switch (fp->ptregs.format) {
275             default:
276                 info.si_addr = (void *) fp->ptregs.pc;
277                 break;
278             case 2:
279                 info.si_addr = (void *) fp->un.fmt2.iaddr;
280                 break;
281             case 7:
282                 info.si_addr = (void *) fp->un.fmt7.effaddr;
283                 break;
284             case 9:
285                 info.si_addr = (void *) fp->un.fmt9.iaddr;
286                 break;
287             case 10:
288                 info.si_addr = (void *) fp->un.fmta.daddr;
289                 break;
290             case 11:
291                 info.si_addr = (void *) fp->un.fmtb.daddr;
292                 break;
293         }
294         force_sig_info (sig, &info, current);
295 }
296
297 asmlinkage void set_esp0(unsigned long ssp)
298 {
299         current->thread.esp0 = ssp;
300 }
301
302
303 /*
304  * The architecture-independent backtrace generator
305  */
306 void dump_stack(void)
307 {
308         unsigned long stack;
309
310         show_stack(current, &stack);
311 }
312
313 EXPORT_SYMBOL(dump_stack);
314
315 #ifdef CONFIG_M68KFPU_EMU
316 asmlinkage void fpemu_signal(int signal, int code, void *addr)
317 {
318         siginfo_t info;
319
320         info.si_signo = signal;
321         info.si_errno = 0;
322         info.si_code = code;
323         info.si_addr = addr;
324         force_sig_info(signal, &info, current);
325 }
326 #endif