• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * arch/score/kernel/traps.c
3  *
4  * Score Processor version.
5  *
6  * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
7  *  Chen Liqin <liqin.chen@sunplusct.com>
8  *  Lennox Wu <lennox.wu@sunplusct.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, see the file COPYING, or write
22  * to the Free Software Foundation, Inc.,
23  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24  */
25 
26 #include <linux/extable.h>
27 #include <linux/ptrace.h>
28 #include <linux/sched/mm.h>
29 #include <linux/sched/signal.h>
30 #include <linux/sched/debug.h>
31 #include <linux/mm_types.h>
32 
33 #include <asm/cacheflush.h>
34 #include <asm/irq.h>
35 #include <asm/irq_regs.h>
36 #include <linux/uaccess.h>
37 
38 unsigned long exception_handlers[32];
39 
40 /*
41  * The architecture-independent show_stack generator
42  */
show_stack(struct task_struct * task,unsigned long * sp)43 void show_stack(struct task_struct *task, unsigned long *sp)
44 {
45 	int i;
46 	long stackdata;
47 
48 	sp = sp ? sp : (unsigned long *)&sp;
49 
50 	printk(KERN_NOTICE "Stack: ");
51 	i = 1;
52 	while ((long) sp & (PAGE_SIZE - 1)) {
53 		if (i && ((i % 8) == 0))
54 			printk(KERN_NOTICE "\n");
55 		if (i > 40) {
56 			printk(KERN_NOTICE " ...");
57 			break;
58 		}
59 
60 		if (__get_user(stackdata, sp++)) {
61 			printk(KERN_NOTICE " (Bad stack address)");
62 			break;
63 		}
64 
65 		printk(KERN_NOTICE " %08lx", stackdata);
66 		i++;
67 	}
68 	printk(KERN_NOTICE "\n");
69 }
70 
show_trace(long * sp)71 static void show_trace(long *sp)
72 {
73 	int i;
74 	long addr;
75 
76 	sp = sp ? sp : (long *) &sp;
77 
78 	printk(KERN_NOTICE "Call Trace:  ");
79 	i = 1;
80 	while ((long) sp & (PAGE_SIZE - 1)) {
81 		if (__get_user(addr, sp++)) {
82 			if (i && ((i % 6) == 0))
83 				printk(KERN_NOTICE "\n");
84 			printk(KERN_NOTICE " (Bad stack address)\n");
85 			break;
86 		}
87 
88 		if (kernel_text_address(addr)) {
89 			if (i && ((i % 6) == 0))
90 				printk(KERN_NOTICE "\n");
91 			if (i > 40) {
92 				printk(KERN_NOTICE " ...");
93 				break;
94 			}
95 
96 			printk(KERN_NOTICE " [<%08lx>]", addr);
97 			i++;
98 		}
99 	}
100 	printk(KERN_NOTICE "\n");
101 }
102 
show_code(unsigned int * pc)103 static void show_code(unsigned int *pc)
104 {
105 	long i;
106 
107 	printk(KERN_NOTICE "\nCode:");
108 
109 	for (i = -3; i < 6; i++) {
110 		unsigned long insn;
111 		if (__get_user(insn, pc + i)) {
112 			printk(KERN_NOTICE " (Bad address in epc)\n");
113 			break;
114 		}
115 		printk(KERN_NOTICE "%c%08lx%c", (i ? ' ' : '<'),
116 			insn, (i ? ' ' : '>'));
117 	}
118 }
119 
120 /*
121  * FIXME: really the generic show_regs should take a const pointer argument.
122  */
show_regs(struct pt_regs * regs)123 void show_regs(struct pt_regs *regs)
124 {
125 	show_regs_print_info(KERN_DEFAULT);
126 
127 	printk("r0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
128 		regs->regs[0], regs->regs[1], regs->regs[2], regs->regs[3],
129 		regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]);
130 	printk("r8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
131 		regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11],
132 		regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]);
133 	printk("r16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
134 		regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19],
135 		regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]);
136 	printk("r24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
137 		regs->regs[24], regs->regs[25], regs->regs[26], regs->regs[27],
138 		regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]);
139 
140 	printk("CEH : %08lx\n", regs->ceh);
141 	printk("CEL : %08lx\n", regs->cel);
142 
143 	printk("EMA:%08lx, epc:%08lx %s\nPSR: %08lx\nECR:%08lx\nCondition : %08lx\n",
144 		regs->cp0_ema, regs->cp0_epc, print_tainted(), regs->cp0_psr,
145 		regs->cp0_ecr, regs->cp0_condition);
146 }
147 
show_registers(struct pt_regs * regs)148 static void show_registers(struct pt_regs *regs)
149 {
150 	show_regs(regs);
151 	printk(KERN_NOTICE "Process %s (pid: %d, stackpage=%08lx)\n",
152 		current->comm, current->pid, (unsigned long) current);
153 	show_stack(current_thread_info()->task, (long *) regs->regs[0]);
154 	show_trace((long *) regs->regs[0]);
155 	show_code((unsigned int *) regs->cp0_epc);
156 	printk(KERN_NOTICE "\n");
157 }
158 
__die(const char * str,struct pt_regs * regs,const char * file,const char * func,unsigned long line)159 void __die(const char *str, struct pt_regs *regs, const char *file,
160 	const char *func, unsigned long line)
161 {
162 	console_verbose();
163 	printk("%s", str);
164 	if (file && func)
165 		printk(" in %s:%s, line %ld", file, func, line);
166 	printk(":\n");
167 	show_registers(regs);
168 	do_exit(SIGSEGV);
169 }
170 
__die_if_kernel(const char * str,struct pt_regs * regs,const char * file,const char * func,unsigned long line)171 void __die_if_kernel(const char *str, struct pt_regs *regs,
172 		const char *file, const char *func, unsigned long line)
173 {
174 	if (!user_mode(regs))
175 		__die(str, regs, file, func, line);
176 }
177 
do_adelinsn(struct pt_regs * regs)178 asmlinkage void do_adelinsn(struct pt_regs *regs)
179 {
180 	printk("do_ADE-linsn:ema:0x%08lx:epc:0x%08lx\n",
181 		 regs->cp0_ema, regs->cp0_epc);
182 	die_if_kernel("do_ade execution Exception\n", regs);
183 	force_sig(SIGBUS, current);
184 }
185 
do_adedata(struct pt_regs * regs)186 asmlinkage void do_adedata(struct pt_regs *regs)
187 {
188 	const struct exception_table_entry *fixup;
189 	fixup = search_exception_tables(regs->cp0_epc);
190 	if (fixup) {
191 		regs->cp0_epc = fixup->fixup;
192 		return;
193 	}
194 	printk("do_ADE-data:ema:0x%08lx:epc:0x%08lx\n",
195 		 regs->cp0_ema, regs->cp0_epc);
196 	die_if_kernel("do_ade execution Exception\n", regs);
197 	force_sig(SIGBUS, current);
198 }
199 
do_pel(struct pt_regs * regs)200 asmlinkage void do_pel(struct pt_regs *regs)
201 {
202 	die_if_kernel("do_pel execution Exception", regs);
203 	force_sig(SIGFPE, current);
204 }
205 
do_cee(struct pt_regs * regs)206 asmlinkage void do_cee(struct pt_regs *regs)
207 {
208 	die_if_kernel("do_cee execution Exception", regs);
209 	force_sig(SIGFPE, current);
210 }
211 
do_cpe(struct pt_regs * regs)212 asmlinkage void do_cpe(struct pt_regs *regs)
213 {
214 	die_if_kernel("do_cpe execution Exception", regs);
215 	force_sig(SIGFPE, current);
216 }
217 
do_be(struct pt_regs * regs)218 asmlinkage void do_be(struct pt_regs *regs)
219 {
220 	die_if_kernel("do_be execution Exception", regs);
221 	force_sig(SIGBUS, current);
222 }
223 
do_ov(struct pt_regs * regs)224 asmlinkage void do_ov(struct pt_regs *regs)
225 {
226 	siginfo_t info;
227 
228 	die_if_kernel("do_ov execution Exception", regs);
229 
230 	info.si_code = FPE_INTOVF;
231 	info.si_signo = SIGFPE;
232 	info.si_errno = 0;
233 	info.si_addr = (void *)regs->cp0_epc;
234 	force_sig_info(SIGFPE, &info, current);
235 }
236 
do_tr(struct pt_regs * regs)237 asmlinkage void do_tr(struct pt_regs *regs)
238 {
239 	die_if_kernel("do_tr execution Exception", regs);
240 	force_sig(SIGTRAP, current);
241 }
242 
do_ri(struct pt_regs * regs)243 asmlinkage void do_ri(struct pt_regs *regs)
244 {
245 	unsigned long epc_insn;
246 	unsigned long epc = regs->cp0_epc;
247 
248 	read_tsk_long(current, epc, &epc_insn);
249 	if (current->thread.single_step == 1) {
250 		if ((epc == current->thread.addr1) ||
251 		    (epc == current->thread.addr2)) {
252 			user_disable_single_step(current);
253 			force_sig(SIGTRAP, current);
254 			return;
255 		} else
256 			BUG();
257 	} else if ((epc_insn == BREAKPOINT32_INSN) ||
258 		   ((epc_insn & 0x0000FFFF) == 0x7002) ||
259 		   ((epc_insn & 0xFFFF0000) == 0x70020000)) {
260 			force_sig(SIGTRAP, current);
261 			return;
262 	} else {
263 		die_if_kernel("do_ri execution Exception", regs);
264 		force_sig(SIGILL, current);
265 	}
266 }
267 
do_ccu(struct pt_regs * regs)268 asmlinkage void do_ccu(struct pt_regs *regs)
269 {
270 	die_if_kernel("do_ccu execution Exception", regs);
271 	force_sig(SIGILL, current);
272 }
273 
do_reserved(struct pt_regs * regs)274 asmlinkage void do_reserved(struct pt_regs *regs)
275 {
276 	/*
277 	 * Game over - no way to handle this if it ever occurs.  Most probably
278 	 * caused by a new unknown cpu type or after another deadly
279 	 * hard/software error.
280 	 */
281 	die_if_kernel("do_reserved execution Exception", regs);
282 	show_regs(regs);
283 	panic("Caught reserved exception - should not happen.");
284 }
285 
286 /*
287  * NMI exception handler.
288  */
nmi_exception_handler(struct pt_regs * regs)289 void nmi_exception_handler(struct pt_regs *regs)
290 {
291 	die_if_kernel("nmi_exception_handler execution Exception", regs);
292 	die("NMI", regs);
293 }
294 
295 /* Install CPU exception handler */
set_except_vector(int n,void * addr)296 void *set_except_vector(int n, void *addr)
297 {
298 	unsigned long handler = (unsigned long) addr;
299 	unsigned long old_handler = exception_handlers[n];
300 
301 	exception_handlers[n] = handler;
302 	return (void *)old_handler;
303 }
304 
trap_init(void)305 void __init trap_init(void)
306 {
307 	int i;
308 
309 	pgd_current = (unsigned long)init_mm.pgd;
310 	/* DEBUG EXCEPTION */
311 	memcpy((void *)DEBUG_VECTOR_BASE_ADDR,
312 			&debug_exception_vector, DEBUG_VECTOR_SIZE);
313 	/* NMI EXCEPTION */
314 	memcpy((void *)GENERAL_VECTOR_BASE_ADDR,
315 			&general_exception_vector, GENERAL_VECTOR_SIZE);
316 
317 	/*
318 	 * Initialise exception handlers
319 	 */
320 	for (i = 0; i <= 31; i++)
321 		set_except_vector(i, handle_reserved);
322 
323 	set_except_vector(1, handle_nmi);
324 	set_except_vector(2, handle_adelinsn);
325 	set_except_vector(3, handle_tlb_refill);
326 	set_except_vector(4, handle_tlb_invaild);
327 	set_except_vector(5, handle_ibe);
328 	set_except_vector(6, handle_pel);
329 	set_except_vector(7, handle_sys);
330 	set_except_vector(8, handle_ccu);
331 	set_except_vector(9, handle_ri);
332 	set_except_vector(10, handle_tr);
333 	set_except_vector(11, handle_adedata);
334 	set_except_vector(12, handle_adedata);
335 	set_except_vector(13, handle_tlb_refill);
336 	set_except_vector(14, handle_tlb_invaild);
337 	set_except_vector(15, handle_mod);
338 	set_except_vector(16, handle_cee);
339 	set_except_vector(17, handle_cpe);
340 	set_except_vector(18, handle_dbe);
341 	flush_icache_range(DEBUG_VECTOR_BASE_ADDR, IRQ_VECTOR_BASE_ADDR);
342 
343 	mmgrab(&init_mm);
344 	current->active_mm = &init_mm;
345 	cpu_cache_init();
346 }
347