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