From ad90d7a699cb7f4ade5097ead2b5a9ab8f6781e5 Mon Sep 17 00:00:00 2001 From: Petar Jovanovic Date: Mon, 13 Mar 2017 17:50:25 +0000 Subject: [PATCH] mips: emulate LL/SC w/ guest_LLaddr and guest_LLdata Improve LL/SC emulation with introduction of LLaddr and LLdata in the guest state. LLaddr gets invalidated when the threads switch. More info at KDE #344524. This patch should fix the issue. Currently, this is effective for Cavium boards only. Patch by Maran Pakkirisamy. git-svn-id: svn://svn.valgrind.org/vex/trunk@3316 --- VEX/priv/guest_mips_defs.h | 6 ++ VEX/priv/guest_mips_helpers.c | 6 ++ VEX/priv/guest_mips_toIR.c | 167 ++++++++++++++++++++++++++-------- VEX/pub/libvex_guest_mips32.h | 5 +- VEX/pub/libvex_guest_mips64.h | 5 +- 5 files changed, 147 insertions(+), 42 deletions(-) diff --git a/VEX/priv/guest_mips_defs.h b/VEX/priv/guest_mips_defs.h index 84cfb695a3..28b96b0893 100644 --- a/VEX/priv/guest_mips_defs.h +++ b/VEX/priv/guest_mips_defs.h @@ -94,6 +94,12 @@ typedef enum { SUBS, SUBD, DIVS } flt_op; +#if defined (_MIPSEL) + #define MIPS_IEND Iend_LE +#else + #define MIPS_IEND Iend_BE +#endif + #if defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev >= 2)) extern UInt mips32_dirtyhelper_rdhwr ( UInt rt, UInt rd ); extern ULong mips64_dirtyhelper_rdhwr ( ULong rt, ULong rd ); diff --git a/VEX/priv/guest_mips_helpers.c b/VEX/priv/guest_mips_helpers.c index 07dccec1e1..4f0c1c882f 100644 --- a/VEX/priv/guest_mips_helpers.c +++ b/VEX/priv/guest_mips_helpers.c @@ -167,6 +167,9 @@ void LibVEX_GuestMIPS32_initialise( /*OUT*/ VexGuestMIPS32State * vex_state) vex_state->guest_CP0_status = 0; + vex_state->guest_LLaddr = 0xFFFFFFFF; + vex_state->guest_LLdata = 0; + /* MIPS32 DSP ASE(r2) specific registers */ vex_state->guest_DSPControl = 0; /* DSPControl register */ vex_state->guest_ac0 = 0; /* Accumulator 0 */ @@ -276,6 +279,9 @@ void LibVEX_GuestMIPS64_initialise ( /*OUT*/ VexGuestMIPS64State * vex_state ) vex_state->guest_COND = 0; vex_state->guest_CP0_status = MIPS_CP0_STATUS_FR; + + vex_state->guest_LLaddr = 0xFFFFFFFFFFFFFFFFULL; + vex_state->guest_LLdata = 0; } /*-----------------------------------------------------------*/ diff --git a/VEX/priv/guest_mips_toIR.c b/VEX/priv/guest_mips_toIR.c index 2ed6b0e3e2..77cd1f29e4 100644 --- a/VEX/priv/guest_mips_toIR.c +++ b/VEX/priv/guest_mips_toIR.c @@ -549,6 +549,9 @@ static inline UInt getUInt(const UChar * p) dres.jk_StopHere = Ijk_SigILL; \ dres.whatNext = Dis_StopHere; +#define LLADDR_INVALID \ + (mode64 ? mkU64(0xFFFFFFFFFFFFFFFFULL) : mkU32(0xFFFFFFFF)) + /*------------------------------------------------------------*/ /*--- Field helpers ---*/ /*------------------------------------------------------------*/ @@ -1087,6 +1090,22 @@ static IRExpr *getFCSR(void) return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_FCSR), Ity_I32); } +static IRExpr *getLLaddr(void) +{ + if (mode64) + return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_LLaddr), Ity_I64); + else + return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_LLaddr), Ity_I32); +} + +static IRExpr *getLLdata(void) +{ + if (mode64) + return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_LLdata), Ity_I64); + else + return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_LLdata), Ity_I32); +} + /* Get byte from register reg, byte pos from 0 to 3 (or 7 for MIPS64) . */ static IRExpr *getByteFromReg(UInt reg, UInt byte_pos) { @@ -1109,6 +1128,22 @@ static void putFCSR(IRExpr * e) stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_FCSR), e)); } +static void putLLaddr(IRExpr * e) +{ + if (mode64) + stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_LLaddr), e)); + else + stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_LLaddr), e)); +} + +static void putLLdata(IRExpr * e) +{ + if (mode64) + stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_LLdata), e)); + else + stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_LLdata), e)); +} + /* fs - fpu source register number. inst - fpu instruction that needs to be executed. sz32 - size of source register. @@ -1339,6 +1374,16 @@ static IRExpr *mkWidenFromF32(IRType ty, IRExpr * src) return src; } +/* Convenience function to move to next instruction on condition. */ +static void mips_next_insn_if(IRExpr *condition) { + vassert(typeOfIRExpr(irsb->tyenv, condition) == Ity_I1); + + stmt(IRStmt_Exit(condition, Ijk_Boring, + mode64 ? IRConst_U64(guest_PC_curr_instr + 4) : + IRConst_U32(guest_PC_curr_instr + 4), + OFFB_PC)); +} + static IRExpr *dis_branch_likely(IRExpr * guard, UInt imm) { ULong branch_offset; @@ -16935,64 +16980,106 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, putIReg(rt, mkWidenFrom32(ty, load(Ity_I32, mkexpr(t1)), False)); break; - case 0x30: /* LL / LWC0 */ + case 0x30: /* LL */ DIP("ll r%u, %u(r%u)", rt, imm, rs); LOAD_STORE_PATTERN; - - t2 = newTemp(Ity_I32); -#if defined (_MIPSEL) - stmt(IRStmt_LLSC(Iend_LE, t2, mkexpr(t1), NULL /* this is a load */ )); -#elif defined (_MIPSEB) - stmt(IRStmt_LLSC(Iend_BE, t2, mkexpr(t1), NULL /* this is a load */ )); -#endif - if (mode64) - putIReg(rt, unop(Iop_32Sto64, mkexpr(t2))); - else + if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) { + t2 = newTemp(ty); + assign(t2, mkWidenFrom32(ty, load(Ity_I32, mkexpr(t1)), True)); + putLLaddr(mkexpr(t1)); + putLLdata(mkexpr(t2)); putIReg(rt, mkexpr(t2)); + } else { + t2 = newTemp(Ity_I32); + stmt(IRStmt_LLSC(MIPS_IEND, t2, mkexpr(t1), NULL)); + putIReg(rt, mkWidenFrom32(ty, mkexpr(t2), True)); + } break; case 0x34: /* Load Linked Doubleword - LLD; MIPS64 */ DIP("lld r%u, %u(r%u)", rt, imm, rs); - LOAD_STORE_PATTERN; - - t2 = newTemp(Ity_I64); -#if defined (_MIPSEL) - stmt(IRStmt_LLSC - (Iend_LE, t2, mkexpr(t1), NULL /* this is a load */ )); -#elif defined (_MIPSEB) - stmt(IRStmt_LLSC - (Iend_BE, t2, mkexpr(t1), NULL /* this is a load */ )); -#endif - - putIReg(rt, mkexpr(t2)); + if (mode64) { + LOAD_STORE_PATTERN; + t2 = newTemp(Ity_I64); + if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) { + assign(t2, load(Ity_I64, mkexpr(t1))); + putLLaddr(mkexpr(t1)); + putLLdata(mkexpr(t2)); + } else { + stmt(IRStmt_LLSC(MIPS_IEND, t2, mkexpr(t1), NULL)); + } + putIReg(rt, mkexpr(t2)); + } else { + ILLEGAL_INSTRUCTON; + } break; - case 0x38: /* SC / SWC0 */ + case 0x38: /* SC */ DIP("sc r%u, %u(r%u)", rt, imm, rs); + t2 = newTemp(Ity_I1); LOAD_STORE_PATTERN; + if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) { + t3 = newTemp(Ity_I32); + assign(t2, binop(mode64 ? Iop_CmpNE64 : Iop_CmpNE32, + mkexpr(t1), getLLaddr())); + assign(t3, mkNarrowTo32(ty, getIReg(rt))); + putLLaddr(LLADDR_INVALID); + putIReg(rt, getIReg(0)); - t2 = newTemp(Ity_I1); -#if defined (_MIPSEL) - stmt(IRStmt_LLSC(Iend_LE, t2, mkexpr(t1), mkNarrowTo32(ty, getIReg(rt)))); -#elif defined (_MIPSEB) - stmt(IRStmt_LLSC(Iend_BE, t2, mkexpr(t1), mkNarrowTo32(ty, getIReg(rt)))); -#endif + mips_next_insn_if(mkexpr(t2)); + + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + + assign(t5, mkNarrowTo32(ty, getLLdata())); + + stmt(IRStmt_CAS(mkIRCAS(IRTemp_INVALID, t4, /* old_mem */ + MIPS_IEND, mkexpr(t1), /* addr */ + NULL, mkexpr(t5), /* expected value */ + NULL, mkexpr(t3) /* new value */))); - putIReg(rt, unop(mode64 ? Iop_1Uto64 : Iop_1Uto32, mkexpr(t2))); + putIReg(rt, unop(mode64 ? Iop_1Uto64 : Iop_1Uto32, + binop(Iop_CmpEQ32, mkexpr(t4), mkexpr(t5)))); + } else { + stmt(IRStmt_LLSC(MIPS_IEND, t2, mkexpr(t1), + mkNarrowTo32(ty, getIReg(rt)))); + putIReg(rt, unop(mode64 ? Iop_1Uto64 : Iop_1Uto32, mkexpr(t2))); + } break; case 0x3C: /* Store Conditional Doubleword - SCD; MIPS64 */ - DIP("sdc r%u, %u(r%u)", rt, imm, rs); - LOAD_STORE_PATTERN; + DIP("scd r%u, %u(r%u)", rt, imm, rs); + if (mode64) { + t2 = newTemp(Ity_I1); + LOAD_STORE_PATTERN; + if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) { + t3 = newTemp(Ity_I64); + assign(t2, binop(Iop_CmpNE64, mkexpr(t1), getLLaddr())); + assign(t3, getIReg(rt)); + putLLaddr(LLADDR_INVALID); + putIReg(rt, getIReg(0)); - t2 = newTemp(Ity_I1); -#if defined (_MIPSEL) - stmt(IRStmt_LLSC(Iend_LE, t2, mkexpr(t1), getIReg(rt))); -#elif defined (_MIPSEB) - stmt(IRStmt_LLSC(Iend_BE, t2, mkexpr(t1), getIReg(rt))); -#endif + mips_next_insn_if(mkexpr(t2)); - putIReg(rt, unop(Iop_1Uto64, mkexpr(t2))); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + + assign(t5, getLLdata()); + + stmt(IRStmt_CAS(mkIRCAS(IRTemp_INVALID, t4, /* old_mem */ + MIPS_IEND, mkexpr(t1), /* addr */ + NULL, mkexpr(t5), /* expected value */ + NULL, mkexpr(t3) /* new value */))); + + putIReg(rt, unop(Iop_1Uto64, + binop(Iop_CmpEQ64, mkexpr(t4), mkexpr(t5)))); + } else { + stmt(IRStmt_LLSC(MIPS_IEND, t2, mkexpr(t1), getIReg(rt))); + putIReg(rt, unop(Iop_1Uto64, mkexpr(t2))); + } + } else { + ILLEGAL_INSTRUCTON; + } break; case 0x37: /* Load Doubleword - LD; MIPS64 */ diff --git a/VEX/pub/libvex_guest_mips32.h b/VEX/pub/libvex_guest_mips32.h index dd787486d4..1349b14657 100644 --- a/VEX/pub/libvex_guest_mips32.h +++ b/VEX/pub/libvex_guest_mips32.h @@ -151,7 +151,10 @@ typedef /* 488 */ UInt guest_CP0_status; - /* 492 */ UInt _padding2; + /* 492 */ UInt guest_LLaddr; + /* 496 */ UInt guest_LLdata; + + /* 500 */ UInt _padding2[3]; } VexGuestMIPS32State; /*---------------------------------------------------------------*/ /*--- Utility functions for MIPS32 guest stuff. ---*/ diff --git a/VEX/pub/libvex_guest_mips64.h b/VEX/pub/libvex_guest_mips64.h index 7584320fd0..c68f43bd88 100644 --- a/VEX/pub/libvex_guest_mips64.h +++ b/VEX/pub/libvex_guest_mips64.h @@ -148,7 +148,10 @@ typedef /* 608 */ ULong guest_NRADDR; - /* 616 */ ULong _padding2; + /* 616 */ ULong guest_LLaddr; + /* 624 */ ULong guest_LLdata; + + /* 632 */ ULong _padding2; } VexGuestMIPS64State; /*---------------------------------------------------------------*/ -- 2.47.2