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/sched/signal.h>
18 #include <linux/sched/debug.h>
19 #include <linux/sched/task_stack.h>
20 #include <linux/spinlock.h>
21 #include <linux/personality.h>
22 #include <linux/kallsyms.h>
23 #include <linux/kdebug.h>
24 #include <linux/uaccess.h>
25 #include <linux/delay.h>
26 #include <linux/hardirq.h>
27 #include <linux/init.h>
28 #include <linux/atomic.h>
29 #include <linux/unistd.h>
31 #include <asm/cacheflush.h>
32 #include <asm/traps.h>
36 static void dump_mem(const char *, const char *, unsigned long, unsigned long);
38 void dump_backtrace_entry(unsigned long where
,
39 unsigned long from
, unsigned long frame
)
41 #ifdef CONFIG_KALLSYMS
42 printk(KERN_DEFAULT
"[<%08lx>] (%pS) from [<%08lx>] (%pS)\n",
43 where
, (void *)where
, from
, (void *)from
);
45 printk(KERN_DEFAULT
"Function entered at [<%08lx>] from [<%08lx>]\n",
51 * Stack pointers should always be within the kernels view of
52 * physical memory. If it is not there, then we can't dump
53 * out any information relating to the stack.
55 static int verify_stack(unsigned long sp
)
57 if (sp
< PAGE_OFFSET
||
58 (sp
> (unsigned long)high_memory
&& high_memory
!= NULL
))
65 * Dump out the contents of some memory nicely...
67 static void dump_mem(const char *lvl
, const char *str
, unsigned long bottom
,
75 * We need to switch to kernel mode so that we can use __get_user
76 * to safely read from kernel space. Note that we now dump the
77 * code first, just in case the backtrace kills us.
82 printk(KERN_DEFAULT
"%s%s(0x%08lx to 0x%08lx)\n",
83 lvl
, str
, bottom
, top
);
85 for (first
= bottom
& ~31; first
< top
; first
+= 32) {
87 char str
[sizeof(" 12345678") * 8 + 1];
89 memset(str
, ' ', sizeof(str
));
90 str
[sizeof(str
) - 1] = '\0';
92 for (p
= first
, i
= 0; i
< 8 && p
< top
; i
++, p
+= 4) {
93 if (p
>= bottom
&& p
< top
) {
95 if (__get_user(val
, (unsigned long *)p
) == 0)
96 sprintf(str
+ i
* 9, " %08lx", val
);
98 sprintf(str
+ i
* 9, " ????????");
101 printk(KERN_DEFAULT
"%s%04lx:%s\n", lvl
, first
& 0xffff, str
);
107 static void dump_instr(const char *lvl
, struct pt_regs
*regs
)
109 unsigned long addr
= instruction_pointer(regs
);
112 char str
[sizeof("00000000 ") * 5 + 2 + 1], *p
= str
;
116 * We need to switch to kernel mode so that we can use __get_user
117 * to safely read from kernel space. Note that we now dump the
118 * code first, just in case the backtrace kills us.
123 for (i
= -4; i
< 1; i
++) {
124 unsigned int val
, bad
;
126 bad
= __get_user(val
, &((u32
*)addr
)[i
]);
129 p
+= sprintf(p
, i
== 0 ? "(%0*x) " : "%0*x ",
132 p
+= sprintf(p
, "bad PC value");
136 printk(KERN_DEFAULT
"%sCode: %s\n", lvl
, str
);
141 static void dump_backtrace(struct pt_regs
*regs
, struct task_struct
*tsk
)
143 unsigned int fp
, mode
;
146 printk(KERN_DEFAULT
"Backtrace: ");
153 mode
= processor_mode(regs
);
154 } else if (tsk
!= current
) {
155 fp
= thread_saved_fp(tsk
);
158 asm("mov %0, fp" : "=r" (fp
) : : "cc");
163 printk("no frame pointer");
165 } else if (verify_stack(fp
)) {
166 printk("invalid frame pointer 0x%08x", fp
);
168 } else if (fp
< (unsigned long)end_of_stack(tsk
))
169 printk("frame pointer underflow");
173 c_backtrace(fp
, mode
);
176 void show_stack(struct task_struct
*tsk
, unsigned long *sp
)
178 dump_backtrace(NULL
, tsk
);
182 static int __die(const char *str
, int err
, struct thread_info
*thread
,
183 struct pt_regs
*regs
)
185 struct task_struct
*tsk
= thread
->task
;
186 static int die_counter
;
189 printk(KERN_EMERG
"Internal error: %s: %x [#%d]\n",
190 str
, err
, ++die_counter
);
192 /* trap and error numbers are mostly meaningless on UniCore */
193 ret
= notify_die(DIE_OOPS
, str
, regs
, err
, tsk
->thread
.trap_no
, \
195 if (ret
== NOTIFY_STOP
)
200 printk(KERN_EMERG
"Process %.*s (pid: %d, stack limit = 0x%p)\n",
201 TASK_COMM_LEN
, tsk
->comm
, task_pid_nr(tsk
), thread
+ 1);
203 if (!user_mode(regs
) || in_interrupt()) {
204 dump_mem(KERN_EMERG
, "Stack: ", regs
->UCreg_sp
,
205 THREAD_SIZE
+ (unsigned long)task_stack_page(tsk
));
206 dump_backtrace(regs
, tsk
);
207 dump_instr(KERN_EMERG
, regs
);
213 DEFINE_SPINLOCK(die_lock
);
216 * This function is protected against re-entrancy.
218 void die(const char *str
, struct pt_regs
*regs
, int err
)
220 struct thread_info
*thread
= current_thread_info();
225 spin_lock_irq(&die_lock
);
228 ret
= __die(str
, err
, thread
, regs
);
231 add_taint(TAINT_DIE
, LOCKDEP_NOW_UNRELIABLE
);
232 spin_unlock_irq(&die_lock
);
236 panic("Fatal exception in interrupt");
238 panic("Fatal exception");
239 if (ret
!= NOTIFY_STOP
)
243 void uc32_notify_die(const char *str
, struct pt_regs
*regs
,
244 struct siginfo
*info
, unsigned long err
, unsigned long trap
)
246 if (user_mode(regs
)) {
247 current
->thread
.error_code
= err
;
248 current
->thread
.trap_no
= trap
;
250 force_sig_info(info
->si_signo
, info
, current
);
256 * bad_mode handles the impossible case in the vectors. If you see one of
257 * these, then it's extremely serious, and could mean you have buggy hardware.
258 * It never returns, and never tries to sync. We hope that we can at least
259 * dump out some state information...
261 asmlinkage
void bad_mode(struct pt_regs
*regs
, unsigned int reason
)
265 printk(KERN_CRIT
"Bad mode detected with reason 0x%x\n", reason
);
267 die("Oops - bad mode", regs
, 0);
272 void __pte_error(const char *file
, int line
, unsigned long val
)
274 printk(KERN_DEFAULT
"%s:%d: bad pte %08lx.\n", file
, line
, val
);
277 void __pmd_error(const char *file
, int line
, unsigned long val
)
279 printk(KERN_DEFAULT
"%s:%d: bad pmd %08lx.\n", file
, line
, val
);
282 void __pgd_error(const char *file
, int line
, unsigned long val
)
284 printk(KERN_DEFAULT
"%s:%d: bad pgd %08lx.\n", file
, line
, val
);
287 asmlinkage
void __div0(void)
289 printk(KERN_DEFAULT
"Division by zero in kernel.\n");
292 EXPORT_SYMBOL(__div0
);
298 /* if that doesn't kill us, halt */
299 panic("Oops failed to kill thread");
302 void __init
trap_init(void)
307 void __init
early_trap_init(void)
309 unsigned long vectors
= VECTORS_BASE
;
312 * Copy the vectors, stubs (in entry-unicore.S)
313 * into the vector page, mapped at 0xffff0000, and ensure these
314 * are visible to the instruction stream.
316 memcpy((void *)vectors
,
318 __vectors_end
- __vectors_start
);
319 memcpy((void *)vectors
+ 0x200,
321 __stubs_end
- __stubs_start
);
325 flush_icache_range(vectors
, vectors
+ PAGE_SIZE
);