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