From: Xin Tong <trent.t...@gmail.com> A better looking patch generated by git format-patch.
Implement a rudimentary support for intel RTM. Xbegin always fails to fallback code path. Handle Xbegin, Xend, Xtest, Xabort described in Intel ISA extension manual @ http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf Signed-off-by: Xin Tong <trent.t...@gmail.com> --- target-i386/cpu.c | 8 ++-- target-i386/cpu.h | 8 ++++ target-i386/helper.h | 5 +++ target-i386/misc_helper.c | 19 +++++++++ target-i386/translate.c | 99 +++++++++++++++++++++++++++++++++++------------ 5 files changed, 111 insertions(+), 28 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 3a9b32e..9397665 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -334,7 +334,8 @@ static const char *cpuid_xsave_feature_name[] = { #define TCG_SVM_FEATURES 0 #define TCG_KVM_FEATURES 0 #define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP | \ - CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX) + CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | \ + CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM) /* missing: CPUID_7_0_EBX_FSGSBASE, CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2, CPUID_7_0_EBX_ERMS, CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM, @@ -1101,7 +1102,8 @@ static X86CPUDefinition builtin_x86_defs[] = { .features[FEAT_7_0_EBX] = CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | - CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID, + CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | + CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM, .features[FEAT_XSAVE] = CPUID_XSAVE_XSAVEOPT, .xlevel = 0x8000000A, @@ -1137,7 +1139,7 @@ static X86CPUDefinition builtin_x86_defs[] = { CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | - CPUID_7_0_EBX_SMAP, + CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM, .features[FEAT_XSAVE] = CPUID_XSAVE_XSAVEOPT, .xlevel = 0x8000000A, diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 478450c..2879c3a 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -625,6 +625,14 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; #define EXCP_SYSCALL 0x100 /* only happens in user only emulation for syscall instruction */ +/* intel rtm abort reason bit */ +#define INTEL_RTM_XABORT 0 +#define INTEL_RTM_RETRY 1 +#define INTEL_RTM_CONFLICT 2 +#define INTEL_RTM_OVERFLOW 3 +#define INTEL_RTM_BREAKPOINT 4 +#define INTEL_RTM_ABORT_NEST 5 + /* i386-specific interrupt pending bits. */ #define CPU_INTERRUPT_POLL CPU_INTERRUPT_TGT_EXT_1 #define CPU_INTERRUPT_SMI CPU_INTERRUPT_TGT_EXT_2 diff --git a/target-i386/helper.h b/target-i386/helper.h index 8eb0145..52a97fe 100644 --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -202,6 +202,11 @@ DEF_HELPER_1(enter_mmx, void, env) DEF_HELPER_1(emms, void, env) DEF_HELPER_3(movq, void, env, ptr, ptr) +/* Intel RTM */ +DEF_HELPER_2(xbegin, void, env, i32) +DEF_HELPER_1(xend, void, env) +DEF_HELPER_1(xtest, void, env) + #define SHIFT 0 #include "ops_sse_header.h" #define SHIFT 1 diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c index 4aaf1e4..b5690c9 100644 --- a/target-i386/misc_helper.c +++ b/target-i386/misc_helper.c @@ -600,3 +600,22 @@ void helper_debug(CPUX86State *env) cs->exception_index = EXCP_DEBUG; cpu_loop_exit(cs); } + +void helper_xbegin(CPUX86State *env, uint32_t next_eip_addend) +{ + /* as a degenerate implementation, always fail xbegin. */ + env->eip += next_eip_addend; + env->regs[R_EAX] = ~(1<<INTEL_RTM_OVERFLOW); /* internal buffer overflow */ +} + +void helper_xend(CPUX86State *env) +{ + /* only way to get here is to execute a xend without xbegin. GPF. */ + raise_exception(env, EXCP0D_GPF); +} + +void helper_xtest(CPUX86State *env) +{ + /* xbegin always fails to fallback code, set RTM not active. */ + env->eflags &= ~(1<<6); /* zf */ +} diff --git a/target-i386/translate.c b/target-i386/translate.c index 9ebdf4b..064f35e 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4433,6 +4433,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, next_byte: b = cpu_ldub_code(env, s->pc); s->pc++; + /* Collect prefixes. */ switch (b) { case 0xf3: @@ -5364,20 +5365,45 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_ldst_modrm(env, s, modrm, ot, reg, 1); break; case 0xc6: - case 0xc7: /* mov Ev, Iv */ + case 0xc7: /* mov Ev, Iv or xbegin, xabort*/ ot = mo_b_d(b, dflag); modrm = cpu_ldub_code(env, s->pc++); mod = (modrm >> 6) & 3; - if (mod != 3) { - s->rip_offset = insn_const_size(ot); - gen_lea_modrm(env, s, modrm); - } - val = insn_get(env, s, ot); - tcg_gen_movi_tl(cpu_T[0], val); - if (mod != 3) { - gen_op_st_v(s, ot, cpu_T[0], cpu_A0); - } else { - gen_op_mov_reg_v(ot, (modrm & 7) | REX_B(s), cpu_T[0]); + op = (modrm >> 3) & 7; + switch (op) { + case 0: /* mov Ev, Iv */ + if (mod != 3) { + s->rip_offset = insn_const_size(ot); + gen_lea_modrm(env, s, modrm); + } + val = insn_get(env, s, ot); + tcg_gen_movi_tl(cpu_T[0], val); + if (mod != 3) { + gen_op_st_v(s, ot, cpu_T[0], cpu_A0); + } else { + gen_op_mov_reg_v(ot, (modrm & 7) | REX_B(s), cpu_T[0]); + } + break; + case 7: /* xbegin or xabort */ + if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_RTM) || + (s->prefix & PREFIX_LOCK)) { + goto illegal_op; + } + val = insn_get(env, s, ot); + if (b == 0xc6) { + /* xbegin always fails to fallback address, the only way to get + * here is to execute a xabort without xbegin, which will treat + * xabort as a NOP. + */ + break; + } + if (b == 0xc7) { + tcg_gen_movi_i32(cpu_tmp2_i32, val); + gen_helper_xbegin(cpu_env, cpu_tmp2_i32); + break; + } + default: + goto illegal_op; } break; case 0x8a: @@ -7349,22 +7375,45 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_helper_stgi(cpu_env); } break; - case 5: /* CLGI */ - if (!(s->flags & HF_SVME_MASK) || !s->pe) - goto illegal_op; - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - break; - } else { - gen_helper_clgi(cpu_env); + case 5: /* XEND or CLGI */ + if (op == 0x2) { + if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_RTM) || + (s->prefix & (PREFIX_REPZ | PREFIX_REPNZ + | PREFIX_LOCK | PREFIX_DATA))) { + goto illegal_op; + } + gen_helper_xend(cpu_env); + } + if (op == 0x3) { + if (!(s->flags & HF_SVME_MASK) || !s->pe) { + goto illegal_op; + } + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + break; + } else { + gen_helper_clgi(cpu_env); + } } break; - case 6: /* SKINIT */ - if ((!(s->flags & HF_SVME_MASK) && - !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) || - !s->pe) - goto illegal_op; - gen_helper_skinit(cpu_env); + case 6: /* XTEST or SKINIT */ + if (op == 0x2) { + if (!(s->cpuid_7_0_ebx_features & + (CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM)) || + (s->prefix & (PREFIX_REPZ | PREFIX_REPNZ + | PREFIX_LOCK | PREFIX_DATA))) { + goto illegal_op; + } + gen_helper_xtest(cpu_env); + } + if (op == 0x3) { + if ((!(s->flags & HF_SVME_MASK) && + !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) || + !s->pe) { + goto illegal_op; + } + gen_helper_skinit(cpu_env); + } break; case 7: /* INVLPGA */ if (!(s->flags & HF_SVME_MASK) || !s->pe) -- 1.9.1