X-Git-Url: https://git.stricted.de/?p=GitHub%2Fmt8127%2Fandroid_kernel_alcatel_ttab.git;a=blobdiff_plain;f=arch%2Farm%2Fmm%2Ffault.c;h=ce5f1130a13cae607d166c630003e4f4f1e67dd0;hp=5dbf13f954f6f493aaae525d4f3b93282ac88f75;hb=6fa3eb70c07b7ce2061fd6602159ac2d45a7dc3d;hpb=cbd8aca472134e666eee87462177f1be854ebbf8 diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 5dbf13f954f6..ce5f1130a13c 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -276,10 +277,10 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) local_irq_enable(); /* - * If we're in an interrupt or have no user + * If we're in an interrupt, or have no irqs, or have no user * context, we must not take the fault.. */ - if (in_atomic() || !mm) + if (in_atomic() || irqs_disabled() || !mm) goto no_context; /* @@ -521,7 +522,7 @@ struct fsr_info { #include "fsr-2level.c" #endif -void __init +void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *), int sig, int code, const char *name) { @@ -533,6 +534,7 @@ hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *) fsr_info[nr].code = code; fsr_info[nr].name = name; } +EXPORT_SYMBOL(hook_fault_code); /* * Dispatch a data abort to the relevant handler. @@ -540,11 +542,37 @@ hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *) asmlinkage void __exception do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) { + struct thread_info *thread = current_thread_info(); + int ret; const struct fsr_info *inf = fsr_info + fsr_fs(fsr); struct siginfo info; - if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs)) + if (!user_mode(regs)) { + thread->cpu_excp++; + if (thread->cpu_excp == 1) { + thread->regs_on_excp = (void *)regs; + aee_excp_regs = (void*)regs; + } + /* + * NoteXXX: The data abort exception may happen twice + * when calling probe_kernel_address() in which. + * __copy_from_user_inatomic() is used and the + * fixup table lookup may be performed. + * Check if the nested panic happens via + * (cpu_excp >= 3). + */ + if (thread->cpu_excp >= 3) { + aee_stop_nested_panic(regs); + } + } + + ret = inf->fn(addr, fsr & ~FSR_LNX_PF, regs); + if (!ret) { + if (!user_mode(regs)) { + thread->cpu_excp--; + } return; + } printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n", inf->name, fsr, addr); @@ -572,11 +600,36 @@ hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs * asmlinkage void __exception do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs) { + struct thread_info *thread = current_thread_info(); + int ret; const struct fsr_info *inf = ifsr_info + fsr_fs(ifsr); struct siginfo info; - if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs)) + if (!user_mode(regs)) { + thread->cpu_excp++; + if (thread->cpu_excp == 1) { + thread->regs_on_excp = (void *)regs; + } + /* + * NoteXXX: The data abort exception may happen twice + * when calling probe_kernel_address() in which. + * __copy_from_user_inatomic() is used and the + * fixup table lookup may be performed. + * Check if the nested panic happens via + * (cpu_excp >= 3). + */ + if (thread->cpu_excp >= 3) { + aee_stop_nested_panic(regs); + } + } + + ret = inf->fn(addr, ifsr | FSR_LNX_PF, regs); + if (!ret) { + if (!user_mode(regs)) { + thread->cpu_excp--; + } return; + } printk(KERN_ALERT "Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n", inf->name, ifsr, addr);