import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / arm / kernel / traps.c
index 18b32e8e4497f4c1966f43ac6fbb4963315fb968..a8eada1dba87ae5df0b4e2cf7121cddafeaf718d 100644 (file)
 #include <asm/unwind.h>
 #include <asm/tls.h>
 #include <asm/system_misc.h>
-
-#include "signal.h"
-
-static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
+#include <linux/aee.h>
+static const char *handler[]= {
+       "prefetch abort",
+       "data abort",
+       "address exception",
+       "interrupt",
+       "undefined instruction",
+};
 
 void *vectors_page;
 
@@ -204,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);
@@ -229,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;
 
@@ -238,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);
@@ -246,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);
        }
@@ -294,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())
@@ -393,12 +411,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) {
@@ -426,8 +461,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
@@ -438,13 +478,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)
 {
@@ -800,47 +881,55 @@ void __init trap_init(void)
        return;
 }
 
-static void __init kuser_get_tls_init(unsigned long vectors)
+#ifdef CONFIG_KUSER_HELPERS
+static void __init kuser_init(void *vectors)
 {
+       extern char __kuser_helper_start[], __kuser_helper_end[];
+       int kuser_sz = __kuser_helper_end - __kuser_helper_start;
+
+       memcpy(vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
+
        /*
         * vectors + 0xfe0 = __kuser_get_tls
         * vectors + 0xfe8 = hardware TLS instruction at 0xffff0fe8
         */
        if (tls_emu || has_tls_reg)
-               memcpy((void *)vectors + 0xfe0, (void *)vectors + 0xfe8, 4);
+               memcpy(vectors + 0xfe0, vectors + 0xfe8, 4);
 }
+#else
+static void __init kuser_init(void *vectors)
+{
+}
+#endif
 
 void __init early_trap_init(void *vectors_base)
 {
        unsigned long vectors = (unsigned long)vectors_base;
        extern char __stubs_start[], __stubs_end[];
        extern char __vectors_start[], __vectors_end[];
-       extern char __kuser_helper_start[], __kuser_helper_end[];
-       int kuser_sz = __kuser_helper_end - __kuser_helper_start;
+       unsigned i;
 
        vectors_page = vectors_base;
 
+       /*
+        * Poison the vectors page with an undefined instruction.  This
+        * instruction is chosen to be undefined for both ARM and Thumb
+        * ISAs.  The Thumb version is an undefined instruction with a
+        * branch back to the undefined instruction.
+        */
+       for (i = 0; i < PAGE_SIZE / sizeof(u32); i++)
+               ((u32 *)vectors_base)[i] = 0xe7fddef1;
+
        /*
         * Copy the vectors, stubs and kuser helpers (in entry-armv.S)
         * into the vector page, mapped at 0xffff0000, and ensure these
         * are visible to the instruction stream.
         */
        memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
-       memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
-       memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
+       memcpy((void *)vectors + 0x1000, __stubs_start, __stubs_end - __stubs_start);
 
-       /*
-        * Do processor specific fixups for the kuser helpers
-        */
-       kuser_get_tls_init(vectors);
-
-       /*
-        * Copy signal return handlers into the vector page, and
-        * set sigreturn to be a pointer to these.
-        */
-       memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE),
-              sigreturn_codes, sizeof(sigreturn_codes));
+       kuser_init(vectors_base);
 
-       flush_icache_range(vectors, vectors + PAGE_SIZE);
+       flush_icache_range(vectors, vectors + PAGE_SIZE * 2);
        modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
 }