#include <linux/sched.h>
#include <linux/highmem.h>
#include <linux/perf_event.h>
+#include <linux/aee.h>
#include <asm/exception.h>
#include <asm/pgtable.h>
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;
/*
#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)
{
fsr_info[nr].code = code;
fsr_info[nr].name = name;
}
+EXPORT_SYMBOL(hook_fault_code);
/*
* Dispatch a data abort to the relevant handler.
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);
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);