Blame view
arch/avr32/mm/fault.c
5.7 KB
5f97f7f94 [PATCH] avr32 arc... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* * Copyright (C) 2004-2006 Atmel Corporation * * Based on linux/arch/sh/mm/fault.c: * Copyright (C) 1999 Niibe Yutaka * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include <linux/mm.h> #include <linux/module.h> #include <linux/pagemap.h> |
1eeb66a1b move die notifier... |
15 |
#include <linux/kdebug.h> |
9caebec7b [AVR32] optimize ... |
16 |
#include <linux/kprobes.h> |
5f97f7f94 [PATCH] avr32 arc... |
17 18 |
#include <asm/mmu_context.h> #include <asm/sysreg.h> |
5f97f7f94 [PATCH] avr32 arc... |
19 |
#include <asm/tlb.h> |
623b0355d [AVR32] Clean up ... |
20 |
#include <asm/uaccess.h> |
5f97f7f94 [PATCH] avr32 arc... |
21 22 |
#ifdef CONFIG_KPROBES |
9caebec7b [AVR32] optimize ... |
23 |
static inline int notify_page_fault(struct pt_regs *regs, int trap) |
5f97f7f94 [PATCH] avr32 arc... |
24 |
{ |
9caebec7b [AVR32] optimize ... |
25 |
int ret = 0; |
5f97f7f94 [PATCH] avr32 arc... |
26 |
|
9caebec7b [AVR32] optimize ... |
27 28 29 30 |
if (!user_mode(regs)) { if (kprobe_running() && kprobe_fault_handler(regs, trap)) ret = 1; } |
5f97f7f94 [PATCH] avr32 arc... |
31 |
|
9caebec7b [AVR32] optimize ... |
32 |
return ret; |
5f97f7f94 [PATCH] avr32 arc... |
33 34 |
} #else |
9caebec7b [AVR32] optimize ... |
35 |
static inline int notify_page_fault(struct pt_regs *regs, int trap) |
5f97f7f94 [PATCH] avr32 arc... |
36 |
{ |
9caebec7b [AVR32] optimize ... |
37 |
return 0; |
5f97f7f94 [PATCH] avr32 arc... |
38 39 |
} #endif |
623b0355d [AVR32] Clean up ... |
40 |
int exception_trace = 1; |
5f97f7f94 [PATCH] avr32 arc... |
41 42 43 44 45 |
/* * This routine handles page faults. It determines the address and the * problem, and then passes it off to one of the appropriate routines. * * ecr is the Exception Cause Register. Possible values are: |
5f97f7f94 [PATCH] avr32 arc... |
46 |
* 6: Protection fault (instruction access) |
623b0355d [AVR32] Clean up ... |
47 48 49 50 51 |
* 15: Protection fault (read access) * 16: Protection fault (write access) * 20: Page not found (instruction access) * 24: Page not found (read access) * 28: Page not found (write access) |
5f97f7f94 [PATCH] avr32 arc... |
52 53 54 55 56 57 58 59 60 |
*/ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs) { struct task_struct *tsk; struct mm_struct *mm; struct vm_area_struct *vma; const struct exception_table_entry *fixup; unsigned long address; unsigned long page; |
623b0355d [AVR32] Clean up ... |
61 62 63 |
int writeaccess; long signr; int code; |
83c54070e mm: fault feedbac... |
64 |
int fault; |
5f97f7f94 [PATCH] avr32 arc... |
65 |
|
9caebec7b [AVR32] optimize ... |
66 |
if (notify_page_fault(regs, ecr)) |
5f97f7f94 [PATCH] avr32 arc... |
67 68 69 70 71 72 |
return; address = sysreg_read(TLBEAR); tsk = current; mm = tsk->mm; |
623b0355d [AVR32] Clean up ... |
73 74 |
signr = SIGSEGV; code = SEGV_MAPERR; |
5f97f7f94 [PATCH] avr32 arc... |
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
/* * If we're in an interrupt or have no user context, we must * not take the fault... */ if (in_atomic() || !mm || regs->sr & SYSREG_BIT(GM)) goto no_context; local_irq_enable(); down_read(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) goto bad_area; if (vma->vm_start <= address) goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; if (expand_stack(vma, address)) goto bad_area; /* * Ok, we have a good vm_area for this memory access, so we * can handle it... */ good_area: |
623b0355d [AVR32] Clean up ... |
101 102 |
code = SEGV_ACCERR; writeaccess = 0; |
5f97f7f94 [PATCH] avr32 arc... |
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
switch (ecr) { case ECR_PROTECTION_X: case ECR_TLB_MISS_X: if (!(vma->vm_flags & VM_EXEC)) goto bad_area; break; case ECR_PROTECTION_R: case ECR_TLB_MISS_R: if (!(vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC))) goto bad_area; break; case ECR_PROTECTION_W: case ECR_TLB_MISS_W: if (!(vma->vm_flags & VM_WRITE)) goto bad_area; writeaccess = 1; break; default: panic("Unhandled case %lu in do_page_fault!", ecr); } /* * If for any reason at all we couldn't handle the fault, make * sure we exit gracefully rather than endlessly redo the * fault. */ |
d06063cc2 Move FAULT_FLAG_x... |
129 |
fault = handle_mm_fault(mm, vma, address, writeaccess ? FAULT_FLAG_WRITE : 0); |
83c54070e mm: fault feedbac... |
130 131 132 133 134 |
if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; |
5f97f7f94 [PATCH] avr32 arc... |
135 136 |
BUG(); } |
83c54070e mm: fault feedbac... |
137 138 139 140 |
if (fault & VM_FAULT_MAJOR) tsk->maj_flt++; else tsk->min_flt++; |
5f97f7f94 [PATCH] avr32 arc... |
141 142 143 144 145 146 147 148 149 |
up_read(&mm->mmap_sem); return; /* * Something tried to access memory that isn't in our memory * map. Fix it, but check if it's kernel or user first... */ bad_area: |
5f97f7f94 [PATCH] avr32 arc... |
150 151 152 |
up_read(&mm->mmap_sem); if (user_mode(regs)) { |
126187f1e [AVR32] ratelimit... |
153 |
if (exception_trace && printk_ratelimit()) |
623b0355d [AVR32] Clean up ... |
154 155 156 |
printk("%s%s[%d]: segfault at %08lx pc %08lx " "sp %08lx ecr %lu ", |
b460cbc58 pid namespaces: d... |
157 |
is_global_init(tsk) ? KERN_EMERG : KERN_INFO, |
623b0355d [AVR32] Clean up ... |
158 159 160 |
tsk->comm, tsk->pid, address, regs->pc, regs->sp, ecr); _exception(SIGSEGV, regs, code, address); |
5f97f7f94 [PATCH] avr32 arc... |
161 162 163 164 |
return; } no_context: |
5f97f7f94 [PATCH] avr32 arc... |
165 166 167 168 |
/* Are we prepared to handle this kernel fault? */ fixup = search_exception_tables(regs->pc); if (fixup) { regs->pc = fixup->fixup; |
5f97f7f94 [PATCH] avr32 arc... |
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
return; } /* * Oops. The kernel tried to access some bad page. We'll have * to terminate things with extreme prejudice. */ if (address < PAGE_SIZE) printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); else printk(KERN_ALERT "Unable to handle kernel paging request"); printk(" at virtual address %08lx ", address); |
5f97f7f94 [PATCH] avr32 arc... |
184 185 186 |
page = sysreg_read(PTBR); printk(KERN_ALERT "ptbr = %08lx", page); |
32019828d avr32: Fix broken... |
187 188 |
if (address >= TASK_SIZE) page = (unsigned long)swapper_pg_dir; |
5f97f7f94 [PATCH] avr32 arc... |
189 190 191 192 193 194 195 |
if (page) { page = ((unsigned long *)page)[address >> 22]; printk(" pgd = %08lx", page); if (page & _PAGE_PRESENT) { page &= PAGE_MASK; address &= 0x003ff000; page = ((unsigned long *)__va(page))[address >> PAGE_SHIFT]; |
623b0355d [AVR32] Clean up ... |
196 |
printk(" pte = %08lx", page); |
5f97f7f94 [PATCH] avr32 arc... |
197 198 |
} } |
623b0355d [AVR32] Clean up ... |
199 200 201 202 |
printk(" "); die("Kernel access of bad area", regs, signr); return; |
5f97f7f94 [PATCH] avr32 arc... |
203 204 205 206 207 208 |
/* * We ran out of memory, or some other thing happened to us * that made us unable to handle the page fault gracefully. */ out_of_memory: |
5f97f7f94 [PATCH] avr32 arc... |
209 |
up_read(&mm->mmap_sem); |
67a8a20fe avr32: invoke oom... |
210 211 212 213 |
pagefault_out_of_memory(); if (!user_mode(regs)) goto no_context; return; |
5f97f7f94 [PATCH] avr32 arc... |
214 215 216 |
do_sigbus: up_read(&mm->mmap_sem); |
5f97f7f94 [PATCH] avr32 arc... |
217 |
/* Kernel mode? Handle exceptions or die */ |
623b0355d [AVR32] Clean up ... |
218 219 |
signr = SIGBUS; code = BUS_ADRERR; |
5f97f7f94 [PATCH] avr32 arc... |
220 221 |
if (!user_mode(regs)) goto no_context; |
623b0355d [AVR32] Clean up ... |
222 223 224 225 226 |
if (exception_trace) printk("%s%s[%d]: bus error at %08lx pc %08lx " "sp %08lx ecr %lu ", |
b460cbc58 pid namespaces: d... |
227 |
is_global_init(tsk) ? KERN_EMERG : KERN_INFO, |
623b0355d [AVR32] Clean up ... |
228 229 230 231 |
tsk->comm, tsk->pid, address, regs->pc, regs->sp, ecr); _exception(SIGBUS, regs, BUS_ADRERR, address); |
5f97f7f94 [PATCH] avr32 arc... |
232 233 234 235 236 237 238 239 240 241 242 243 |
} asmlinkage void do_bus_error(unsigned long addr, int write_access, struct pt_regs *regs) { printk(KERN_ALERT "Bus error at physical address 0x%08lx (%s access) ", addr, write_access ? "write" : "read"); printk(KERN_INFO "DTLB dump: "); dump_dtlb(); |
623b0355d [AVR32] Clean up ... |
244 |
die("Bus Error", regs, SIGKILL); |
5f97f7f94 [PATCH] avr32 arc... |
245 |
} |