• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/frv/kernel/
1/* traps.c: high-level exception handler for FR-V
2 *
3 * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <linux/sched.h>
13#include <linux/signal.h>
14#include <linux/kernel.h>
15#include <linux/mm.h>
16#include <linux/types.h>
17#include <linux/user.h>
18#include <linux/string.h>
19#include <linux/linkage.h>
20#include <linux/init.h>
21#include <linux/module.h>
22
23#include <asm/asm-offsets.h>
24#include <asm/setup.h>
25#include <asm/fpu.h>
26#include <asm/system.h>
27#include <asm/uaccess.h>
28#include <asm/pgtable.h>
29#include <asm/siginfo.h>
30#include <asm/unaligned.h>
31
32void show_backtrace(struct pt_regs *, unsigned long);
33
34extern asmlinkage void __break_hijack_kernel_event(void);
35
36/*****************************************************************************/
37/*
38 * instruction access error
39 */
40asmlinkage void insn_access_error(unsigned long esfr1, unsigned long epcr0, unsigned long esr0)
41{
42	siginfo_t info;
43
44	die_if_kernel("-- Insn Access Error --\n"
45		      "EPCR0 : %08lx\n"
46		      "ESR0  : %08lx\n",
47		      epcr0, esr0);
48
49	info.si_signo	= SIGSEGV;
50	info.si_code	= SEGV_ACCERR;
51	info.si_errno	= 0;
52	info.si_addr	= (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc);
53
54	force_sig_info(info.si_signo, &info, current);
55} /* end insn_access_error() */
56
57/*****************************************************************************/
58/*
59 * handler for:
60 * - illegal instruction
61 * - privileged instruction
62 * - unsupported trap
63 * - debug exceptions
64 */
65asmlinkage void illegal_instruction(unsigned long esfr1, unsigned long epcr0, unsigned long esr0)
66{
67	siginfo_t info;
68
69	die_if_kernel("-- Illegal Instruction --\n"
70		      "EPCR0 : %08lx\n"
71		      "ESR0  : %08lx\n"
72		      "ESFR1 : %08lx\n",
73		      epcr0, esr0, esfr1);
74
75	info.si_errno	= 0;
76	info.si_addr	= (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc);
77
78	switch (__frame->tbr & TBR_TT) {
79	case TBR_TT_ILLEGAL_INSTR:
80		info.si_signo	= SIGILL;
81		info.si_code	= ILL_ILLOPC;
82		break;
83	case TBR_TT_PRIV_INSTR:
84		info.si_signo	= SIGILL;
85		info.si_code	= ILL_PRVOPC;
86		break;
87	case TBR_TT_TRAP2 ... TBR_TT_TRAP126:
88		info.si_signo	= SIGILL;
89		info.si_code	= ILL_ILLTRP;
90		break;
91	/* GDB uses "tira gr0, #1" as a breakpoint instruction.  */
92	case TBR_TT_TRAP1:
93	case TBR_TT_BREAK:
94		info.si_signo	= SIGTRAP;
95		info.si_code	=
96			(__frame->__status & REG__STATUS_STEPPED) ? TRAP_TRACE : TRAP_BRKPT;
97		break;
98	}
99
100	force_sig_info(info.si_signo, &info, current);
101} /* end illegal_instruction() */
102
103/*****************************************************************************/
104/*
105 * handle atomic operations with errors
106 * - arguments in gr8, gr9, gr10
107 * - original memory value placed in gr5
108 * - replacement memory value placed in gr9
109 */
110asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0,
111				 unsigned long esr0)
112{
113	static DEFINE_SPINLOCK(atomic_op_lock);
114	unsigned long x, y, z;
115	unsigned long __user *p;
116	mm_segment_t oldfs;
117	siginfo_t info;
118	int ret;
119
120	y = 0;
121	z = 0;
122
123	oldfs = get_fs();
124	if (!user_mode(__frame))
125		set_fs(KERNEL_DS);
126
127	switch (__frame->tbr & TBR_TT) {
128		/* TIRA gr0,#120
129		 * u32 __atomic_user_cmpxchg32(u32 *ptr, u32 test, u32 new)
130		 */
131	case TBR_TT_ATOMIC_CMPXCHG32:
132		p = (unsigned long __user *) __frame->gr8;
133		x = __frame->gr9;
134		y = __frame->gr10;
135
136		for (;;) {
137			ret = get_user(z, p);
138			if (ret < 0)
139				goto error;
140
141			if (z != x)
142				goto done;
143
144			spin_lock_irq(&atomic_op_lock);
145
146			if (__get_user(z, p) == 0) {
147				if (z != x)
148					goto done2;
149
150				if (__put_user(y, p) == 0)
151					goto done2;
152				goto error2;
153			}
154
155			spin_unlock_irq(&atomic_op_lock);
156		}
157
158		/* TIRA gr0,#121
159		 * u32 __atomic_kernel_xchg32(void *v, u32 new)
160		 */
161	case TBR_TT_ATOMIC_XCHG32:
162		p = (unsigned long __user *) __frame->gr8;
163		y = __frame->gr9;
164
165		for (;;) {
166			ret = get_user(z, p);
167			if (ret < 0)
168				goto error;
169
170			spin_lock_irq(&atomic_op_lock);
171
172			if (__get_user(z, p) == 0) {
173				if (__put_user(y, p) == 0)
174					goto done2;
175				goto error2;
176			}
177
178			spin_unlock_irq(&atomic_op_lock);
179		}
180
181		/* TIRA gr0,#122
182		 * ulong __atomic_kernel_XOR_return(ulong i, ulong *v)
183		 */
184	case TBR_TT_ATOMIC_XOR:
185		p = (unsigned long __user *) __frame->gr8;
186		x = __frame->gr9;
187
188		for (;;) {
189			ret = get_user(z, p);
190			if (ret < 0)
191				goto error;
192
193			spin_lock_irq(&atomic_op_lock);
194
195			if (__get_user(z, p) == 0) {
196				y = x ^ z;
197				if (__put_user(y, p) == 0)
198					goto done2;
199				goto error2;
200			}
201
202			spin_unlock_irq(&atomic_op_lock);
203		}
204
205		/* TIRA gr0,#123
206		 * ulong __atomic_kernel_OR_return(ulong i, ulong *v)
207		 */
208	case TBR_TT_ATOMIC_OR:
209		p = (unsigned long __user *) __frame->gr8;
210		x = __frame->gr9;
211
212		for (;;) {
213			ret = get_user(z, p);
214			if (ret < 0)
215				goto error;
216
217			spin_lock_irq(&atomic_op_lock);
218
219			if (__get_user(z, p) == 0) {
220				y = x ^ z;
221				if (__put_user(y, p) == 0)
222					goto done2;
223				goto error2;
224			}
225
226			spin_unlock_irq(&atomic_op_lock);
227		}
228
229		/* TIRA gr0,#124
230		 * ulong __atomic_kernel_AND_return(ulong i, ulong *v)
231		 */
232	case TBR_TT_ATOMIC_AND:
233		p = (unsigned long __user *) __frame->gr8;
234		x = __frame->gr9;
235
236		for (;;) {
237			ret = get_user(z, p);
238			if (ret < 0)
239				goto error;
240
241			spin_lock_irq(&atomic_op_lock);
242
243			if (__get_user(z, p) == 0) {
244				y = x & z;
245				if (__put_user(y, p) == 0)
246					goto done2;
247				goto error2;
248			}
249
250			spin_unlock_irq(&atomic_op_lock);
251		}
252
253		/* TIRA gr0,#125
254		 * int __atomic_user_sub_return(atomic_t *v, int i)
255		 */
256	case TBR_TT_ATOMIC_SUB:
257		p = (unsigned long __user *) __frame->gr8;
258		x = __frame->gr9;
259
260		for (;;) {
261			ret = get_user(z, p);
262			if (ret < 0)
263				goto error;
264
265			spin_lock_irq(&atomic_op_lock);
266
267			if (__get_user(z, p) == 0) {
268				y = z - x;
269				if (__put_user(y, p) == 0)
270					goto done2;
271				goto error2;
272			}
273
274			spin_unlock_irq(&atomic_op_lock);
275		}
276
277		/* TIRA gr0,#126
278		 * int __atomic_user_add_return(atomic_t *v, int i)
279		 */
280	case TBR_TT_ATOMIC_ADD:
281		p = (unsigned long __user *) __frame->gr8;
282		x = __frame->gr9;
283
284		for (;;) {
285			ret = get_user(z, p);
286			if (ret < 0)
287				goto error;
288
289			spin_lock_irq(&atomic_op_lock);
290
291			if (__get_user(z, p) == 0) {
292				y = z + x;
293				if (__put_user(y, p) == 0)
294					goto done2;
295				goto error2;
296			}
297
298			spin_unlock_irq(&atomic_op_lock);
299		}
300
301	default:
302		BUG();
303	}
304
305done2:
306	spin_unlock_irq(&atomic_op_lock);
307done:
308	if (!user_mode(__frame))
309		set_fs(oldfs);
310	__frame->gr5 = z;
311	__frame->gr9 = y;
312	return;
313
314error2:
315	spin_unlock_irq(&atomic_op_lock);
316error:
317	if (!user_mode(__frame))
318		set_fs(oldfs);
319	__frame->pc -= 4;
320
321	die_if_kernel("-- Atomic Op Error --\n");
322
323	info.si_signo	= SIGSEGV;
324	info.si_code	= SEGV_ACCERR;
325	info.si_errno	= 0;
326	info.si_addr	= (void __user *) __frame->pc;
327
328	force_sig_info(info.si_signo, &info, current);
329}
330
331/*****************************************************************************/
332/*
333 *
334 */
335asmlinkage void media_exception(unsigned long msr0, unsigned long msr1)
336{
337	siginfo_t info;
338
339	die_if_kernel("-- Media Exception --\n"
340		      "MSR0 : %08lx\n"
341		      "MSR1 : %08lx\n",
342		      msr0, msr1);
343
344	info.si_signo	= SIGFPE;
345	info.si_code	= FPE_MDAOVF;
346	info.si_errno	= 0;
347	info.si_addr	= (void __user *) __frame->pc;
348
349	force_sig_info(info.si_signo, &info, current);
350} /* end media_exception() */
351
352/*****************************************************************************/
353/*
354 * instruction or data access exception
355 */
356asmlinkage void memory_access_exception(unsigned long esr0,
357					unsigned long ear0,
358					unsigned long epcr0)
359{
360	siginfo_t info;
361
362#ifdef CONFIG_MMU
363	unsigned long fixup;
364
365	fixup = search_exception_table(__frame->pc);
366	if (fixup) {
367		__frame->pc = fixup;
368		return;
369	}
370#endif
371
372	die_if_kernel("-- Memory Access Exception --\n"
373		      "ESR0  : %08lx\n"
374		      "EAR0  : %08lx\n"
375		      "EPCR0 : %08lx\n",
376		      esr0, ear0, epcr0);
377
378	info.si_signo	= SIGSEGV;
379	info.si_code	= SEGV_ACCERR;
380	info.si_errno	= 0;
381	info.si_addr	= NULL;
382
383	if ((esr0 & (ESRx_VALID | ESR0_EAV)) == (ESRx_VALID | ESR0_EAV))
384		info.si_addr = (void __user *) ear0;
385
386	force_sig_info(info.si_signo, &info, current);
387
388} /* end memory_access_exception() */
389
390/*****************************************************************************/
391/*
392 * data access error
393 * - double-word data load from CPU control area (0xFExxxxxx)
394 * - read performed on inactive or self-refreshing SDRAM
395 * - error notification from slave device
396 * - misaligned address
397 * - access to out of bounds memory region
398 * - user mode accessing privileged memory region
399 * - write to R/O memory region
400 */
401asmlinkage void data_access_error(unsigned long esfr1, unsigned long esr15, unsigned long ear15)
402{
403	siginfo_t info;
404
405	die_if_kernel("-- Data Access Error --\n"
406		      "ESR15 : %08lx\n"
407		      "EAR15 : %08lx\n",
408		      esr15, ear15);
409
410	info.si_signo	= SIGSEGV;
411	info.si_code	= SEGV_ACCERR;
412	info.si_errno	= 0;
413	info.si_addr	= (void __user *)
414		(((esr15 & (ESRx_VALID|ESR15_EAV)) == (ESRx_VALID|ESR15_EAV)) ? ear15 : 0);
415
416	force_sig_info(info.si_signo, &info, current);
417} /* end data_access_error() */
418
419/*****************************************************************************/
420/*
421 * data store error - should only happen if accessing inactive or self-refreshing SDRAM
422 */
423asmlinkage void data_store_error(unsigned long esfr1, unsigned long esr15)
424{
425	die_if_kernel("-- Data Store Error --\n"
426		      "ESR15 : %08lx\n",
427		      esr15);
428	BUG();
429} /* end data_store_error() */
430
431/*****************************************************************************/
432/*
433 *
434 */
435asmlinkage void division_exception(unsigned long esfr1, unsigned long esr0, unsigned long isr)
436{
437	siginfo_t info;
438
439	die_if_kernel("-- Division Exception --\n"
440		      "ESR0 : %08lx\n"
441		      "ISR  : %08lx\n",
442		      esr0, isr);
443
444	info.si_signo	= SIGFPE;
445	info.si_code	= FPE_INTDIV;
446	info.si_errno	= 0;
447	info.si_addr	= (void __user *) __frame->pc;
448
449	force_sig_info(info.si_signo, &info, current);
450} /* end division_exception() */
451
452/*****************************************************************************/
453/*
454 *
455 */
456asmlinkage void compound_exception(unsigned long esfr1,
457				   unsigned long esr0, unsigned long esr14, unsigned long esr15,
458				   unsigned long msr0, unsigned long msr1)
459{
460	die_if_kernel("-- Compound Exception --\n"
461		      "ESR0  : %08lx\n"
462		      "ESR15 : %08lx\n"
463		      "ESR15 : %08lx\n"
464		      "MSR0  : %08lx\n"
465		      "MSR1  : %08lx\n",
466		      esr0, esr14, esr15, msr0, msr1);
467	BUG();
468} /* end compound_exception() */
469
470/*****************************************************************************/
471/*
472 * The architecture-independent backtrace generator
473 */
474void dump_stack(void)
475{
476	show_stack(NULL, NULL);
477}
478
479EXPORT_SYMBOL(dump_stack);
480
481void show_stack(struct task_struct *task, unsigned long *sp)
482{
483}
484
485void show_trace_task(struct task_struct *tsk)
486{
487	printk("CONTEXT: stack=0x%lx frame=0x%p LR=0x%lx RET=0x%lx\n",
488	       tsk->thread.sp, tsk->thread.frame, tsk->thread.lr, tsk->thread.sched_lr);
489}
490
491static const char *regnames[] = {
492	"PSR ", "ISR ", "CCR ", "CCCR",
493	"LR  ", "LCR ", "PC  ", "_stt",
494	"sys ", "GR8*", "GNE0", "GNE1",
495	"IACH", "IACL",
496	"TBR ", "SP  ", "FP  ", "GR3 ",
497	"GR4 ", "GR5 ", "GR6 ", "GR7 ",
498	"GR8 ", "GR9 ", "GR10", "GR11",
499	"GR12", "GR13", "GR14", "GR15",
500	"GR16", "GR17", "GR18", "GR19",
501	"GR20", "GR21", "GR22", "GR23",
502	"GR24", "GR25", "GR26", "GR27",
503	"EFRM", "CURR", "GR30", "BFRM"
504};
505
506void show_regs(struct pt_regs *regs)
507{
508	unsigned long *reg;
509	int loop;
510
511	printk("\n");
512
513	printk("Frame: @%08lx [%s]\n",
514	       (unsigned long) regs,
515	       regs->psr & PSR_S ? "kernel" : "user");
516
517	reg = (unsigned long *) regs;
518	for (loop = 0; loop < NR_PT_REGS; loop++) {
519		printk("%s %08lx", regnames[loop + 0], reg[loop + 0]);
520
521		if (loop == NR_PT_REGS - 1 || loop % 5 == 4)
522			printk("\n");
523		else
524			printk(" | ");
525	}
526
527	printk("Process %s (pid: %d)\n", current->comm, current->pid);
528}
529
530void die_if_kernel(const char *str, ...)
531{
532	char buffer[256];
533	va_list va;
534
535	if (user_mode(__frame))
536		return;
537
538	va_start(va, str);
539	vsprintf(buffer, str, va);
540	va_end(va);
541
542	console_verbose();
543	printk("\n===================================\n");
544	printk("%s\n", buffer);
545	show_backtrace(__frame, 0);
546
547	__break_hijack_kernel_event();
548	do_exit(SIGSEGV);
549}
550
551/*****************************************************************************/
552/*
553 * dump the contents of an exception frame
554 */
555static void show_backtrace_regs(struct pt_regs *frame)
556{
557	unsigned long *reg;
558	int loop;
559
560	/* print the registers for this frame */
561	printk("<-- %s Frame: @%p -->\n",
562	       frame->psr & PSR_S ? "Kernel Mode" : "User Mode",
563	       frame);
564
565	reg = (unsigned long *) frame;
566	for (loop = 0; loop < NR_PT_REGS; loop++) {
567		printk("%s %08lx", regnames[loop + 0], reg[loop + 0]);
568
569		if (loop == NR_PT_REGS - 1 || loop % 5 == 4)
570			printk("\n");
571		else
572			printk(" | ");
573	}
574
575	printk("--------\n");
576} /* end show_backtrace_regs() */
577
578/*****************************************************************************/
579/*
580 * generate a backtrace of the kernel stack
581 */
582void show_backtrace(struct pt_regs *frame, unsigned long sp)
583{
584	struct pt_regs *frame0;
585	unsigned long tos = 0, stop = 0, base;
586	int format;
587
588	base = ((((unsigned long) frame) + 8191) & ~8191) - sizeof(struct user_context);
589	frame0 = (struct pt_regs *) base;
590
591	if (sp) {
592		tos = sp;
593		stop = (unsigned long) frame;
594	}
595
596	printk("\nProcess %s (pid: %d)\n\n", current->comm, current->pid);
597
598	for (;;) {
599		/* dump stack segment between frames */
600		//printk("%08lx -> %08lx\n", tos, stop);
601		format = 0;
602		while (tos < stop) {
603			if (format == 0)
604				printk(" %04lx :", tos & 0xffff);
605
606			printk(" %08lx", *(unsigned long *) tos);
607
608			tos += 4;
609			format++;
610			if (format == 8) {
611				printk("\n");
612				format = 0;
613			}
614		}
615
616		if (format > 0)
617			printk("\n");
618
619		/* dump frame 0 outside of the loop */
620		if (frame == frame0)
621			break;
622
623		tos = frame->sp;
624		if (((unsigned long) frame) + sizeof(*frame) != tos) {
625			printk("-- TOS %08lx does not follow frame %p --\n",
626			       tos, frame);
627			break;
628		}
629
630		show_backtrace_regs(frame);
631
632		/* dump the stack between this frame and the next */
633		stop = (unsigned long) frame->next_frame;
634		if (stop != base &&
635		    (stop < tos ||
636		     stop > base ||
637		     (stop < base && stop + sizeof(*frame) > base) ||
638		     stop & 3)) {
639			printk("-- next_frame %08lx is invalid (range %08lx-%08lx) --\n",
640			       stop, tos, base);
641			break;
642		}
643
644		/* move to next frame */
645		frame = frame->next_frame;
646	}
647
648	/* we can always dump frame 0, even if the rest of the stack is corrupt */
649	show_backtrace_regs(frame0);
650
651} /* end show_backtrace() */
652
653/*****************************************************************************/
654/*
655 * initialise traps
656 */
657void __init trap_init (void)
658{
659} /* end trap_init() */
660