diff options
Diffstat (limited to 'target-i386')
-rw-r--r-- | target-i386/helper.c | 26 | ||||
-rw-r--r-- | target-i386/helper.h | 3 | ||||
-rw-r--r-- | target-i386/translate.c | 25 |
3 files changed, 47 insertions, 7 deletions
diff --git a/target-i386/helper.c b/target-i386/helper.c index 0317f9ca1d..4562a16a83 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1879,8 +1879,8 @@ void helper_cmpxchg8b(target_ulong a0) eflags = cc_table[CC_OP].compute_all(); d = ldq(a0); - if (d == (((uint64_t)EDX << 32) | EAX)) { - stq(a0, ((uint64_t)ECX << 32) | EBX); + if (d == (((uint64_t)EDX << 32) | (uint32_t)EAX)) { + stq(a0, ((uint64_t)ECX << 32) | (uint32_t)EBX); eflags |= CC_Z; } else { EDX = (uint32_t)(d >> 32); @@ -1890,6 +1890,28 @@ void helper_cmpxchg8b(target_ulong a0) CC_SRC = eflags; } +#ifdef TARGET_X86_64 +void helper_cmpxchg16b(target_ulong a0) +{ + uint64_t d0, d1; + int eflags; + + eflags = cc_table[CC_OP].compute_all(); + d0 = ldq(a0); + d1 = ldq(a0 + 8); + if (d0 == EAX && d1 == EDX) { + stq(a0, EBX); + stq(a0 + 8, ECX); + eflags |= CC_Z; + } else { + EDX = d1; + EAX = d0; + eflags &= ~CC_Z; + } + CC_SRC = eflags; +} +#endif + void helper_single_step(void) { env->dr[6] |= 0x4000; diff --git a/target-i386/helper.h b/target-i386/helper.h index 9df198a0e4..9bbf4fc180 100644 --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -75,6 +75,9 @@ void helper_boundl(target_ulong a0, int v); void helper_rsm(void); void helper_into(int next_eip_addend); void helper_cmpxchg8b(target_ulong a0); +#ifdef TARGET_X86_64 +void helper_cmpxchg16b(target_ulong a0); +#endif void helper_single_step(void); void helper_cpuid(void); void helper_rdtsc(void); diff --git a/target-i386/translate.c b/target-i386/translate.c index 85b3d6db4a..6e55930131 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4333,11 +4333,26 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) mod = (modrm >> 6) & 3; if ((mod == 3) || ((modrm & 0x38) != 0x8)) goto illegal_op; - gen_jmp_im(pc_start - s->cs_base); - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - tcg_gen_helper_0_1(helper_cmpxchg8b, cpu_A0); +#ifdef TARGET_X86_64 + if (dflag == 2) { + if (!(s->cpuid_ext_features & CPUID_EXT_CX16)) + goto illegal_op; + gen_jmp_im(pc_start - s->cs_base); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + tcg_gen_helper_0_1(helper_cmpxchg16b, cpu_A0); + } else +#endif + { + if (!(s->cpuid_features & CPUID_CX8)) + goto illegal_op; + gen_jmp_im(pc_start - s->cs_base); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + tcg_gen_helper_0_1(helper_cmpxchg8b, cpu_A0); + } s->cc_op = CC_OP_EFLAGS; break; |