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