x86: Remove fpu_initialised/fpu_dirty

With lazy FPU removed, fpu_initialised and fpu_dirty are always set to
true in vcpu_restore_fpu() so remove them and adjust the code
accordingly.

There is a small user-visible change here. After this commit, calling
XEN_DOMCTL_getvcpucontext immediately after vCPU creation would show the
FPU as initialized (with a clean state) whereas before it would show as
uninitialized.

Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
This commit is contained in:
Ross Lagerwall authored and Andrew Cooper committed 2026-03-30 15:48:13 +01:00
1 parent dba44e0512
commit 4b9851c645
10 files changed
+16 -83

No files matched your search

+2 -3
View File
@@ -1406,11 +1406,10 @@ void arch_get_info_guest(struct vcpu *v, vcpu_guest_context_u c)
VCPU_UNMAP_XSAVE_AREA(v, xsave_area); VCPU_UNMAP_XSAVE_AREA(v, xsave_area);
if ( is_pv_domain(d) ) if ( is_pv_domain(d) )
c(flags = v->arch.pv.vgc_flags & ~(VGCF_i387_valid|VGCF_in_kernel)); c(flags = v->arch.pv.vgc_flags & ~VGCF_in_kernel);
else else
c(flags = 0); c(flags = 0);
if ( v->fpu_initialised ) c(flags |= VGCF_i387_valid);
c(flags |= VGCF_i387_valid);
if ( !(v->pause_flags & VPF_down) ) if ( !(v->pause_flags & VPF_down) )
c(flags |= VGCF_online); c(flags |= VGCF_online);
if ( !compat ) if ( !compat )
+1 -5
View File
@@ -2517,9 +2517,7 @@ static int cf_check hvmemul_get_fpu(
{ {
struct vcpu *curr = current; struct vcpu *curr = current;
if ( !curr->fpu_dirtied ) if ( type == X86EMUL_FPU_fpu )
alternative_vcall(hvm_funcs.fpu_dirty_intercept);
else if ( type == X86EMUL_FPU_fpu )
{ {
/* Has a fastpath for `current`, so there's no actual map */ /* Has a fastpath for `current`, so there's no actual map */
const struct xsave_struct *xsave_area = VCPU_MAP_XSAVE_AREA(curr); const struct xsave_struct *xsave_area = VCPU_MAP_XSAVE_AREA(curr);
@@ -2537,8 +2535,6 @@ static int cf_check hvmemul_get_fpu(
* masking of all exceptions by FNSTENV.) * masking of all exceptions by FNSTENV.)
*/ */
save_fpu_enable(); save_fpu_enable();
curr->fpu_initialised = true;
curr->fpu_dirtied = true;
if ( (fpu_ctxt->fcw & 0x3f) != 0x3f ) if ( (fpu_ctxt->fcw & 0x3f) != 0x3f )
{ {
uint16_t fcw; uint16_t fcw;
+6 -9
View File
@@ -866,6 +866,7 @@ static int cf_check hvm_save_cpu_ctxt(struct vcpu *v, hvm_domain_context_t *h)
.dr7 = v->arch.dr7, .dr7 = v->arch.dr7,
.msr_efer = v->arch.hvm.guest_efer, .msr_efer = v->arch.hvm.guest_efer,
}; };
const struct xsave_struct *xsave_area;
/* /*
* We don't need to save state for a vcpu that is down; the restore * We don't need to save state for a vcpu that is down; the restore
@@ -933,15 +934,11 @@ static int cf_check hvm_save_cpu_ctxt(struct vcpu *v, hvm_domain_context_t *h)
ctxt.ldtr_base = seg.base; ctxt.ldtr_base = seg.base;
ctxt.ldtr_arbytes = seg.attr; ctxt.ldtr_arbytes = seg.attr;
if ( v->fpu_initialised ) xsave_area = VCPU_MAP_XSAVE_AREA(v);
{ BUILD_BUG_ON(sizeof(ctxt.fpu_regs) != sizeof(xsave_area->fpu_sse));
const struct xsave_struct *xsave_area = VCPU_MAP_XSAVE_AREA(v); memcpy(ctxt.fpu_regs, &xsave_area->fpu_sse, sizeof(ctxt.fpu_regs));
VCPU_UNMAP_XSAVE_AREA(v, xsave_area);
BUILD_BUG_ON(sizeof(ctxt.fpu_regs) != sizeof(xsave_area->fpu_sse)); ctxt.flags = XEN_X86_FPU_INITIALISED;
memcpy(ctxt.fpu_regs, &xsave_area->fpu_sse, sizeof(ctxt.fpu_regs));
VCPU_UNMAP_XSAVE_AREA(v, xsave_area);
ctxt.flags = XEN_X86_FPU_INITIALISED;
}
return hvm_save_entry(CPU, v->vcpu_id, h, &ctxt); return hvm_save_entry(CPU, v->vcpu_id, h, &ctxt);
} }
-3
View File
@@ -276,7 +276,6 @@ static void vlapic_init_sipi_one(struct vcpu *target, uint32_t icr)
switch ( icr & APIC_DM_MASK ) switch ( icr & APIC_DM_MASK )
{ {
case APIC_DM_INIT: { case APIC_DM_INIT: {
bool fpu_initialised;
int rc; int rc;
/* No work on INIT de-assert for P4-type APIC. */ /* No work on INIT de-assert for P4-type APIC. */
@@ -289,10 +288,8 @@ static void vlapic_init_sipi_one(struct vcpu *target, uint32_t icr)
hvm_vcpu_down(target); hvm_vcpu_down(target);
domain_lock(target->domain); domain_lock(target->domain);
/* Reset necessary VCPU state. This does not include FPU state. */ /* Reset necessary VCPU state. This does not include FPU state. */
fpu_initialised = target->fpu_initialised;
rc = vcpu_reset(target); rc = vcpu_reset(target);
ASSERT(!rc); ASSERT(!rc);
target->fpu_initialised = fpu_initialised;
vlapic_do_init(vcpu_vlapic(target)); vlapic_do_init(vcpu_vlapic(target));
domain_unlock(target->domain); domain_unlock(target->domain);
break; break;
+2 -29
View File
@@ -110,22 +110,7 @@ static inline void fpu_fxrstor(struct vcpu *v)
static inline uint64_t vcpu_xsave_mask(const struct vcpu *v) 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_ALL : XSTATE_LAZY;
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.
*/
return xstate_all(v) ? XSTATE_ALL : XSTATE_NONLAZY;
} }
/* Save x87 extended state */ /* Save x87 extended state */
@@ -201,19 +186,11 @@ void vcpu_restore_fpu(struct vcpu *v)
/* Avoid recursion */ /* Avoid recursion */
clts(); clts();
/*
* When saving full state even with !v->fpu_dirtied (see vcpu_xsave_mask()
* above) we also need to restore full state, to prevent subsequently
* saving state belonging to another vCPU.
*/
if ( cpu_has_xsave ) if ( cpu_has_xsave )
fpu_xrstor(v, XSTATE_ALL); fpu_xrstor(v, XSTATE_ALL);
else else
fpu_fxrstor(v); fpu_fxrstor(v);
v->fpu_initialised = 1;
v->fpu_dirtied = 1;
/* Xen doesn't need TS set, but the guest might. */ /* Xen doesn't need TS set, but the guest might. */
if ( is_pv_vcpu(v) && (v->arch.pv.ctrlreg[0] & X86_CR0_TS) ) if ( is_pv_vcpu(v) && (v->arch.pv.ctrlreg[0] & X86_CR0_TS) )
stts(); stts();
@@ -225,7 +202,7 @@ void vcpu_restore_fpu(struct vcpu *v)
*/ */
static bool _vcpu_save_fpu(struct vcpu *v) static bool _vcpu_save_fpu(struct vcpu *v)
{ {
if ( !v->fpu_dirtied && !v->arch.nonlazy_xstate_used ) if ( !v->arch.nonlazy_xstate_used )
return false; return false;
ASSERT(!is_idle_vcpu(v)); ASSERT(!is_idle_vcpu(v));
@@ -238,8 +215,6 @@ static bool _vcpu_save_fpu(struct vcpu *v)
else else
fpu_fxsave(v); fpu_fxsave(v);
v->fpu_dirtied = 0;
return true; return true;
} }
@@ -265,7 +240,6 @@ void vcpu_reset_fpu(struct vcpu *v)
{ {
struct xsave_struct *xsave_area = VCPU_MAP_XSAVE_AREA(v); struct xsave_struct *xsave_area = VCPU_MAP_XSAVE_AREA(v);
v->fpu_initialised = false;
*xsave_area = (struct xsave_struct) { *xsave_area = (struct xsave_struct) {
.xsave_hdr.xstate_bv = X86_XCR0_X87, .xsave_hdr.xstate_bv = X86_XCR0_X87,
}; };
@@ -282,7 +256,6 @@ void vcpu_setup_fpu(struct vcpu *v, const void *data)
{ {
struct xsave_struct *xsave_area = VCPU_MAP_XSAVE_AREA(v); struct xsave_struct *xsave_area = VCPU_MAP_XSAVE_AREA(v);
v->fpu_initialised = true;
*xsave_area = (struct xsave_struct) { *xsave_area = (struct xsave_struct) {
.fpu_sse = *(const fpusse_t*)data, .fpu_sse = *(const fpusse_t*)data,
.xsave_hdr.xstate_bv = XSTATE_FP_SSE, .xsave_hdr.xstate_bv = XSTATE_FP_SSE,
-1
View File
@@ -184,7 +184,6 @@ struct hvm_function_table {
/* Instruction intercepts: non-void return values are X86EMUL codes. */ /* Instruction intercepts: non-void return values are X86EMUL codes. */
void (*wbinvd_intercept)(void); void (*wbinvd_intercept)(void);
void (*fpu_dirty_intercept)(void);
int (*msr_read_intercept)(unsigned int msr, uint64_t *msr_content); int (*msr_read_intercept)(unsigned int msr, uint64_t *msr_content);
int (*msr_write_intercept)(unsigned int msr, uint64_t msr_content); int (*msr_write_intercept)(unsigned int msr, uint64_t msr_content);
void (*handle_cd)(struct vcpu *v, unsigned long value); void (*handle_cd)(struct vcpu *v, unsigned long value);
-11
View File
@@ -132,17 +132,6 @@ xsave_area_compressed(const struct xsave_struct *xsave_area)
return xsave_area->xsave_hdr.xcomp_bv & XSTATE_COMPACTION_ENABLED; return xsave_area->xsave_hdr.xcomp_bv & XSTATE_COMPACTION_ENABLED;
} }
static inline bool xstate_all(const struct vcpu *v)
{
/*
* 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 with XSAVES/XSAVEC.
*/
return xsave_area_compressed(v->arch.xsave_area) &&
(v->arch.xcr0_accum & XSTATE_LAZY & ~XSTATE_FP_SSE);
}
/* /*
* Fetch a pointer to a vCPU's XSAVE area * Fetch a pointer to a vCPU's XSAVE area
* *
+5 -16
View File
@@ -1005,28 +1005,17 @@ int handle_xsetbv(u32 index, u64 new_bv)
if ( new_bv & XSTATE_NONLAZY ) if ( new_bv & XSTATE_NONLAZY )
curr->arch.nonlazy_xstate_used = 1; curr->arch.nonlazy_xstate_used = 1;
mask &= curr->fpu_dirtied ? ~XSTATE_FP_SSE : XSTATE_NONLAZY; mask &= ~XSTATE_FP_SSE;
if ( mask ) if ( mask )
{ {
unsigned long cr0 = read_cr0(); unsigned long cr0 = read_cr0();
/* Has a fastpath for `current`, so there's no actual map */
struct xsave_struct *xsave_area = VCPU_MAP_XSAVE_AREA(curr);
clts(); clts();
if ( curr->fpu_dirtied )
{
/* Has a fastpath for `current`, so there's no actual map */
struct xsave_struct *xsave_area = VCPU_MAP_XSAVE_AREA(curr);
asm ( "stmxcsr %0" : "=m" (xsave_area->fpu_sse.mxcsr) ); asm ( "stmxcsr %0" : "=m" (xsave_area->fpu_sse.mxcsr) );
VCPU_UNMAP_XSAVE_AREA(curr, xsave_area); VCPU_UNMAP_XSAVE_AREA(curr, xsave_area);
}
else if ( xstate_all(curr) )
{
/* See the comment in i387.c:vcpu_restore_fpu_eager(). */
mask |= XSTATE_LAZY;
curr->fpu_initialised = 1;
curr->fpu_dirtied = 1;
cr0 &= ~X86_CR0_TS;
}
xrstor(curr, mask); xrstor(curr, mask);
if ( cr0 & X86_CR0_TS ) if ( cr0 & X86_CR0_TS )
write_cr0(cr0); write_cr0(cr0);
-2
View File
@@ -1824,8 +1824,6 @@ int vcpu_reset(struct vcpu *v)
clear_bit(v->vcpu_id, d->poll_mask); clear_bit(v->vcpu_id, d->poll_mask);
v->poll_evtchn = 0; v->poll_evtchn = 0;
v->fpu_initialised = 0;
v->fpu_dirtied = 0;
v->is_initialised = 0; v->is_initialised = 0;
if ( v->affinity_broken & VCPU_AFFINITY_OVERRIDE ) if ( v->affinity_broken & VCPU_AFFINITY_OVERRIDE )
vcpu_temporary_affinity(v, NR_CPUS, VCPU_AFFINITY_OVERRIDE); vcpu_temporary_affinity(v, NR_CPUS, VCPU_AFFINITY_OVERRIDE);
-4
View File
@@ -212,10 +212,6 @@ struct vcpu
struct guest_area runstate_guest_area; struct guest_area runstate_guest_area;
unsigned int new_state; unsigned int new_state;
/* Has the FPU been initialised? */
bool fpu_initialised;
/* Has the FPU been used since it was last saved? */
bool fpu_dirtied;
/* Initialization completed for this VCPU? */ /* Initialization completed for this VCPU? */
bool is_initialised; bool is_initialised;
/* Currently running on a CPU? */ /* Currently running on a CPU? */
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.