diff options
Diffstat (limited to 'arch/avr32/mm/fault.c')
-rw-r--r-- | arch/avr32/mm/fault.c | 268 |
1 files changed, 0 insertions, 268 deletions
diff --git a/arch/avr32/mm/fault.c b/arch/avr32/mm/fault.c deleted file mode 100644 index b3977e9..0000000 --- a/arch/avr32/mm/fault.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - * 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/extable.h> -#include <linux/pagemap.h> -#include <linux/kdebug.h> -#include <linux/kprobes.h> -#include <linux/uaccess.h> - -#include <asm/mmu_context.h> -#include <asm/sysreg.h> -#include <asm/tlb.h> - -#ifdef CONFIG_KPROBES -static inline int notify_page_fault(struct pt_regs *regs, int trap) -{ - int ret = 0; - - if (!user_mode(regs)) { - if (kprobe_running() && kprobe_fault_handler(regs, trap)) - ret = 1; - } - - return ret; -} -#else -static inline int notify_page_fault(struct pt_regs *regs, int trap) -{ - return 0; -} -#endif - -int exception_trace = 1; - -/* - * 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: - * 6: Protection fault (instruction access) - * 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) - */ -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; - long signr; - int code; - int fault; - unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; - - if (notify_page_fault(regs, ecr)) - return; - - address = sysreg_read(TLBEAR); - - tsk = current; - mm = tsk->mm; - - signr = SIGSEGV; - code = SEGV_MAPERR; - - /* - * If we're in an interrupt or have no user context, we must - * not take the fault... - */ - if (faulthandler_disabled() || !mm || regs->sr & SYSREG_BIT(GM)) - goto no_context; - - local_irq_enable(); - - if (user_mode(regs)) - flags |= FAULT_FLAG_USER; -retry: - 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: - code = SEGV_ACCERR; - - 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; - flags |= FAULT_FLAG_WRITE; - 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. - */ - fault = handle_mm_fault(vma, address, flags); - - if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) - return; - - if (unlikely(fault & VM_FAULT_ERROR)) { - if (fault & VM_FAULT_OOM) - goto out_of_memory; - else if (fault & VM_FAULT_SIGSEGV) - goto bad_area; - else if (fault & VM_FAULT_SIGBUS) - goto do_sigbus; - BUG(); - } - - if (flags & FAULT_FLAG_ALLOW_RETRY) { - if (fault & VM_FAULT_MAJOR) - tsk->maj_flt++; - else - tsk->min_flt++; - if (fault & VM_FAULT_RETRY) { - flags &= ~FAULT_FLAG_ALLOW_RETRY; - flags |= FAULT_FLAG_TRIED; - - /* - * No need to up_read(&mm->mmap_sem) as we would have - * already released it in __lock_page_or_retry() in - * mm/filemap.c. - */ - goto retry; - } - } - - 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: - up_read(&mm->mmap_sem); - - if (user_mode(regs)) { - if (exception_trace && printk_ratelimit()) - printk("%s%s[%d]: segfault at %08lx pc %08lx " - "sp %08lx ecr %lu\n", - is_global_init(tsk) ? KERN_EMERG : KERN_INFO, - tsk->comm, tsk->pid, address, regs->pc, - regs->sp, ecr); - _exception(SIGSEGV, regs, code, address); - return; - } - -no_context: - /* Are we prepared to handle this kernel fault? */ - fixup = search_exception_tables(regs->pc); - if (fixup) { - regs->pc = fixup->fixup; - 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\n", address); - - page = sysreg_read(PTBR); - printk(KERN_ALERT "ptbr = %08lx", page); - if (address >= TASK_SIZE) - page = (unsigned long)swapper_pg_dir; - 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]; - printk(" pte = %08lx", page); - } - } - printk("\n"); - die("Kernel access of bad area", regs, signr); - return; - - /* - * 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: - up_read(&mm->mmap_sem); - if (!user_mode(regs)) - goto no_context; - pagefault_out_of_memory(); - return; - -do_sigbus: - up_read(&mm->mmap_sem); - - /* Kernel mode? Handle exceptions or die */ - signr = SIGBUS; - code = BUS_ADRERR; - if (!user_mode(regs)) - goto no_context; - - if (exception_trace) - printk("%s%s[%d]: bus error at %08lx pc %08lx " - "sp %08lx ecr %lu\n", - is_global_init(tsk) ? KERN_EMERG : KERN_INFO, - tsk->comm, tsk->pid, address, regs->pc, - regs->sp, ecr); - - _exception(SIGBUS, regs, BUS_ADRERR, address); -} - -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)\n", - addr, write_access ? "write" : "read"); - printk(KERN_INFO "DTLB dump:\n"); - dump_dtlb(); - die("Bus Error", regs, SIGKILL); -} |