From c9cfe8f9fb21f086e24b3a8f7ccd9c06e4d8d9d6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 2 Jul 2015 15:21:23 +0100 Subject: [PATCH] target-i386: Implement XSAVEOPT Signed-off-by: Richard Henderson --- target-i386/cpu.c | 6 ++++-- target-i386/fpu_helper.c | 29 +++++++++++++++++++++++------ target-i386/helper.h | 1 + target-i386/translate.c | 18 +++++++++++++++--- 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index fb8a646a20..dcc6e9ca5e 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -366,7 +366,9 @@ static const char *cpuid_6_feature_name[] = { #define TCG_7_0_ECX_FEATURES 0 #define TCG_APM_FEATURES 0 #define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT - +#define TCG_XSAVE_FEATURES (CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1) + /* missing: + CPUID_XSAVE_XSAVEC, CPUID_XSAVE_XSAVES */ typedef struct FeatureWordInfo { const char **feat_names; @@ -440,7 +442,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { .cpuid_eax = 0xd, .cpuid_needs_ecx = true, .cpuid_ecx = 1, .cpuid_reg = R_EAX, - .tcg_features = 0, + .tcg_features = TCG_XSAVE_FEATURES, }, [FEAT_6_EAX] = { .feat_names = cpuid_6_feature_name, diff --git a/target-i386/fpu_helper.c b/target-i386/fpu_helper.c index 159e1df185..9750cd2206 100644 --- a/target-i386/fpu_helper.c +++ b/target-i386/fpu_helper.c @@ -1197,9 +1197,9 @@ static uint64_t get_xinuse(CPUX86State *env) return -1; } -void helper_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm) +static void do_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm, + uint64_t inuse, uint64_t opt, uintptr_t ra) { - uintptr_t ra = GETPC(); uint64_t old_bv, new_bv; /* The OS must have enabled XSAVE. */ @@ -1214,21 +1214,36 @@ void helper_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm) /* Never save anything not enabled by XCR0. */ rfbm &= env->xcr0; + opt &= rfbm; - if (rfbm & XSTATE_FP) { + if (opt & XSTATE_FP) { do_xsave_fpu(env, ptr, ra); } if (rfbm & XSTATE_SSE) { + /* Note that saving MXCSR is not suppressed by XSAVEOPT. */ do_xsave_mxcsr(env, ptr, ra); + } + if (opt & XSTATE_SSE) { do_xsave_sse(env, ptr, ra); } /* Update the XSTATE_BV field. */ old_bv = cpu_ldq_data_ra(env, ptr + 512, ra); - new_bv = (old_bv & ~rfbm) | (get_xinuse(env) & rfbm); + new_bv = (old_bv & ~rfbm) | (inuse & rfbm); cpu_stq_data_ra(env, ptr + 512, new_bv, ra); } +void helper_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm) +{ + do_xsave(env, ptr, rfbm, get_xinuse(env), -1, GETPC()); +} + +void helper_xsaveopt(CPUX86State *env, target_ulong ptr, uint64_t rfbm) +{ + uint64_t inuse = get_xinuse(env); + do_xsave(env, ptr, rfbm, inuse, inuse, GETPC()); +} + static void do_xrstor_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra) { int i, fpus, fptag; @@ -1369,8 +1384,10 @@ uint64_t helper_xgetbv(CPUX86State *env, uint32_t ecx) case 0: return env->xcr0; case 1: - /* FIXME: #GP if !CPUID.(EAX=0DH,ECX=1):EAX.XG1[bit 2]. */ - return env->xcr0 & get_xinuse(env); + if (env->features[FEAT_XSAVE] & CPUID_XSAVE_XGETBV1) { + return env->xcr0 & get_xinuse(env); + } + break; } raise_exception_ra(env, EXCP0D_GPF, GETPC()); } diff --git a/target-i386/helper.h b/target-i386/helper.h index 9dfc735429..9a83955868 100644 --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -188,6 +188,7 @@ DEF_HELPER_3(frstor, void, env, tl, int) DEF_HELPER_FLAGS_2(fxsave, TCG_CALL_NO_WG, void, env, tl) DEF_HELPER_FLAGS_2(fxrstor, TCG_CALL_NO_WG, void, env, tl) DEF_HELPER_FLAGS_3(xsave, TCG_CALL_NO_WG, void, env, tl, i64) +DEF_HELPER_FLAGS_3(xsaveopt, TCG_CALL_NO_WG, void, env, tl, i64) DEF_HELPER_FLAGS_3(xrstor, TCG_CALL_NO_WG, void, env, tl, i64) DEF_HELPER_FLAGS_2(xgetbv, TCG_CALL_NO_WG, i64, env, i32) DEF_HELPER_FLAGS_3(xsetbv, TCG_CALL_NO_WG, void, env, i32, i64) diff --git a/target-i386/translate.c b/target-i386/translate.c index 7571e850d5..ce2ffc1bca 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -127,6 +127,7 @@ typedef struct DisasContext { int cpuid_ext2_features; int cpuid_ext3_features; int cpuid_7_0_ebx_features; + int cpuid_xsave_features; } DisasContext; static void gen_eob(DisasContext *s); @@ -7634,7 +7635,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_helper_xrstor(cpu_env, cpu_A0, cpu_tmp1_i64); break; - CASE_MEM_OP(6): /* clwb */ + CASE_MEM_OP(6): /* xsaveopt / clwb */ if (prefixes & PREFIX_LOCK) { goto illegal_op; } @@ -7644,9 +7645,19 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, goto illegal_op; } gen_nop_modrm(env, s, modrm); - break; + } else { + /* xsaveopt */ + if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0 + || (s->cpuid_xsave_features & CPUID_XSAVE_XSAVEOPT) == 0 + || (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))) { + goto illegal_op; + } + gen_lea_modrm(env, s, modrm); + tcg_gen_concat_tl_i64(cpu_tmp1_i64, cpu_regs[R_EAX], + cpu_regs[R_EDX]); + gen_helper_xsaveopt(cpu_env, cpu_A0, cpu_tmp1_i64); } - goto illegal_op; + break; CASE_MEM_OP(7): /* clflush / clflushopt */ if (prefixes & PREFIX_LOCK) { @@ -7868,6 +7879,7 @@ void gen_intermediate_code(CPUX86State *env, TranslationBlock *tb) dc->cpuid_ext2_features = env->features[FEAT_8000_0001_EDX]; dc->cpuid_ext3_features = env->features[FEAT_8000_0001_ECX]; dc->cpuid_7_0_ebx_features = env->features[FEAT_7_0_EBX]; + dc->cpuid_xsave_features = env->features[FEAT_XSAVE]; #ifdef TARGET_X86_64 dc->lma = (flags >> HF_LMA_SHIFT) & 1; dc->code64 = (flags >> HF_CS64_SHIFT) & 1; -- 2.11.0