]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - arch/frv/kernel/traps.c
Linux-2.6.12-rc2
[mirror_ubuntu-bionic-kernel.git] / arch / frv / kernel / traps.c
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/config.h>
13 #include <linux/sched.h>
14 #include <linux/signal.h>
15 #include <linux/kernel.h>
16 #include <linux/mm.h>
17 #include <linux/types.h>
18 #include <linux/user.h>
19 #include <linux/string.h>
20 #include <linux/linkage.h>
21 #include <linux/init.h>
22
23 #include <asm/setup.h>
24 #include <asm/fpu.h>
25 #include <asm/system.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 */
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 *) ((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 */
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 *) ((epcr0 & EPCR0_PC) ? (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 *
105 */
106 asmlinkage void media_exception(unsigned long msr0, unsigned long msr1)
107 {
108 siginfo_t info;
109
110 die_if_kernel("-- Media Exception --\n"
111 "MSR0 : %08lx\n"
112 "MSR1 : %08lx\n",
113 msr0, msr1);
114
115 info.si_signo = SIGFPE;
116 info.si_code = FPE_MDAOVF;
117 info.si_errno = 0;
118 info.si_addr = (void *) __frame->pc;
119
120 force_sig_info(info.si_signo, &info, current);
121 } /* end media_exception() */
122
123 /*****************************************************************************/
124 /*
125 * instruction or data access exception
126 */
127 asmlinkage void memory_access_exception(unsigned long esr0,
128 unsigned long ear0,
129 unsigned long epcr0)
130 {
131 siginfo_t info;
132
133 #ifdef CONFIG_MMU
134 unsigned long fixup;
135
136 if ((esr0 & ESRx_EC) == ESRx_EC_DATA_ACCESS)
137 if (handle_misalignment(esr0, ear0, epcr0) == 0)
138 return;
139
140 if ((fixup = search_exception_table(__frame->pc)) != 0) {
141 __frame->pc = fixup;
142 return;
143 }
144 #endif
145
146 die_if_kernel("-- Memory Access Exception --\n"
147 "ESR0 : %08lx\n"
148 "EAR0 : %08lx\n"
149 "EPCR0 : %08lx\n",
150 esr0, ear0, epcr0);
151
152 info.si_signo = SIGSEGV;
153 info.si_code = SEGV_ACCERR;
154 info.si_errno = 0;
155 info.si_addr = NULL;
156
157 if ((esr0 & (ESRx_VALID | ESR0_EAV)) == (ESRx_VALID | ESR0_EAV))
158 info.si_addr = (void *) ear0;
159
160 force_sig_info(info.si_signo, &info, current);
161
162 } /* end memory_access_exception() */
163
164 /*****************************************************************************/
165 /*
166 * data access error
167 * - double-word data load from CPU control area (0xFExxxxxx)
168 * - read performed on inactive or self-refreshing SDRAM
169 * - error notification from slave device
170 * - misaligned address
171 * - access to out of bounds memory region
172 * - user mode accessing privileged memory region
173 * - write to R/O memory region
174 */
175 asmlinkage void data_access_error(unsigned long esfr1, unsigned long esr15, unsigned long ear15)
176 {
177 siginfo_t info;
178
179 die_if_kernel("-- Data Access Error --\n"
180 "ESR15 : %08lx\n"
181 "EAR15 : %08lx\n",
182 esr15, ear15);
183
184 info.si_signo = SIGSEGV;
185 info.si_code = SEGV_ACCERR;
186 info.si_errno = 0;
187 info.si_addr = (void *)
188 (((esr15 & (ESRx_VALID|ESR15_EAV)) == (ESRx_VALID|ESR15_EAV)) ? ear15 : 0);
189
190 force_sig_info(info.si_signo, &info, current);
191 } /* end data_access_error() */
192
193 /*****************************************************************************/
194 /*
195 * data store error - should only happen if accessing inactive or self-refreshing SDRAM
196 */
197 asmlinkage void data_store_error(unsigned long esfr1, unsigned long esr15)
198 {
199 die_if_kernel("-- Data Store Error --\n"
200 "ESR15 : %08lx\n",
201 esr15);
202 BUG();
203 } /* end data_store_error() */
204
205 /*****************************************************************************/
206 /*
207 *
208 */
209 asmlinkage void division_exception(unsigned long esfr1, unsigned long esr0, unsigned long isr)
210 {
211 siginfo_t info;
212
213 die_if_kernel("-- Division Exception --\n"
214 "ESR0 : %08lx\n"
215 "ISR : %08lx\n",
216 esr0, isr);
217
218 info.si_signo = SIGFPE;
219 info.si_code = FPE_INTDIV;
220 info.si_errno = 0;
221 info.si_addr = (void *) __frame->pc;
222
223 force_sig_info(info.si_signo, &info, current);
224 } /* end division_exception() */
225
226 /*****************************************************************************/
227 /*
228 *
229 */
230 asmlinkage void compound_exception(unsigned long esfr1,
231 unsigned long esr0, unsigned long esr14, unsigned long esr15,
232 unsigned long msr0, unsigned long msr1)
233 {
234 die_if_kernel("-- Compound Exception --\n"
235 "ESR0 : %08lx\n"
236 "ESR15 : %08lx\n"
237 "ESR15 : %08lx\n"
238 "MSR0 : %08lx\n"
239 "MSR1 : %08lx\n",
240 esr0, esr14, esr15, msr0, msr1);
241 BUG();
242 } /* end compound_exception() */
243
244 /*****************************************************************************/
245 /*
246 * The architecture-independent backtrace generator
247 */
248 void dump_stack(void)
249 {
250 show_stack(NULL, NULL);
251 }
252
253 void show_stack(struct task_struct *task, unsigned long *sp)
254 {
255 }
256
257 void show_trace_task(struct task_struct *tsk)
258 {
259 printk("CONTEXT: stack=0x%lx frame=0x%p LR=0x%lx RET=0x%lx\n",
260 tsk->thread.sp, tsk->thread.frame, tsk->thread.lr, tsk->thread.sched_lr);
261 }
262
263 static const char *regnames[] = {
264 "PSR ", "ISR ", "CCR ", "CCCR",
265 "LR ", "LCR ", "PC ", "_stt",
266 "sys ", "GR8*", "GNE0", "GNE1",
267 "IACH", "IACL",
268 "TBR ", "SP ", "FP ", "GR3 ",
269 "GR4 ", "GR5 ", "GR6 ", "GR7 ",
270 "GR8 ", "GR9 ", "GR10", "GR11",
271 "GR12", "GR13", "GR14", "GR15",
272 "GR16", "GR17", "GR18", "GR19",
273 "GR20", "GR21", "GR22", "GR23",
274 "GR24", "GR25", "GR26", "GR27",
275 "EFRM", "CURR", "GR30", "BFRM"
276 };
277
278 void show_regs(struct pt_regs *regs)
279 {
280 uint32_t *reg;
281 int loop;
282
283 printk("\n");
284
285 printk("Frame: @%08x [%s]\n",
286 (uint32_t) regs,
287 regs->psr & PSR_S ? "kernel" : "user");
288
289 reg = (uint32_t *) regs;
290 for (loop = 0; loop < REG__END; loop++) {
291 printk("%s %08x", regnames[loop + 0], reg[loop + 0]);
292
293 if (loop == REG__END - 1 || loop % 5 == 4)
294 printk("\n");
295 else
296 printk(" | ");
297 }
298
299 printk("Process %s (pid: %d)\n", current->comm, current->pid);
300 }
301
302 void die_if_kernel(const char *str, ...)
303 {
304 char buffer[256];
305 va_list va;
306
307 if (user_mode(__frame))
308 return;
309
310 va_start(va, str);
311 vsprintf(buffer, str, va);
312 va_end(va);
313
314 console_verbose();
315 printk("\n===================================\n");
316 printk("%s\n", buffer);
317 show_backtrace(__frame, 0);
318
319 __break_hijack_kernel_event();
320 do_exit(SIGSEGV);
321 }
322
323 /*****************************************************************************/
324 /*
325 * dump the contents of an exception frame
326 */
327 static void show_backtrace_regs(struct pt_regs *frame)
328 {
329 uint32_t *reg;
330 int loop;
331
332 /* print the registers for this frame */
333 printk("<-- %s Frame: @%p -->\n",
334 frame->psr & PSR_S ? "Kernel Mode" : "User Mode",
335 frame);
336
337 reg = (uint32_t *) frame;
338 for (loop = 0; loop < REG__END; loop++) {
339 printk("%s %08x", regnames[loop + 0], reg[loop + 0]);
340
341 if (loop == REG__END - 1 || loop % 5 == 4)
342 printk("\n");
343 else
344 printk(" | ");
345 }
346
347 printk("--------\n");
348 } /* end show_backtrace_regs() */
349
350 /*****************************************************************************/
351 /*
352 * generate a backtrace of the kernel stack
353 */
354 void show_backtrace(struct pt_regs *frame, unsigned long sp)
355 {
356 struct pt_regs *frame0;
357 unsigned long tos = 0, stop = 0, base;
358 int format;
359
360 base = ((((unsigned long) frame) + 8191) & ~8191) - sizeof(struct user_context);
361 frame0 = (struct pt_regs *) base;
362
363 if (sp) {
364 tos = sp;
365 stop = (unsigned long) frame;
366 }
367
368 printk("\nProcess %s (pid: %d)\n\n", current->comm, current->pid);
369
370 for (;;) {
371 /* dump stack segment between frames */
372 //printk("%08lx -> %08lx\n", tos, stop);
373 format = 0;
374 while (tos < stop) {
375 if (format == 0)
376 printk(" %04lx :", tos & 0xffff);
377
378 printk(" %08lx", *(unsigned long *) tos);
379
380 tos += 4;
381 format++;
382 if (format == 8) {
383 printk("\n");
384 format = 0;
385 }
386 }
387
388 if (format > 0)
389 printk("\n");
390
391 /* dump frame 0 outside of the loop */
392 if (frame == frame0)
393 break;
394
395 tos = frame->sp;
396 if (((unsigned long) frame) + sizeof(*frame) != tos) {
397 printk("-- TOS %08lx does not follow frame %p --\n",
398 tos, frame);
399 break;
400 }
401
402 show_backtrace_regs(frame);
403
404 /* dump the stack between this frame and the next */
405 stop = (unsigned long) frame->next_frame;
406 if (stop != base &&
407 (stop < tos ||
408 stop > base ||
409 (stop < base && stop + sizeof(*frame) > base) ||
410 stop & 3)) {
411 printk("-- next_frame %08lx is invalid (range %08lx-%08lx) --\n",
412 stop, tos, base);
413 break;
414 }
415
416 /* move to next frame */
417 frame = frame->next_frame;
418 }
419
420 /* we can always dump frame 0, even if the rest of the stack is corrupt */
421 show_backtrace_regs(frame0);
422
423 } /* end show_backtrace() */
424
425 /*****************************************************************************/
426 /*
427 * initialise traps
428 */
429 void __init trap_init (void)
430 {
431 } /* end trap_init() */