]>
git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - arch/unicore32/kernel/traps.c
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/spinlock.h>
20 #include <linux/personality.h>
21 #include <linux/kallsyms.h>
22 #include <linux/kdebug.h>
23 #include <linux/uaccess.h>
24 #include <linux/delay.h>
25 #include <linux/hardirq.h>
26 #include <linux/init.h>
27 #include <linux/atomic.h>
28 #include <linux/unistd.h>
30 #include <asm/cacheflush.h>
31 #include <asm/traps.h>
35 static void dump_mem(const char *, const char *, unsigned long, unsigned long);
37 void dump_backtrace_entry(unsigned long where
,
38 unsigned long from
, unsigned long frame
)
40 #ifdef CONFIG_KALLSYMS
41 printk(KERN_DEFAULT
"[<%08lx>] (%pS) from [<%08lx>] (%pS)\n",
42 where
, (void *)where
, from
, (void *)from
);
44 printk(KERN_DEFAULT
"Function entered at [<%08lx>] from [<%08lx>]\n",
50 * Stack pointers should always be within the kernels view of
51 * physical memory. If it is not there, then we can't dump
52 * out any information relating to the stack.
54 static int verify_stack(unsigned long sp
)
56 if (sp
< PAGE_OFFSET
||
57 (sp
> (unsigned long)high_memory
&& high_memory
!= NULL
))
64 * Dump out the contents of some memory nicely...
66 static void dump_mem(const char *lvl
, const char *str
, unsigned long bottom
,
74 * We need to switch to kernel mode so that we can use __get_user
75 * to safely read from kernel space. Note that we now dump the
76 * code first, just in case the backtrace kills us.
81 printk(KERN_DEFAULT
"%s%s(0x%08lx to 0x%08lx)\n",
82 lvl
, str
, bottom
, top
);
84 for (first
= bottom
& ~31; first
< top
; first
+= 32) {
86 char str
[sizeof(" 12345678") * 8 + 1];
88 memset(str
, ' ', sizeof(str
));
89 str
[sizeof(str
) - 1] = '\0';
91 for (p
= first
, i
= 0; i
< 8 && p
< top
; i
++, p
+= 4) {
92 if (p
>= bottom
&& p
< top
) {
94 if (__get_user(val
, (unsigned long *)p
) == 0)
95 sprintf(str
+ i
* 9, " %08lx", val
);
97 sprintf(str
+ i
* 9, " ????????");
100 printk(KERN_DEFAULT
"%s%04lx:%s\n", lvl
, first
& 0xffff, str
);
106 static void dump_instr(const char *lvl
, struct pt_regs
*regs
)
108 unsigned long addr
= instruction_pointer(regs
);
111 char str
[sizeof("00000000 ") * 5 + 2 + 1], *p
= str
;
115 * We need to switch to kernel mode so that we can use __get_user
116 * to safely read from kernel space. Note that we now dump the
117 * code first, just in case the backtrace kills us.
122 for (i
= -4; i
< 1; i
++) {
123 unsigned int val
, bad
;
125 bad
= __get_user(val
, &((u32
*)addr
)[i
]);
128 p
+= sprintf(p
, i
== 0 ? "(%0*x) " : "%0*x ",
131 p
+= sprintf(p
, "bad PC value");
135 printk(KERN_DEFAULT
"%sCode: %s\n", lvl
, str
);
140 static void dump_backtrace(struct pt_regs
*regs
, struct task_struct
*tsk
)
142 unsigned int fp
, mode
;
145 printk(KERN_DEFAULT
"Backtrace: ");
152 mode
= processor_mode(regs
);
153 } else if (tsk
!= current
) {
154 fp
= thread_saved_fp(tsk
);
157 asm("mov %0, fp" : "=r" (fp
) : : "cc");
162 printk("no frame pointer");
164 } else if (verify_stack(fp
)) {
165 printk("invalid frame pointer 0x%08x", fp
);
167 } else if (fp
< (unsigned long)end_of_stack(tsk
))
168 printk("frame pointer underflow");
172 c_backtrace(fp
, mode
);
175 void show_stack(struct task_struct
*tsk
, unsigned long *sp
)
177 dump_backtrace(NULL
, tsk
);
181 static int __die(const char *str
, int err
, struct thread_info
*thread
,
182 struct pt_regs
*regs
)
184 struct task_struct
*tsk
= thread
->task
;
185 static int die_counter
;
188 printk(KERN_EMERG
"Internal error: %s: %x [#%d]\n",
189 str
, err
, ++die_counter
);
191 /* trap and error numbers are mostly meaningless on UniCore */
192 ret
= notify_die(DIE_OOPS
, str
, regs
, err
, tsk
->thread
.trap_no
, \
194 if (ret
== NOTIFY_STOP
)
199 printk(KERN_EMERG
"Process %.*s (pid: %d, stack limit = 0x%p)\n",
200 TASK_COMM_LEN
, tsk
->comm
, task_pid_nr(tsk
), thread
+ 1);
202 if (!user_mode(regs
) || in_interrupt()) {
203 dump_mem(KERN_EMERG
, "Stack: ", regs
->UCreg_sp
,
204 THREAD_SIZE
+ (unsigned long)task_stack_page(tsk
));
205 dump_backtrace(regs
, tsk
);
206 dump_instr(KERN_EMERG
, regs
);
212 DEFINE_SPINLOCK(die_lock
);
215 * This function is protected against re-entrancy.
217 void die(const char *str
, struct pt_regs
*regs
, int err
)
219 struct thread_info
*thread
= current_thread_info();
224 spin_lock_irq(&die_lock
);
227 ret
= __die(str
, err
, thread
, regs
);
230 add_taint(TAINT_DIE
, LOCKDEP_NOW_UNRELIABLE
);
231 spin_unlock_irq(&die_lock
);
235 panic("Fatal exception in interrupt");
237 panic("Fatal exception");
238 if (ret
!= NOTIFY_STOP
)
242 void uc32_notify_die(const char *str
, struct pt_regs
*regs
,
243 struct siginfo
*info
, unsigned long err
, unsigned long trap
)
245 if (user_mode(regs
)) {
246 current
->thread
.error_code
= err
;
247 current
->thread
.trap_no
= trap
;
249 force_sig_info(info
->si_signo
, info
, current
);
255 * bad_mode handles the impossible case in the vectors. If you see one of
256 * these, then it's extremely serious, and could mean you have buggy hardware.
257 * It never returns, and never tries to sync. We hope that we can at least
258 * dump out some state information...
260 asmlinkage
void bad_mode(struct pt_regs
*regs
, unsigned int reason
)
264 printk(KERN_CRIT
"Bad mode detected with reason 0x%x\n", reason
);
266 die("Oops - bad mode", regs
, 0);
271 void __pte_error(const char *file
, int line
, unsigned long val
)
273 printk(KERN_DEFAULT
"%s:%d: bad pte %08lx.\n", file
, line
, val
);
276 void __pmd_error(const char *file
, int line
, unsigned long val
)
278 printk(KERN_DEFAULT
"%s:%d: bad pmd %08lx.\n", file
, line
, val
);
281 void __pgd_error(const char *file
, int line
, unsigned long val
)
283 printk(KERN_DEFAULT
"%s:%d: bad pgd %08lx.\n", file
, line
, val
);
286 asmlinkage
void __div0(void)
288 printk(KERN_DEFAULT
"Division by zero in kernel.\n");
291 EXPORT_SYMBOL(__div0
);
297 /* if that doesn't kill us, halt */
298 panic("Oops failed to kill thread");
300 EXPORT_SYMBOL(abort
);
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
);