|
@@ -62,15 +62,17 @@ static nokprobe_inline unsigned long truncate_if_32bit(unsigned long msr,
|
|
|
/*
|
|
|
* Determine whether a conditional branch instruction would branch.
|
|
|
*/
|
|
|
-static nokprobe_inline int branch_taken(unsigned int instr, struct pt_regs *regs)
|
|
|
+static nokprobe_inline int branch_taken(unsigned int instr,
|
|
|
+ const struct pt_regs *regs,
|
|
|
+ struct instruction_op *op)
|
|
|
{
|
|
|
unsigned int bo = (instr >> 21) & 0x1f;
|
|
|
unsigned int bi;
|
|
|
|
|
|
if ((bo & 4) == 0) {
|
|
|
/* decrement counter */
|
|
|
- --regs->ctr;
|
|
|
- if (((bo >> 1) & 1) ^ (regs->ctr == 0))
|
|
|
+ op->type |= DECCTR;
|
|
|
+ if (((bo >> 1) & 1) ^ (regs->ctr == 1))
|
|
|
return 0;
|
|
|
}
|
|
|
if ((bo & 0x10) == 0) {
|
|
@@ -92,7 +94,8 @@ static nokprobe_inline long address_ok(struct pt_regs *regs, unsigned long ea, i
|
|
|
/*
|
|
|
* Calculate effective address for a D-form instruction
|
|
|
*/
|
|
|
-static nokprobe_inline unsigned long dform_ea(unsigned int instr, struct pt_regs *regs)
|
|
|
+static nokprobe_inline unsigned long dform_ea(unsigned int instr,
|
|
|
+ const struct pt_regs *regs)
|
|
|
{
|
|
|
int ra;
|
|
|
unsigned long ea;
|
|
@@ -109,7 +112,8 @@ static nokprobe_inline unsigned long dform_ea(unsigned int instr, struct pt_regs
|
|
|
/*
|
|
|
* Calculate effective address for a DS-form instruction
|
|
|
*/
|
|
|
-static nokprobe_inline unsigned long dsform_ea(unsigned int instr, struct pt_regs *regs)
|
|
|
+static nokprobe_inline unsigned long dsform_ea(unsigned int instr,
|
|
|
+ const struct pt_regs *regs)
|
|
|
{
|
|
|
int ra;
|
|
|
unsigned long ea;
|
|
@@ -127,7 +131,7 @@ static nokprobe_inline unsigned long dsform_ea(unsigned int instr, struct pt_reg
|
|
|
* Calculate effective address for an X-form instruction
|
|
|
*/
|
|
|
static nokprobe_inline unsigned long xform_ea(unsigned int instr,
|
|
|
- struct pt_regs *regs)
|
|
|
+ const struct pt_regs *regs)
|
|
|
{
|
|
|
int ra, rb;
|
|
|
unsigned long ea;
|
|
@@ -526,24 +530,27 @@ static nokprobe_inline int do_vsx_store(int rn, int (*func)(int, unsigned long),
|
|
|
: "=r" (err) \
|
|
|
: "r" (addr), "i" (-EFAULT), "0" (err))
|
|
|
|
|
|
-static nokprobe_inline void set_cr0(struct pt_regs *regs, int rd)
|
|
|
+static nokprobe_inline void set_cr0(const struct pt_regs *regs,
|
|
|
+ struct instruction_op *op, int rd)
|
|
|
{
|
|
|
long val = regs->gpr[rd];
|
|
|
|
|
|
- regs->ccr = (regs->ccr & 0x0fffffff) | ((regs->xer >> 3) & 0x10000000);
|
|
|
+ op->type |= SETCC;
|
|
|
+ op->ccval = (regs->ccr & 0x0fffffff) | ((regs->xer >> 3) & 0x10000000);
|
|
|
#ifdef __powerpc64__
|
|
|
if (!(regs->msr & MSR_64BIT))
|
|
|
val = (int) val;
|
|
|
#endif
|
|
|
if (val < 0)
|
|
|
- regs->ccr |= 0x80000000;
|
|
|
+ op->ccval |= 0x80000000;
|
|
|
else if (val > 0)
|
|
|
- regs->ccr |= 0x40000000;
|
|
|
+ op->ccval |= 0x40000000;
|
|
|
else
|
|
|
- regs->ccr |= 0x20000000;
|
|
|
+ op->ccval |= 0x20000000;
|
|
|
}
|
|
|
|
|
|
-static nokprobe_inline void add_with_carry(struct pt_regs *regs, int rd,
|
|
|
+static nokprobe_inline void add_with_carry(const struct pt_regs *regs,
|
|
|
+ struct instruction_op *op, int rd,
|
|
|
unsigned long val1, unsigned long val2,
|
|
|
unsigned long carry_in)
|
|
|
{
|
|
@@ -551,24 +558,29 @@ static nokprobe_inline void add_with_carry(struct pt_regs *regs, int rd,
|
|
|
|
|
|
if (carry_in)
|
|
|
++val;
|
|
|
- regs->gpr[rd] = val;
|
|
|
+ op->type = COMPUTE + SETREG + SETXER;
|
|
|
+ op->reg = rd;
|
|
|
+ op->val = val;
|
|
|
#ifdef __powerpc64__
|
|
|
if (!(regs->msr & MSR_64BIT)) {
|
|
|
val = (unsigned int) val;
|
|
|
val1 = (unsigned int) val1;
|
|
|
}
|
|
|
#endif
|
|
|
+ op->xerval = regs->xer;
|
|
|
if (val < val1 || (carry_in && val == val1))
|
|
|
- regs->xer |= XER_CA;
|
|
|
+ op->xerval |= XER_CA;
|
|
|
else
|
|
|
- regs->xer &= ~XER_CA;
|
|
|
+ op->xerval &= ~XER_CA;
|
|
|
}
|
|
|
|
|
|
-static nokprobe_inline void do_cmp_signed(struct pt_regs *regs, long v1, long v2,
|
|
|
- int crfld)
|
|
|
+static nokprobe_inline void do_cmp_signed(const struct pt_regs *regs,
|
|
|
+ struct instruction_op *op,
|
|
|
+ long v1, long v2, int crfld)
|
|
|
{
|
|
|
unsigned int crval, shift;
|
|
|
|
|
|
+ op->type = COMPUTE + SETCC;
|
|
|
crval = (regs->xer >> 31) & 1; /* get SO bit */
|
|
|
if (v1 < v2)
|
|
|
crval |= 8;
|
|
@@ -577,14 +589,17 @@ static nokprobe_inline void do_cmp_signed(struct pt_regs *regs, long v1, long v2
|
|
|
else
|
|
|
crval |= 2;
|
|
|
shift = (7 - crfld) * 4;
|
|
|
- regs->ccr = (regs->ccr & ~(0xf << shift)) | (crval << shift);
|
|
|
+ op->ccval = (regs->ccr & ~(0xf << shift)) | (crval << shift);
|
|
|
}
|
|
|
|
|
|
-static nokprobe_inline void do_cmp_unsigned(struct pt_regs *regs, unsigned long v1,
|
|
|
- unsigned long v2, int crfld)
|
|
|
+static nokprobe_inline void do_cmp_unsigned(const struct pt_regs *regs,
|
|
|
+ struct instruction_op *op,
|
|
|
+ unsigned long v1,
|
|
|
+ unsigned long v2, int crfld)
|
|
|
{
|
|
|
unsigned int crval, shift;
|
|
|
|
|
|
+ op->type = COMPUTE + SETCC;
|
|
|
crval = (regs->xer >> 31) & 1; /* get SO bit */
|
|
|
if (v1 < v2)
|
|
|
crval |= 8;
|
|
@@ -593,11 +608,12 @@ static nokprobe_inline void do_cmp_unsigned(struct pt_regs *regs, unsigned long
|
|
|
else
|
|
|
crval |= 2;
|
|
|
shift = (7 - crfld) * 4;
|
|
|
- regs->ccr = (regs->ccr & ~(0xf << shift)) | (crval << shift);
|
|
|
+ op->ccval = (regs->ccr & ~(0xf << shift)) | (crval << shift);
|
|
|
}
|
|
|
|
|
|
-static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1,
|
|
|
- unsigned long v2, int rd)
|
|
|
+static nokprobe_inline void do_cmpb(const struct pt_regs *regs,
|
|
|
+ struct instruction_op *op,
|
|
|
+ unsigned long v1, unsigned long v2)
|
|
|
{
|
|
|
unsigned long long out_val, mask;
|
|
|
int i;
|
|
@@ -608,16 +624,16 @@ static nokprobe_inline void do_cmpb(struct pt_regs *regs, unsigned long v1,
|
|
|
if ((v1 & mask) == (v2 & mask))
|
|
|
out_val |= mask;
|
|
|
}
|
|
|
-
|
|
|
- regs->gpr[rd] = out_val;
|
|
|
+ op->val = out_val;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* The size parameter is used to adjust the equivalent popcnt instruction.
|
|
|
* popcntb = 8, popcntw = 32, popcntd = 64
|
|
|
*/
|
|
|
-static nokprobe_inline void do_popcnt(struct pt_regs *regs, unsigned long v1,
|
|
|
- int size, int ra)
|
|
|
+static nokprobe_inline void do_popcnt(const struct pt_regs *regs,
|
|
|
+ struct instruction_op *op,
|
|
|
+ unsigned long v1, int size)
|
|
|
{
|
|
|
unsigned long long out = v1;
|
|
|
|
|
@@ -626,23 +642,24 @@ static nokprobe_inline void do_popcnt(struct pt_regs *regs, unsigned long v1,
|
|
|
out = (out + (out >> 4)) & 0x0f0f0f0f0f0f0f0f;
|
|
|
|
|
|
if (size == 8) { /* popcntb */
|
|
|
- regs->gpr[ra] = out;
|
|
|
+ op->val = out;
|
|
|
return;
|
|
|
}
|
|
|
out += out >> 8;
|
|
|
out += out >> 16;
|
|
|
if (size == 32) { /* popcntw */
|
|
|
- regs->gpr[ra] = out & 0x0000003f0000003f;
|
|
|
+ op->val = out & 0x0000003f0000003f;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
out = (out + (out >> 32)) & 0x7f;
|
|
|
- regs->gpr[ra] = out; /* popcntd */
|
|
|
+ op->val = out; /* popcntd */
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_PPC64
|
|
|
-static nokprobe_inline void do_bpermd(struct pt_regs *regs, unsigned long v1,
|
|
|
- unsigned long v2, int ra)
|
|
|
+static nokprobe_inline void do_bpermd(const struct pt_regs *regs,
|
|
|
+ struct instruction_op *op,
|
|
|
+ unsigned long v1, unsigned long v2)
|
|
|
{
|
|
|
unsigned char perm, idx;
|
|
|
unsigned int i;
|
|
@@ -654,26 +671,27 @@ static nokprobe_inline void do_bpermd(struct pt_regs *regs, unsigned long v1,
|
|
|
if (v2 & PPC_BIT(idx))
|
|
|
perm |= 1 << i;
|
|
|
}
|
|
|
- regs->gpr[ra] = perm;
|
|
|
+ op->val = perm;
|
|
|
}
|
|
|
#endif /* CONFIG_PPC64 */
|
|
|
/*
|
|
|
* The size parameter adjusts the equivalent prty instruction.
|
|
|
* prtyw = 32, prtyd = 64
|
|
|
*/
|
|
|
-static nokprobe_inline void do_prty(struct pt_regs *regs, unsigned long v,
|
|
|
- int size, int ra)
|
|
|
+static nokprobe_inline void do_prty(const struct pt_regs *regs,
|
|
|
+ struct instruction_op *op,
|
|
|
+ unsigned long v, int size)
|
|
|
{
|
|
|
unsigned long long res = v ^ (v >> 8);
|
|
|
|
|
|
res ^= res >> 16;
|
|
|
if (size == 32) { /* prtyw */
|
|
|
- regs->gpr[ra] = res & 0x0000000100000001;
|
|
|
+ op->val = res & 0x0000000100000001;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
res ^= res >> 32;
|
|
|
- regs->gpr[ra] = res & 1; /*prtyd */
|
|
|
+ op->val = res & 1; /*prtyd */
|
|
|
}
|
|
|
|
|
|
static nokprobe_inline int trap_compare(long v1, long v2)
|
|
@@ -709,14 +727,18 @@ static nokprobe_inline int trap_compare(long v1, long v2)
|
|
|
#define ROTATE(x, n) ((n) ? (((x) << (n)) | ((x) >> (8 * sizeof(long) - (n)))) : (x))
|
|
|
|
|
|
/*
|
|
|
- * Decode an instruction, and execute it if that can be done just by
|
|
|
- * modifying *regs (i.e. integer arithmetic and logical instructions,
|
|
|
- * branches, and barrier instructions).
|
|
|
- * Returns 1 if the instruction has been executed, or 0 if not.
|
|
|
- * Sets *op to indicate what the instruction does.
|
|
|
+ * Decode an instruction, and return information about it in *op
|
|
|
+ * without changing *regs.
|
|
|
+ * Integer arithmetic and logical instructions, branches, and barrier
|
|
|
+ * instructions can be emulated just using the information in *op.
|
|
|
+ *
|
|
|
+ * Return value is 1 if the instruction can be emulated just by
|
|
|
+ * updating *regs with the information in *op, -1 if we need the
|
|
|
+ * GPRs but *regs doesn't contain the full register set, or 0
|
|
|
+ * otherwise.
|
|
|
*/
|
|
|
-int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
|
|
|
- unsigned int instr)
|
|
|
+int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
|
|
|
+ unsigned int instr)
|
|
|
{
|
|
|
unsigned int opcode, ra, rb, rd, spr, u;
|
|
|
unsigned long int imm;
|
|
@@ -733,12 +755,11 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
|
|
|
imm = (signed short)(instr & 0xfffc);
|
|
|
if ((instr & 2) == 0)
|
|
|
imm += regs->nip;
|
|
|
- regs->nip += 4;
|
|
|
- regs->nip = truncate_if_32bit(regs->msr, regs->nip);
|
|
|
+ op->val = truncate_if_32bit(regs->msr, imm);
|
|
|
if (instr & 1)
|
|
|
- regs->link = regs->nip;
|
|
|
- if (branch_taken(instr, regs))
|
|
|
- regs->nip = truncate_if_32bit(regs->msr, imm);
|
|
|
+ op->type |= SETLK;
|
|
|
+ if (branch_taken(instr, regs, op))
|
|
|
+ op->type |= BRTAKEN;
|
|
|
return 1;
|
|
|
#ifdef CONFIG_PPC64
|
|
|
case 17: /* sc */
|
|
@@ -749,38 +770,37 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
|
|
|
return 0;
|
|
|
#endif
|
|
|
case 18: /* b */
|
|
|
- op->type = BRANCH;
|
|
|
+ op->type = BRANCH | BRTAKEN;
|
|
|
imm = instr & 0x03fffffc;
|
|
|
if (imm & 0x02000000)
|
|
|
imm -= 0x04000000;
|
|
|
if ((instr & 2) == 0)
|
|
|
imm += regs->nip;
|
|
|
+ op->val = truncate_if_32bit(regs->msr, imm);
|
|
|
if (instr & 1)
|
|
|
- regs->link = truncate_if_32bit(regs->msr, regs->nip + 4);
|
|
|
- imm = truncate_if_32bit(regs->msr, imm);
|
|
|
- regs->nip = imm;
|
|
|
+ op->type |= SETLK;
|
|
|
return 1;
|
|
|
case 19:
|
|
|
switch ((instr >> 1) & 0x3ff) {
|
|
|
case 0: /* mcrf */
|
|
|
+ op->type = COMPUTE + SETCC;
|
|
|
rd = 7 - ((instr >> 23) & 0x7);
|
|
|
ra = 7 - ((instr >> 18) & 0x7);
|
|
|
rd *= 4;
|
|
|
ra *= 4;
|
|
|
val = (regs->ccr >> ra) & 0xf;
|
|
|
- regs->ccr = (regs->ccr & ~(0xfUL << rd)) | (val << rd);
|
|
|
- goto instr_done;
|
|
|
+ op->ccval = (regs->ccr & ~(0xfUL << rd)) | (val << rd);
|
|
|
+ return 1;
|
|
|
|
|
|
case 16: /* bclr */
|
|
|
case 528: /* bcctr */
|
|
|
op->type = BRANCH;
|
|
|
imm = (instr & 0x400)? regs->ctr: regs->link;
|
|
|
- regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
|
|
|
- imm = truncate_if_32bit(regs->msr, imm);
|
|
|
+ op->val = truncate_if_32bit(regs->msr, imm);
|
|
|
if (instr & 1)
|
|
|
- regs->link = regs->nip;
|
|
|
- if (branch_taken(instr, regs))
|
|
|
- regs->nip = imm;
|
|
|
+ op->type |= SETLK;
|
|
|
+ if (branch_taken(instr, regs, op))
|
|
|
+ op->type |= BRTAKEN;
|
|
|
return 1;
|
|
|
|
|
|
case 18: /* rfid, scary */
|
|
@@ -790,9 +810,8 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
|
|
|
return 0;
|
|
|
|
|
|
case 150: /* isync */
|
|
|
- op->type = BARRIER;
|
|
|
- isync();
|
|
|
- goto instr_done;
|
|
|
+ op->type = BARRIER | BARRIER_ISYNC;
|
|
|
+ return 1;
|
|
|
|
|
|
case 33: /* crnor */
|
|
|
case 129: /* crandc */
|
|
@@ -802,45 +821,47 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
|
|
|
case 289: /* creqv */
|
|
|
case 417: /* crorc */
|
|
|
case 449: /* cror */
|
|
|
+ op->type = COMPUTE + SETCC;
|
|
|
ra = (instr >> 16) & 0x1f;
|
|
|
rb = (instr >> 11) & 0x1f;
|
|
|
rd = (instr >> 21) & 0x1f;
|
|
|
ra = (regs->ccr >> (31 - ra)) & 1;
|
|
|
rb = (regs->ccr >> (31 - rb)) & 1;
|
|
|
val = (instr >> (6 + ra * 2 + rb)) & 1;
|
|
|
- regs->ccr = (regs->ccr & ~(1UL << (31 - rd))) |
|
|
|
+ op->ccval = (regs->ccr & ~(1UL << (31 - rd))) |
|
|
|
(val << (31 - rd));
|
|
|
- goto instr_done;
|
|
|
+ return 1;
|
|
|
+ default:
|
|
|
+ op->type = UNKNOWN;
|
|
|
+ return 0;
|
|
|
}
|
|
|
break;
|
|
|
case 31:
|
|
|
switch ((instr >> 1) & 0x3ff) {
|
|
|
case 598: /* sync */
|
|
|
- op->type = BARRIER;
|
|
|
+ op->type = BARRIER + BARRIER_SYNC;
|
|
|
#ifdef __powerpc64__
|
|
|
switch ((instr >> 21) & 3) {
|
|
|
case 1: /* lwsync */
|
|
|
- asm volatile("lwsync" : : : "memory");
|
|
|
- goto instr_done;
|
|
|
+ op->type = BARRIER + BARRIER_LWSYNC;
|
|
|
+ break;
|
|
|
case 2: /* ptesync */
|
|
|
- asm volatile("ptesync" : : : "memory");
|
|
|
- goto instr_done;
|
|
|
+ op->type = BARRIER + BARRIER_PTESYNC;
|
|
|
+ break;
|
|
|
}
|
|
|
#endif
|
|
|
- mb();
|
|
|
- goto instr_done;
|
|
|
+ return 1;
|
|
|
|
|
|
case 854: /* eieio */
|
|
|
- op->type = BARRIER;
|
|
|
- eieio();
|
|
|
- goto instr_done;
|
|
|
+ op->type = BARRIER + BARRIER_EIEIO;
|
|
|
+ return 1;
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
/* Following cases refer to regs->gpr[], so we need all regs */
|
|
|
if (!FULL_REGS(regs))
|
|
|
- return 0;
|
|
|
+ return -1;
|
|
|
|
|
|
rd = (instr >> 21) & 0x1f;
|
|
|
ra = (instr >> 16) & 0x1f;
|
|
@@ -851,21 +872,21 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
|
|
|
case 2: /* tdi */
|
|
|
if (rd & trap_compare(regs->gpr[ra], (short) instr))
|
|
|
goto trap;
|
|
|
- goto instr_done;
|
|
|
+ return 1;
|
|
|
#endif
|
|
|
case 3: /* twi */
|
|
|
if (rd & trap_compare((int)regs->gpr[ra], (short) instr))
|
|
|
goto trap;
|
|
|
- goto instr_done;
|
|
|
+ return 1;
|
|
|
|
|
|
case 7: /* mulli */
|
|
|
- regs->gpr[rd] = regs->gpr[ra] * (short) instr;
|
|
|
- goto instr_done;
|
|
|
+ op->val = regs->gpr[ra] * (short) instr;
|
|
|
+ goto compute_done;
|
|
|
|
|
|
case 8: /* subfic */
|
|
|
imm = (short) instr;
|
|
|
- add_with_carry(regs, rd, ~regs->gpr[ra], imm, 1);
|
|
|
- goto instr_done;
|
|
|
+ add_with_carry(regs, op, rd, ~regs->gpr[ra], imm, 1);
|
|
|
+ return 1;
|
|
|
|
|
|
case 10: /* cmpli */
|
|
|
imm = (unsigned short) instr;
|
|
@@ -874,8 +895,8 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
|
|
|
if ((rd & 1) == 0)
|
|
|
val = (unsigned int) val;
|
|
|
#endif
|
|
|
- do_cmp_unsigned(regs, val, imm, rd >> 2);
|
|
|
- goto instr_done;
|
|
|
+ do_cmp_unsigned(regs, op, val, imm, rd >> 2);
|
|
|
+ return 1;
|
|
|
|
|
|
case 11: /* cmpi */
|
|
|
imm = (short) instr;
|
|
@@ -884,47 +905,47 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
|
|
|
if ((rd & 1) == 0)
|
|
|
val = (int) val;
|
|
|
#endif
|
|
|
- do_cmp_signed(regs, val, imm, rd >> 2);
|
|
|
- goto instr_done;
|
|
|
+ do_cmp_signed(regs, op, val, imm, rd >> 2);
|
|
|
+ return 1;
|
|
|
|
|
|
case 12: /* addic */
|
|
|
imm = (short) instr;
|
|
|
- add_with_carry(regs, rd, regs->gpr[ra], imm, 0);
|
|
|
- goto instr_done;
|
|
|
+ add_with_carry(regs, op, rd, regs->gpr[ra], imm, 0);
|
|
|
+ return 1;
|
|
|
|
|
|
case 13: /* addic. */
|
|
|
imm = (short) instr;
|
|
|
- add_with_carry(regs, rd, regs->gpr[ra], imm, 0);
|
|
|
- set_cr0(regs, rd);
|
|
|
- goto instr_done;
|
|
|
+ add_with_carry(regs, op, rd, regs->gpr[ra], imm, 0);
|
|
|
+ set_cr0(regs, op, rd);
|
|
|
+ return 1;
|
|
|
|
|
|
case 14: /* addi */
|
|
|
imm = (short) instr;
|
|
|
if (ra)
|
|
|
imm += regs->gpr[ra];
|
|
|
- regs->gpr[rd] = imm;
|
|
|
- goto instr_done;
|
|
|
+ op->val = imm;
|
|
|
+ goto compute_done;
|
|
|
|
|
|
case 15: /* addis */
|
|
|
imm = ((short) instr) << 16;
|
|
|
if (ra)
|
|
|
imm += regs->gpr[ra];
|
|
|
- regs->gpr[rd] = imm;
|
|
|
- goto instr_done;
|
|
|
+ op->val = imm;
|
|
|
+ goto compute_done;
|
|
|
|
|
|
case 20: /* rlwimi */
|
|
|
mb = (instr >> 6) & 0x1f;
|
|
|
me = (instr >> 1) & 0x1f;
|
|
|
val = DATA32(regs->gpr[rd]);
|
|
|
imm = MASK32(mb, me);
|
|
|
- regs->gpr[ra] = (regs->gpr[ra] & ~imm) | (ROTATE(val, rb) & imm);
|
|
|
+ op->val = (regs->gpr[ra] & ~imm) | (ROTATE(val, rb) & imm);
|
|
|
goto logical_done;
|
|
|
|
|
|
case 21: /* rlwinm */
|
|
|
mb = (instr >> 6) & 0x1f;
|
|
|
me = (instr >> 1) & 0x1f;
|
|
|
val = DATA32(regs->gpr[rd]);
|
|
|
- regs->gpr[ra] = ROTATE(val, rb) & MASK32(mb, me);
|
|
|
+ op->val = ROTATE(val, rb) & MASK32(mb, me);
|
|
|
goto logical_done;
|
|
|
|
|
|
case 23: /* rlwnm */
|
|
@@ -932,40 +953,37 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
|
|
|
me = (instr >> 1) & 0x1f;
|
|
|
rb = regs->gpr[rb] & 0x1f;
|
|
|
val = DATA32(regs->gpr[rd]);
|
|
|
- regs->gpr[ra] = ROTATE(val, rb) & MASK32(mb, me);
|
|
|
+ op->val = ROTATE(val, rb) & MASK32(mb, me);
|
|
|
goto logical_done;
|
|
|
|
|
|
case 24: /* ori */
|
|
|
- imm = (unsigned short) instr;
|
|
|
- regs->gpr[ra] = regs->gpr[rd] | imm;
|
|
|
- goto instr_done;
|
|
|
+ op->val = regs->gpr[rd] | (unsigned short) instr;
|
|
|
+ goto logical_done_nocc;
|
|
|
|
|
|
case 25: /* oris */
|
|
|
imm = (unsigned short) instr;
|
|
|
- regs->gpr[ra] = regs->gpr[rd] | (imm << 16);
|
|
|
- goto instr_done;
|
|
|
+ op->val = regs->gpr[rd] | (imm << 16);
|
|
|
+ goto logical_done_nocc;
|
|
|
|
|
|
case 26: /* xori */
|
|
|
- imm = (unsigned short) instr;
|
|
|
- regs->gpr[ra] = regs->gpr[rd] ^ imm;
|
|
|
- goto instr_done;
|
|
|
+ op->val = regs->gpr[rd] ^ (unsigned short) instr;
|
|
|
+ goto logical_done_nocc;
|
|
|
|
|
|
case 27: /* xoris */
|
|
|
imm = (unsigned short) instr;
|
|
|
- regs->gpr[ra] = regs->gpr[rd] ^ (imm << 16);
|
|
|
- goto instr_done;
|
|
|
+ op->val = regs->gpr[rd] ^ (imm << 16);
|
|
|
+ goto logical_done_nocc;
|
|
|
|
|
|
case 28: /* andi. */
|
|
|
- imm = (unsigned short) instr;
|
|
|
- regs->gpr[ra] = regs->gpr[rd] & imm;
|
|
|
- set_cr0(regs, ra);
|
|
|
- goto instr_done;
|
|
|
+ op->val = regs->gpr[rd] & (unsigned short) instr;
|
|
|
+ set_cr0(regs, op, ra);
|
|
|
+ goto logical_done_nocc;
|
|
|
|
|
|
case 29: /* andis. */
|
|
|
imm = (unsigned short) instr;
|
|
|
- regs->gpr[ra] = regs->gpr[rd] & (imm << 16);
|
|
|
- set_cr0(regs, ra);
|
|
|
- goto instr_done;
|
|
|
+ op->val = regs->gpr[rd] & (imm << 16);
|
|
|
+ set_cr0(regs, op, ra);
|
|
|
+ goto logical_done_nocc;
|
|
|
|
|
|
#ifdef __powerpc64__
|
|
|
case 30: /* rld* */
|
|
@@ -976,34 +994,36 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
|
|
|
val = ROTATE(val, sh);
|
|
|
switch ((instr >> 2) & 3) {
|
|
|
case 0: /* rldicl */
|
|
|
- regs->gpr[ra] = val & MASK64_L(mb);
|
|
|
- goto logical_done;
|
|
|
+ val &= MASK64_L(mb);
|
|
|
+ break;
|
|
|
case 1: /* rldicr */
|
|
|
- regs->gpr[ra] = val & MASK64_R(mb);
|
|
|
- goto logical_done;
|
|
|
+ val &= MASK64_R(mb);
|
|
|
+ break;
|
|
|
case 2: /* rldic */
|
|
|
- regs->gpr[ra] = val & MASK64(mb, 63 - sh);
|
|
|
- goto logical_done;
|
|
|
+ val &= MASK64(mb, 63 - sh);
|
|
|
+ break;
|
|
|
case 3: /* rldimi */
|
|
|
imm = MASK64(mb, 63 - sh);
|
|
|
- regs->gpr[ra] = (regs->gpr[ra] & ~imm) |
|
|
|
+ val = (regs->gpr[ra] & ~imm) |
|
|
|
(val & imm);
|
|
|
- goto logical_done;
|
|
|
}
|
|
|
+ op->val = val;
|
|
|
+ goto logical_done;
|
|
|
} else {
|
|
|
sh = regs->gpr[rb] & 0x3f;
|
|
|
val = ROTATE(val, sh);
|
|
|
switch ((instr >> 1) & 7) {
|
|
|
case 0: /* rldcl */
|
|
|
- regs->gpr[ra] = val & MASK64_L(mb);
|
|
|
+ op->val = val & MASK64_L(mb);
|
|
|
goto logical_done;
|
|
|
case 1: /* rldcr */
|
|
|
- regs->gpr[ra] = val & MASK64_R(mb);
|
|
|
+ op->val = val & MASK64_R(mb);
|
|
|
goto logical_done;
|
|
|
}
|
|
|
}
|
|
|
#endif
|
|
|
- break; /* illegal instruction */
|
|
|
+ op->type = UNKNOWN; /* illegal instruction */
|
|
|
+ return 0;
|
|
|
|
|
|
case 31:
|
|
|
switch ((instr >> 1) & 0x3ff) {
|
|
@@ -1012,12 +1032,12 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
|
|
|
(rd & trap_compare((int)regs->gpr[ra],
|
|
|
(int)regs->gpr[rb])))
|
|
|
goto trap;
|
|
|
- goto instr_done;
|
|
|
+ return 1;
|
|
|
#ifdef __powerpc64__
|
|
|
case 68: /* td */
|
|
|
if (rd & trap_compare(regs->gpr[ra], regs->gpr[rb]))
|
|
|
goto trap;
|
|
|
- goto instr_done;
|
|
|
+ return 1;
|
|
|
#endif
|
|
|
case 83: /* mfmsr */
|
|
|
if (regs->msr & MSR_PR)
|
|
@@ -1046,74 +1066,50 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
|
|
|
#endif
|
|
|
|
|
|
case 19: /* mfcr */
|
|
|
+ imm = 0xffffffffUL;
|
|
|
if ((instr >> 20) & 1) {
|
|
|
imm = 0xf0000000UL;
|
|
|
for (sh = 0; sh < 8; ++sh) {
|
|
|
- if (instr & (0x80000 >> sh)) {
|
|
|
- regs->gpr[rd] = regs->ccr & imm;
|
|
|
+ if (instr & (0x80000 >> sh))
|
|
|
break;
|
|
|
- }
|
|
|
imm >>= 4;
|
|
|
}
|
|
|
-
|
|
|
- goto instr_done;
|
|
|
}
|
|
|
-
|
|
|
- regs->gpr[rd] = regs->ccr;
|
|
|
- regs->gpr[rd] &= 0xffffffffUL;
|
|
|
- goto instr_done;
|
|
|
+ op->val = regs->ccr & imm;
|
|
|
+ goto compute_done;
|
|
|
|
|
|
case 144: /* mtcrf */
|
|
|
+ op->type = COMPUTE + SETCC;
|
|
|
imm = 0xf0000000UL;
|
|
|
val = regs->gpr[rd];
|
|
|
+ op->val = regs->ccr;
|
|
|
for (sh = 0; sh < 8; ++sh) {
|
|
|
if (instr & (0x80000 >> sh))
|
|
|
- regs->ccr = (regs->ccr & ~imm) |
|
|
|
+ op->val = (op->val & ~imm) |
|
|
|
(val & imm);
|
|
|
imm >>= 4;
|
|
|
}
|
|
|
- goto instr_done;
|
|
|
+ return 1;
|
|
|
|
|
|
case 339: /* mfspr */
|
|
|
spr = ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0);
|
|
|
- switch (spr) {
|
|
|
- case SPRN_XER: /* mfxer */
|
|
|
- regs->gpr[rd] = regs->xer;
|
|
|
- regs->gpr[rd] &= 0xffffffffUL;
|
|
|
- goto instr_done;
|
|
|
- case SPRN_LR: /* mflr */
|
|
|
- regs->gpr[rd] = regs->link;
|
|
|
- goto instr_done;
|
|
|
- case SPRN_CTR: /* mfctr */
|
|
|
- regs->gpr[rd] = regs->ctr;
|
|
|
- goto instr_done;
|
|
|
- default:
|
|
|
- op->type = MFSPR;
|
|
|
- op->reg = rd;
|
|
|
- op->spr = spr;
|
|
|
- return 0;
|
|
|
- }
|
|
|
- break;
|
|
|
+ op->type = MFSPR;
|
|
|
+ op->reg = rd;
|
|
|
+ op->spr = spr;
|
|
|
+ if (spr == SPRN_XER || spr == SPRN_LR ||
|
|
|
+ spr == SPRN_CTR)
|
|
|
+ return 1;
|
|
|
+ return 0;
|
|
|
|
|
|
case 467: /* mtspr */
|
|
|
spr = ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0);
|
|
|
- switch (spr) {
|
|
|
- case SPRN_XER: /* mtxer */
|
|
|
- regs->xer = (regs->gpr[rd] & 0xffffffffUL);
|
|
|
- goto instr_done;
|
|
|
- case SPRN_LR: /* mtlr */
|
|
|
- regs->link = regs->gpr[rd];
|
|
|
- goto instr_done;
|
|
|
- case SPRN_CTR: /* mtctr */
|
|
|
- regs->ctr = regs->gpr[rd];
|
|
|
- goto instr_done;
|
|
|
- default:
|
|
|
- op->type = MTSPR;
|
|
|
- op->val = regs->gpr[rd];
|
|
|
- op->spr = spr;
|
|
|
- return 0;
|
|
|
- }
|
|
|
- break;
|
|
|
+ op->type = MTSPR;
|
|
|
+ op->val = regs->gpr[rd];
|
|
|
+ op->spr = spr;
|
|
|
+ if (spr == SPRN_XER || spr == SPRN_LR ||
|
|
|
+ spr == SPRN_CTR)
|
|
|
+ return 1;
|
|
|
+ return 0;
|
|
|
|
|
|
/*
|
|
|
* Compare instructions
|
|
@@ -1128,8 +1124,8 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
|
|
|
val2 = (int) val2;
|
|
|
}
|
|
|
#endif
|
|
|
- do_cmp_signed(regs, val, val2, rd >> 2);
|
|
|
- goto instr_done;
|
|
|
+ do_cmp_signed(regs, op, val, val2, rd >> 2);
|
|
|
+ return 1;
|
|
|
|
|
|
case 32: /* cmpl */
|
|
|
val = regs->gpr[ra];
|
|
@@ -1141,113 +1137,113 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
|
|
|
val2 = (unsigned int) val2;
|
|
|
}
|
|
|
#endif
|
|
|
- do_cmp_unsigned(regs, val, val2, rd >> 2);
|
|
|
- goto instr_done;
|
|
|
+ do_cmp_unsigned(regs, op, val, val2, rd >> 2);
|
|
|
+ return 1;
|
|
|
|
|
|
case 508: /* cmpb */
|
|
|
- do_cmpb(regs, regs->gpr[rd], regs->gpr[rb], ra);
|
|
|
- goto instr_done;
|
|
|
+ do_cmpb(regs, op, regs->gpr[rd], regs->gpr[rb]);
|
|
|
+ goto logical_done_nocc;
|
|
|
|
|
|
/*
|
|
|
* Arithmetic instructions
|
|
|
*/
|
|
|
case 8: /* subfc */
|
|
|
- add_with_carry(regs, rd, ~regs->gpr[ra],
|
|
|
+ add_with_carry(regs, op, rd, ~regs->gpr[ra],
|
|
|
regs->gpr[rb], 1);
|
|
|
goto arith_done;
|
|
|
#ifdef __powerpc64__
|
|
|
case 9: /* mulhdu */
|
|
|
- asm("mulhdu %0,%1,%2" : "=r" (regs->gpr[rd]) :
|
|
|
+ asm("mulhdu %0,%1,%2" : "=r" (op->val) :
|
|
|
"r" (regs->gpr[ra]), "r" (regs->gpr[rb]));
|
|
|
goto arith_done;
|
|
|
#endif
|
|
|
case 10: /* addc */
|
|
|
- add_with_carry(regs, rd, regs->gpr[ra],
|
|
|
+ add_with_carry(regs, op, rd, regs->gpr[ra],
|
|
|
regs->gpr[rb], 0);
|
|
|
goto arith_done;
|
|
|
|
|
|
case 11: /* mulhwu */
|
|
|
- asm("mulhwu %0,%1,%2" : "=r" (regs->gpr[rd]) :
|
|
|
+ asm("mulhwu %0,%1,%2" : "=r" (op->val) :
|
|
|
"r" (regs->gpr[ra]), "r" (regs->gpr[rb]));
|
|
|
goto arith_done;
|
|
|
|
|
|
case 40: /* subf */
|
|
|
- regs->gpr[rd] = regs->gpr[rb] - regs->gpr[ra];
|
|
|
+ op->val = regs->gpr[rb] - regs->gpr[ra];
|
|
|
goto arith_done;
|
|
|
#ifdef __powerpc64__
|
|
|
case 73: /* mulhd */
|
|
|
- asm("mulhd %0,%1,%2" : "=r" (regs->gpr[rd]) :
|
|
|
+ asm("mulhd %0,%1,%2" : "=r" (op->val) :
|
|
|
"r" (regs->gpr[ra]), "r" (regs->gpr[rb]));
|
|
|
goto arith_done;
|
|
|
#endif
|
|
|
case 75: /* mulhw */
|
|
|
- asm("mulhw %0,%1,%2" : "=r" (regs->gpr[rd]) :
|
|
|
+ asm("mulhw %0,%1,%2" : "=r" (op->val) :
|
|
|
"r" (regs->gpr[ra]), "r" (regs->gpr[rb]));
|
|
|
goto arith_done;
|
|
|
|
|
|
case 104: /* neg */
|
|
|
- regs->gpr[rd] = -regs->gpr[ra];
|
|
|
+ op->val = -regs->gpr[ra];
|
|
|
goto arith_done;
|
|
|
|
|
|
case 136: /* subfe */
|
|
|
- add_with_carry(regs, rd, ~regs->gpr[ra], regs->gpr[rb],
|
|
|
- regs->xer & XER_CA);
|
|
|
+ add_with_carry(regs, op, rd, ~regs->gpr[ra],
|
|
|
+ regs->gpr[rb], regs->xer & XER_CA);
|
|
|
goto arith_done;
|
|
|
|
|
|
case 138: /* adde */
|
|
|
- add_with_carry(regs, rd, regs->gpr[ra], regs->gpr[rb],
|
|
|
- regs->xer & XER_CA);
|
|
|
+ add_with_carry(regs, op, rd, regs->gpr[ra],
|
|
|
+ regs->gpr[rb], regs->xer & XER_CA);
|
|
|
goto arith_done;
|
|
|
|
|
|
case 200: /* subfze */
|
|
|
- add_with_carry(regs, rd, ~regs->gpr[ra], 0L,
|
|
|
+ add_with_carry(regs, op, rd, ~regs->gpr[ra], 0L,
|
|
|
regs->xer & XER_CA);
|
|
|
goto arith_done;
|
|
|
|
|
|
case 202: /* addze */
|
|
|
- add_with_carry(regs, rd, regs->gpr[ra], 0L,
|
|
|
+ add_with_carry(regs, op, rd, regs->gpr[ra], 0L,
|
|
|
regs->xer & XER_CA);
|
|
|
goto arith_done;
|
|
|
|
|
|
case 232: /* subfme */
|
|
|
- add_with_carry(regs, rd, ~regs->gpr[ra], -1L,
|
|
|
+ add_with_carry(regs, op, rd, ~regs->gpr[ra], -1L,
|
|
|
regs->xer & XER_CA);
|
|
|
goto arith_done;
|
|
|
#ifdef __powerpc64__
|
|
|
case 233: /* mulld */
|
|
|
- regs->gpr[rd] = regs->gpr[ra] * regs->gpr[rb];
|
|
|
+ op->val = regs->gpr[ra] * regs->gpr[rb];
|
|
|
goto arith_done;
|
|
|
#endif
|
|
|
case 234: /* addme */
|
|
|
- add_with_carry(regs, rd, regs->gpr[ra], -1L,
|
|
|
+ add_with_carry(regs, op, rd, regs->gpr[ra], -1L,
|
|
|
regs->xer & XER_CA);
|
|
|
goto arith_done;
|
|
|
|
|
|
case 235: /* mullw */
|
|
|
- regs->gpr[rd] = (unsigned int) regs->gpr[ra] *
|
|
|
+ op->val = (unsigned int) regs->gpr[ra] *
|
|
|
(unsigned int) regs->gpr[rb];
|
|
|
goto arith_done;
|
|
|
|
|
|
case 266: /* add */
|
|
|
- regs->gpr[rd] = regs->gpr[ra] + regs->gpr[rb];
|
|
|
+ op->val = regs->gpr[ra] + regs->gpr[rb];
|
|
|
goto arith_done;
|
|
|
#ifdef __powerpc64__
|
|
|
case 457: /* divdu */
|
|
|
- regs->gpr[rd] = regs->gpr[ra] / regs->gpr[rb];
|
|
|
+ op->val = regs->gpr[ra] / regs->gpr[rb];
|
|
|
goto arith_done;
|
|
|
#endif
|
|
|
case 459: /* divwu */
|
|
|
- regs->gpr[rd] = (unsigned int) regs->gpr[ra] /
|
|
|
+ op->val = (unsigned int) regs->gpr[ra] /
|
|
|
(unsigned int) regs->gpr[rb];
|
|
|
goto arith_done;
|
|
|
#ifdef __powerpc64__
|
|
|
case 489: /* divd */
|
|
|
- regs->gpr[rd] = (long int) regs->gpr[ra] /
|
|
|
+ op->val = (long int) regs->gpr[ra] /
|
|
|
(long int) regs->gpr[rb];
|
|
|
goto arith_done;
|
|
|
#endif
|
|
|
case 491: /* divw */
|
|
|
- regs->gpr[rd] = (int) regs->gpr[ra] /
|
|
|
+ op->val = (int) regs->gpr[ra] /
|
|
|
(int) regs->gpr[rb];
|
|
|
goto arith_done;
|
|
|
|
|
@@ -1260,85 +1256,83 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
|
|
|
val = (regs->ccr >> (31 - mb)) & 1;
|
|
|
val2 = (ra) ? regs->gpr[ra] : 0;
|
|
|
|
|
|
- regs->gpr[rd] = (val) ? val2 : regs->gpr[rb];
|
|
|
- goto logical_done;
|
|
|
+ op->val = (val) ? val2 : regs->gpr[rb];
|
|
|
+ goto compute_done;
|
|
|
|
|
|
case 26: /* cntlzw */
|
|
|
- asm("cntlzw %0,%1" : "=r" (regs->gpr[ra]) :
|
|
|
- "r" (regs->gpr[rd]));
|
|
|
+ op->val = __builtin_clz((unsigned int) regs->gpr[rd]);
|
|
|
goto logical_done;
|
|
|
#ifdef __powerpc64__
|
|
|
case 58: /* cntlzd */
|
|
|
- asm("cntlzd %0,%1" : "=r" (regs->gpr[ra]) :
|
|
|
- "r" (regs->gpr[rd]));
|
|
|
+ op->val = __builtin_clzl(regs->gpr[rd]);
|
|
|
goto logical_done;
|
|
|
#endif
|
|
|
case 28: /* and */
|
|
|
- regs->gpr[ra] = regs->gpr[rd] & regs->gpr[rb];
|
|
|
+ op->val = regs->gpr[rd] & regs->gpr[rb];
|
|
|
goto logical_done;
|
|
|
|
|
|
case 60: /* andc */
|
|
|
- regs->gpr[ra] = regs->gpr[rd] & ~regs->gpr[rb];
|
|
|
+ op->val = regs->gpr[rd] & ~regs->gpr[rb];
|
|
|
goto logical_done;
|
|
|
|
|
|
case 122: /* popcntb */
|
|
|
- do_popcnt(regs, regs->gpr[rd], 8, ra);
|
|
|
+ do_popcnt(regs, op, regs->gpr[rd], 8);
|
|
|
goto logical_done;
|
|
|
|
|
|
case 124: /* nor */
|
|
|
- regs->gpr[ra] = ~(regs->gpr[rd] | regs->gpr[rb]);
|
|
|
+ op->val = ~(regs->gpr[rd] | regs->gpr[rb]);
|
|
|
goto logical_done;
|
|
|
|
|
|
case 154: /* prtyw */
|
|
|
- do_prty(regs, regs->gpr[rd], 32, ra);
|
|
|
+ do_prty(regs, op, regs->gpr[rd], 32);
|
|
|
goto logical_done;
|
|
|
|
|
|
case 186: /* prtyd */
|
|
|
- do_prty(regs, regs->gpr[rd], 64, ra);
|
|
|
+ do_prty(regs, op, regs->gpr[rd], 64);
|
|
|
goto logical_done;
|
|
|
#ifdef CONFIG_PPC64
|
|
|
case 252: /* bpermd */
|
|
|
- do_bpermd(regs, regs->gpr[rd], regs->gpr[rb], ra);
|
|
|
+ do_bpermd(regs, op, regs->gpr[rd], regs->gpr[rb]);
|
|
|
goto logical_done;
|
|
|
#endif
|
|
|
case 284: /* xor */
|
|
|
- regs->gpr[ra] = ~(regs->gpr[rd] ^ regs->gpr[rb]);
|
|
|
+ op->val = ~(regs->gpr[rd] ^ regs->gpr[rb]);
|
|
|
goto logical_done;
|
|
|
|
|
|
case 316: /* xor */
|
|
|
- regs->gpr[ra] = regs->gpr[rd] ^ regs->gpr[rb];
|
|
|
+ op->val = regs->gpr[rd] ^ regs->gpr[rb];
|
|
|
goto logical_done;
|
|
|
|
|
|
case 378: /* popcntw */
|
|
|
- do_popcnt(regs, regs->gpr[rd], 32, ra);
|
|
|
+ do_popcnt(regs, op, regs->gpr[rd], 32);
|
|
|
goto logical_done;
|
|
|
|
|
|
case 412: /* orc */
|
|
|
- regs->gpr[ra] = regs->gpr[rd] | ~regs->gpr[rb];
|
|
|
+ op->val = regs->gpr[rd] | ~regs->gpr[rb];
|
|
|
goto logical_done;
|
|
|
|
|
|
case 444: /* or */
|
|
|
- regs->gpr[ra] = regs->gpr[rd] | regs->gpr[rb];
|
|
|
+ op->val = regs->gpr[rd] | regs->gpr[rb];
|
|
|
goto logical_done;
|
|
|
|
|
|
case 476: /* nand */
|
|
|
- regs->gpr[ra] = ~(regs->gpr[rd] & regs->gpr[rb]);
|
|
|
+ op->val = ~(regs->gpr[rd] & regs->gpr[rb]);
|
|
|
goto logical_done;
|
|
|
#ifdef CONFIG_PPC64
|
|
|
case 506: /* popcntd */
|
|
|
- do_popcnt(regs, regs->gpr[rd], 64, ra);
|
|
|
+ do_popcnt(regs, op, regs->gpr[rd], 64);
|
|
|
goto logical_done;
|
|
|
#endif
|
|
|
case 922: /* extsh */
|
|
|
- regs->gpr[ra] = (signed short) regs->gpr[rd];
|
|
|
+ op->val = (signed short) regs->gpr[rd];
|
|
|
goto logical_done;
|
|
|
|
|
|
case 954: /* extsb */
|
|
|
- regs->gpr[ra] = (signed char) regs->gpr[rd];
|
|
|
+ op->val = (signed char) regs->gpr[rd];
|
|
|
goto logical_done;
|
|
|
#ifdef __powerpc64__
|
|
|
case 986: /* extsw */
|
|
|
- regs->gpr[ra] = (signed int) regs->gpr[rd];
|
|
|
+ op->val = (signed int) regs->gpr[rd];
|
|
|
goto logical_done;
|
|
|
#endif
|
|
|
|
|
@@ -1348,75 +1342,83 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
|
|
|
case 24: /* slw */
|
|
|
sh = regs->gpr[rb] & 0x3f;
|
|
|
if (sh < 32)
|
|
|
- regs->gpr[ra] = (regs->gpr[rd] << sh) & 0xffffffffUL;
|
|
|
+ op->val = (regs->gpr[rd] << sh) & 0xffffffffUL;
|
|
|
else
|
|
|
- regs->gpr[ra] = 0;
|
|
|
+ op->val = 0;
|
|
|
goto logical_done;
|
|
|
|
|
|
case 536: /* srw */
|
|
|
sh = regs->gpr[rb] & 0x3f;
|
|
|
if (sh < 32)
|
|
|
- regs->gpr[ra] = (regs->gpr[rd] & 0xffffffffUL) >> sh;
|
|
|
+ op->val = (regs->gpr[rd] & 0xffffffffUL) >> sh;
|
|
|
else
|
|
|
- regs->gpr[ra] = 0;
|
|
|
+ op->val = 0;
|
|
|
goto logical_done;
|
|
|
|
|
|
case 792: /* sraw */
|
|
|
+ op->type = COMPUTE + SETREG + SETXER;
|
|
|
sh = regs->gpr[rb] & 0x3f;
|
|
|
ival = (signed int) regs->gpr[rd];
|
|
|
- regs->gpr[ra] = ival >> (sh < 32 ? sh : 31);
|
|
|
+ op->val = ival >> (sh < 32 ? sh : 31);
|
|
|
+ op->xerval = regs->xer;
|
|
|
if (ival < 0 && (sh >= 32 || (ival & ((1ul << sh) - 1)) != 0))
|
|
|
- regs->xer |= XER_CA;
|
|
|
+ op->xerval |= XER_CA;
|
|
|
else
|
|
|
- regs->xer &= ~XER_CA;
|
|
|
+ op->xerval &= ~XER_CA;
|
|
|
goto logical_done;
|
|
|
|
|
|
case 824: /* srawi */
|
|
|
+ op->type = COMPUTE + SETREG + SETXER;
|
|
|
sh = rb;
|
|
|
ival = (signed int) regs->gpr[rd];
|
|
|
- regs->gpr[ra] = ival >> sh;
|
|
|
+ op->val = ival >> sh;
|
|
|
+ op->xerval = regs->xer;
|
|
|
if (ival < 0 && (ival & ((1ul << sh) - 1)) != 0)
|
|
|
- regs->xer |= XER_CA;
|
|
|
+ op->xerval |= XER_CA;
|
|
|
else
|
|
|
- regs->xer &= ~XER_CA;
|
|
|
+ op->xerval &= ~XER_CA;
|
|
|
goto logical_done;
|
|
|
|
|
|
#ifdef __powerpc64__
|
|
|
case 27: /* sld */
|
|
|
sh = regs->gpr[rb] & 0x7f;
|
|
|
if (sh < 64)
|
|
|
- regs->gpr[ra] = regs->gpr[rd] << sh;
|
|
|
+ op->val = regs->gpr[rd] << sh;
|
|
|
else
|
|
|
- regs->gpr[ra] = 0;
|
|
|
+ op->val = 0;
|
|
|
goto logical_done;
|
|
|
|
|
|
case 539: /* srd */
|
|
|
sh = regs->gpr[rb] & 0x7f;
|
|
|
if (sh < 64)
|
|
|
- regs->gpr[ra] = regs->gpr[rd] >> sh;
|
|
|
+ op->val = regs->gpr[rd] >> sh;
|
|
|
else
|
|
|
- regs->gpr[ra] = 0;
|
|
|
+ op->val = 0;
|
|
|
goto logical_done;
|
|
|
|
|
|
case 794: /* srad */
|
|
|
+ op->type = COMPUTE + SETREG + SETXER;
|
|
|
sh = regs->gpr[rb] & 0x7f;
|
|
|
ival = (signed long int) regs->gpr[rd];
|
|
|
- regs->gpr[ra] = ival >> (sh < 64 ? sh : 63);
|
|
|
+ op->val = ival >> (sh < 64 ? sh : 63);
|
|
|
+ op->xerval = regs->xer;
|
|
|
if (ival < 0 && (sh >= 64 || (ival & ((1ul << sh) - 1)) != 0))
|
|
|
- regs->xer |= XER_CA;
|
|
|
+ op->xerval |= XER_CA;
|
|
|
else
|
|
|
- regs->xer &= ~XER_CA;
|
|
|
+ op->xerval &= ~XER_CA;
|
|
|
goto logical_done;
|
|
|
|
|
|
case 826: /* sradi with sh_5 = 0 */
|
|
|
case 827: /* sradi with sh_5 = 1 */
|
|
|
+ op->type = COMPUTE + SETREG + SETXER;
|
|
|
sh = rb | ((instr & 2) << 4);
|
|
|
ival = (signed long int) regs->gpr[rd];
|
|
|
- regs->gpr[ra] = ival >> sh;
|
|
|
+ op->val = ival >> sh;
|
|
|
+ op->xerval = regs->xer;
|
|
|
if (ival < 0 && (ival & ((1ul << sh) - 1)) != 0)
|
|
|
- regs->xer |= XER_CA;
|
|
|
+ op->xerval |= XER_CA;
|
|
|
else
|
|
|
- regs->xer &= ~XER_CA;
|
|
|
+ op->xerval &= ~XER_CA;
|
|
|
goto logical_done;
|
|
|
#endif /* __powerpc64__ */
|
|
|
|
|
@@ -1787,15 +1789,18 @@ int analyse_instr(struct instruction_op *op, struct pt_regs *regs,
|
|
|
|
|
|
logical_done:
|
|
|
if (instr & 1)
|
|
|
- set_cr0(regs, ra);
|
|
|
- goto instr_done;
|
|
|
+ set_cr0(regs, op, ra);
|
|
|
+ logical_done_nocc:
|
|
|
+ op->reg = ra;
|
|
|
+ op->type |= SETREG;
|
|
|
+ return 1;
|
|
|
|
|
|
arith_done:
|
|
|
if (instr & 1)
|
|
|
- set_cr0(regs, rd);
|
|
|
-
|
|
|
- instr_done:
|
|
|
- regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
|
|
|
+ set_cr0(regs, op, rd);
|
|
|
+ compute_done:
|
|
|
+ op->reg = rd;
|
|
|
+ op->type |= SETREG;
|
|
|
return 1;
|
|
|
|
|
|
priv:
|
|
@@ -1886,6 +1891,92 @@ static nokprobe_inline void do_byterev(unsigned long *valp, int size)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Emulate an instruction that can be executed just by updating
|
|
|
+ * fields in *regs.
|
|
|
+ */
|
|
|
+void emulate_update_regs(struct pt_regs *regs, struct instruction_op *op)
|
|
|
+{
|
|
|
+ unsigned long next_pc;
|
|
|
+
|
|
|
+ next_pc = truncate_if_32bit(regs->msr, regs->nip + 4);
|
|
|
+ switch (op->type & INSTR_TYPE_MASK) {
|
|
|
+ case COMPUTE:
|
|
|
+ if (op->type & SETREG)
|
|
|
+ regs->gpr[op->reg] = op->val;
|
|
|
+ if (op->type & SETCC)
|
|
|
+ regs->ccr = op->ccval;
|
|
|
+ if (op->type & SETXER)
|
|
|
+ regs->xer = op->xerval;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case BRANCH:
|
|
|
+ if (op->type & SETLK)
|
|
|
+ regs->link = next_pc;
|
|
|
+ if (op->type & BRTAKEN)
|
|
|
+ next_pc = op->val;
|
|
|
+ if (op->type & DECCTR)
|
|
|
+ --regs->ctr;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case BARRIER:
|
|
|
+ switch (op->type & BARRIER_MASK) {
|
|
|
+ case BARRIER_SYNC:
|
|
|
+ mb();
|
|
|
+ break;
|
|
|
+ case BARRIER_ISYNC:
|
|
|
+ isync();
|
|
|
+ break;
|
|
|
+ case BARRIER_EIEIO:
|
|
|
+ eieio();
|
|
|
+ break;
|
|
|
+ case BARRIER_LWSYNC:
|
|
|
+ asm volatile("lwsync" : : : "memory");
|
|
|
+ break;
|
|
|
+ case BARRIER_PTESYNC:
|
|
|
+ asm volatile("ptesync" : : : "memory");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case MFSPR:
|
|
|
+ switch (op->spr) {
|
|
|
+ case SPRN_XER:
|
|
|
+ regs->gpr[op->reg] = regs->xer & 0xffffffffUL;
|
|
|
+ break;
|
|
|
+ case SPRN_LR:
|
|
|
+ regs->gpr[op->reg] = regs->link;
|
|
|
+ break;
|
|
|
+ case SPRN_CTR:
|
|
|
+ regs->gpr[op->reg] = regs->ctr;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ WARN_ON_ONCE(1);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case MTSPR:
|
|
|
+ switch (op->spr) {
|
|
|
+ case SPRN_XER:
|
|
|
+ regs->xer = op->val & 0xffffffffUL;
|
|
|
+ break;
|
|
|
+ case SPRN_LR:
|
|
|
+ regs->link = op->val;
|
|
|
+ break;
|
|
|
+ case SPRN_CTR:
|
|
|
+ regs->ctr = op->val;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ WARN_ON_ONCE(1);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ WARN_ON_ONCE(1);
|
|
|
+ }
|
|
|
+ regs->nip = next_pc;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Emulate instructions that cause a transfer of control,
|
|
|
* loads and stores, and a few other instructions.
|
|
@@ -1902,8 +1993,12 @@ int emulate_step(struct pt_regs *regs, unsigned int instr)
|
|
|
int i, rd, nb;
|
|
|
|
|
|
r = analyse_instr(&op, regs, instr);
|
|
|
- if (r != 0)
|
|
|
+ if (r < 0)
|
|
|
return r;
|
|
|
+ if (r > 0) {
|
|
|
+ emulate_update_regs(regs, &op);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
|
|
|
err = 0;
|
|
|
size = GETSIZE(op.type);
|