Import 2.3.18pre1
[davej-history.git] / arch / arm / kernel / traps.c
blob9f9e6934f8e718a073eb7393315ede914ecc8db3
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
6 */
8 /*
9 * 'traps.c' handles hardware exceptions after we have saved some state in
10 * 'linux/arch/arm/lib/traps.S'. Mostly a debugging aid, but will probably
11 * kill the offending process.
13 #include <linux/config.h>
14 #include <linux/types.h>
15 #include <linux/kernel.h>
16 #include <linux/signal.h>
17 #include <linux/sched.h>
18 #include <linux/mm.h>
19 #include <linux/spinlock.h>
21 #include <asm/system.h>
22 #include <asm/uaccess.h>
23 #include <asm/io.h>
24 #include <asm/atomic.h>
25 #include <asm/pgtable.h>
27 extern void c_backtrace (unsigned long fp, int pmode);
28 extern int ptrace_cancel_bpt (struct task_struct *);
30 char *processor_modes[]=
31 { "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
32 "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26",
33 "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , "UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" ,
34 "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32"
37 static char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
39 static inline void console_verbose(void)
41 extern int console_loglevel;
42 console_loglevel = 15;
45 int kstack_depth_to_print = 200;
48 * Stack pointers should always be within the kernels view of
49 * physical memory. If it is not there, then we can't dump
50 * out any information relating to the stack.
52 static int verify_stack(unsigned long sp)
54 if (sp < PAGE_OFFSET || sp > (unsigned long)high_memory)
55 return -EFAULT;
57 return 0;
61 * Dump out the contents of some memory nicely...
63 void dump_mem(unsigned long bottom, unsigned long top)
65 unsigned long p = bottom & ~31;
66 int i;
68 for (p = bottom & ~31; p < top;) {
69 printk("%08lx: ", p);
71 for (i = 0; i < 8; i++, p += 4) {
72 if (p < bottom || p >= top)
73 printk(" ");
74 else
75 printk("%08lx ", *(unsigned long *)p);
76 if (i == 3)
77 printk(" ");
79 printk ("\n");
84 * These constants are for searching for possible module text
85 * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
86 * a guess of how much space is likely to be vmalloced.
88 #define VMALLOC_OFFSET (8*1024*1024)
89 #define MODULE_RANGE (8*1024*1024)
91 static void dump_instr(unsigned long pc, int user)
93 int pmin = -2, pmax = 3, ok = 0;
94 extern char start_kernel, _etext;
96 if (!user) {
97 unsigned long module_start, module_end;
98 unsigned long kernel_start, kernel_end;
100 module_start = VMALLOC_START;
101 module_end = module_start + MODULE_RANGE;
103 kernel_start = (unsigned long)&start_kernel;
104 kernel_end = (unsigned long)&_etext;
106 if (pc >= kernel_start && pc < kernel_end) {
107 if (pc + pmin < kernel_start)
108 pmin = kernel_start - pc;
109 if (pc + pmax > kernel_end)
110 pmax = kernel_end - pc;
111 ok = 1;
112 } else if (pc >= module_start && pc < module_end) {
113 if (pc + pmin < module_start)
114 pmin = module_start - pc;
115 if (pc + pmax > module_end)
116 pmax = module_end - pc;
117 ok = 1;
119 } else
120 ok = verify_area(VERIFY_READ, (void *)(pc + pmin), pmax - pmin) == 0;
122 printk ("Code: ");
123 if (ok) {
124 int i;
125 for (i = pmin; i < pmax; i++)
126 printk(i == 0 ? "(%08lx) " : "%08lx ", ((unsigned long *)pc)[i]);
127 printk ("\n");
128 } else
129 printk ("pc not in code space\n");
132 spinlock_t die_lock;
135 * This function is protected against re-entrancy.
137 void die(const char *str, struct pt_regs *regs, int err)
139 struct task_struct *tsk = current;
141 spin_lock_irq(&die_lock);
143 console_verbose();
144 printk("Internal error: %s: %x\n", str, err);
145 printk("CPU: %d\n", smp_processor_id());
146 show_regs(regs);
147 printk("Process %s (pid: %d, stackpage=%08lx)\n",
148 current->comm, current->pid, 4096+(unsigned long)tsk);
150 if (!user_mode(regs)) {
151 unsigned long sp = (unsigned long)(regs + 1);
152 unsigned long fp;
153 int dump_info = 1;
155 printk("Stack: ");
156 if (verify_stack(sp)) {
157 printk("invalid kernel stack pointer %08lx", sp);
158 dump_info = 0;
159 } else if (sp < 4096+(unsigned long)tsk)
160 printk("kernel stack pointer underflow");
161 printk("\n");
163 if (dump_info)
164 dump_mem(sp - 16, 8192+(unsigned long)tsk);
166 dump_info = 1;
168 printk("Backtrace: ");
169 fp = regs->ARM_fp;
170 if (!fp) {
171 printk("no frame pointer");
172 dump_info = 0;
173 } else if (verify_stack(fp)) {
174 printk("invalid frame pointer %08lx", fp);
175 dump_info = 0;
176 } else if (fp < 4096+(unsigned long)tsk)
177 printk("frame pointer underflow");
178 printk("\n");
180 if (dump_info)
181 c_backtrace(fp, processor_mode(regs));
183 dump_instr(instruction_pointer(regs), 0);
186 spin_unlock_irq(&die_lock);
189 static void die_if_kernel(const char *str, struct pt_regs *regs, int err)
191 if (user_mode(regs))
192 return;
194 die(str, regs, err);
197 void bad_user_access_alignment(const void *ptr)
199 printk(KERN_ERR "bad user access alignment: ptr = %p, pc = %p\n", ptr,
200 __builtin_return_address(0));
201 current->thread.error_code = 0;
202 current->thread.trap_no = 11;
203 force_sig(SIGBUS, current);
204 /* die_if_kernel("Oops - bad user access alignment", regs, mode);*/
207 asmlinkage void do_undefinstr(int address, struct pt_regs *regs, int mode)
209 #ifdef CONFIG_DEBUG_USER
210 printk(KERN_INFO "%s (%d): undefined instruction: pc=%08lx\n",
211 current->comm, current->pid, instruction_pointer(regs));
212 #endif
213 current->thread.error_code = 0;
214 current->thread.trap_no = 6;
215 force_sig(SIGILL, current);
216 die_if_kernel("Oops - undefined instruction", regs, mode);
219 asmlinkage void do_excpt(int address, struct pt_regs *regs, int mode)
221 #ifdef CONFIG_DEBUG_USER
222 printk(KERN_INFO "%s (%d): address exception: pc=%08lx\n",
223 current->comm, current->pid, instruction_pointer(regs));
224 #endif
225 current->thread.error_code = 0;
226 current->thread.trap_no = 11;
227 force_sig(SIGBUS, current);
228 die_if_kernel("Oops - address exception", regs, mode);
231 asmlinkage void do_unexp_fiq (struct pt_regs *regs)
233 #ifndef CONFIG_IGNORE_FIQ
234 printk("Hmm. Unexpected FIQ received, but trying to continue\n");
235 printk("You may have a hardware problem...\n");
236 #endif
240 * bad_mode handles the impossible case in the vectors.
241 * If you see one of these, then it's extremely serious,
242 * and could mean you have buggy hardware. It never
243 * returns, and never tries to sync. We hope that we
244 * can dump out some state information...
246 asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode)
248 console_verbose();
250 printk(KERN_CRIT "Bad mode in %s handler detected: mode %s\n",
251 handler[reason], processor_modes[proc_mode]);
254 * Dump out the vectors and stub routines
256 printk(KERN_CRIT "Vectors:\n");
257 dump_mem(0, 0x40);
258 printk(KERN_CRIT "Stubs:\n");
259 dump_mem(0x200, 0x4b8);
261 die("Oops", regs, 0);
262 cli();
263 while(1);
267 * 'math_state_restore()' saves the current math information in the
268 * old math state array, and gets the new ones from the current task.
270 * We no longer save/restore the math state on every context switch
271 * any more. We only do this now if it actually gets used.
273 asmlinkage void math_state_restore (void)
275 current->used_math = 1;
278 asmlinkage int arm_syscall (int no, struct pt_regs *regs)
280 switch (no) {
281 case 0: /* branch through 0 */
282 force_sig(SIGSEGV, current);
283 die_if_kernel("branch through zero", regs, 0);
284 break;
286 case 1: /* SWI_BREAK_POINT */
287 regs->ARM_pc -= 4; /* Decrement PC by one instruction */
288 ptrace_cancel_bpt(current);
289 force_sig(SIGTRAP, current);
290 return regs->ARM_r0;
292 case 2: /* sys_cacheflush */
293 #ifdef CONFIG_CPU_32
294 /* r0 = start, r1 = length, r2 = flags */
295 cpu_flush_cache_area(regs->ARM_r0, regs->ARM_r1, 1);
296 #endif
297 break;
299 default:
300 /* Calls 9f00xx..9f07ff are defined to return -ENOSYS
301 if not implemented, rather than raising SIGILL. This
302 way the calling program can gracefully determine whether
303 a feature is supported. */
304 if (no <= 0x7ff)
305 return -ENOSYS;
306 #ifdef CONFIG_DEBUG_USER
307 /* experiance shows that these seem to indicate that
308 * something catastrophic has happened
310 printk("[%d] %s: arm syscall %d\n", current->pid, current->comm, no);
311 if (user_mode(regs)) {
312 show_regs(regs);
313 c_backtrace(regs->ARM_fp, processor_mode(regs));
315 #endif
316 force_sig(SIGILL, current);
317 die_if_kernel("Oops", regs, no);
318 break;
320 return 0;
323 asmlinkage void deferred(int n, struct pt_regs *regs)
325 /* You might think just testing `handler' would be enough, but PER_LINUX
326 * points it to no_lcall7 to catch undercover SVr4 binaries. Gutted.
328 if (current->personality != PER_LINUX && current->exec_domain->handler) {
329 /* Hand it off to iBCS. The extra parameter and consequent type
330 * forcing is necessary because of the weird ARM calling convention.
332 void (*handler)(int nr, struct pt_regs *regs) = (void *)current->exec_domain->handler;
333 (*handler)(n, regs);
334 return;
337 #ifdef CONFIG_DEBUG_USER
338 printk(KERN_ERR "[%d] %s: old system call.\n", current->pid,
339 current->comm);
340 #endif
341 force_sig(SIGILL, current);
344 asmlinkage void arm_malalignedptr(const char *str, void *pc, volatile void *ptr)
346 printk("Mal-aligned pointer in %s: %p (PC=%p)\n", str, ptr, pc);
349 asmlinkage void arm_invalidptr(const char *function, int size)
351 printk("Invalid pointer size in %s (pc=%p) size %d\n",
352 function, __builtin_return_address(0), size);
355 #ifdef CONFIG_CPU_26
356 asmlinkage void baddataabort(int code, unsigned long instr, struct pt_regs *regs)
358 unsigned long phys, addr = instruction_pointer(regs);
360 #ifdef CONFIG_DEBUG_ERRORS
361 printk("pid=%d\n", current->pid);
363 show_regs(regs);
364 dump_instr(instruction_pointer(regs), 1);
366 pgd_t *pgd;
368 printk ("current->thread.memmap = %08lX\n", current->thread.memmap);
369 pgd = pgd_offset(current->mm, addr);
370 printk ("*pgd = %08lx", pgd_val (*pgd));
371 if (!pgd_none (*pgd)) {
372 pmd_t *pmd;
373 pmd = pmd_offset (pgd, addr);
374 printk (", *pmd = %08lx", pmd_val (*pmd));
375 if (!pmd_none (*pmd)) {
376 unsigned long ptr = pte_page(*pte_offset(pmd, addr));
377 printk (", *pte = %08lx", pte_val (*pte_offset (pmd, addr)));
378 phys = ptr + (addr & 0x7fff);
381 printk ("\n");
383 #endif
384 panic("unknown data abort code %d [pc=%08lx *pc=%08lx lr=%08lx sp=%08lx]",
385 code, regs->ARM_pc, instr, regs->ARM_lr, regs->ARM_sp);
387 #endif
389 asmlinkage void __div0(void)
391 printk("Awooga, division by zero in kernel.\n");
392 __backtrace();