#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;
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;
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;
}
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))
/* 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)
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);