diff options
Diffstat (limited to 'arch/cris/kernel/traps.c')
| -rw-r--r-- | arch/cris/kernel/traps.c | 192 |
1 files changed, 140 insertions, 52 deletions
diff --git a/arch/cris/kernel/traps.c b/arch/cris/kernel/traps.c index d4dfa050e3a..0ffda73734f 100644 --- a/arch/cris/kernel/traps.c +++ b/arch/cris/kernel/traps.c @@ -1,64 +1,79 @@ -/* $Id: traps.c,v 1.9 2004/05/11 12:28:26 starvik Exp $ - * +/* * linux/arch/cris/traps.c * - * Here we handle the break vectors not used by the system call - * mechanism, as well as some general stack/register dumping + * Here we handle the break vectors not used by the system call + * mechanism, as well as some general stack/register dumping * things. - * - * Copyright (C) 2000-2002 Axis Communications AB + * + * Copyright (C) 2000-2007 Axis Communications AB * * Authors: Bjorn Wesen - * Hans-Peter Nilsson + * Hans-Peter Nilsson * */ #include <linux/init.h> #include <linux/module.h> + #include <asm/pgtable.h> #include <asm/uaccess.h> +#include <arch/system.h> + +extern void arch_enable_nmi(void); +extern void stop_watchdog(void); +extern void reset_watchdog(void); +extern void show_registers(struct pt_regs *regs); + +#ifdef CONFIG_DEBUG_BUGVERBOSE +extern void handle_BUG(struct pt_regs *regs); +#else +#define handle_BUG(regs) +#endif static int kstack_depth_to_print = 24; -void show_trace(unsigned long * stack) +void (*nmi_handler)(struct pt_regs *); + +void +show_trace(unsigned long *stack) { unsigned long addr, module_start, module_end; extern char _stext, _etext; int i; - printk("\nCall Trace: "); + printk("\nCall Trace: "); - i = 1; - module_start = VMALLOC_START; - module_end = VMALLOC_END; + i = 1; + module_start = VMALLOC_START; + module_end = VMALLOC_END; - while (((long) stack & (THREAD_SIZE-1)) != 0) { - if (__get_user (addr, stack)) { + while (((long)stack & (THREAD_SIZE-1)) != 0) { + if (__get_user(addr, stack)) { /* This message matches "failing address" marked s390 in ksymoops, so lines containing it will not be filtered out by ksymoops. */ - printk ("Failing address 0x%lx\n", (unsigned long)stack); + printk("Failing address 0x%lx\n", (unsigned long)stack); break; } stack++; - /* - * If the address is either in the text segment of the - * kernel, or in the region which contains vmalloc'ed - * memory, it *may* be the address of a calling - * routine; if so, print it so that someone tracing - * down the cause of the crash will be able to figure - * out the call path that was taken. - */ - if (((addr >= (unsigned long) &_stext) && - (addr <= (unsigned long) &_etext)) || - ((addr >= module_start) && (addr <= module_end))) { - if (i && ((i % 8) == 0)) - printk("\n "); - printk("[<%08lx>] ", addr); - i++; - } - } + /* + * If the address is either in the text segment of the + * kernel, or in the region which contains vmalloc'ed + * memory, it *may* be the address of a calling + * routine; if so, print it so that someone tracing + * down the cause of the crash will be able to figure + * out the call path that was taken. + */ + if (((addr >= (unsigned long)&_stext) && + (addr <= (unsigned long)&_etext)) || + ((addr >= module_start) && (addr <= module_end))) { + if (i && ((i % 8) == 0)) + printk("\n "); + printk("[<%08lx>] ", addr); + i++; + } + } } /* @@ -76,68 +91,141 @@ void show_trace(unsigned long * stack) * with the ksymoops maintainer. */ -void +void show_stack(struct task_struct *task, unsigned long *sp) { - unsigned long *stack, addr; - int i; + unsigned long *stack, addr; + int i; /* * debugging aid: "show_stack(NULL);" prints a * back trace. */ - if(sp == NULL) { + if (sp == NULL) { if (task) sp = (unsigned long*)task->thread.ksp; else sp = (unsigned long*)rdsp(); } - stack = sp; + stack = sp; printk("\nStack from %08lx:\n ", (unsigned long)stack); - for(i = 0; i < kstack_depth_to_print; i++) { - if (((long) stack & (THREAD_SIZE-1)) == 0) - break; - if (i && ((i % 8) == 0)) - printk("\n "); - if (__get_user (addr, stack)) { + for (i = 0; i < kstack_depth_to_print; i++) { + if (((long)stack & (THREAD_SIZE-1)) == 0) + break; + if (i && ((i % 8) == 0)) + printk("\n "); + if (__get_user(addr, stack)) { /* This message matches "failing address" marked s390 in ksymoops, so lines containing it will not be filtered out by ksymoops. */ - printk ("Failing address 0x%lx\n", (unsigned long)stack); + printk("Failing address 0x%lx\n", (unsigned long)stack); break; } stack++; printk("%08lx ", addr); - } + } show_trace(sp); } #if 0 /* displays a short stack trace */ -int -show_stack() +int +show_stack(void) { unsigned long *sp = (unsigned long *)rdusp(); int i; + printk("Stack dump [0x%08lx]:\n", (unsigned long)sp); - for(i = 0; i < 16; i++) + for (i = 0; i < 16; i++) printk("sp + %d: 0x%08lx\n", i*4, sp[i]); return 0; } #endif -void dump_stack(void) +void +set_nmi_handler(void (*handler)(struct pt_regs *)) +{ + nmi_handler = handler; + arch_enable_nmi(); +} + +#ifdef CONFIG_DEBUG_NMI_OOPS +void +oops_nmi_handler(struct pt_regs *regs) +{ + stop_watchdog(); + oops_in_progress = 1; + printk("NMI!\n"); + show_registers(regs); + oops_in_progress = 0; +} + +static int __init +oops_nmi_register(void) +{ + set_nmi_handler(oops_nmi_handler); + return 0; +} + +__initcall(oops_nmi_register); + +#endif + +/* + * This gets called from entry.S when the watchdog has bitten. Show something + * similar to an Oops dump, and if the kernel is configured to be a nice + * doggy, then halt instead of reboot. + */ +void +watchdog_bite_hook(struct pt_regs *regs) { - show_stack(NULL, NULL); +#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY + local_irq_disable(); + stop_watchdog(); + show_registers(regs); + + while (1) + ; /* Do nothing. */ +#else + show_registers(regs); +#endif } -EXPORT_SYMBOL(dump_stack); +/* This is normally the Oops function. */ +void +die_if_kernel(const char *str, struct pt_regs *regs, long err) +{ + if (user_mode(regs)) + return; + +#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY + /* + * This printout might take too long and could trigger + * the watchdog normally. If NICE_DOGGY is set, simply + * stop the watchdog during the printout. + */ + stop_watchdog(); +#endif + + handle_BUG(regs); + + printk("%s: %04lx\n", str, err & 0xffff); + + show_registers(regs); + + oops_in_progress = 0; + +#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY + reset_watchdog(); +#endif + do_exit(SIGSEGV); +} -void __init +void __init trap_init(void) { /* Nothing needs to be done */ |
