Remove obsolete #include <linux/config.h>
[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/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/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 EXPORT_SYMBOL(dump_stack);
254
255 void show_stack(struct task_struct *task, unsigned long *sp)
256 {
257 }
258
259 void show_trace_task(struct task_struct *tsk)
260 {
261         printk("CONTEXT: stack=0x%lx frame=0x%p LR=0x%lx RET=0x%lx\n",
262                tsk->thread.sp, tsk->thread.frame, tsk->thread.lr, tsk->thread.sched_lr);
263 }
264
265 static const char *regnames[] = {
266         "PSR ", "ISR ", "CCR ", "CCCR",
267         "LR  ", "LCR ", "PC  ", "_stt",
268         "sys ", "GR8*", "GNE0", "GNE1",
269         "IACH", "IACL",
270         "TBR ", "SP  ", "FP  ", "GR3 ",
271         "GR4 ", "GR5 ", "GR6 ", "GR7 ",
272         "GR8 ", "GR9 ", "GR10", "GR11",
273         "GR12", "GR13", "GR14", "GR15",
274         "GR16", "GR17", "GR18", "GR19",
275         "GR20", "GR21", "GR22", "GR23",
276         "GR24", "GR25", "GR26", "GR27",
277         "EFRM", "CURR", "GR30", "BFRM"
278 };
279
280 void show_regs(struct pt_regs *regs)
281 {
282         uint32_t *reg;
283         int loop;
284
285         printk("\n");
286
287         printk("Frame: @%08x [%s]\n",
288                (uint32_t) regs,
289                regs->psr & PSR_S ? "kernel" : "user");
290
291         reg = (uint32_t *) regs;
292         for (loop = 0; loop < REG__END; loop++) {
293                 printk("%s %08x", regnames[loop + 0], reg[loop + 0]);
294
295                 if (loop == REG__END - 1 || loop % 5 == 4)
296                         printk("\n");
297                 else
298                         printk(" | ");
299         }
300
301         printk("Process %s (pid: %d)\n", current->comm, current->pid);
302 }
303
304 void die_if_kernel(const char *str, ...)
305 {
306         char buffer[256];
307         va_list va;
308
309         if (user_mode(__frame))
310                 return;
311
312         va_start(va, str);
313         vsprintf(buffer, str, va);
314         va_end(va);
315
316         console_verbose();
317         printk("\n===================================\n");
318         printk("%s\n", buffer);
319         show_backtrace(__frame, 0);
320
321         __break_hijack_kernel_event();
322         do_exit(SIGSEGV);
323 }
324
325 /*****************************************************************************/
326 /*
327  * dump the contents of an exception frame
328  */
329 static void show_backtrace_regs(struct pt_regs *frame)
330 {
331         uint32_t *reg;
332         int loop;
333
334         /* print the registers for this frame */
335         printk("<-- %s Frame: @%p -->\n",
336                frame->psr & PSR_S ? "Kernel Mode" : "User Mode",
337                frame);
338
339         reg = (uint32_t *) frame;
340         for (loop = 0; loop < REG__END; loop++) {
341                 printk("%s %08x", regnames[loop + 0], reg[loop + 0]);
342
343                 if (loop == REG__END - 1 || loop % 5 == 4)
344                         printk("\n");
345                 else
346                         printk(" | ");
347         }
348
349         printk("--------\n");
350 } /* end show_backtrace_regs() */
351
352 /*****************************************************************************/
353 /*
354  * generate a backtrace of the kernel stack
355  */
356 void show_backtrace(struct pt_regs *frame, unsigned long sp)
357 {
358         struct pt_regs *frame0;
359         unsigned long tos = 0, stop = 0, base;
360         int format;
361
362         base = ((((unsigned long) frame) + 8191) & ~8191) - sizeof(struct user_context);
363         frame0 = (struct pt_regs *) base;
364
365         if (sp) {
366                 tos = sp;
367                 stop = (unsigned long) frame;
368         }
369
370         printk("\nProcess %s (pid: %d)\n\n", current->comm, current->pid);
371
372         for (;;) {
373                 /* dump stack segment between frames */
374                 //printk("%08lx -> %08lx\n", tos, stop);
375                 format = 0;
376                 while (tos < stop) {
377                         if (format == 0)
378                                 printk(" %04lx :", tos & 0xffff);
379
380                         printk(" %08lx", *(unsigned long *) tos);
381
382                         tos += 4;
383                         format++;
384                         if (format == 8) {
385                                 printk("\n");
386                                 format = 0;
387                         }
388                 }
389
390                 if (format > 0)
391                         printk("\n");
392
393                 /* dump frame 0 outside of the loop */
394                 if (frame == frame0)
395                         break;
396
397                 tos = frame->sp;
398                 if (((unsigned long) frame) + sizeof(*frame) != tos) {
399                         printk("-- TOS %08lx does not follow frame %p --\n",
400                                tos, frame);
401                         break;
402                 }
403
404                 show_backtrace_regs(frame);
405
406                 /* dump the stack between this frame and the next */
407                 stop = (unsigned long) frame->next_frame;
408                 if (stop != base &&
409                     (stop < tos ||
410                      stop > base ||
411                      (stop < base && stop + sizeof(*frame) > base) ||
412                      stop & 3)) {
413                         printk("-- next_frame %08lx is invalid (range %08lx-%08lx) --\n",
414                                stop, tos, base);
415                         break;
416                 }
417
418                 /* move to next frame */
419                 frame = frame->next_frame;
420         }
421
422         /* we can always dump frame 0, even if the rest of the stack is corrupt */
423         show_backtrace_regs(frame0);
424
425 } /* end show_backtrace() */
426
427 /*****************************************************************************/
428 /*
429  * initialise traps
430  */
431 void __init trap_init (void)
432 {
433 } /* end trap_init() */