Merge ../linux-2.6-watchdog-mm
[linux-drm-fsl-dcu.git] / arch / powerpc / kernel / traps.c
index 9b352bd0a46011714482b1b9daaa2216f5e421e9..c66b4771ef445e264194bbc8ac039ce9297b31e2 100644 (file)
@@ -598,6 +598,9 @@ static void parse_fpe(struct pt_regs *regs)
 #define INST_STSWI             0x7c0005aa
 #define INST_STSWX             0x7c00052a
 
+#define INST_POPCNTB           0x7c0000f4
+#define INST_POPCNTB_MASK      0xfc0007fe
+
 static int emulate_string_inst(struct pt_regs *regs, u32 instword)
 {
        u8 rT = (instword >> 21) & 0x1f;
@@ -666,6 +669,23 @@ static int emulate_string_inst(struct pt_regs *regs, u32 instword)
        return 0;
 }
 
+static int emulate_popcntb_inst(struct pt_regs *regs, u32 instword)
+{
+       u32 ra,rs;
+       unsigned long tmp;
+
+       ra = (instword >> 16) & 0x1f;
+       rs = (instword >> 21) & 0x1f;
+
+       tmp = regs->gpr[rs];
+       tmp = tmp - ((tmp >> 1) & 0x5555555555555555ULL);
+       tmp = (tmp & 0x3333333333333333ULL) + ((tmp >> 2) & 0x3333333333333333ULL);
+       tmp = (tmp + (tmp >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
+       regs->gpr[ra] = tmp;
+
+       return 0;
+}
+
 static int emulate_instruction(struct pt_regs *regs)
 {
        u32 instword;
@@ -703,6 +723,11 @@ static int emulate_instruction(struct pt_regs *regs)
        if ((instword & INST_STRING_GEN_MASK) == INST_STRING)
                return emulate_string_inst(regs, instword);
 
+       /* Emulate the popcntb (Population Count Bytes) instruction. */
+       if ((instword & INST_POPCNTB_MASK) == INST_POPCNTB) {
+               return emulate_popcntb_inst(regs, instword);
+       }
+
        return -EINVAL;
 }
 
@@ -818,7 +843,7 @@ void __kprobes program_check_exception(struct pt_regs *regs)
 
 void alignment_exception(struct pt_regs *regs)
 {
-       int fixed = 0;
+       int sig, code, fixed = 0;
 
        /* we don't implement logging of alignment exceptions */
        if (!(current->thread.align_ctl & PR_UNALIGN_SIGBUS))
@@ -832,14 +857,16 @@ void alignment_exception(struct pt_regs *regs)
 
        /* Operand address was bad */
        if (fixed == -EFAULT) {
-               if (user_mode(regs))
-                       _exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar);
-               else
-                       /* Search exception table */
-                       bad_page_fault(regs, regs->dar, SIGSEGV);
-               return;
+               sig = SIGSEGV;
+               code = SEGV_ACCERR;
+       } else {
+               sig = SIGBUS;
+               code = BUS_ADRALN;
        }
-       _exception(SIGBUS, regs, BUS_ADRALN, regs->dar);
+       if (user_mode(regs))
+               _exception(sig, regs, code, regs->dar);
+       else
+               bad_page_fault(regs, regs->dar, sig);
 }
 
 void StackOverflow(struct pt_regs *regs)
@@ -875,14 +902,13 @@ void kernel_fp_unavailable_exception(struct pt_regs *regs)
 
 void altivec_unavailable_exception(struct pt_regs *regs)
 {
-#if !defined(CONFIG_ALTIVEC)
        if (user_mode(regs)) {
                /* A user program has executed an altivec instruction,
                   but this kernel doesn't support altivec. */
                _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
                return;
        }
-#endif
+
        printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception "
                        "%lx at %lx\n", regs->trap, regs->nip);
        die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT);