X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=arch%2Farm%2Fmm%2Ffault.c;h=ea34eb9d694b0755ca038fb92e11939e37ba3d4a;hb=a4cb4b1277a499ebced7f7534d5cfb11a30eb224;hp=aa33949fef608cb4c5b7b9a76e0f4020ba0f1db6;hpb=06d381484fe8fb1ba2996c22e89595a273e3634c;p=pandora-kernel.git diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index aa33949fef60..ea34eb9d694b 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -27,19 +27,6 @@ #include "fault.h" -/* - * Fault status register encodings. We steal bit 31 for our own purposes. - */ -#define FSR_LNX_PF (1 << 31) -#define FSR_WRITE (1 << 11) -#define FSR_FS4 (1 << 10) -#define FSR_FS3_0 (15) - -static inline int fsr_fs(unsigned int fsr) -{ - return (fsr & FSR_FS3_0) | (fsr & FSR_FS4) >> 6; -} - #ifdef CONFIG_MMU #ifdef CONFIG_KPROBES @@ -123,8 +110,10 @@ void show_pte(struct mm_struct *mm, unsigned long addr) pte = pte_offset_map(pmd, addr); printk(", *pte=%08llx", (long long)pte_val(*pte)); +#ifndef CONFIG_ARM_LPAE printk(", *ppte=%08llx", (long long)pte_val(pte[PTE_HWTABLE_PTRS])); +#endif pte_unmap(pte); } while(0); @@ -163,6 +152,39 @@ __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, do_exit(SIGKILL); } +#ifdef CONFIG_DEBUG_USER +static void +print_user_faulter_location(const char *name, struct pt_regs *regs) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + char *p, *t, buf[128]; + + printk(KERN_DEBUG "%s: pc=%08lx", + name, regs->ARM_pc); + + do { + if (!mm) + break; + vma = find_vma(mm, regs->ARM_pc); + if (!vma || !vma->vm_file) + break; + + p = d_path(&vma->vm_file->f_path, buf, sizeof(buf)); + if (IS_ERR(p)) + break; + + t = strrchr(p, '/'); + if (t) + p = t + 1; + + printk(KERN_CONT " (%s+%lx)", p, regs->ARM_pc - vma->vm_start); + } while (0); + + printk(KERN_CONT ", lr=%08lx\n", regs->ARM_lr); +} +#endif + /* * Something tried to access memory that isn't in our memory map.. * User mode accesses just cause a SIGSEGV @@ -175,9 +197,13 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr, struct siginfo si; #ifdef CONFIG_DEBUG_USER + if (user_debug & (UDBG_SEGV | UDBG_SEGV_SHORT)) { + printk(KERN_DEBUG "%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x (%s)\n", + tsk->comm, sig, addr, fsr, + (fsr & FSR_WRITE) ? "write" : "read"); + print_user_faulter_location(tsk->comm, regs); + } if (user_debug & UDBG_SEGV) { - printk(KERN_DEBUG "%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n", - tsk->comm, sig, addr, fsr); show_pte(tsk->mm, addr); show_regs(regs); } @@ -267,7 +293,9 @@ good_area: return fault; check_stack: - if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr)) + /* Don't allow expansion below FIRST_USER_ADDRESS */ + if (vma->vm_flags & VM_GROWSDOWN && + addr >= FIRST_USER_ADDRESS && !expand_stack(vma, addr)) goto good_area; out: return fault; @@ -441,6 +469,12 @@ do_translation_fault(unsigned long addr, unsigned int fsr, pmd = pmd_offset(pud, addr); pmd_k = pmd_offset(pud_k, addr); +#ifdef CONFIG_ARM_LPAE + /* + * Only one hardware entry per PMD with LPAE. + */ + index = 0; +#else /* * On ARM one Linux PGD entry contains two hardware entries (see page * tables layout in pgtable.h). We normally guarantee that we always @@ -450,6 +484,7 @@ do_translation_fault(unsigned long addr, unsigned int fsr, * for the first of pair. */ index = (addr >> SECTION_SHIFT) & 1; +#endif if (pmd_none(pmd_k[index])) goto bad_area; @@ -469,17 +504,6 @@ do_translation_fault(unsigned long addr, unsigned int fsr, } #endif /* CONFIG_MMU */ -/* - * Some section permission faults need to be handled gracefully. - * They can happen due to a __{get,put}_user during an oops. - */ -static int -do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) -{ - do_bad_area(addr, fsr, regs); - return 0; -} - /* * This abort handler always returns "fault". */ @@ -489,55 +513,20 @@ do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs) return 1; } -static struct fsr_info { +struct fsr_info { int (*fn)(unsigned long addr, unsigned int fsr, struct pt_regs *regs); int sig; int code; const char *name; -} fsr_info[] = { - /* - * The following are the standard ARMv3 and ARMv4 aborts. ARMv5 - * defines these to be "precise" aborts. - */ - { do_bad, SIGSEGV, 0, "vector exception" }, - { do_bad, SIGBUS, BUS_ADRALN, "alignment exception" }, - { do_bad, SIGKILL, 0, "terminal exception" }, - { do_bad, SIGBUS, BUS_ADRALN, "alignment exception" }, - { do_bad, SIGBUS, 0, "external abort on linefetch" }, - { do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault" }, - { do_bad, SIGBUS, 0, "external abort on linefetch" }, - { do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" }, - { do_bad, SIGBUS, 0, "external abort on non-linefetch" }, - { do_bad, SIGSEGV, SEGV_ACCERR, "section domain fault" }, - { do_bad, SIGBUS, 0, "external abort on non-linefetch" }, - { do_bad, SIGSEGV, SEGV_ACCERR, "page domain fault" }, - { do_bad, SIGBUS, 0, "external abort on translation" }, - { do_sect_fault, SIGSEGV, SEGV_ACCERR, "section permission fault" }, - { do_bad, SIGBUS, 0, "external abort on translation" }, - { do_page_fault, SIGSEGV, SEGV_ACCERR, "page permission fault" }, - /* - * The following are "imprecise" aborts, which are signalled by bit - * 10 of the FSR, and may not be recoverable. These are only - * supported if the CPU abort handler supports bit 10. - */ - { do_bad, SIGBUS, 0, "unknown 16" }, - { do_bad, SIGBUS, 0, "unknown 17" }, - { do_bad, SIGBUS, 0, "unknown 18" }, - { do_bad, SIGBUS, 0, "unknown 19" }, - { do_bad, SIGBUS, 0, "lock abort" }, /* xscale */ - { do_bad, SIGBUS, 0, "unknown 21" }, - { do_bad, SIGBUS, BUS_OBJERR, "imprecise external abort" }, /* xscale */ - { do_bad, SIGBUS, 0, "unknown 23" }, - { do_bad, SIGBUS, 0, "dcache parity error" }, /* xscale */ - { do_bad, SIGBUS, 0, "unknown 25" }, - { do_bad, SIGBUS, 0, "unknown 26" }, - { do_bad, SIGBUS, 0, "unknown 27" }, - { do_bad, SIGBUS, 0, "unknown 28" }, - { do_bad, SIGBUS, 0, "unknown 29" }, - { do_bad, SIGBUS, 0, "unknown 30" }, - { do_bad, SIGBUS, 0, "unknown 31" } }; +/* FSR definition */ +#ifdef CONFIG_ARM_LPAE +#include "fsr-3level.c" +#else +#include "fsr-2level.c" +#endif + void __init hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *), int sig, int code, const char *name) @@ -573,42 +562,6 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) arm_notify_die("", regs, &info, fsr, 0); } - -static struct fsr_info ifsr_info[] = { - { do_bad, SIGBUS, 0, "unknown 0" }, - { do_bad, SIGBUS, 0, "unknown 1" }, - { do_bad, SIGBUS, 0, "debug event" }, - { do_bad, SIGSEGV, SEGV_ACCERR, "section access flag fault" }, - { do_bad, SIGBUS, 0, "unknown 4" }, - { do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault" }, - { do_bad, SIGSEGV, SEGV_ACCERR, "page access flag fault" }, - { do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" }, - { do_bad, SIGBUS, 0, "external abort on non-linefetch" }, - { do_bad, SIGSEGV, SEGV_ACCERR, "section domain fault" }, - { do_bad, SIGBUS, 0, "unknown 10" }, - { do_bad, SIGSEGV, SEGV_ACCERR, "page domain fault" }, - { do_bad, SIGBUS, 0, "external abort on translation" }, - { do_sect_fault, SIGSEGV, SEGV_ACCERR, "section permission fault" }, - { do_bad, SIGBUS, 0, "external abort on translation" }, - { do_page_fault, SIGSEGV, SEGV_ACCERR, "page permission fault" }, - { do_bad, SIGBUS, 0, "unknown 16" }, - { do_bad, SIGBUS, 0, "unknown 17" }, - { do_bad, SIGBUS, 0, "unknown 18" }, - { do_bad, SIGBUS, 0, "unknown 19" }, - { do_bad, SIGBUS, 0, "unknown 20" }, - { do_bad, SIGBUS, 0, "unknown 21" }, - { do_bad, SIGBUS, 0, "unknown 22" }, - { do_bad, SIGBUS, 0, "unknown 23" }, - { do_bad, SIGBUS, 0, "unknown 24" }, - { do_bad, SIGBUS, 0, "unknown 25" }, - { do_bad, SIGBUS, 0, "unknown 26" }, - { do_bad, SIGBUS, 0, "unknown 27" }, - { do_bad, SIGBUS, 0, "unknown 28" }, - { do_bad, SIGBUS, 0, "unknown 29" }, - { do_bad, SIGBUS, 0, "unknown 30" }, - { do_bad, SIGBUS, 0, "unknown 31" }, -}; - void __init hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *), int sig, int code, const char *name) @@ -641,6 +594,7 @@ do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs) arm_notify_die("", regs, &info, ifsr, 0); } +#ifndef CONFIG_ARM_LPAE static int __init exceptions_init(void) { if (cpu_architecture() >= CPU_ARCH_ARMv6) { @@ -663,3 +617,4 @@ static int __init exceptions_init(void) } arch_initcall(exceptions_init); +#endif