Commit 3cdfcbfd authored by Paul Mackerras's avatar Paul Mackerras Committed by Michael Ellerman

powerpc: Change analyse_instr so it doesn't modify *regs

The analyse_instr function currently doesn't just work out what an
instruction does, it also executes those instructions whose effect
is only to update CPU registers that are stored in struct pt_regs.
This is undesirable because optprobes uses analyse_instr to work out
if an instruction could be successfully emulated in future.

This changes analyse_instr so it doesn't modify *regs; instead it
stores information in the instruction_op structure to indicate what
registers (GPRs, CR, XER, LR) would be set and what value they would
be set to.  A companion function called emulate_update_regs() can
then use that information to update a pt_regs struct appropriately.

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