KVM: Lazy FPU support for SVM
Avoid saving and restoring the guest fpu state on every exit. This shaves ~100 cycles off the guest/host switch. Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
This commit is contained in:
parent
4c690a1e86
commit
7807fa6ca5
|
@ -63,6 +63,7 @@
|
||||||
#define FX_BUF_SIZE (2 * FX_IMAGE_SIZE + FX_IMAGE_ALIGN)
|
#define FX_BUF_SIZE (2 * FX_IMAGE_SIZE + FX_IMAGE_ALIGN)
|
||||||
|
|
||||||
#define DE_VECTOR 0
|
#define DE_VECTOR 0
|
||||||
|
#define NM_VECTOR 7
|
||||||
#define DF_VECTOR 8
|
#define DF_VECTOR 8
|
||||||
#define TS_VECTOR 10
|
#define TS_VECTOR 10
|
||||||
#define NP_VECTOR 11
|
#define NP_VECTOR 11
|
||||||
|
@ -301,6 +302,7 @@ struct kvm_vcpu {
|
||||||
char fx_buf[FX_BUF_SIZE];
|
char fx_buf[FX_BUF_SIZE];
|
||||||
char *host_fx_image;
|
char *host_fx_image;
|
||||||
char *guest_fx_image;
|
char *guest_fx_image;
|
||||||
|
int fpu_active;
|
||||||
|
|
||||||
int mmio_needed;
|
int mmio_needed;
|
||||||
int mmio_read_completed;
|
int mmio_read_completed;
|
||||||
|
|
|
@ -587,6 +587,7 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu)
|
||||||
init_vmcb(vcpu->svm->vmcb);
|
init_vmcb(vcpu->svm->vmcb);
|
||||||
|
|
||||||
fx_init(vcpu);
|
fx_init(vcpu);
|
||||||
|
vcpu->fpu_active = 1;
|
||||||
vcpu->apic_base = 0xfee00000 |
|
vcpu->apic_base = 0xfee00000 |
|
||||||
/*for vcpu 0*/ MSR_IA32_APICBASE_BSP |
|
/*for vcpu 0*/ MSR_IA32_APICBASE_BSP |
|
||||||
MSR_IA32_APICBASE_ENABLE;
|
MSR_IA32_APICBASE_ENABLE;
|
||||||
|
@ -756,6 +757,11 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if ((vcpu->cr0 & CR0_TS_MASK) && !(cr0 & CR0_TS_MASK)) {
|
||||||
|
vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
|
||||||
|
vcpu->fpu_active = 1;
|
||||||
|
}
|
||||||
|
|
||||||
vcpu->cr0 = cr0;
|
vcpu->cr0 = cr0;
|
||||||
cr0 |= CR0_PG_MASK | CR0_WP_MASK;
|
cr0 |= CR0_PG_MASK | CR0_WP_MASK;
|
||||||
cr0 &= ~(CR0_CD_MASK | CR0_NW_MASK);
|
cr0 &= ~(CR0_CD_MASK | CR0_NW_MASK);
|
||||||
|
@ -928,6 +934,16 @@ static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nm_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
||||||
|
{
|
||||||
|
vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
|
||||||
|
if (!(vcpu->cr0 & CR0_TS_MASK))
|
||||||
|
vcpu->svm->vmcb->save.cr0 &= ~CR0_TS_MASK;
|
||||||
|
vcpu->fpu_active = 1;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int shutdown_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
static int shutdown_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -1292,6 +1308,7 @@ static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu,
|
||||||
[SVM_EXIT_WRITE_DR5] = emulate_on_interception,
|
[SVM_EXIT_WRITE_DR5] = emulate_on_interception,
|
||||||
[SVM_EXIT_WRITE_DR7] = emulate_on_interception,
|
[SVM_EXIT_WRITE_DR7] = emulate_on_interception,
|
||||||
[SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception,
|
[SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception,
|
||||||
|
[SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception,
|
||||||
[SVM_EXIT_INTR] = nop_on_interception,
|
[SVM_EXIT_INTR] = nop_on_interception,
|
||||||
[SVM_EXIT_NMI] = nop_on_interception,
|
[SVM_EXIT_NMI] = nop_on_interception,
|
||||||
[SVM_EXIT_SMI] = nop_on_interception,
|
[SVM_EXIT_SMI] = nop_on_interception,
|
||||||
|
@ -1481,8 +1498,10 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
||||||
load_db_regs(vcpu->svm->db_regs);
|
load_db_regs(vcpu->svm->db_regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
fx_save(vcpu->host_fx_image);
|
if (vcpu->fpu_active) {
|
||||||
fx_restore(vcpu->guest_fx_image);
|
fx_save(vcpu->host_fx_image);
|
||||||
|
fx_restore(vcpu->guest_fx_image);
|
||||||
|
}
|
||||||
|
|
||||||
asm volatile (
|
asm volatile (
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
|
@ -1593,8 +1612,10 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
|
||||||
#endif
|
#endif
|
||||||
: "cc", "memory" );
|
: "cc", "memory" );
|
||||||
|
|
||||||
fx_save(vcpu->guest_fx_image);
|
if (vcpu->fpu_active) {
|
||||||
fx_restore(vcpu->host_fx_image);
|
fx_save(vcpu->guest_fx_image);
|
||||||
|
fx_restore(vcpu->host_fx_image);
|
||||||
|
}
|
||||||
|
|
||||||
if ((vcpu->svm->vmcb->save.dr7 & 0xff))
|
if ((vcpu->svm->vmcb->save.dr7 & 0xff))
|
||||||
load_db_regs(vcpu->svm->host_db_regs);
|
load_db_regs(vcpu->svm->host_db_regs);
|
||||||
|
@ -1664,6 +1685,12 @@ static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root)
|
||||||
{
|
{
|
||||||
vcpu->svm->vmcb->save.cr3 = root;
|
vcpu->svm->vmcb->save.cr3 = root;
|
||||||
force_new_asid(vcpu);
|
force_new_asid(vcpu);
|
||||||
|
|
||||||
|
if (vcpu->fpu_active) {
|
||||||
|
vcpu->svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR);
|
||||||
|
vcpu->svm->vmcb->save.cr0 |= CR0_TS_MASK;
|
||||||
|
vcpu->fpu_active = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void svm_inject_page_fault(struct kvm_vcpu *vcpu,
|
static void svm_inject_page_fault(struct kvm_vcpu *vcpu,
|
||||||
|
|
Loading…
Reference in New Issue