xref: /openbmc/linux/arch/arc/kernel/traps.c (revision 054419ed8405da7aa93f88f698d696980efd3e37)
1*054419edSVineet Gupta /*
2*054419edSVineet Gupta  * Traps/Non-MMU Exception handling for ARC
3*054419edSVineet Gupta  *
4*054419edSVineet Gupta  * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
5*054419edSVineet Gupta  *
6*054419edSVineet Gupta  * This program is free software; you can redistribute it and/or modify
7*054419edSVineet Gupta  * it under the terms of the GNU General Public License version 2 as
8*054419edSVineet Gupta  * published by the Free Software Foundation.
9*054419edSVineet Gupta  *
10*054419edSVineet Gupta  * Rahul Trivedi: Codito Technologies 2004
11*054419edSVineet Gupta  */
12*054419edSVineet Gupta 
13*054419edSVineet Gupta #include <linux/sched.h>
14*054419edSVineet Gupta #include <linux/kdebug.h>
15*054419edSVineet Gupta #include <linux/uaccess.h>
16*054419edSVineet Gupta #include <asm/ptrace.h>
17*054419edSVineet Gupta #include <asm/setup.h>
18*054419edSVineet Gupta 
19*054419edSVineet Gupta void __init trap_init(void)
20*054419edSVineet Gupta {
21*054419edSVineet Gupta 	return;
22*054419edSVineet Gupta }
23*054419edSVineet Gupta 
24*054419edSVineet Gupta void die(const char *str, struct pt_regs *regs, unsigned long address,
25*054419edSVineet Gupta 	 unsigned long cause_reg)
26*054419edSVineet Gupta {
27*054419edSVineet Gupta 	show_kernel_fault_diag(str, regs, address, cause_reg);
28*054419edSVineet Gupta 
29*054419edSVineet Gupta 	/* DEAD END */
30*054419edSVineet Gupta 	__asm__("flag 1");
31*054419edSVineet Gupta }
32*054419edSVineet Gupta 
33*054419edSVineet Gupta /*
34*054419edSVineet Gupta  * Helper called for bulk of exceptions NOT needing specific handling
35*054419edSVineet Gupta  *  -for user faults enqueues requested signal
36*054419edSVineet Gupta  *  -for kernel, chk if due to copy_(to|from)_user, otherwise die()
37*054419edSVineet Gupta  */
38*054419edSVineet Gupta static noinline int handle_exception(unsigned long cause, char *str,
39*054419edSVineet Gupta 				     struct pt_regs *regs, siginfo_t *info)
40*054419edSVineet Gupta {
41*054419edSVineet Gupta 	if (user_mode(regs)) {
42*054419edSVineet Gupta 		struct task_struct *tsk = current;
43*054419edSVineet Gupta 
44*054419edSVineet Gupta 		tsk->thread.fault_address = (__force unsigned int)info->si_addr;
45*054419edSVineet Gupta 		tsk->thread.cause_code = cause;
46*054419edSVineet Gupta 
47*054419edSVineet Gupta 		force_sig_info(info->si_signo, info, tsk);
48*054419edSVineet Gupta 
49*054419edSVineet Gupta 	} else {
50*054419edSVineet Gupta 		/* If not due to copy_(to|from)_user, we are doomed */
51*054419edSVineet Gupta 		if (fixup_exception(regs))
52*054419edSVineet Gupta 			return 0;
53*054419edSVineet Gupta 
54*054419edSVineet Gupta 		die(str, regs, (unsigned long)info->si_addr, cause);
55*054419edSVineet Gupta 	}
56*054419edSVineet Gupta 
57*054419edSVineet Gupta 	return 1;
58*054419edSVineet Gupta }
59*054419edSVineet Gupta 
60*054419edSVineet Gupta #define DO_ERROR_INFO(signr, str, name, sicode) \
61*054419edSVineet Gupta int name(unsigned long cause, unsigned long address, struct pt_regs *regs) \
62*054419edSVineet Gupta {						\
63*054419edSVineet Gupta 	siginfo_t info = {			\
64*054419edSVineet Gupta 		.si_signo = signr,		\
65*054419edSVineet Gupta 		.si_errno = 0,			\
66*054419edSVineet Gupta 		.si_code  = sicode,		\
67*054419edSVineet Gupta 		.si_addr = (void __user *)address,	\
68*054419edSVineet Gupta 	};					\
69*054419edSVineet Gupta 	return handle_exception(cause, str, regs, &info);\
70*054419edSVineet Gupta }
71*054419edSVineet Gupta 
72*054419edSVineet Gupta /*
73*054419edSVineet Gupta  * Entry points for exceptions NOT needing specific handling
74*054419edSVineet Gupta  */
75*054419edSVineet Gupta DO_ERROR_INFO(SIGILL, "Priv Op/Disabled Extn", do_privilege_fault, ILL_PRVOPC)
76*054419edSVineet Gupta DO_ERROR_INFO(SIGILL, "Invalid Extn Insn", do_extension_fault, ILL_ILLOPC)
77*054419edSVineet Gupta DO_ERROR_INFO(SIGILL, "Illegal Insn (or Seq)", insterror_is_error, ILL_ILLOPC)
78*054419edSVineet Gupta DO_ERROR_INFO(SIGBUS, "Invalid Mem Access", do_memory_error, BUS_ADRERR)
79*054419edSVineet Gupta DO_ERROR_INFO(SIGTRAP, "Breakpoint Set", trap_is_brkpt, TRAP_BRKPT)
80*054419edSVineet Gupta 
81*054419edSVineet Gupta DO_ERROR_INFO(SIGSEGV, "Misaligned Access", do_misaligned_access, SEGV_ACCERR)
82*054419edSVineet Gupta 
83*054419edSVineet Gupta /*
84*054419edSVineet Gupta  * Entry point for miscll errors such as Nested Exceptions
85*054419edSVineet Gupta  *  -Duplicate TLB entry is handled seperately though
86*054419edSVineet Gupta  */
87*054419edSVineet Gupta void do_machine_check_fault(unsigned long cause, unsigned long address,
88*054419edSVineet Gupta 			    struct pt_regs *regs)
89*054419edSVineet Gupta {
90*054419edSVineet Gupta 	die("Machine Check Exception", regs, address, cause);
91*054419edSVineet Gupta }
92*054419edSVineet Gupta 
93*054419edSVineet Gupta /*
94*054419edSVineet Gupta  * Entry point for traps induced by ARCompact TRAP_S <n> insn
95*054419edSVineet Gupta  * This is same family as TRAP0/SWI insn (use the same vector).
96*054419edSVineet Gupta  * The only difference being SWI insn take no operand, while TRAP_S does
97*054419edSVineet Gupta  * which reflects in ECR Reg as 8 bit param.
98*054419edSVineet Gupta  * Thus TRAP_S <n> can be used for specific purpose
99*054419edSVineet Gupta  *  -1 used for software breakpointing (gdb)
100*054419edSVineet Gupta  *  -2 used by kprobes
101*054419edSVineet Gupta  */
102*054419edSVineet Gupta void do_non_swi_trap(unsigned long cause, unsigned long address,
103*054419edSVineet Gupta 			struct pt_regs *regs)
104*054419edSVineet Gupta {
105*054419edSVineet Gupta 	unsigned int param = cause & 0xff;
106*054419edSVineet Gupta 
107*054419edSVineet Gupta 	switch (param) {
108*054419edSVineet Gupta 	case 1:
109*054419edSVineet Gupta 		trap_is_brkpt(cause, address, regs);
110*054419edSVineet Gupta 		break;
111*054419edSVineet Gupta 
112*054419edSVineet Gupta 	default:
113*054419edSVineet Gupta 		break;
114*054419edSVineet Gupta 	}
115*054419edSVineet Gupta }
116*054419edSVineet Gupta 
117*054419edSVineet Gupta /*
118*054419edSVineet Gupta  * Entry point for Instruction Error Exception
119*054419edSVineet Gupta  */
120*054419edSVineet Gupta void do_insterror_or_kprobe(unsigned long cause,
121*054419edSVineet Gupta 				       unsigned long address,
122*054419edSVineet Gupta 				       struct pt_regs *regs)
123*054419edSVineet Gupta {
124*054419edSVineet Gupta 	insterror_is_error(cause, address, regs);
125*054419edSVineet Gupta }
126