if ( v->fpu_dirtied )
return v->arch.nonlazy_xstate_used ? XSTATE_ALL : XSTATE_LAZY;
- return v->arch.nonlazy_xstate_used ? XSTATE_NONLAZY : 0;
+ ASSERT(v->arch.nonlazy_xstate_used);
+
+ /*
+ * The offsets of components which live in the extended region of
+ * compact xsave area are not fixed. Xsave area may be overwritten
+ * when a xsave with v->fpu_dirtied set is followed by one with
+ * v->fpu_dirtied clear.
+ * In such case, if hypervisor uses compact xsave area and guest
+ * has ever used lazy states (checking xcr0_accum excluding
+ * XSTATE_FP_SSE), vcpu_xsave_mask will return XSTATE_ALL. Otherwise
+ * return XSTATE_NONLAZY.
+ * XSTATE_FP_SSE may be excluded, because the offsets of XSTATE_FP_SSE
+ * (in the legacy region of xsave area) are fixed, so saving
+ * XSTATE_FP_SSE will not cause overwriting problem.
+ */
+ return (v->arch.xsave_area->xsave_hdr.xcomp_bv & XSTATE_COMPACTION_ENABLED)
+ && (v->arch.xcr0_accum & XSTATE_LAZY & ~XSTATE_FP_SSE)
+ ? XSTATE_ALL : XSTATE_NONLAZY;
}
/* Save x87 extended state */
return rc;
if ( v->arch.xsave_area )
- {
v->arch.fpu_ctxt = &v->arch.xsave_area->fpu_sse;
- if ( cpu_has_xsaves )
- v->arch.xsave_area->xsave_hdr.xcomp_bv = XSTATE_COMPACTION_ENABLED;
- }
else
{
BUILD_BUG_ON(__alignof(v->arch.xsave_area->fpu_sse) < 16);
u64 xstate_bv = xsave->xsave_hdr.xstate_bv;
u64 valid;
- if ( !cpu_has_xsaves && !cpu_has_xsavec )
+ if ( !(xsave->xsave_hdr.xcomp_bv & XSTATE_COMPACTION_ENABLED) )
{
memcpy(dest, xsave, size);
return;
u64 xstate_bv = ((const struct xsave_struct *)src)->xsave_hdr.xstate_bv;
u64 valid;
- if ( !cpu_has_xsaves && !cpu_has_xsavec )
+ ASSERT(!xsave_area_compressed(src));
+
+ if ( !(v->arch.xcr0_accum & XSTATE_XSAVES_ONLY) )
{
memcpy(xsave, src, size);
return;
}
- ASSERT(!xsave_area_compressed(src));
/*
* Copy legacy XSAVE area, to avoid complications with CPUID
* leaves 0 and 1 in the loop below.
uint32_t lmask = mask;
unsigned int fip_width = v->domain->arch.x87_fip_width;
#define XSAVE(pfx) \
- alternative_io_3(".byte " pfx "0x0f,0xae,0x27\n", /* xsave */ \
- ".byte " pfx "0x0f,0xae,0x37\n", /* xsaveopt */ \
- X86_FEATURE_XSAVEOPT, \
- ".byte " pfx "0x0f,0xc7,0x27\n", /* xsavec */ \
- X86_FEATURE_XSAVEC, \
- ".byte " pfx "0x0f,0xc7,0x2f\n", /* xsaves */ \
- X86_FEATURE_XSAVES, \
- "=m" (*ptr), \
- "a" (lmask), "d" (hmask), "D" (ptr))
+ if ( v->arch.xcr0_accum & XSTATE_XSAVES_ONLY ) \
+ asm volatile ( ".byte " pfx "0x0f,0xc7,0x2f\n" /* xsaves */ \
+ : "=m" (*ptr) \
+ : "a" (lmask), "d" (hmask), "D" (ptr) ); \
+ else \
+ alternative_io(".byte " pfx "0x0f,0xae,0x27\n", /* xsave */ \
+ ".byte " pfx "0x0f,0xae,0x37\n", /* xsaveopt */ \
+ X86_FEATURE_XSAVEOPT, \
+ "=m" (*ptr), \
+ "a" (lmask), "d" (hmask), "D" (ptr))
if ( fip_width == 8 || !(mask & XSTATE_FP) )
{
switch ( __builtin_expect(ptr->fpu_sse.x[FPU_WORD_SIZE_OFFSET], 8) )
{
BUILD_BUG_ON(sizeof(faults) != 4); /* Clang doesn't support %z in asm. */
-#define XRSTOR(pfx) \
- alternative_io("1: .byte " pfx "0x0f,0xae,0x2f\n" \
+#define _xrstor(insn) \
+ asm volatile ( "1: .byte " insn "\n" \
"3:\n" \
" .section .fixup,\"ax\"\n" \
"2: incl %[faults]\n" \
" jmp 3b\n" \
" .previous\n" \
- _ASM_EXTABLE(1b, 2b), \
- ".byte " pfx "0x0f,0xc7,0x1f\n", \
- X86_FEATURE_XSAVES, \
- ASM_OUTPUT2([mem] "+m" (*ptr), [faults] "+g" (faults)), \
- [lmask] "a" (lmask), [hmask] "d" (hmask), \
- [ptr] "D" (ptr))
+ _ASM_EXTABLE(1b, 2b) \
+ : [mem] "+m" (*ptr), [faults] "+g" (faults) \
+ : [lmask] "a" (lmask), [hmask] "d" (hmask), \
+ [ptr] "D" (ptr) )
+
+#define XRSTOR(pfx) \
+ if ( v->arch.xcr0_accum & XSTATE_XSAVES_ONLY ) \
+ { \
+ if ( unlikely(!(ptr->xsave_hdr.xcomp_bv & \
+ XSTATE_COMPACTION_ENABLED)) ) \
+ ptr->xsave_hdr.xcomp_bv |= ptr->xsave_hdr.xstate_bv | \
+ XSTATE_COMPACTION_ENABLED; \
+ _xrstor(pfx "0x0f,0xc7,0x1f"); /* xrstors */ \
+ } \
+ else \
+ _xrstor(pfx "0x0f,0xae,0x2f") /* xrstor */
default:
XRSTOR("0x48,");
XRSTOR("");
break;
#undef XRSTOR
+#undef _xrstor
}
if ( likely(faults == prev_faults) )
break;
((mask & XSTATE_YMM) &&
!(ptr->xsave_hdr.xcomp_bv & XSTATE_COMPACTION_ENABLED))) )
ptr->fpu_sse.mxcsr &= mxcsr_mask;
- if ( cpu_has_xsaves || cpu_has_xsavec )
+ if ( v->arch.xcr0_accum & XSTATE_XSAVES_ONLY )
{
ptr->xsave_hdr.xcomp_bv &= this_cpu(xcr0) | this_cpu(xss);
ptr->xsave_hdr.xstate_bv &= ptr->xsave_hdr.xcomp_bv;
case 2: /* Stage 2: Reset all state. */
ptr->fpu_sse.mxcsr = MXCSR_DEFAULT;
ptr->xsave_hdr.xstate_bv = 0;
- ptr->xsave_hdr.xcomp_bv = cpu_has_xsaves
+ ptr->xsave_hdr.xcomp_bv = v->arch.xcr0_accum & XSTATE_XSAVES_ONLY
? XSTATE_COMPACTION_ENABLED : 0;
continue;
}