mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
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@citrix.com> Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
This commit is contained in:
1 parent
511ab162ef
commit
3356d685db
4 files changed
+4
-154
No files matched your search
@@ -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) )
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) )
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
|
||||