diff options
author | Richard Henderson <rth@twiddle.net> | 2015-11-18 12:55:47 +0100 |
---|---|---|
committer | Richard Henderson <rth@twiddle.net> | 2016-02-15 14:50:00 +1100 |
commit | 07929f2ab2ab9c9e01d4ae79f48f2b2476b715c8 (patch) | |
tree | 5df97c0cda565f1a3156b6dd6c60a8ea0902cf30 /target-i386 | |
parent | a114d25d5b42600871d75929604c0b9fcc448ec0 (diff) | |
download | qemu-07929f2ab2ab9c9e01d4ae79f48f2b2476b715c8.zip qemu-07929f2ab2ab9c9e01d4ae79f48f2b2476b715c8.tar.gz qemu-07929f2ab2ab9c9e01d4ae79f48f2b2476b715c8.tar.bz2 |
target-i386: Implement FSGSBASE
Signed-off-by: Richard Henderson <rth@twiddle.net>
Diffstat (limited to 'target-i386')
-rw-r--r-- | target-i386/cpu.c | 7 | ||||
-rw-r--r-- | target-i386/helper.h | 1 | ||||
-rw-r--r-- | target-i386/int_helper.c | 10 | ||||
-rw-r--r-- | target-i386/translate.c | 34 |
4 files changed, 50 insertions, 2 deletions
diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 063c8fb..0af43a3 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -358,9 +358,9 @@ static const char *cpuid_6_feature_name[] = { #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_PCOMMIT | CPUID_7_0_EBX_CLFLUSHOPT | \ - CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_MPX) + CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_FSGSBASE) /* missing: - CPUID_7_0_EBX_FSGSBASE, CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2, + 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, CPUID_7_0_EBX_RDSEED */ #define TCG_7_0_ECX_FEATURES 0 @@ -2730,6 +2730,9 @@ static void x86_cpu_reset(CPUState *s) if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) { cr4 |= CR4_OSFXSR_MASK | CR4_OSXSAVE_MASK; } + if (env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_FSGSBASE) { + cr4 |= CR4_FSGSBASE_MASK; + } #endif env->xcr0 = xcr0; diff --git a/target-i386/helper.h b/target-i386/helper.h index 60a615f..e33451a 100644 --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -15,6 +15,7 @@ DEF_HELPER_2(idivl_EAX, void, env, tl) DEF_HELPER_2(divq_EAX, void, env, tl) DEF_HELPER_2(idivq_EAX, void, env, tl) #endif +DEF_HELPER_FLAGS_2(cr4_testbit, TCG_CALL_NO_WG, void, env, i32) DEF_HELPER_FLAGS_2(bndck, TCG_CALL_NO_WG, void, env, i32) DEF_HELPER_FLAGS_3(bndldx32, TCG_CALL_NO_WG, i64, env, tl, tl) diff --git a/target-i386/int_helper.c b/target-i386/int_helper.c index 9d0d21e..cf5bbb0 100644 --- a/target-i386/int_helper.c +++ b/target-i386/int_helper.c @@ -470,3 +470,13 @@ target_ulong helper_pext(target_ulong src, target_ulong mask) #include "shift_helper_template.h" #undef SHIFT #endif + +/* Test that BIT is enabled in CR4. If not, raise an illegal opcode + exception. This reduces the requirements for rare CR4 bits being + mapped into HFLAGS. */ +void helper_cr4_testbit(CPUX86State *env, uint32_t bit) +{ + if (unlikely((env->cr[4] & bit) == 0)) { + raise_exception_ra(env, EXCP06_ILLOP, GETPC()); + } +} diff --git a/target-i386/translate.c b/target-i386/translate.c index ad7053e..9171929 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -7902,6 +7902,40 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_nop_modrm(env, s, modrm); break; + case 0xc0 ... 0xc7: /* rdfsbase (f3 0f ae /0) */ + case 0xc8 ... 0xc8: /* rdgsbase (f3 0f ae /1) */ + case 0xd0 ... 0xd7: /* wrfsbase (f3 0f ae /2) */ + case 0xd8 ... 0xd8: /* wrgsbase (f3 0f ae /3) */ + if (CODE64(s) + && (prefixes & PREFIX_REPZ) + && !(prefixes & PREFIX_LOCK) + && (s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_FSGSBASE)) { + TCGv base, treg, src, dst; + + /* Preserve hflags bits by testing CR4 at runtime. */ + tcg_gen_movi_i32(cpu_tmp2_i32, CR4_FSGSBASE_MASK); + gen_helper_cr4_testbit(cpu_env, cpu_tmp2_i32); + + base = cpu_seg_base[modrm & 8 ? R_GS : R_FS]; + treg = cpu_regs[(modrm & 7) | REX_B(s)]; + + if (modrm & 0x10) { + /* wr*base */ + dst = base, src = treg; + } else { + /* rd*base */ + dst = treg, src = base; + } + + if (s->dflag == MO_32) { + tcg_gen_ext32u_tl(dst, src); + } else { + tcg_gen_mov_tl(dst, src); + } + break; + } + goto illegal_op; + case 0xf8: /* sfence / pcommit */ if (prefixes & PREFIX_DATA) { /* pcommit */ |