| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  *  linux/arch/cris/traps.c | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  |  *  Here we handle the break vectors not used by the system call | 
					
						
							|  |  |  |  *  mechanism, as well as some general stack/register dumping | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  *  things. | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  |  * | 
					
						
							|  |  |  |  *  Copyright (C) 2000-2007 Axis Communications AB | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  *  Authors:   Bjorn Wesen | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  |  *             Hans-Peter Nilsson | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/init.h>
 | 
					
						
							|  |  |  | #include <linux/module.h>
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #include <asm/pgtable.h>
 | 
					
						
							|  |  |  | #include <asm/uaccess.h>
 | 
					
						
							| 
									
										
										
										
											2012-03-28 18:30:02 +01:00
										 |  |  | #include <arch/system.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 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
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | static int kstack_depth_to_print = 24; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | void (*nmi_handler)(struct pt_regs *); | 
					
						
							| 
									
										
										
										
											2005-07-27 11:44:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | void | 
					
						
							|  |  |  | show_trace(unsigned long *stack) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	unsigned long addr, module_start, module_end; | 
					
						
							|  |  |  | 	extern char _stext, _etext; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 	printk("\nCall Trace: "); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 	i = 1; | 
					
						
							|  |  |  | 	module_start = VMALLOC_START; | 
					
						
							|  |  |  | 	module_end = VMALLOC_END; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 	while (((long)stack & (THREAD_SIZE-1)) != 0) { | 
					
						
							|  |  |  | 		if (__get_user(addr, stack)) { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			/* This message matches "failing address" marked
 | 
					
						
							|  |  |  | 			   s390 in ksymoops, so lines containing it will | 
					
						
							|  |  |  | 			   not be filtered out by ksymoops.  */ | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 			printk("Failing address 0x%lx\n", (unsigned long)stack); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		stack++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * 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++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * 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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | void | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | show_stack(struct task_struct *task, unsigned long *sp) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 	unsigned long *stack, addr; | 
					
						
							|  |  |  | 	int i; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * debugging aid: "show_stack(NULL);" prints a | 
					
						
							|  |  |  | 	 * back trace. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 	if (sp == NULL) { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		if (task) | 
					
						
							|  |  |  | 			sp = (unsigned long*)task->thread.ksp; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			sp = (unsigned long*)rdsp(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 	stack = sp; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 	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)) { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			/* This message matches "failing address" marked
 | 
					
						
							|  |  |  | 			   s390 in ksymoops, so lines containing it will | 
					
						
							|  |  |  | 			   not be filtered out by ksymoops.  */ | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 			printk("Failing address 0x%lx\n", (unsigned long)stack); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		stack++; | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 		printk("%08lx ", addr); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	show_trace(sp); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | #if 0
 | 
					
						
							|  |  |  | /* displays a short stack trace */ | 
					
						
							| 
									
										
										
										
											2005-07-27 11:44:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | int | 
					
						
							|  |  |  | show_stack(void) | 
					
						
							| 
									
										
										
										
											2005-07-27 11:44:32 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 	unsigned long *sp = (unsigned long *)rdusp(); | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	printk("Stack dump [0x%08lx]:\n", (unsigned long)sp); | 
					
						
							|  |  |  | 	for (i = 0; i < 16; i++) | 
					
						
							|  |  |  | 		printk("sp + %d: 0x%08lx\n", i*4, sp[i]); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2005-07-27 11:44:32 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2005-07-27 11:44:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | void | 
					
						
							|  |  |  | dump_stack(void) | 
					
						
							| 
									
										
										
										
											2005-07-27 11:44:32 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 	show_stack(NULL, NULL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL(dump_stack); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | set_nmi_handler(void (*handler)(struct pt_regs *)) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	nmi_handler = handler; | 
					
						
							|  |  |  | 	arch_enable_nmi(); | 
					
						
							| 
									
										
										
										
											2005-07-27 11:44:32 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_DEBUG_NMI_OOPS
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | void | 
					
						
							|  |  |  | oops_nmi_handler(struct pt_regs *regs) | 
					
						
							| 
									
										
										
										
											2005-07-27 11:44:32 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 	stop_watchdog(); | 
					
						
							|  |  |  | 	oops_in_progress = 1; | 
					
						
							|  |  |  | 	printk("NMI!\n"); | 
					
						
							|  |  |  | 	show_registers(regs); | 
					
						
							|  |  |  | 	oops_in_progress = 0; | 
					
						
							| 
									
										
										
										
											2005-07-27 11:44:32 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | static int __init | 
					
						
							|  |  |  | oops_nmi_register(void) | 
					
						
							| 
									
										
										
										
											2005-07-27 11:44:32 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 	set_nmi_handler(oops_nmi_handler); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2005-07-27 11:44:32 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __initcall(oops_nmi_register); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This gets called from entry.S when the watchdog has bitten. Show something | 
					
						
							| 
									
										
										
										
											2011-03-30 22:57:33 -03:00
										 |  |  |  * similar to an Oops dump, and if the kernel is configured to be a nice | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  |  * doggy, then halt instead of reboot. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | watchdog_bite_hook(struct pt_regs *regs) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | #ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
 | 
					
						
							|  |  |  | 	local_irq_disable(); | 
					
						
							|  |  |  | 	stop_watchdog(); | 
					
						
							|  |  |  | 	show_registers(regs); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (1) | 
					
						
							|  |  |  | 		; /* Do nothing. */ | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	show_registers(regs); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | /* This is normally the Oops function. */ | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | die_if_kernel(const char *str, struct pt_regs *regs, long err) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 	if (user_mode(regs)) | 
					
						
							|  |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | #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
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 	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); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2005-07-27 11:44:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | void __init | 
					
						
							|  |  |  | trap_init(void) | 
					
						
							| 
									
										
										
										
											2005-07-27 11:44:32 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-30 14:11:29 +01:00
										 |  |  | 	/* Nothing needs to be done */ | 
					
						
							| 
									
										
										
										
											2005-07-27 11:44:32 -07:00
										 |  |  | } |