- Andries Brouwer: final isofs pieces.
[davej-history.git] / arch / arm / kernel / traps.c
blob9d0cc5c698a0d82a6b13ba1d3b49ce0dab781720
1 /*
2 * linux/arch/arm/kernel/traps.c
4 * Copyright (C) 1995, 1996 Russell King
5 * Fragments that appear the same as linux/arch/i386/kernel/traps.c (C) Linus Torvalds
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * 'traps.c' handles hardware exceptions after we have saved some state in
12 * 'linux/arch/arm/lib/traps.S'. Mostly a debugging aid, but will probably
13 * kill the offending process.
15 #include <linux/config.h>
16 #include <linux/types.h>
17 #include <linux/kernel.h>
18 #include <linux/signal.h>
19 #include <linux/sched.h>
20 #include <linux/mm.h>
21 #include <linux/spinlock.h>
22 #include <linux/ptrace.h>
23 #include <linux/init.h>
25 #include <asm/atomic.h>
26 #include <asm/io.h>
27 #include <asm/pgtable.h>
28 #include <asm/system.h>
29 #include <asm/uaccess.h>
31 #include "ptrace.h"
33 extern void c_backtrace (unsigned long fp, int pmode);
34 extern void show_pte(struct mm_struct *mm, unsigned long addr);
36 const char *processor_modes[]=
37 { "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
38 "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26",
39 "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , "UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" ,
40 "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32"
43 static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
46 * Stack pointers should always be within the kernels view of
47 * physical memory. If it is not there, then we can't dump
48 * out any information relating to the stack.
50 static int verify_stack(unsigned long sp)
52 if (sp < PAGE_OFFSET || sp > (unsigned long)high_memory)
53 return -EFAULT;
55 return 0;
59 * Dump out the contents of some memory nicely...
61 void dump_mem(unsigned long bottom, unsigned long top)
63 unsigned long p = bottom & ~31;
64 int i;
66 for (p = bottom & ~31; p < top;) {
67 printk("%08lx: ", p);
69 for (i = 0; i < 8; i++, p += 4) {
70 unsigned int val;
72 if (p < bottom || p >= top)
73 printk(" ");
74 else {
75 __get_user(val, (unsigned long *)p);
76 printk("%08x ", val);
78 if (i == 3)
79 printk(" ");
81 printk ("\n");
86 * These constants are for searching for possible module text
87 * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
88 * a guess of how much space is likely to be vmalloced.
90 #define VMALLOC_OFFSET (8*1024*1024)
91 #define MODULE_RANGE (8*1024*1024)
93 static void dump_instr(struct pt_regs *regs)
95 unsigned long addr = instruction_pointer(regs);
96 const int thumb = thumb_mode(regs);
97 const int width = thumb ? 4 : 8;
98 int i;
100 printk("Code: ");
101 for (i = -2; i < 3; i++) {
102 unsigned int val, bad;
104 if (thumb)
105 bad = __get_user(val, &((u16 *)addr)[i]);
106 else
107 bad = __get_user(val, &((u32 *)addr)[i]);
109 if (!bad)
110 printk(i == 0 ? "(%0*x) " : "%0*x", width, val);
111 else {
112 printk("bad PC value.");
113 break;
116 printk("\n");
119 static void dump_stack(struct task_struct *tsk, unsigned long sp)
121 printk("Stack:\n");
122 dump_mem(sp - 16, 8192+(unsigned long)tsk);
125 static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
127 unsigned int fp;
128 int ok = 1;
130 printk("Backtrace: ");
131 fp = regs->ARM_fp;
132 if (!fp) {
133 printk("no frame pointer");
134 ok = 0;
135 } else if (verify_stack(fp)) {
136 printk("invalid frame pointer %08lx", fp);
137 ok = 0;
138 } else if (fp < 4096+(unsigned long)tsk)
139 printk("frame pointer underflow");
140 printk("\n");
142 if (ok)
143 c_backtrace(fp, processor_mode(regs));
146 spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
149 * This function is protected against re-entrancy.
151 void die(const char *str, struct pt_regs *regs, int err)
153 struct task_struct *tsk = current;
155 console_verbose();
156 spin_lock_irq(&die_lock);
158 printk("Internal error: %s: %x\n", str, err);
159 printk("CPU: %d\n", smp_processor_id());
160 show_regs(regs);
161 printk("Process %s (pid: %d, stackpage=%08lx)\n",
162 current->comm, current->pid, 4096+(unsigned long)tsk);
164 if (!user_mode(regs)) {
165 mm_segment_t fs;
168 * We need to switch to kernel mode so that we can
169 * use __get_user to safely read from kernel space.
170 * Note that we now dump the code first, just in case
171 * the backtrace kills us.
173 fs = get_fs();
174 set_fs(KERNEL_DS);
176 dump_instr(regs);
177 dump_stack(tsk, (unsigned long)(regs + 1));
178 dump_backtrace(regs, tsk);
180 set_fs(fs);
183 spin_unlock_irq(&die_lock);
184 do_exit(SIGSEGV);
187 void die_if_kernel(const char *str, struct pt_regs *regs, int err)
189 if (user_mode(regs))
190 return;
192 die(str, regs, err);
195 asmlinkage void do_undefinstr(int address, struct pt_regs *regs, int mode)
197 unsigned long addr = instruction_pointer(regs);
198 siginfo_t info;
200 #ifdef CONFIG_DEBUG_USER
201 printk(KERN_INFO "%s (%d): undefined instruction: pc=%08lx\n",
202 current->comm, current->pid, addr);
203 dump_instr(regs);
204 #endif
206 current->thread.error_code = 0;
207 current->thread.trap_no = 6;
209 info.si_signo = SIGILL;
210 info.si_errno = 0;
211 info.si_code = ILL_ILLOPC;
212 info.si_addr = (void *)addr;
214 force_sig_info(SIGILL, &info, current);
216 die_if_kernel("Oops - undefined instruction", regs, mode);
219 asmlinkage void do_excpt(int address, struct pt_regs *regs, int mode)
221 siginfo_t info;
223 #ifdef CONFIG_DEBUG_USER
224 printk(KERN_INFO "%s (%d): address exception: pc=%08lx\n",
225 current->comm, current->pid, instruction_pointer(regs));
226 dump_instr(regs);
227 #endif
229 current->thread.error_code = 0;
230 current->thread.trap_no = 11;
232 info.si_signo = SIGBUS;
233 info.si_errno = 0;
234 info.si_code = BUS_ADRERR;
235 info.si_addr = (void *)address;
237 force_sig_info(SIGBUS, &info, current);
239 die_if_kernel("Oops - address exception", regs, mode);
242 asmlinkage void do_unexp_fiq (struct pt_regs *regs)
244 #ifndef CONFIG_IGNORE_FIQ
245 printk("Hmm. Unexpected FIQ received, but trying to continue\n");
246 printk("You may have a hardware problem...\n");
247 #endif
251 * bad_mode handles the impossible case in the vectors. If you see one of
252 * these, then it's extremely serious, and could mean you have buggy hardware.
253 * It never returns, and never tries to sync. We hope that we can at least
254 * dump out some state information...
256 asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode)
258 console_verbose();
260 printk(KERN_CRIT "Bad mode in %s handler detected: mode %s\n",
261 handler[reason], processor_modes[proc_mode]);
264 * Dump out the vectors and stub routines. Maybe a better solution
265 * would be to dump them out only if we detect that they are corrupted.
267 printk(KERN_CRIT "Vectors:\n");
268 dump_mem(0, 0x40);
269 printk(KERN_CRIT "Stubs:\n");
270 dump_mem(0x200, 0x4b8);
272 die("Oops", regs, 0);
273 cli();
274 panic("bad mode");
278 * Handle some more esoteric system calls
280 asmlinkage int arm_syscall(int no, struct pt_regs *regs)
282 siginfo_t info;
284 switch (no) {
285 case 0: /* branch through 0 */
286 info.si_signo = SIGSEGV;
287 info.si_errno = 0;
288 info.si_code = SEGV_MAPERR;
289 info.si_addr = NULL;
291 force_sig_info(SIGSEGV, &info, current);
293 die_if_kernel("branch through zero", regs, 0);
294 break;
296 case 1: /* SWI BREAK_POINT */
298 * The PC is always left pointing at the next
299 * instruction. Fix this.
301 regs->ARM_pc -= 4;
302 __ptrace_cancel_bpt(current);
304 info.si_signo = SIGTRAP;
305 info.si_errno = 0;
306 info.si_code = TRAP_BRKPT;
307 info.si_addr = (void *)instruction_pointer(regs);
309 force_sig_info(SIGTRAP, &info, current);
310 return regs->ARM_r0;
312 case 2: /* sys_cacheflush */
313 #ifdef CONFIG_CPU_32
314 /* r0 = start, r1 = end, r2 = flags */
315 cpu_cache_clean_invalidate_range(regs->ARM_r0, regs->ARM_r1, 1);
316 #endif
317 break;
319 default:
320 /* Calls 9f00xx..9f07ff are defined to return -ENOSYS
321 if not implemented, rather than raising SIGILL. This
322 way the calling program can gracefully determine whether
323 a feature is supported. */
324 if (no <= 0x7ff)
325 return -ENOSYS;
326 #ifdef CONFIG_DEBUG_USER
327 /* experience shows that these seem to indicate that
328 * something catastrophic has happened
330 printk("[%d] %s: arm syscall %d\n", current->pid, current->comm, no);
331 dump_instr(regs);
332 if (user_mode(regs)) {
333 show_regs(regs);
334 c_backtrace(regs->ARM_fp, processor_mode(regs));
336 #endif
337 force_sig(SIGILL, current);
338 die_if_kernel("Oops", regs, no);
339 break;
341 return 0;
344 asmlinkage void deferred(int n, struct pt_regs *regs)
346 /* You might think just testing `handler' would be enough, but PER_LINUX
347 * points it to no_lcall7 to catch undercover SVr4 binaries. Gutted.
349 if (current->personality != PER_LINUX && current->exec_domain->handler) {
350 /* Hand it off to iBCS. The extra parameter and consequent type
351 * forcing is necessary because of the weird ARM calling convention.
353 void (*handler)(int nr, struct pt_regs *regs) = (void *)current->exec_domain->handler;
354 (*handler)(n, regs);
355 return;
358 #ifdef CONFIG_DEBUG_USER
359 printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n",
360 current->pid, current->comm, n);
361 dump_instr(regs);
362 #endif
363 force_sig(SIGILL, current);
364 die_if_kernel("Oops", regs, n);
367 void __bad_xchg(volatile void *ptr, int size)
369 printk("xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n",
370 __builtin_return_address(0), ptr, size);
371 BUG();
375 * A data abort trap was taken, but we did not handle the instruction.
376 * Try to abort the user program, or panic if it was the kernel.
378 asmlinkage void
379 baddataabort(int code, unsigned long instr, struct pt_regs *regs)
381 unsigned long addr = instruction_pointer(regs);
382 siginfo_t info;
384 #ifdef CONFIG_DEBUG_USER
385 printk(KERN_ERR "[%d] %s: bad data abort: code %d instr 0x%08lx\n",
386 current->pid, current->comm, code, instr);
387 dump_instr(regs);
388 show_pte(current->mm, addr);
389 #endif
391 info.si_signo = SIGILL;
392 info.si_errno = 0;
393 info.si_code = ILL_ILLOPC;
394 info.si_addr = (void *)addr;
396 force_sig_info(SIGILL, &info, current);
397 die_if_kernel("unknown data abort code", regs, instr);
400 void __bug(const char *file, int line, void *data)
402 printk(KERN_CRIT"kernel BUG at %s:%d!", file, line);
403 if (data)
404 printk(KERN_CRIT" - extra data = %p", data);
405 printk("\n");
406 *(int *)0 = 0;
409 void __readwrite_bug(const char *fn)
411 printk("%s called, but not implemented", fn);
412 BUG();
415 void __pte_error(const char *file, int line, unsigned long val)
417 printk("%s:%d: bad pte %08lx.\n", file, line, val);
420 void __pmd_error(const char *file, int line, unsigned long val)
422 printk("%s:%d: bad pmd %08lx.\n", file, line, val);
425 void __pgd_error(const char *file, int line, unsigned long val)
427 printk("%s:%d: bad pgd %08lx.\n", file, line, val);
430 asmlinkage void __div0(void)
432 printk("Division by zero in kernel.\n");
433 __backtrace();
436 void abort(void)
438 void *lr = __builtin_return_address(0);
440 printk(KERN_CRIT "abort() called from %p! (Please "
441 "report to rmk@arm.linux.org.uk)\n", lr);
443 BUG();
445 /* if that doesn't kill us, halt */
446 panic("Oops failed to kill thread");
449 void __init trap_init(void)
451 extern void __trap_init(void);
453 __trap_init();
454 #ifdef CONFIG_CPU_32
455 modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
456 #endif