Merge branch 'for-linus' of git://git.kernel.dk/data/git/linux-2.6-block
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / arch / avr32 / kernel / traps.c
blobadc01a12d15487ff8ae335f8352b9820d00b9395
1 /*
2 * Copyright (C) 2004-2006 Atmel Corporation
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8 #undef DEBUG
9 #include <linux/sched.h>
10 #include <linux/init.h>
11 #include <linux/module.h>
12 #include <linux/kallsyms.h>
13 #include <linux/notifier.h>
15 #include <asm/traps.h>
16 #include <asm/sysreg.h>
17 #include <asm/addrspace.h>
18 #include <asm/ocd.h>
19 #include <asm/mmu_context.h>
20 #include <asm/uaccess.h>
22 static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
24 unsigned long p;
25 int i;
27 printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
29 for (p = bottom & ~31; p < top; ) {
30 printk("%04lx: ", p & 0xffff);
32 for (i = 0; i < 8; i++, p += 4) {
33 unsigned int val;
35 if (p < bottom || p >= top)
36 printk(" ");
37 else {
38 if (__get_user(val, (unsigned int __user *)p)) {
39 printk("\n");
40 goto out;
42 printk("%08x ", val);
45 printk("\n");
48 out:
49 return;
52 static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p)
54 return (p > (unsigned long)tinfo)
55 && (p < (unsigned long)tinfo + THREAD_SIZE - 3);
58 #ifdef CONFIG_FRAME_POINTER
59 static inline void __show_trace(struct task_struct *tsk, unsigned long *sp,
60 struct pt_regs *regs)
62 unsigned long lr, fp;
63 struct thread_info *tinfo;
65 tinfo = (struct thread_info *)
66 ((unsigned long)sp & ~(THREAD_SIZE - 1));
68 if (regs)
69 fp = regs->r7;
70 else if (tsk == current)
71 asm("mov %0, r7" : "=r"(fp));
72 else
73 fp = tsk->thread.cpu_context.r7;
76 * Walk the stack as long as the frame pointer (a) is within
77 * the kernel stack of the task, and (b) it doesn't move
78 * downwards.
80 while (valid_stack_ptr(tinfo, fp)) {
81 unsigned long new_fp;
83 lr = *(unsigned long *)fp;
84 printk(" [<%08lx>] ", lr);
85 print_symbol("%s\n", lr);
87 new_fp = *(unsigned long *)(fp + 4);
88 if (new_fp <= fp)
89 break;
90 fp = new_fp;
92 printk("\n");
94 #else
95 static inline void __show_trace(struct task_struct *tsk, unsigned long *sp,
96 struct pt_regs *regs)
98 unsigned long addr;
100 while (!kstack_end(sp)) {
101 addr = *sp++;
102 if (kernel_text_address(addr)) {
103 printk(" [<%08lx>] ", addr);
104 print_symbol("%s\n", addr);
108 #endif
110 void show_trace(struct task_struct *tsk, unsigned long *sp,
111 struct pt_regs *regs)
113 if (regs &&
114 (((regs->sr & MODE_MASK) == MODE_EXCEPTION) ||
115 ((regs->sr & MODE_MASK) == MODE_USER)))
116 return;
118 printk ("Call trace:");
119 #ifdef CONFIG_KALLSYMS
120 printk("\n");
121 #endif
123 __show_trace(tsk, sp, regs);
124 printk("\n");
127 void show_stack(struct task_struct *tsk, unsigned long *sp)
129 unsigned long stack;
131 if (!tsk)
132 tsk = current;
133 if (sp == 0) {
134 if (tsk == current) {
135 register unsigned long *real_sp __asm__("sp");
136 sp = real_sp;
137 } else {
138 sp = (unsigned long *)tsk->thread.cpu_context.ksp;
142 stack = (unsigned long)sp;
143 dump_mem("Stack: ", stack,
144 THREAD_SIZE + (unsigned long)tsk->thread_info);
145 show_trace(tsk, sp, NULL);
148 void dump_stack(void)
150 show_stack(NULL, NULL);
152 EXPORT_SYMBOL(dump_stack);
154 ATOMIC_NOTIFIER_HEAD(avr32_die_chain);
156 int register_die_notifier(struct notifier_block *nb)
158 pr_debug("register_die_notifier: %p\n", nb);
160 return atomic_notifier_chain_register(&avr32_die_chain, nb);
162 EXPORT_SYMBOL(register_die_notifier);
164 int unregister_die_notifier(struct notifier_block *nb)
166 return atomic_notifier_chain_unregister(&avr32_die_chain, nb);
168 EXPORT_SYMBOL(unregister_die_notifier);
170 static DEFINE_SPINLOCK(die_lock);
172 void __die(const char *str, struct pt_regs *regs, unsigned long err,
173 const char *file, const char *func, unsigned long line)
175 struct task_struct *tsk = current;
176 static int die_counter;
178 console_verbose();
179 spin_lock_irq(&die_lock);
180 bust_spinlocks(1);
182 printk(KERN_ALERT "%s", str);
183 if (file && func)
184 printk(" in %s:%s, line %ld", file, func, line);
185 printk("[#%d]:\n", ++die_counter);
186 print_modules();
187 show_regs(regs);
188 printk("Process %s (pid: %d, stack limit = 0x%p)\n",
189 tsk->comm, tsk->pid, tsk->thread_info + 1);
191 if (!user_mode(regs) || in_interrupt()) {
192 dump_mem("Stack: ", regs->sp,
193 THREAD_SIZE + (unsigned long)tsk->thread_info);
196 bust_spinlocks(0);
197 spin_unlock_irq(&die_lock);
198 do_exit(SIGSEGV);
201 void __die_if_kernel(const char *str, struct pt_regs *regs, unsigned long err,
202 const char *file, const char *func, unsigned long line)
204 if (!user_mode(regs))
205 __die(str, regs, err, file, func, line);
208 asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs)
210 #ifdef CONFIG_SUBARCH_AVR32B
212 * The exception entry always saves RSR_EX. For NMI, this is
213 * wrong; it should be RSR_NMI
215 regs->sr = sysreg_read(RSR_NMI);
216 #endif
218 printk("NMI taken!!!!\n");
219 die("NMI", regs, ecr);
220 BUG();
223 asmlinkage void do_critical_exception(unsigned long ecr, struct pt_regs *regs)
225 printk("Unable to handle critical exception %lu at pc = %08lx!\n",
226 ecr, regs->pc);
227 die("Oops", regs, ecr);
228 BUG();
231 asmlinkage void do_address_exception(unsigned long ecr, struct pt_regs *regs)
233 siginfo_t info;
235 die_if_kernel("Oops: Address exception in kernel mode", regs, ecr);
237 #ifdef DEBUG
238 if (ecr == ECR_ADDR_ALIGN_X)
239 pr_debug("Instruction Address Exception at pc = %08lx\n",
240 regs->pc);
241 else if (ecr == ECR_ADDR_ALIGN_R)
242 pr_debug("Data Address Exception (Read) at pc = %08lx\n",
243 regs->pc);
244 else if (ecr == ECR_ADDR_ALIGN_W)
245 pr_debug("Data Address Exception (Write) at pc = %08lx\n",
246 regs->pc);
247 else
248 BUG();
250 show_regs(regs);
251 #endif
253 info.si_signo = SIGBUS;
254 info.si_errno = 0;
255 info.si_code = BUS_ADRALN;
256 info.si_addr = (void __user *)regs->pc;
258 force_sig_info(SIGBUS, &info, current);
261 /* This way of handling undefined instructions is stolen from ARM */
262 static LIST_HEAD(undef_hook);
263 static spinlock_t undef_lock = SPIN_LOCK_UNLOCKED;
265 void register_undef_hook(struct undef_hook *hook)
267 spin_lock_irq(&undef_lock);
268 list_add(&hook->node, &undef_hook);
269 spin_unlock_irq(&undef_lock);
272 void unregister_undef_hook(struct undef_hook *hook)
274 spin_lock_irq(&undef_lock);
275 list_del(&hook->node);
276 spin_unlock_irq(&undef_lock);
279 static int do_cop_absent(u32 insn)
281 int cop_nr;
282 u32 cpucr;
283 if ( (insn & 0xfdf00000) == 0xf1900000 )
284 /* LDC0 */
285 cop_nr = 0;
286 else
287 cop_nr = (insn >> 13) & 0x7;
289 /* Try enabling the coprocessor */
290 cpucr = sysreg_read(CPUCR);
291 cpucr |= (1 << (24 + cop_nr));
292 sysreg_write(CPUCR, cpucr);
294 cpucr = sysreg_read(CPUCR);
295 if ( !(cpucr & (1 << (24 + cop_nr))) ){
296 printk("Coprocessor #%i not found!\n", cop_nr);
297 return -1;
300 return 0;
303 #ifdef CONFIG_BUG
304 #ifdef CONFIG_DEBUG_BUGVERBOSE
305 static inline void do_bug_verbose(struct pt_regs *regs, u32 insn)
307 char *file;
308 u16 line;
309 char c;
311 if (__get_user(line, (u16 __user *)(regs->pc + 2)))
312 return;
313 if (__get_user(file, (char * __user *)(regs->pc + 4))
314 || (unsigned long)file < PAGE_OFFSET
315 || __get_user(c, file))
316 file = "<bad filename>";
318 printk(KERN_ALERT "kernel BUG at %s:%d!\n", file, line);
320 #else
321 static inline void do_bug_verbose(struct pt_regs *regs, u32 insn)
325 #endif
326 #endif
328 asmlinkage void do_illegal_opcode(unsigned long ecr, struct pt_regs *regs)
330 u32 insn;
331 struct undef_hook *hook;
332 siginfo_t info;
333 void __user *pc;
335 if (!user_mode(regs))
336 goto kernel_trap;
338 local_irq_enable();
340 pc = (void __user *)instruction_pointer(regs);
341 if (__get_user(insn, (u32 __user *)pc))
342 goto invalid_area;
344 if (ecr == ECR_COPROC_ABSENT) {
345 if (do_cop_absent(insn) == 0)
346 return;
349 spin_lock_irq(&undef_lock);
350 list_for_each_entry(hook, &undef_hook, node) {
351 if ((insn & hook->insn_mask) == hook->insn_val) {
352 if (hook->fn(regs, insn) == 0) {
353 spin_unlock_irq(&undef_lock);
354 return;
358 spin_unlock_irq(&undef_lock);
360 invalid_area:
362 #ifdef DEBUG
363 printk("Illegal instruction at pc = %08lx\n", regs->pc);
364 if (regs->pc < TASK_SIZE) {
365 unsigned long ptbr, pgd, pte, *p;
367 ptbr = sysreg_read(PTBR);
368 p = (unsigned long *)ptbr;
369 pgd = p[regs->pc >> 22];
370 p = (unsigned long *)((pgd & 0x1ffff000) | 0x80000000);
371 pte = p[(regs->pc >> 12) & 0x3ff];
372 printk("page table: 0x%08lx -> 0x%08lx -> 0x%08lx\n", ptbr, pgd, pte);
374 #endif
376 info.si_signo = SIGILL;
377 info.si_errno = 0;
378 info.si_addr = (void __user *)regs->pc;
379 switch (ecr) {
380 case ECR_ILLEGAL_OPCODE:
381 case ECR_UNIMPL_INSTRUCTION:
382 info.si_code = ILL_ILLOPC;
383 break;
384 case ECR_PRIVILEGE_VIOLATION:
385 info.si_code = ILL_PRVOPC;
386 break;
387 case ECR_COPROC_ABSENT:
388 info.si_code = ILL_COPROC;
389 break;
390 default:
391 BUG();
394 force_sig_info(SIGILL, &info, current);
395 return;
397 kernel_trap:
398 #ifdef CONFIG_BUG
399 if (__kernel_text_address(instruction_pointer(regs))) {
400 insn = *(u16 *)instruction_pointer(regs);
401 if (insn == AVR32_BUG_OPCODE) {
402 do_bug_verbose(regs, insn);
403 die("Kernel BUG", regs, 0);
404 return;
407 #endif
409 die("Oops: Illegal instruction in kernel code", regs, ecr);
412 asmlinkage void do_fpe(unsigned long ecr, struct pt_regs *regs)
414 siginfo_t info;
416 printk("Floating-point exception at pc = %08lx\n", regs->pc);
418 /* We have no FPU... */
419 info.si_signo = SIGILL;
420 info.si_errno = 0;
421 info.si_addr = (void __user *)regs->pc;
422 info.si_code = ILL_COPROC;
424 force_sig_info(SIGILL, &info, current);
428 void __init trap_init(void)