2 * linux/arch/unicore32/kernel/traps.c
4 * Code specific to PKUnity SoC and UniCore ISA
6 * Copyright (C) 2001-2010 GUAN Xue-tao
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * 'traps.c' handles hardware exceptions after we have saved some state.
13 * Mostly a debugging aid, but will probably kill the offending process.
15 #include <linux/module.h>
16 #include <linux/signal.h>
17 #include <linux/spinlock.h>
18 #include <linux/personality.h>
19 #include <linux/kallsyms.h>
20 #include <linux/kdebug.h>
21 #include <linux/uaccess.h>
22 #include <linux/delay.h>
23 #include <linux/hardirq.h>
24 #include <linux/init.h>
25 #include <linux/atomic.h>
26 #include <linux/unistd.h>
28 #include <asm/cacheflush.h>
29 #include <asm/system.h>
30 #include <asm/traps.h>
34 static void dump_mem(const char *, const char *, unsigned long, unsigned long);
36 void dump_backtrace_entry(unsigned long where
,
37 unsigned long from
, unsigned long frame
)
39 #ifdef CONFIG_KALLSYMS
40 printk(KERN_DEFAULT
"[<%08lx>] (%pS) from [<%08lx>] (%pS)\n",
41 where
, (void *)where
, from
, (void *)from
);
43 printk(KERN_DEFAULT
"Function entered at [<%08lx>] from [<%08lx>]\n",
49 * Stack pointers should always be within the kernels view of
50 * physical memory. If it is not there, then we can't dump
51 * out any information relating to the stack.
53 static int verify_stack(unsigned long sp
)
55 if (sp
< PAGE_OFFSET
||
56 (sp
> (unsigned long)high_memory
&& high_memory
!= NULL
))
63 * Dump out the contents of some memory nicely...
65 static void dump_mem(const char *lvl
, const char *str
, unsigned long bottom
,
73 * We need to switch to kernel mode so that we can use __get_user
74 * to safely read from kernel space. Note that we now dump the
75 * code first, just in case the backtrace kills us.
80 printk(KERN_DEFAULT
"%s%s(0x%08lx to 0x%08lx)\n",
81 lvl
, str
, bottom
, top
);
83 for (first
= bottom
& ~31; first
< top
; first
+= 32) {
85 char str
[sizeof(" 12345678") * 8 + 1];
87 memset(str
, ' ', sizeof(str
));
88 str
[sizeof(str
) - 1] = '\0';
90 for (p
= first
, i
= 0; i
< 8 && p
< top
; i
++, p
+= 4) {
91 if (p
>= bottom
&& p
< top
) {
93 if (__get_user(val
, (unsigned long *)p
) == 0)
94 sprintf(str
+ i
* 9, " %08lx", val
);
96 sprintf(str
+ i
* 9, " ????????");
99 printk(KERN_DEFAULT
"%s%04lx:%s\n", lvl
, first
& 0xffff, str
);
105 static void dump_instr(const char *lvl
, struct pt_regs
*regs
)
107 unsigned long addr
= instruction_pointer(regs
);
110 char str
[sizeof("00000000 ") * 5 + 2 + 1], *p
= str
;
114 * We need to switch to kernel mode so that we can use __get_user
115 * to safely read from kernel space. Note that we now dump the
116 * code first, just in case the backtrace kills us.
121 for (i
= -4; i
< 1; i
++) {
122 unsigned int val
, bad
;
124 bad
= __get_user(val
, &((u32
*)addr
)[i
]);
127 p
+= sprintf(p
, i
== 0 ? "(%0*x) " : "%0*x ",
130 p
+= sprintf(p
, "bad PC value");
134 printk(KERN_DEFAULT
"%sCode: %s\n", lvl
, str
);
139 static void dump_backtrace(struct pt_regs
*regs
, struct task_struct
*tsk
)
141 unsigned int fp
, mode
;
144 printk(KERN_DEFAULT
"Backtrace: ");
151 mode
= processor_mode(regs
);
152 } else if (tsk
!= current
) {
153 fp
= thread_saved_fp(tsk
);
156 asm("mov %0, fp" : "=r" (fp
) : : "cc");
161 printk("no frame pointer");
163 } else if (verify_stack(fp
)) {
164 printk("invalid frame pointer 0x%08x", fp
);
166 } else if (fp
< (unsigned long)end_of_stack(tsk
))
167 printk("frame pointer underflow");
171 c_backtrace(fp
, mode
);
174 void dump_stack(void)
176 dump_backtrace(NULL
, NULL
);
178 EXPORT_SYMBOL(dump_stack
);
180 void show_stack(struct task_struct
*tsk
, unsigned long *sp
)
182 dump_backtrace(NULL
, tsk
);
186 static int __die(const char *str
, int err
, struct thread_info
*thread
,
187 struct pt_regs
*regs
)
189 struct task_struct
*tsk
= thread
->task
;
190 static int die_counter
;
193 printk(KERN_EMERG
"Internal error: %s: %x [#%d]\n",
194 str
, err
, ++die_counter
);
196 /* trap and error numbers are mostly meaningless on UniCore */
197 ret
= notify_die(DIE_OOPS
, str
, regs
, err
, tsk
->thread
.trap_no
, \
199 if (ret
== NOTIFY_STOP
)
204 printk(KERN_EMERG
"Process %.*s (pid: %d, stack limit = 0x%p)\n",
205 TASK_COMM_LEN
, tsk
->comm
, task_pid_nr(tsk
), thread
+ 1);
207 if (!user_mode(regs
) || in_interrupt()) {
208 dump_mem(KERN_EMERG
, "Stack: ", regs
->UCreg_sp
,
209 THREAD_SIZE
+ (unsigned long)task_stack_page(tsk
));
210 dump_backtrace(regs
, tsk
);
211 dump_instr(KERN_EMERG
, regs
);
217 DEFINE_SPINLOCK(die_lock
);
220 * This function is protected against re-entrancy.
222 void die(const char *str
, struct pt_regs
*regs
, int err
)
224 struct thread_info
*thread
= current_thread_info();
229 spin_lock_irq(&die_lock
);
232 ret
= __die(str
, err
, thread
, regs
);
235 add_taint(TAINT_DIE
);
236 spin_unlock_irq(&die_lock
);
240 panic("Fatal exception in interrupt");
242 panic("Fatal exception");
243 if (ret
!= NOTIFY_STOP
)
247 void uc32_notify_die(const char *str
, struct pt_regs
*regs
,
248 struct siginfo
*info
, unsigned long err
, unsigned long trap
)
250 if (user_mode(regs
)) {
251 current
->thread
.error_code
= err
;
252 current
->thread
.trap_no
= trap
;
254 force_sig_info(info
->si_signo
, info
, current
);
260 * bad_mode handles the impossible case in the vectors. If you see one of
261 * these, then it's extremely serious, and could mean you have buggy hardware.
262 * It never returns, and never tries to sync. We hope that we can at least
263 * dump out some state information...
265 asmlinkage
void bad_mode(struct pt_regs
*regs
, unsigned int reason
)
269 printk(KERN_CRIT
"Bad mode detected with reason 0x%x\n", reason
);
271 die("Oops - bad mode", regs
, 0);
276 void __pte_error(const char *file
, int line
, unsigned long val
)
278 printk(KERN_DEFAULT
"%s:%d: bad pte %08lx.\n", file
, line
, val
);
281 void __pmd_error(const char *file
, int line
, unsigned long val
)
283 printk(KERN_DEFAULT
"%s:%d: bad pmd %08lx.\n", file
, line
, val
);
286 void __pgd_error(const char *file
, int line
, unsigned long val
)
288 printk(KERN_DEFAULT
"%s:%d: bad pgd %08lx.\n", file
, line
, val
);
291 asmlinkage
void __div0(void)
293 printk(KERN_DEFAULT
"Division by zero in kernel.\n");
296 EXPORT_SYMBOL(__div0
);
302 /* if that doesn't kill us, halt */
303 panic("Oops failed to kill thread");
305 EXPORT_SYMBOL(abort
);
307 void __init
trap_init(void)
312 void __init
early_trap_init(void)
314 unsigned long vectors
= VECTORS_BASE
;
317 * Copy the vectors, stubs (in entry-unicore.S)
318 * into the vector page, mapped at 0xffff0000, and ensure these
319 * are visible to the instruction stream.
321 memcpy((void *)vectors
,
323 __vectors_end
- __vectors_start
);
324 memcpy((void *)vectors
+ 0x200,
326 __stubs_end
- __stubs_start
);
330 flush_icache_range(vectors
, vectors
+ PAGE_SIZE
);