Merge tag 'v3.10.61' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / arm / kernel / traps.c
index a2a2804b1bc21801c7b4b166ab65506a77e23a31..b7a2a8fd0ad47d9772a775d7290c9cf586991a59 100644 (file)
@@ -34,7 +34,7 @@
 #include <asm/unwind.h>
 #include <asm/tls.h>
 #include <asm/system_misc.h>
-
+#include <linux/aee.h>
 static const char *handler[]= {
        "prefetch abort",
        "data abort",
@@ -208,6 +208,13 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
 }
 #endif
 
+void dump_stack(void)
+{
+       dump_backtrace(NULL, NULL);
+}
+
+EXPORT_SYMBOL(dump_stack);
+
 void show_stack(struct task_struct *tsk, unsigned long *sp)
 {
        dump_backtrace(NULL, tsk);
@@ -233,6 +240,7 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)
 static int __die(const char *str, int err, struct pt_regs *regs)
 {
        struct task_struct *tsk = current;
+       unsigned long sp, stack;
        static int die_counter;
        int ret;
 
@@ -242,7 +250,7 @@ static int __die(const char *str, int err, struct pt_regs *regs)
        /* trap and error numbers are mostly meaningless on ARM */
        ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV);
        if (ret == NOTIFY_STOP)
-               return 1;
+        return ret;
 
        print_modules();
        __show_regs(regs);
@@ -250,8 +258,13 @@ static int __die(const char *str, int err, struct pt_regs *regs)
                TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), end_of_stack(tsk));
 
        if (!user_mode(regs) || in_interrupt()) {
-               dump_mem(KERN_EMERG, "Stack: ", regs->ARM_sp,
-                        THREAD_SIZE + (unsigned long)task_stack_page(tsk));
+               sp = regs->ARM_sp;
+               stack = (unsigned long)task_stack_page(tsk);
+               dump_mem(KERN_EMERG, "Stack: ", sp, ALIGN(sp, THREAD_SIZE));
+               if (sp < stack || (sp - stack) > THREAD_SIZE) {
+                       printk(KERN_EMERG "Invalid sp[%lx] or stack address[%lx]\n", sp, stack);
+                       dump_mem(KERN_EMERG, "Stack(backup) ", stack, THREAD_SIZE + stack);
+               }
                dump_backtrace(regs, tsk);
                dump_instr(KERN_EMERG, regs);
        }
@@ -298,7 +311,8 @@ static void oops_end(unsigned long flags, struct pt_regs *regs, int signr)
        if (!die_nest_count)
                /* Nest count reaches zero, release the lock. */
                arch_spin_unlock(&die_lock);
-       raw_local_irq_restore(flags);
+       /* not enable irq incase softirq many turn off msdc clock */
+       //raw_local_irq_restore(flags);
        oops_exit();
 
        if (in_interrupt())
@@ -399,12 +413,29 @@ static int call_undef_hook(struct pt_regs *regs, unsigned int instr)
        return fn ? fn(regs, instr) : 1;
 }
 
+volatile static void __user *prev_undefinstr_pc=0;
+volatile static int prev_undefinstr_counter=0;
+volatile static unsigned long prev_undefinstr_curr=0;
 asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
 {
+       struct thread_info *thread = current_thread_info();
+       int ret;
        unsigned int instr;
        siginfo_t info;
        void __user *pc;
 
+       if (!user_mode(regs)) {
+               thread->cpu_excp++;
+               if (thread->cpu_excp == 1) {
+                       thread->regs_on_excp = (void *)regs;
+                       aee_excp_regs = (void*)regs;
+               }
+               if (thread->cpu_excp >= 2) {
+                       aee_stop_nested_panic(regs);
+               }
+       }
+
        pc = (void __user *)instruction_pointer(regs);
 
        if (processor_mode(regs) == SVC_MODE) {
@@ -432,8 +463,13 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
                goto die_sig;
        }
 
-       if (call_undef_hook(regs, instr) == 0)
+       ret = call_undef_hook(regs, instr);
+       if (ret == 0) {
+               if (!user_mode(regs)) {
+                       thread->cpu_excp--;
+               }         
                return;
+       }
 
 die_sig:
 #ifdef CONFIG_DEBUG_USER
@@ -444,13 +480,54 @@ die_sig:
        }
 #endif
 
+       /* Place the SIGILL ICache Invalidate after the Debugger Undefined-Instruction Solution. */
+       if ((processor_mode(regs) == USR_MODE) || (processor_mode(regs) == SVC_MODE)) {
+                /* Only do it for User-Space Application. */
+               printk("USR_MODE/SVC_MODE Undefined Instruction Address curr:%p pc=%p:%p\n",
+                       (void *)current, (void *)pc, (void *)prev_undefinstr_pc);
+               if ((prev_undefinstr_pc != pc) || (prev_undefinstr_curr != (unsigned long)current)) {
+                       /* If the current process or program counter is changed......renew the counter. */
+                       printk("First Time Recovery curr:%p pc=%p:%p\n",
+                               (void *)current, (void *)pc, (void *)prev_undefinstr_pc);
+                       prev_undefinstr_pc = pc;
+                       prev_undefinstr_curr = (unsigned long)current;
+                       prev_undefinstr_counter = 0;
+                       __cpuc_flush_icache_all();
+                       flush_cache_all();
+                       if (!user_mode(regs)) {
+                               thread->cpu_excp--;
+                       }
+                       return;
+               }
+               else if(prev_undefinstr_counter < 1) {
+                       printk("2nd Time Recovery curr:%p pc=%p:%p\n",
+                               (void *)current, (void *)pc, (void *)prev_undefinstr_pc);
+                       prev_undefinstr_counter++;
+                       __cpuc_flush_icache_all();
+                       flush_cache_all();
+                       if (!user_mode(regs)) {
+                               thread->cpu_excp--;
+                       }
+                       return;
+               }
+               prev_undefinstr_counter++;
+               if(prev_undefinstr_counter >= 4) {
+                       /* 2=first time SigILL,3=2nd time NE-SigILL,4=3rd time CoreDump-SigILL */
+                       prev_undefinstr_pc = 0;
+                       prev_undefinstr_curr = 0;
+                       prev_undefinstr_counter = 0;
+               }
+               printk("Go to ARM Notify Die curr:%p pc=%p:%p\n",
+                       (void *)current, (void *)pc, (void *)prev_undefinstr_pc);
+       }
+
        info.si_signo = SIGILL;
        info.si_errno = 0;
        info.si_code  = ILL_ILLOPC;
        info.si_addr  = pc;
 
        arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
-}
+       }
 
 asmlinkage void do_unexp_fiq (struct pt_regs *regs)
 {
@@ -587,7 +664,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
                return regs->ARM_r0;
 
        case NR(set_tls):
-               thread->tp_value = regs->ARM_r0;
+               thread->tp_value[0] = regs->ARM_r0;
                if (tls_emu)
                        return 0;
                if (has_tls_reg) {
@@ -705,7 +782,7 @@ static int get_tp_trap(struct pt_regs *regs, unsigned int instr)
        int reg = (instr >> 12) & 15;
        if (reg == 15)
                return 1;
-       regs->uregs[reg] = current_thread_info()->tp_value;
+       regs->uregs[reg] = current_thread_info()->tp_value[0];
        regs->ARM_pc += 4;
        return 0;
 }