1/*
2 *  linux/arch/cris/traps.c
3 *
4 *  Here we handle the break vectors not used by the system call
5 *  mechanism, as well as some general stack/register dumping
6 *  things.
7 *
8 *  Copyright (C) 2000-2007 Axis Communications AB
9 *
10 *  Authors:   Bjorn Wesen
11 *             Hans-Peter Nilsson
12 *
13 */
14
15#include <linux/init.h>
16#include <linux/module.h>
17
18#include <asm/pgtable.h>
19#include <asm/uaccess.h>
20#include <arch/system.h>
21
22extern void arch_enable_nmi(void);
23extern void stop_watchdog(void);
24extern void reset_watchdog(void);
25extern void show_registers(struct pt_regs *regs);
26
27#ifdef CONFIG_DEBUG_BUGVERBOSE
28extern void handle_BUG(struct pt_regs *regs);
29#else
30#define handle_BUG(regs)
31#endif
32
33static int kstack_depth_to_print = 24;
34
35void (*nmi_handler)(struct pt_regs *);
36
37void
38show_trace(unsigned long *stack)
39{
40	unsigned long addr, module_start, module_end;
41	extern char _stext, _etext;
42	int i;
43
44	printk("\nCall Trace: ");
45
46	i = 1;
47	module_start = VMALLOC_START;
48	module_end = VMALLOC_END;
49
50	while (((long)stack & (THREAD_SIZE-1)) != 0) {
51		if (__get_user(addr, stack)) {
52			/* This message matches "failing address" marked
53			   s390 in ksymoops, so lines containing it will
54			   not be filtered out by ksymoops.  */
55			printk("Failing address 0x%lx\n", (unsigned long)stack);
56			break;
57		}
58		stack++;
59
60		/*
61		 * If the address is either in the text segment of the
62		 * kernel, or in the region which contains vmalloc'ed
63		 * memory, it *may* be the address of a calling
64		 * routine; if so, print it so that someone tracing
65		 * down the cause of the crash will be able to figure
66		 * out the call path that was taken.
67		 */
68		if (((addr >= (unsigned long)&_stext) &&
69		     (addr <= (unsigned long)&_etext)) ||
70		    ((addr >= module_start) && (addr <= module_end))) {
71			if (i && ((i % 8) == 0))
72				printk("\n       ");
73			printk("[<%08lx>] ", addr);
74			i++;
75		}
76	}
77}
78
79/*
80 * These constants are for searching for possible module text
81 * segments. MODULE_RANGE is a guess of how much space is likely
82 * to be vmalloced.
83 */
84
85#define MODULE_RANGE (8*1024*1024)
86
87/*
88 * The output (format, strings and order) is adjusted to be usable with
89 * ksymoops-2.4.1 with some necessary CRIS-specific patches.  Please don't
90 * change it unless you're serious about adjusting ksymoops and syncing
91 * with the ksymoops maintainer.
92 */
93
94void
95show_stack(struct task_struct *task, unsigned long *sp)
96{
97	unsigned long *stack, addr;
98	int i;
99
100	/*
101	 * debugging aid: "show_stack(NULL);" prints a
102	 * back trace.
103	 */
104
105	if (sp == NULL) {
106		if (task)
107			sp = (unsigned long*)task->thread.ksp;
108		else
109			sp = (unsigned long*)rdsp();
110	}
111
112	stack = sp;
113
114	printk("\nStack from %08lx:\n       ", (unsigned long)stack);
115	for (i = 0; i < kstack_depth_to_print; i++) {
116		if (((long)stack & (THREAD_SIZE-1)) == 0)
117			break;
118		if (i && ((i % 8) == 0))
119			printk("\n       ");
120		if (__get_user(addr, stack)) {
121			/* This message matches "failing address" marked
122			   s390 in ksymoops, so lines containing it will
123			   not be filtered out by ksymoops.  */
124			printk("Failing address 0x%lx\n", (unsigned long)stack);
125			break;
126		}
127		stack++;
128		printk("%08lx ", addr);
129	}
130	show_trace(sp);
131}
132
133#if 0
134/* displays a short stack trace */
135
136int
137show_stack(void)
138{
139	unsigned long *sp = (unsigned long *)rdusp();
140	int i;
141
142	printk("Stack dump [0x%08lx]:\n", (unsigned long)sp);
143	for (i = 0; i < 16; i++)
144		printk("sp + %d: 0x%08lx\n", i*4, sp[i]);
145	return 0;
146}
147#endif
148
149void
150dump_stack(void)
151{
152	show_stack(NULL, NULL);
153}
154EXPORT_SYMBOL(dump_stack);
155
156void
157set_nmi_handler(void (*handler)(struct pt_regs *))
158{
159	nmi_handler = handler;
160	arch_enable_nmi();
161}
162
163#ifdef CONFIG_DEBUG_NMI_OOPS
164void
165oops_nmi_handler(struct pt_regs *regs)
166{
167	stop_watchdog();
168	oops_in_progress = 1;
169	printk("NMI!\n");
170	show_registers(regs);
171	oops_in_progress = 0;
172}
173
174static int __init
175oops_nmi_register(void)
176{
177	set_nmi_handler(oops_nmi_handler);
178	return 0;
179}
180
181__initcall(oops_nmi_register);
182
183#endif
184
185/*
186 * This gets called from entry.S when the watchdog has bitten. Show something
187 * similar to an Oops dump, and if the kernel is configured to be a nice
188 * doggy, then halt instead of reboot.
189 */
190void
191watchdog_bite_hook(struct pt_regs *regs)
192{
193#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
194	local_irq_disable();
195	stop_watchdog();
196	show_registers(regs);
197
198	while (1)
199		; /* Do nothing. */
200#else
201	show_registers(regs);
202#endif
203}
204
205/* This is normally the Oops function. */
206void
207die_if_kernel(const char *str, struct pt_regs *regs, long err)
208{
209	if (user_mode(regs))
210		return;
211
212#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
213	/*
214	 * This printout might take too long and could trigger
215	 * the watchdog normally. If NICE_DOGGY is set, simply
216	 * stop the watchdog during the printout.
217	 */
218	stop_watchdog();
219#endif
220
221	handle_BUG(regs);
222
223	printk("%s: %04lx\n", str, err & 0xffff);
224
225	show_registers(regs);
226
227	oops_in_progress = 0;
228
229#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
230	reset_watchdog();
231#endif
232	do_exit(SIGSEGV);
233}
234
235void __init
236trap_init(void)
237{
238	/* Nothing needs to be done */
239}
240