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