#else
#define get_mc_reason(regs) (mfspr(SPRN_MCSR))
#endif
-#define REASON_FP 0
+#define REASON_FP ESR_FP
#define REASON_ILLEGAL ESR_PIL
#define REASON_PRIVILEGED ESR_PPR
#define REASON_TRAP ESR_PTR
#define INST_MCRXR 0x7c000400
#define INST_MCRXR_MASK 0x7c0007fe
+#define INST_STRING 0x7c00042a
+#define INST_STRING_MASK 0x7c0007fe
+#define INST_STRING_GEN_MASK 0x7c00067e
+#define INST_LSWI 0x7c0004aa
+#define INST_LSWX 0x7c00042a
+#define INST_STSWI 0x7c0005aa
+#define INST_STSWX 0x7c00052a
+
+static int emulate_string_inst(struct pt_regs *regs, u32 instword)
+{
+ u8 rT = (instword >> 21) & 0x1f;
+ u8 rA = (instword >> 16) & 0x1f;
+ u8 NB_RB = (instword >> 11) & 0x1f;
+ u32 num_bytes;
+ unsigned long EA;
+ int pos = 0;
+
+ /* Early out if we are an invalid form of lswx */
+ if ((instword & INST_STRING_MASK) == INST_LSWX)
+ if ((rT == rA) || (rT == NB_RB))
+ return -EINVAL;
+
+ EA = (rA == 0) ? 0 : regs->gpr[rA];
+
+ switch (instword & INST_STRING_MASK) {
+ case INST_LSWX:
+ case INST_STSWX:
+ EA += NB_RB;
+ num_bytes = regs->xer & 0x7f;
+ break;
+ case INST_LSWI:
+ case INST_STSWI:
+ num_bytes = (NB_RB == 0) ? 32 : NB_RB;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ while (num_bytes != 0)
+ {
+ u8 val;
+ u32 shift = 8 * (3 - (pos & 0x3));
+
+ switch ((instword & INST_STRING_MASK)) {
+ case INST_LSWX:
+ case INST_LSWI:
+ if (get_user(val, (u8 __user *)EA))
+ return -EFAULT;
+ /* first time updating this reg,
+ * zero it out */
+ if (pos == 0)
+ regs->gpr[rT] = 0;
+ regs->gpr[rT] |= val << shift;
+ break;
+ case INST_STSWI:
+ case INST_STSWX:
+ val = regs->gpr[rT] >> shift;
+ if (put_user(val, (u8 __user *)EA))
+ return -EFAULT;
+ break;
+ }
+ /* move EA to next address */
+ EA += 1;
+ num_bytes--;
+
+ /* manage our position within the register */
+ if (++pos == 4) {
+ pos = 0;
+ if (++rT == 32)
+ rT = 0;
+ }
+ }
+
+ return 0;
+}
+
static int emulate_instruction(struct pt_regs *regs)
{
u32 instword;
*/
if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) {
rd = (instword >> 21) & 0x1f;
- regs->gpr[rd] = mfspr(PVR);
+ regs->gpr[rd] = mfspr(SPRN_PVR);
return 0;
}
return 0;
}
+ /* Emulate load/store string insn. */
+ if ((instword & INST_STRING_GEN_MASK) == INST_STRING)
+ return emulate_string_inst(regs, instword);
+
return -EINVAL;
}
fixed = fix_alignment(regs);
if (fixed == 1) {
regs->nip += 4; /* skip over emulated instruction */
+ emulate_single_step(regs);
return;
}
if (fixed == -EFAULT) {
if (regs->msr & MSR_VEC)
giveup_altivec(current);
preempt_enable();
+ if (!user_mode(regs)) {
+ printk(KERN_ERR "altivec assist exception in kernel mode"
+ " at %lx\n", regs->nip);
+ debugger(regs);
+ die("altivec assist exception", regs, SIGFPE);
+ return;
+ }
err = emulate_altivec(regs);
if (err == 0) {