2 * linux/arch/m68knommu/kernel/traps.c
4 * Copyright (C) 1993, 1994 by Hamish Macdonald
6 * 68040 fixes by Michael Rausch
7 * 68040 fixes by Martin Apel
8 * 68060 fixes by Roman Hodek
9 * 68060 fixes by Jesper Skov
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
17 * Sets up all exception vectors
19 #include <linux/sched.h>
20 #include <linux/signal.h>
21 #include <linux/kernel.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>
32 #include <asm/setup.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>
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"
63 void __init
trap_init(void)
67 void die_if_kernel(char *str
, struct pt_regs
*fp
, int nr
)
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
);
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));
88 asmlinkage
void buserr_c(struct frame
*fp
)
90 /* Only set esp0 if coming from user mode */
91 if (user_mode(&fp
->ptregs
))
92 current
->thread
.esp0
= (unsigned long) fp
;
95 printk (KERN_DEBUG
"*** Bus Error *** Format is %x\n", fp
->ptregs
.format
);
98 die_if_kernel("bad frame format",&fp
->ptregs
,0);
100 printk(KERN_DEBUG
"Unknown SIGSEGV - 4\n");
102 force_sig(SIGSEGV
, current
);
105 static void print_this_address(unsigned long addr
, int i
)
107 #ifdef CONFIG_KALLSYMS
108 printk(KERN_EMERG
" [%08lx] ", addr
);
109 print_symbol(KERN_CONT
"%s\n", addr
);
112 printk(KERN_CONT
" [%08lx] ", addr
);
114 printk(KERN_CONT
"\n" KERN_EMERG
" [%08lx] ", addr
);
119 int kstack_depth_to_print
= 48;
121 static void __show_stack(struct task_struct
*task
, unsigned long *stack
)
123 unsigned long *endstack
, addr
;
124 #ifdef CONFIG_FRAME_POINTER
125 unsigned long *last_stack
;
130 stack
= (unsigned long *)task
->thread
.ksp
;
132 addr
= (unsigned long) stack
;
133 endstack
= (unsigned long *) PAGE_ALIGN(addr
);
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
)
140 printk("\n" KERN_EMERG
" ");
141 printk(" %08lx", *(stack
+ i
));
146 #ifdef CONFIG_FRAME_POINTER
147 printk(KERN_EMERG
"Call Trace:\n");
149 last_stack
= stack
- 1;
150 while (stack
<= endstack
&& stack
> last_stack
) {
153 print_this_address(addr
, i
);
157 stack
= (unsigned long *)*stack
;
161 printk(KERN_EMERG
"Call Trace with CONFIG_FRAME_POINTER disabled:\n");
162 while (stack
<= endstack
) {
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.
171 if (__kernel_text_address(addr
)) {
172 print_this_address(addr
, i
);
176 printk(KERN_CONT
"\n");
180 void bad_super_trap(struct frame
*fp
)
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],
188 printk (KERN_WARNING
"*** Exception %d *** FORMAT=%X\n",
189 (fp
->ptregs
.vector
) >> 2,
191 printk (KERN_WARNING
"Current process id is %d\n", current
->pid
);
192 die_if_kernel("BAD KERNEL TRAP", &fp
->ptregs
, 0);
195 asmlinkage
void trap_c(struct frame
*fp
)
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
;
209 /* send the appropriate signal to the user program */
210 switch ((fp
->ptregs
.vector
) >> 2) {
212 info
.si_code
= BUS_ADRALN
;
218 info
.si_code
= ILL_ILLOPC
;
222 info
.si_code
= ILL_PRVOPC
;
226 info
.si_code
= ILL_COPROC
;
229 case VEC_TRAP1
: /* gdbserver breakpoint */
231 info
.si_code
= TRAP_TRACE
;
247 info
.si_code
= ILL_ILLTRP
;
253 info
.si_code
= FPE_FLTINV
;
257 info
.si_code
= FPE_FLTRES
;
261 info
.si_code
= FPE_FLTDIV
;
265 info
.si_code
= FPE_FLTUND
;
269 info
.si_code
= FPE_FLTOVF
;
273 info
.si_code
= FPE_INTDIV
;
278 info
.si_code
= FPE_INTOVF
;
281 case VEC_TRACE
: /* ptrace single step */
282 info
.si_code
= TRAP_TRACE
;
285 case VEC_TRAP15
: /* breakpoint */
286 info
.si_code
= TRAP_BRKPT
;
290 info
.si_code
= ILL_ILLOPC
;
296 switch (fp
->ptregs
.format
) {
298 info
.si_addr
= (void *) fp
->ptregs
.pc
;
301 info
.si_addr
= (void *) fp
->un
.fmt2
.iaddr
;
304 info
.si_addr
= (void *) fp
->un
.fmt7
.effaddr
;
307 info
.si_addr
= (void *) fp
->un
.fmt9
.iaddr
;
310 info
.si_addr
= (void *) fp
->un
.fmta
.daddr
;
313 info
.si_addr
= (void *) fp
->un
.fmtb
.daddr
;
316 force_sig_info (sig
, &info
, current
);
319 asmlinkage
void set_esp0(unsigned long ssp
)
321 current
->thread
.esp0
= ssp
;
325 * The architecture-independent backtrace generator
327 void dump_stack(void)
330 * We need frame pointers for this little trick, which works as follows:
332 * +------------+ 0x00
333 * | Next SP | -> 0x0c
334 * +------------+ 0x04
336 * +------------+ 0x08
337 * | Local vars | -> our stack var
338 * +------------+ 0x0c
339 * | Next SP | -> 0x18, that is what we pass to show_stack()
340 * +------------+ 0x10
342 * +------------+ 0x14
344 * +------------+ 0x18
349 unsigned long *stack
;
351 stack
= (unsigned long *)&stack
;
353 __show_stack(current
, stack
);
355 EXPORT_SYMBOL(dump_stack
);
357 void show_stack(struct task_struct
*task
, unsigned long *stack
)
362 __show_stack(task
, stack
);
365 #ifdef CONFIG_M68KFPU_EMU
366 asmlinkage
void fpemu_signal(int signal
, int code
, void *addr
)
370 info
.si_signo
= signal
;
374 force_sig_info(signal
, &info
, current
);