diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c index f7e4586cab..864421864e 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -1146,6 +1146,8 @@ long arch_do_domctl( { v->arch.xcr0 = _xcr0; v->arch.xcr0_accum = _xcr0_accum; + if ( _xcr0_accum & XSTATE_NONLAZY ) + v->arch.nonlazy_xstate_used = 1; memcpy(v->arch.xsave_area, _xsave_area, evc->size - 2 * sizeof(uint64_t)); } diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index b76f041eb0..0094c62cb3 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -1119,6 +1119,8 @@ static int hvm_load_cpu_xsave_states(struct domain *d, hvm_domain_context_t *h) v->arch.xcr0 = ctxt->xcr0; v->arch.xcr0_accum = ctxt->xcr0_accum; + if ( ctxt->xcr0_accum & XSTATE_NONLAZY ) + v->arch.nonlazy_xstate_used = 1; memcpy(v->arch.xsave_area, &ctxt->save_area, desc->length - offsetof(struct hvm_hw_cpu_xsave, save_area)); diff --git a/xen/arch/x86/i387.c b/xen/arch/x86/i387.c index 7649274701..bd72138878 100644 --- a/xen/arch/x86/i387.c +++ b/xen/arch/x86/i387.c @@ -133,11 +133,22 @@ static inline void fpu_frstor(struct vcpu *v) /*******************************/ /* FPU Save Functions */ /*******************************/ + +static inline uint64_t vcpu_xsave_mask(const struct vcpu *v) +{ + if ( v->fpu_dirtied ) + return v->arch.nonlazy_xstate_used ? XSTATE_ALL : XSTATE_LAZY; + + return v->arch.nonlazy_xstate_used ? XSTATE_NONLAZY : 0; +} + /* Save x87 extended state */ static inline void fpu_xsave(struct vcpu *v) { bool_t ok; + uint64_t mask = vcpu_xsave_mask(v); + ASSERT(mask); ASSERT(v->arch.xsave_area); /* * XCR0 normally represents what guest OS set. In case of Xen itself, @@ -145,7 +156,7 @@ static inline void fpu_xsave(struct vcpu *v) */ ok = set_xcr0(v->arch.xcr0_accum | XSTATE_FP_SSE); ASSERT(ok); - xsave(v, v->arch.nonlazy_xstate_used ? XSTATE_ALL : XSTATE_LAZY); + xsave(v, mask); ok = set_xcr0(v->arch.xcr0 ?: XSTATE_FP_SSE); ASSERT(ok); } @@ -257,7 +268,7 @@ void vcpu_restore_fpu_lazy(struct vcpu *v) */ void vcpu_save_fpu(struct vcpu *v) { - if ( !v->fpu_dirtied ) + if ( !v->fpu_dirtied && !v->arch.nonlazy_xstate_used ) return; ASSERT(!is_idle_vcpu(v));