@@ -78,9 +78,11 @@ DEF_HELPER_4(cmpxchgb, tl, env, tl, tl, tl)
DEF_HELPER_4(cmpxchgw, tl, env, tl, tl, tl)
DEF_HELPER_4(cmpxchgl, tl, env, tl, tl, tl)
DEF_HELPER_2(cmpxchg8b, void, env, tl)
+DEF_HELPER_2(cmpxchg8b_unlocked, void, env, tl)
#ifdef TARGET_X86_64
DEF_HELPER_4(cmpxchgq, tl, env, tl, tl, tl)
DEF_HELPER_2(cmpxchg16b, void, env, tl)
+DEF_HELPER_2(cmpxchg16b_unlocked, void, env, tl)
#endif
DEF_HELPER_1(single_step, void, env)
DEF_HELPER_1(cpuid, void, env)
@@ -71,7 +71,7 @@ GEN_CMPXCHG_HELPER(cmpxchgq)
#endif
#undef GEN_CMPXCHG_HELPER
-void helper_cmpxchg8b(CPUX86State *env, target_ulong a0)
+void helper_cmpxchg8b_unlocked(CPUX86State *env, target_ulong a0)
{
uint64_t d;
int eflags;
@@ -92,8 +92,36 @@ void helper_cmpxchg8b(CPUX86State *env, target_ulong a0)
CC_SRC = eflags;
}
+void helper_cmpxchg8b(CPUX86State *env, target_ulong a0)
+{
+ uint64_t d;
+ uint64_t old;
+ uint64_t new;
+ int eflags;
+
+ old = env->regs[R_EDX];
+ old <<= 32;
+ old |= env->regs[R_EAX];
+
+ new = env->regs[R_ECX];
+ new <<= 32;
+ new |= env->regs[R_EBX];
+
+ eflags = cpu_cc_compute_all(env, CC_OP);
+
+ d = cpu_cmpxchgq_data_ra(env, a0, old, new, GETPC());
+ if (d == old) {
+ eflags |= CC_Z;
+ } else {
+ env->regs[R_EDX] = (uint32_t)(d >> 32);
+ env->regs[R_EAX] = (uint32_t)d;
+ eflags &= ~CC_Z;
+ }
+ CC_SRC = eflags;
+}
+
#ifdef TARGET_X86_64
-void helper_cmpxchg16b(CPUX86State *env, target_ulong a0)
+void helper_cmpxchg16b_unlocked(CPUX86State *env, target_ulong a0)
{
uint64_t d0, d1;
int eflags;
@@ -118,6 +146,28 @@ void helper_cmpxchg16b(CPUX86State *env, target_ulong a0)
}
CC_SRC = eflags;
}
+
+void helper_cmpxchg16b(CPUX86State *env, target_ulong a0)
+{
+ uint64_t d0 = env->regs[R_EAX];
+ uint64_t d1 = env->regs[R_EDX];
+ int eflags;
+
+ if ((a0 & 0xf) != 0) {
+ raise_exception_ra(env, EXCP0D_GPF, GETPC());
+ }
+ eflags = cpu_cc_compute_all(env, CC_OP);
+
+ if (cpu_cmpxchgo_data_ra(env, a0, &d0, &d1, env->regs[R_EBX],
+ env->regs[R_ECX], GETPC())) {
+ eflags |= CC_Z;
+ } else {
+ env->regs[R_EDX] = d1;
+ env->regs[R_EAX] = d0;
+ eflags &= ~CC_Z;
+ }
+ CC_SRC = eflags;
+}
#endif
void helper_boundw(CPUX86State *env, target_ulong a0, int v)
@@ -5166,14 +5166,22 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
if (!(s->cpuid_ext_features & CPUID_EXT_CX16))
goto illegal_op;
gen_lea_modrm(env, s, modrm);
- gen_helper_cmpxchg16b(cpu_env, cpu_A0);
+ if (s->prefix & PREFIX_LOCK) {
+ gen_helper_cmpxchg16b(cpu_env, cpu_A0);
+ } else {
+ gen_helper_cmpxchg16b_unlocked(cpu_env, cpu_A0);
+ }
} else
#endif
{
if (!(s->cpuid_features & CPUID_CX8))
goto illegal_op;
gen_lea_modrm(env, s, modrm);
- gen_helper_cmpxchg8b(cpu_env, cpu_A0);
+ if (s->prefix & PREFIX_LOCK) {
+ gen_helper_cmpxchg8b(cpu_env, cpu_A0);
+ } else {
+ gen_helper_cmpxchg8b_unlocked(cpu_env, cpu_A0);
+ }
}
set_cc_op(s, CC_OP_EFLAGS);
break;
For consistency, rename the existing cmpxchg8b/16b helpers by appending _unlocked to them, to stress that they are not atomic. Signed-off-by: Emilio G. Cota <cota@braap.org> --- target-i386/helper.h | 2 ++ target-i386/mem_helper.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++-- target-i386/translate.c | 12 +++++++++-- 3 files changed, 64 insertions(+), 4 deletions(-)