diff options
author | Richard Henderson <rth@twiddle.net> | 2015-07-02 15:21:23 +0100 |
---|---|---|
committer | Richard Henderson <rth@twiddle.net> | 2016-02-13 07:59:59 +1100 |
commit | c9cfe8f9fb21f086e24b3a8f7ccd9c06e4d8d9d6 (patch) | |
tree | 802459173e6c82c15335ed7626b1c1b6c4682046 /target-i386/fpu_helper.c | |
parent | 19dc85dba23c0db1ca932c62e453c37e00761628 (diff) |
target-i386: Implement XSAVEOPT
Signed-off-by: Richard Henderson <rth@twiddle.net>
Diffstat (limited to 'target-i386/fpu_helper.c')
-rw-r--r-- | target-i386/fpu_helper.c | 29 |
1 files changed, 23 insertions, 6 deletions
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()); } |