|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v1 3/8] x86/svm: Remove lazy FPU support
Remove lazy FPU support from the SVM code since fully_eager_fpu is now
always true.
No functional change intended.
Signed-off-by: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
---
xen/arch/x86/hvm/svm/nestedsvm.c | 67 +-------------------
xen/arch/x86/hvm/svm/svm.c | 81 +-----------------------
xen/arch/x86/hvm/svm/vmcb.c | 4 +-
xen/arch/x86/include/asm/hvm/svm-types.h | 6 --
4 files changed, 4 insertions(+), 154 deletions(-)
diff --git a/xen/arch/x86/hvm/svm/nestedsvm.c b/xen/arch/x86/hvm/svm/nestedsvm.c
index a63ec613465f..ef6fa5d23b67 100644
--- a/xen/arch/x86/hvm/svm/nestedsvm.c
+++ b/xen/arch/x86/hvm/svm/nestedsvm.c
@@ -165,58 +165,6 @@ int cf_check nsvm_vcpu_reset(struct vcpu *v)
return 0;
}
-static uint64_t nestedsvm_fpu_vmentry(uint64_t n1cr0,
- struct vmcb_struct *vvmcb,
- struct vmcb_struct *n1vmcb, struct vmcb_struct *n2vmcb)
-{
- uint64_t vcr0;
-
- vcr0 = vvmcb->_cr0;
- if ( !(n1cr0 & X86_CR0_TS) && (n1vmcb->_cr0 & X86_CR0_TS) )
- {
- /*
- * svm_fpu_leave() run while l1 guest was running.
- * Sync FPU state with l2 guest.
- */
- vcr0 |= X86_CR0_TS;
- n2vmcb->_exception_intercepts |= (1U << X86_EXC_NM);
- }
- else if ( !(vcr0 & X86_CR0_TS) && (n2vmcb->_cr0 & X86_CR0_TS) )
- {
- /*
- * svm_fpu_enter() run while l1 guest was running.
- * Sync FPU state with l2 guest.
- */
- vcr0 &= ~X86_CR0_TS;
- n2vmcb->_exception_intercepts &= ~(1U << X86_EXC_NM);
- }
-
- return vcr0;
-}
-
-static void nestedsvm_fpu_vmexit(struct vmcb_struct *n1vmcb,
- struct vmcb_struct *n2vmcb, uint64_t n1cr0, uint64_t guest_cr0)
-{
- if ( !(guest_cr0 & X86_CR0_TS) && (n2vmcb->_cr0 & X86_CR0_TS) )
- {
- /*
- * svm_fpu_leave() run while l2 guest was running.
- * Sync FPU state with l1 guest.
- */
- n1vmcb->_cr0 |= X86_CR0_TS;
- n1vmcb->_exception_intercepts |= (1U << X86_EXC_NM);
- }
- else if ( !(n1cr0 & X86_CR0_TS) && (n1vmcb->_cr0 & X86_CR0_TS) )
- {
- /*
- * svm_fpu_enter() run while l2 guest was running.
- * Sync FPU state with l1 guest.
- */
- n1vmcb->_cr0 &= ~X86_CR0_TS;
- n1vmcb->_exception_intercepts &= ~(1U << X86_EXC_NM);
- }
-}
-
static int nsvm_vcpu_hostsave(struct vcpu *v, unsigned int inst_len)
{
struct nestedsvm *svm = &vcpu_nestedsvm(v);
@@ -246,7 +194,6 @@ static int nsvm_vcpu_hostsave(struct vcpu *v, unsigned int
inst_len)
static int nsvm_vcpu_hostrestore(struct vcpu *v, struct cpu_user_regs *regs)
{
struct nestedvcpu *nv = &vcpu_nestedhvm(v);
- struct nestedsvm *svm = &vcpu_nestedsvm(v);
struct vmcb_struct *n1vmcb, *n2vmcb;
int rc;
@@ -281,8 +228,6 @@ static int nsvm_vcpu_hostrestore(struct vcpu *v, struct
cpu_user_regs *regs)
gdprintk(XENLOG_ERR, "hvm_set_cr4 failed, rc: %u\n", rc);
/* CR0 */
- nestedsvm_fpu_vmexit(n1vmcb, n2vmcb,
- svm->ns_cr0, v->arch.hvm.guest_cr[0]);
v->arch.hvm.guest_cr[0] = n1vmcb->_cr0 | X86_CR0_PE;
n1vmcb->rflags &= ~X86_EFLAGS_VM;
rc = hvm_set_cr0(n1vmcb->_cr0 | X86_CR0_PE, true);
@@ -290,7 +235,6 @@ static int nsvm_vcpu_hostrestore(struct vcpu *v, struct
cpu_user_regs *regs)
hvm_inject_hw_exception(X86_EXC_GP, 0);
if ( rc != X86EMUL_OKAY )
gdprintk(XENLOG_ERR, "hvm_set_cr0 failed, rc: %u\n", rc);
- svm->ns_cr0 = v->arch.hvm.guest_cr[0];
/* CR2 */
v->arch.hvm.guest_cr[2] = n1vmcb->_cr2;
@@ -418,7 +362,6 @@ static int nsvm_vmcb_prepare4vmrun(struct vcpu *v, struct
cpu_user_regs *regs)
struct vmcb_struct *ns_vmcb, *n1vmcb, *n2vmcb;
vmcbcleanbits_t clean = {};
int rc;
- uint64_t cr0;
ns_vmcb = nv->nv_vvmcx;
n1vmcb = nv->nv_n1vmcx;
@@ -452,7 +395,6 @@ static int nsvm_vmcb_prepare4vmrun(struct vcpu *v, struct
cpu_user_regs *regs)
* safed here.
* The overhead comes from (ordered from highest to lowest):
* - svm_ctxt_switch_to (CPU context switching)
- * - svm_fpu_enter, svm_fpu_leave (lazy FPU switching)
* - emulated CLGI (clears VINTR intercept)
* - host clears VINTR intercept
* Test results show that the overhead is high enough that the
@@ -551,10 +493,8 @@ static int nsvm_vmcb_prepare4vmrun(struct vcpu *v, struct
cpu_user_regs *regs)
gdprintk(XENLOG_ERR, "hvm_set_cr4 failed, rc: %u\n", rc);
/* CR0 */
- svm->ns_cr0 = v->arch.hvm.guest_cr[0];
- cr0 = nestedsvm_fpu_vmentry(svm->ns_cr0, ns_vmcb, n1vmcb, n2vmcb);
v->arch.hvm.guest_cr[0] = ns_vmcb->_cr0;
- rc = hvm_set_cr0(cr0, true);
+ rc = hvm_set_cr0(ns_vmcb->_cr0, true);
if ( rc == X86EMUL_EXCEPTION )
hvm_inject_hw_exception(X86_EXC_GP, 0);
if ( rc != X86EMUL_OKAY )
@@ -1305,11 +1245,6 @@ nestedsvm_check_intercepts(struct vcpu *v, struct
cpu_user_regs *regs,
case VMEXIT_INTR:
case VMEXIT_NMI:
return NESTEDHVM_VMEXIT_HOST;
- case VMEXIT_EXCEPTION_NM:
- /* Host must handle lazy fpu context switching first.
- * Then inject the VMEXIT if L1 guest intercepts this.
- */
- return NESTEDHVM_VMEXIT_HOST;
case VMEXIT_NPF:
if ( nestedhvm_paging_mode_hap(v) )
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index 243c41fb13a8..2546705d245c 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -104,38 +104,6 @@ static void cf_check svm_cpu_down(void)
write_efer(read_efer() & ~EFER_SVME);
}
-static void svm_fpu_enter(struct vcpu *v)
-{
- struct vmcb_struct *n1vmcb = vcpu_nestedhvm(v).nv_n1vmcx;
-
- vcpu_restore_fpu_lazy(v);
- vmcb_set_exception_intercepts(
- n1vmcb,
- vmcb_get_exception_intercepts(n1vmcb) & ~(1U << X86_EXC_NM));
-}
-
-static void cf_check svm_fpu_leave(struct vcpu *v)
-{
- struct vmcb_struct *n1vmcb = vcpu_nestedhvm(v).nv_n1vmcx;
-
- ASSERT(!v->fpu_dirtied);
- ASSERT(read_cr0() & X86_CR0_TS);
-
- /*
- * If the guest does not have TS enabled then we must cause and handle an
- * exception on first use of the FPU. If the guest *does* have TS enabled
- * then this is not necessary: no FPU activity can occur until the guest
- * clears CR0.TS, and we will initialise the FPU when that happens.
- */
- if ( !(v->arch.hvm.guest_cr[0] & X86_CR0_TS) )
- {
- vmcb_set_exception_intercepts(
- n1vmcb,
- vmcb_get_exception_intercepts(n1vmcb) | (1U << X86_EXC_NM));
- vmcb_set_cr0(n1vmcb, vmcb_get_cr0(n1vmcb) | X86_CR0_TS);
- }
-}
-
static void cf_check svm_update_guest_cr(
struct vcpu *v, unsigned int cr, unsigned int flags)
{
@@ -145,20 +113,6 @@ static void cf_check svm_update_guest_cr(
switch ( cr )
{
case 0:
- {
- unsigned long hw_cr0_mask = 0;
-
- if ( !(v->arch.hvm.guest_cr[0] & X86_CR0_TS) )
- {
- if ( v != current )
- {
- if ( !v->arch.fully_eager_fpu )
- hw_cr0_mask |= X86_CR0_TS;
- }
- else if ( vmcb_get_cr0(vmcb) & X86_CR0_TS )
- svm_fpu_enter(v);
- }
-
if ( paging_mode_hap(v->domain) )
{
uint32_t intercepts = vmcb_get_cr_intercepts(vmcb);
@@ -169,12 +123,12 @@ static void cf_check svm_update_guest_cr(
vmcb_set_cr_intercepts(vmcb, intercepts |
CR_INTERCEPT_CR3_WRITE);
}
- value = v->arch.hvm.guest_cr[0] | hw_cr0_mask;
+ value = v->arch.hvm.guest_cr[0];
if ( paging_mode_shadow(v->domain) )
value |= X86_CR0_PG | X86_CR0_WP;
vmcb_set_cr0(vmcb, value);
break;
- }
+
case 2:
vmcb_set_cr2(vmcb, v->arch.hvm.guest_cr[2]);
break;
@@ -909,9 +863,6 @@ static void cf_check svm_ctxt_switch_from(struct vcpu *v)
if ( unlikely((read_efer() & EFER_SVME) == 0) )
return;
- if ( !v->arch.fully_eager_fpu )
- svm_fpu_leave(v);
-
svm_save_dr(v);
svm_tsc_ratio_save(v);
@@ -1678,28 +1629,6 @@ static void svm_do_nested_pgfault(struct vcpu *v,
domain_crash(v->domain);
}
-static void cf_check svm_fpu_dirty_intercept(void)
-{
- struct vcpu *v = current;
- struct vmcb_struct *vmcb = v->arch.hvm.svm.vmcb;
- struct vmcb_struct *n1vmcb = vcpu_nestedhvm(v).nv_n1vmcx;
-
- svm_fpu_enter(v);
-
- if ( vmcb != n1vmcb )
- {
- /* Check if l1 guest must make FPU ready for the l2 guest */
- if ( v->arch.hvm.guest_cr[0] & X86_CR0_TS )
- hvm_inject_hw_exception(X86_EXC_NM, X86_EVENT_NO_EC);
- else
- vmcb_set_cr0(n1vmcb, vmcb_get_cr0(n1vmcb) & ~X86_CR0_TS);
- return;
- }
-
- if ( !(v->arch.hvm.guest_cr[0] & X86_CR0_TS) )
- vmcb_set_cr0(vmcb, vmcb_get_cr0(vmcb) & ~X86_CR0_TS);
-}
-
static void svm_vmexit_do_cr_access(
struct vmcb_struct *vmcb, struct cpu_user_regs *regs)
{
@@ -2459,7 +2388,6 @@ static struct hvm_function_table __initdata_cf_clobber
svm_function_table = {
.update_guest_cr = svm_update_guest_cr,
.update_guest_efer = svm_update_guest_efer,
.cpuid_policy_changed = svm_cpuid_policy_changed,
- .fpu_leave = svm_fpu_leave,
.set_guest_pat = svm_set_guest_pat,
.get_guest_pat = svm_get_guest_pat,
.set_tsc_offset = svm_set_tsc_offset,
@@ -2469,7 +2397,6 @@ static struct hvm_function_table __initdata_cf_clobber
svm_function_table = {
.get_pending_event = svm_get_pending_event,
.invlpg = svm_invlpg,
.wbinvd_intercept = svm_wbinvd_intercept,
- .fpu_dirty_intercept = svm_fpu_dirty_intercept,
.msr_read_intercept = svm_msr_read_intercept,
.msr_write_intercept = svm_msr_write_intercept,
#ifdef CONFIG_VM_EVENT
@@ -2783,10 +2710,6 @@ void asmlinkage svm_vmexit_handler(void)
}
break;
- case VMEXIT_EXCEPTION_NM:
- svm_fpu_dirty_intercept();
- break;
-
case VMEXIT_EXCEPTION_PF:
{
unsigned long va = vmcb->ei.exc.cr2;
diff --git a/xen/arch/x86/hvm/svm/vmcb.c b/xen/arch/x86/hvm/svm/vmcb.c
index e583ef8548c7..5ed7123d9a69 100644
--- a/xen/arch/x86/hvm/svm/vmcb.c
+++ b/xen/arch/x86/hvm/svm/vmcb.c
@@ -138,9 +138,7 @@ static int construct_vmcb(struct vcpu *v)
paging_update_paging_modes(v);
- vmcb->_exception_intercepts =
- HVM_TRAP_MASK |
- (v->arch.fully_eager_fpu ? 0 : (1U << X86_EXC_NM));
+ vmcb->_exception_intercepts = HVM_TRAP_MASK;
if ( paging_mode_hap(v->domain) )
{
diff --git a/xen/arch/x86/include/asm/hvm/svm-types.h
b/xen/arch/x86/include/asm/hvm/svm-types.h
index 051b235d8f69..3ede62cade80 100644
--- a/xen/arch/x86/include/asm/hvm/svm-types.h
+++ b/xen/arch/x86/include/asm/hvm/svm-types.h
@@ -65,12 +65,6 @@ struct nestedsvm {
/* Shadow io permission map */
unsigned long *ns_iomap;
- /*
- * Cached guest_cr[0] of l1 guest while l2 guest runs. Needed to handle
- * FPU context switching.
- */
- uint64_t ns_cr0;
-
/*
* Cache guest cr3/host cr3 the guest sets up for the l2 guest.
* Used by Shadow-on-Shadow and Nested-on-Nested.
--
2.53.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |