aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2010-01-20 12:02:54 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-02-15 16:39:14 -0500
commita9221de66d2d94e6e34c3f56bbdd744935020737 (patch)
treed28a14e4a536a282aff11ae135c19c3a8b237b40 /arch/arm/kernel
parent2b0d8c251b8876d530a6bf671eb5425838fa698a (diff)
ARM: add notify_die() support
Kernel debuggers want to be informed of die() events, so that they can take some action to allow the problem to be inspected. Provide the hook in a similar manner to x86. Note that we currently don't implement the individual trap hooks. Acked-by: Jason Wessel <jason.wessel@windriver.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/traps.c35
1 files changed, 25 insertions, 10 deletions
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 3f361a783f43..1621e5327b2a 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -12,15 +12,17 @@
12 * 'linux/arch/arm/lib/traps.S'. Mostly a debugging aid, but will probably 12 * 'linux/arch/arm/lib/traps.S'. Mostly a debugging aid, but will probably
13 * kill the offending process. 13 * kill the offending process.
14 */ 14 */
15#include <linux/module.h>
16#include <linux/signal.h> 15#include <linux/signal.h>
17#include <linux/spinlock.h>
18#include <linux/personality.h> 16#include <linux/personality.h>
19#include <linux/kallsyms.h> 17#include <linux/kallsyms.h>
20#include <linux/delay.h> 18#include <linux/spinlock.h>
19#include <linux/uaccess.h>
21#include <linux/hardirq.h> 20#include <linux/hardirq.h>
21#include <linux/kdebug.h>
22#include <linux/module.h>
23#include <linux/kexec.h>
24#include <linux/delay.h>
22#include <linux/init.h> 25#include <linux/init.h>
23#include <linux/uaccess.h>
24 26
25#include <asm/atomic.h> 27#include <asm/atomic.h>
26#include <asm/cacheflush.h> 28#include <asm/cacheflush.h>
@@ -224,14 +226,21 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)
224#define S_SMP "" 226#define S_SMP ""
225#endif 227#endif
226 228
227static void __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs) 229static int __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs)
228{ 230{
229 struct task_struct *tsk = thread->task; 231 struct task_struct *tsk = thread->task;
230 static int die_counter; 232 static int die_counter;
233 int ret;
231 234
232 printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n", 235 printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n",
233 str, err, ++die_counter); 236 str, err, ++die_counter);
234 sysfs_printk_last_file(); 237 sysfs_printk_last_file();
238
239 /* trap and error numbers are mostly meaningless on ARM */
240 ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV);
241 if (ret == NOTIFY_STOP)
242 return ret;
243
235 print_modules(); 244 print_modules();
236 __show_regs(regs); 245 __show_regs(regs);
237 printk(KERN_EMERG "Process %.*s (pid: %d, stack limit = 0x%p)\n", 246 printk(KERN_EMERG "Process %.*s (pid: %d, stack limit = 0x%p)\n",
@@ -243,6 +252,8 @@ static void __die(const char *str, int err, struct thread_info *thread, struct p
243 dump_backtrace(regs, tsk); 252 dump_backtrace(regs, tsk);
244 dump_instr(KERN_EMERG, regs); 253 dump_instr(KERN_EMERG, regs);
245 } 254 }
255
256 return ret;
246} 257}
247 258
248DEFINE_SPINLOCK(die_lock); 259DEFINE_SPINLOCK(die_lock);
@@ -250,16 +261,21 @@ DEFINE_SPINLOCK(die_lock);
250/* 261/*
251 * This function is protected against re-entrancy. 262 * This function is protected against re-entrancy.
252 */ 263 */
253NORET_TYPE void die(const char *str, struct pt_regs *regs, int err) 264void die(const char *str, struct pt_regs *regs, int err)
254{ 265{
255 struct thread_info *thread = current_thread_info(); 266 struct thread_info *thread = current_thread_info();
267 int ret;
256 268
257 oops_enter(); 269 oops_enter();
258 270
259 spin_lock_irq(&die_lock); 271 spin_lock_irq(&die_lock);
260 console_verbose(); 272 console_verbose();
261 bust_spinlocks(1); 273 bust_spinlocks(1);
262 __die(str, err, thread, regs); 274 ret = __die(str, err, thread, regs);
275
276 if (regs && kexec_should_crash(thread->task))
277 crash_kexec(regs);
278
263 bust_spinlocks(0); 279 bust_spinlocks(0);
264 add_taint(TAINT_DIE); 280 add_taint(TAINT_DIE);
265 spin_unlock_irq(&die_lock); 281 spin_unlock_irq(&die_lock);
@@ -267,11 +283,10 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
267 283
268 if (in_interrupt()) 284 if (in_interrupt())
269 panic("Fatal exception in interrupt"); 285 panic("Fatal exception in interrupt");
270
271 if (panic_on_oops) 286 if (panic_on_oops)
272 panic("Fatal exception"); 287 panic("Fatal exception");
273 288 if (ret != NOTIFY_STOP)
274 do_exit(SIGSEGV); 289 do_exit(SIGSEGV);
275} 290}
276 291
277void arm_notify_die(const char *str, struct pt_regs *regs, 292void arm_notify_die(const char *str, struct pt_regs *regs,