mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
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:
1 parent
dba44e0512
commit
4b9851c645
10 files changed
+16
-83
No files matched your search
@@ -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 )
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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? */
|
||||||
|
|||||||