aboutsummaryrefslogtreecommitdiffstats
path: root/arch/avr32/mm
diff options
context:
space:
mode:
authorHaavard Skinnemoen <hskinnemoen@atmel.com>2007-03-13 12:59:11 -0400
committerHaavard Skinnemoen <hskinnemoen@atmel.com>2007-04-27 07:44:13 -0400
commit623b0355d5b1f9c6d05005b649a2f3a7b9fd7816 (patch)
tree43ef35d4f6e83a49c1fb72df4b538271b650c054 /arch/avr32/mm
parent3b328c98093702c584692bffabd440800b383d73 (diff)
[AVR32] Clean up exception handling code
* Use generic BUG() handling * Remove some useless debug statements * Use a common function _exception() to send signals or oops when an exception can't be handled. This makes sure init doesn't enter an infinite exception loop as well. Borrowed from powerpc. * Add some basic exception tracing support to the page fault code. * Rework dump_stack(), show_regs() and friends and move everything into process.c * Print information about configuration options and chip type when oopsing Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Diffstat (limited to 'arch/avr32/mm')
-rw-r--r--arch/avr32/mm/fault.c116
1 files changed, 41 insertions, 75 deletions
diff --git a/arch/avr32/mm/fault.c b/arch/avr32/mm/fault.c
index 678557260a35..146ebdbdc302 100644
--- a/arch/avr32/mm/fault.c
+++ b/arch/avr32/mm/fault.c
@@ -16,26 +16,8 @@
16#include <asm/kdebug.h> 16#include <asm/kdebug.h>
17#include <asm/mmu_context.h> 17#include <asm/mmu_context.h>
18#include <asm/sysreg.h> 18#include <asm/sysreg.h>
19#include <asm/uaccess.h>
20#include <asm/tlb.h> 19#include <asm/tlb.h>
21 20#include <asm/uaccess.h>
22#ifdef DEBUG
23static void dump_code(unsigned long pc)
24{
25 char *p = (char *)pc;
26 char val;
27 int i;
28
29
30 printk(KERN_DEBUG "Code:");
31 for (i = 0; i < 16; i++) {
32 if (__get_user(val, p + i))
33 break;
34 printk(" %02x", val);
35 }
36 printk("\n");
37}
38#endif
39 21
40#ifdef CONFIG_KPROBES 22#ifdef CONFIG_KPROBES
41ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); 23ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
@@ -68,17 +50,19 @@ static inline int notify_page_fault(enum die_val val, struct pt_regs *regs,
68} 50}
69#endif 51#endif
70 52
53int exception_trace = 1;
54
71/* 55/*
72 * This routine handles page faults. It determines the address and the 56 * This routine handles page faults. It determines the address and the
73 * problem, and then passes it off to one of the appropriate routines. 57 * problem, and then passes it off to one of the appropriate routines.
74 * 58 *
75 * ecr is the Exception Cause Register. Possible values are: 59 * ecr is the Exception Cause Register. Possible values are:
76 * 5: Page not found (instruction access)
77 * 6: Protection fault (instruction access) 60 * 6: Protection fault (instruction access)
78 * 12: Page not found (read access) 61 * 15: Protection fault (read access)
79 * 13: Page not found (write access) 62 * 16: Protection fault (write access)
80 * 14: Protection fault (read access) 63 * 20: Page not found (instruction access)
81 * 15: Protection fault (write access) 64 * 24: Page not found (read access)
65 * 28: Page not found (write access)
82 */ 66 */
83asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs) 67asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
84{ 68{
@@ -88,7 +72,9 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
88 const struct exception_table_entry *fixup; 72 const struct exception_table_entry *fixup;
89 unsigned long address; 73 unsigned long address;
90 unsigned long page; 74 unsigned long page;
91 int writeaccess = 0; 75 int writeaccess;
76 long signr;
77 int code;
92 78
93 if (notify_page_fault(DIE_PAGE_FAULT, regs, 79 if (notify_page_fault(DIE_PAGE_FAULT, regs,
94 ecr, SIGSEGV) == NOTIFY_STOP) 80 ecr, SIGSEGV) == NOTIFY_STOP)
@@ -99,6 +85,9 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
99 tsk = current; 85 tsk = current;
100 mm = tsk->mm; 86 mm = tsk->mm;
101 87
88 signr = SIGSEGV;
89 code = SEGV_MAPERR;
90
102 /* 91 /*
103 * If we're in an interrupt or have no user context, we must 92 * If we're in an interrupt or have no user context, we must
104 * not take the fault... 93 * not take the fault...
@@ -125,7 +114,9 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
125 * can handle it... 114 * can handle it...
126 */ 115 */
127good_area: 116good_area:
128 //pr_debug("good area: vm_flags = 0x%lx\n", vma->vm_flags); 117 code = SEGV_ACCERR;
118 writeaccess = 0;
119
129 switch (ecr) { 120 switch (ecr) {
130 case ECR_PROTECTION_X: 121 case ECR_PROTECTION_X:
131 case ECR_TLB_MISS_X: 122 case ECR_TLB_MISS_X:
@@ -176,46 +167,24 @@ survive:
176 * map. Fix it, but check if it's kernel or user first... 167 * map. Fix it, but check if it's kernel or user first...
177 */ 168 */
178bad_area: 169bad_area:
179 pr_debug("Bad area [%s:%u]: addr %08lx, ecr %lu\n",
180 tsk->comm, tsk->pid, address, ecr);
181
182 up_read(&mm->mmap_sem); 170 up_read(&mm->mmap_sem);
183 171
184 if (user_mode(regs)) { 172 if (user_mode(regs)) {
185 /* Hmm...we have to pass address and ecr somehow... */ 173 if (exception_trace)
186 /* tsk->thread.address = address; 174 printk("%s%s[%d]: segfault at %08lx pc %08lx "
187 tsk->thread.error_code = ecr; */ 175 "sp %08lx ecr %lu\n",
188#ifdef DEBUG 176 is_init(tsk) ? KERN_EMERG : KERN_INFO,
189 show_regs(regs); 177 tsk->comm, tsk->pid, address, regs->pc,
190 dump_code(regs->pc); 178 regs->sp, ecr);
191 179 _exception(SIGSEGV, regs, code, address);
192 page = sysreg_read(PTBR);
193 printk("ptbr = %08lx", page);
194 if (page) {
195 page = ((unsigned long *)page)[address >> 22];
196 printk(" pgd = %08lx", page);
197 if (page & _PAGE_PRESENT) {
198 page &= PAGE_MASK;
199 address &= 0x003ff000;
200 page = ((unsigned long *)__va(page))[address >> PAGE_SHIFT];
201 printk(" pte = %08lx\n", page);
202 }
203 }
204#endif
205 pr_debug("Sending SIGSEGV to PID %d...\n",
206 tsk->pid);
207 force_sig(SIGSEGV, tsk);
208 return; 180 return;
209 } 181 }
210 182
211no_context: 183no_context:
212 pr_debug("No context\n");
213
214 /* Are we prepared to handle this kernel fault? */ 184 /* Are we prepared to handle this kernel fault? */
215 fixup = search_exception_tables(regs->pc); 185 fixup = search_exception_tables(regs->pc);
216 if (fixup) { 186 if (fixup) {
217 regs->pc = fixup->fixup; 187 regs->pc = fixup->fixup;
218 pr_debug("Found fixup at %08lx\n", fixup->fixup);
219 return; 188 return;
220 } 189 }
221 190
@@ -230,7 +199,6 @@ no_context:
230 printk(KERN_ALERT 199 printk(KERN_ALERT
231 "Unable to handle kernel paging request"); 200 "Unable to handle kernel paging request");
232 printk(" at virtual address %08lx\n", address); 201 printk(" at virtual address %08lx\n", address);
233 printk(KERN_ALERT "pc = %08lx\n", regs->pc);
234 202
235 page = sysreg_read(PTBR); 203 page = sysreg_read(PTBR);
236 printk(KERN_ALERT "ptbr = %08lx", page); 204 printk(KERN_ALERT "ptbr = %08lx", page);
@@ -241,20 +209,20 @@ no_context:
241 page &= PAGE_MASK; 209 page &= PAGE_MASK;
242 address &= 0x003ff000; 210 address &= 0x003ff000;
243 page = ((unsigned long *)__va(page))[address >> PAGE_SHIFT]; 211 page = ((unsigned long *)__va(page))[address >> PAGE_SHIFT];
244 printk(" pte = %08lx\n", page); 212 printk(" pte = %08lx", page);
245 } 213 }
246 } 214 }
247 die("\nOops", regs, ecr); 215 printk("\n");
248 do_exit(SIGKILL); 216 die("Kernel access of bad area", regs, signr);
217 return;
249 218
250 /* 219 /*
251 * We ran out of memory, or some other thing happened to us 220 * We ran out of memory, or some other thing happened to us
252 * that made us unable to handle the page fault gracefully. 221 * that made us unable to handle the page fault gracefully.
253 */ 222 */
254out_of_memory: 223out_of_memory:
255 printk("Out of memory\n");
256 up_read(&mm->mmap_sem); 224 up_read(&mm->mmap_sem);
257 if (current->pid == 1) { 225 if (is_init(current)) {
258 yield(); 226 yield();
259 down_read(&mm->mmap_sem); 227 down_read(&mm->mmap_sem);
260 goto survive; 228 goto survive;
@@ -267,21 +235,20 @@ out_of_memory:
267do_sigbus: 235do_sigbus:
268 up_read(&mm->mmap_sem); 236 up_read(&mm->mmap_sem);
269 237
270 /*
271 * Send a sigbus, regardless of whether we were in kernel or
272 * user mode.
273 */
274 /* address, error_code, trap_no, ... */
275#ifdef DEBUG
276 show_regs(regs);
277 dump_code(regs->pc);
278#endif
279 pr_debug("Sending SIGBUS to PID %d...\n", tsk->pid);
280 force_sig(SIGBUS, tsk);
281
282 /* Kernel mode? Handle exceptions or die */ 238 /* Kernel mode? Handle exceptions or die */
239 signr = SIGBUS;
240 code = BUS_ADRERR;
283 if (!user_mode(regs)) 241 if (!user_mode(regs))
284 goto no_context; 242 goto no_context;
243
244 if (exception_trace)
245 printk("%s%s[%d]: bus error at %08lx pc %08lx "
246 "sp %08lx ecr %lu\n",
247 is_init(tsk) ? KERN_EMERG : KERN_INFO,
248 tsk->comm, tsk->pid, address, regs->pc,
249 regs->sp, ecr);
250
251 _exception(SIGBUS, regs, BUS_ADRERR, address);
285} 252}
286 253
287asmlinkage void do_bus_error(unsigned long addr, int write_access, 254asmlinkage void do_bus_error(unsigned long addr, int write_access,
@@ -292,8 +259,7 @@ asmlinkage void do_bus_error(unsigned long addr, int write_access,
292 addr, write_access ? "write" : "read"); 259 addr, write_access ? "write" : "read");
293 printk(KERN_INFO "DTLB dump:\n"); 260 printk(KERN_INFO "DTLB dump:\n");
294 dump_dtlb(); 261 dump_dtlb();
295 die("Bus Error", regs, write_access); 262 die("Bus Error", regs, SIGKILL);
296 do_exit(SIGKILL);
297} 263}
298 264
299/* 265/*