diff options
Diffstat (limited to 'arch/cris/kernel/traps.c')
-rw-r--r-- | arch/cris/kernel/traps.c | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/arch/cris/kernel/traps.c b/arch/cris/kernel/traps.c new file mode 100644 index 000000000..da4c72401 --- /dev/null +++ b/arch/cris/kernel/traps.c @@ -0,0 +1,239 @@ +/* + * 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 + * things. + * + * Copyright (C) 2000-2007 Axis Communications AB + * + * Authors: Bjorn Wesen + * Hans-Peter Nilsson + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/utsname.h> +#ifdef CONFIG_KALLSYMS +#include <linux/kallsyms.h> +#endif + +#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 (*nmi_handler)(struct pt_regs *); + +void show_trace(unsigned long *stack) +{ + unsigned long addr, module_start, module_end; + extern char _stext, _etext; + int i; + + pr_err("\nCall Trace: "); + + i = 1; + module_start = VMALLOC_START; + module_end = VMALLOC_END; + + 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. */ + pr_err("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))) { +#ifdef CONFIG_KALLSYMS + print_ip_sym(addr); +#else + if (i && ((i % 8) == 0)) + pr_err("\n "); + pr_err("[<%08lx>] ", addr); + i++; +#endif + } + } +} + +/* + * These constants are for searching for possible module text + * segments. MODULE_RANGE is a guess of how much space is likely + * to be vmalloced. + */ + +#define MODULE_RANGE (8*1024*1024) + +/* + * The output (format, strings and order) is adjusted to be usable with + * ksymoops-2.4.1 with some necessary CRIS-specific patches. Please don't + * change it unless you're serious about adjusting ksymoops and syncing + * with the ksymoops maintainer. + */ + +void +show_stack(struct task_struct *task, unsigned long *sp) +{ + unsigned long *stack, addr; + int i; + + /* + * debugging aid: "show_stack(NULL);" prints a + * back trace. + */ + + if (sp == NULL) { + if (task) + sp = (unsigned long*)task->thread.ksp; + else + sp = (unsigned long*)rdsp(); + } + + stack = sp; + + pr_err("\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)) + pr_err("\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. */ + pr_err("Failing address 0x%lx\n", (unsigned long)stack); + break; + } + stack++; + pr_err("%08lx ", addr); + } + show_trace(sp); +} + +#if 0 +/* displays a short stack trace */ + +int +show_stack(void) +{ + unsigned long *sp = (unsigned long *)rdusp(); + int i; + + pr_err("Stack dump [0x%08lx]:\n", (unsigned long)sp); + for (i = 0; i < 16; i++) + pr_err("sp + %d: 0x%08lx\n", i*4, sp[i]); + return 0; +} +#endif + +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; + pr_err("NMI!\n"); + show_registers(regs); + oops_in_progress = 0; + oops_exit(); + pr_err("\n"); /* Flush mtdoops. */ +} + +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) +{ +#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY + local_irq_disable(); + stop_watchdog(); + show_registers(regs); + + while (1) + ; /* Do nothing. */ +#else + show_registers(regs); +#endif +} + +/* 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 + + oops_enter(); + handle_BUG(regs); + + pr_err("Linux %s %s\n", utsname()->release, utsname()->version); + pr_err("%s: %04lx\n", str, err & 0xffff); + + show_registers(regs); + + oops_exit(); + oops_in_progress = 0; + pr_err("\n"); /* Flush mtdoops. */ + +#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY + reset_watchdog(); +#endif + do_exit(SIGSEGV); +} + +void __init trap_init(void) +{ + /* Nothing needs to be done */ +} |