diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2007-04-23 10:17:21 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-05-03 03:52:31 -0400 |
commit | 7807fa6ca5af2e5660a0eb3cd90276ca0c5bdfc8 (patch) | |
tree | 8f97af3538acc40a6a72af29f31351d8f0f69296 /drivers/kvm | |
parent | 4c690a1e8667a84b61a6114a4ad293681f32cb11 (diff) |
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>
Diffstat (limited to 'drivers/kvm')
-rw-r--r-- | drivers/kvm/kvm.h | 2 | ||||
-rw-r--r-- | drivers/kvm/svm.c | 35 |
2 files changed, 33 insertions, 4 deletions
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h index d1a90c5d76ce..61ff085df7e6 100644 --- a/drivers/kvm/kvm.h +++ b/drivers/kvm/kvm.h | |||
@@ -63,6 +63,7 @@ | |||
63 | #define FX_BUF_SIZE (2 * FX_IMAGE_SIZE + FX_IMAGE_ALIGN) | 63 | #define FX_BUF_SIZE (2 * FX_IMAGE_SIZE + FX_IMAGE_ALIGN) |
64 | 64 | ||
65 | #define DE_VECTOR 0 | 65 | #define DE_VECTOR 0 |
66 | #define NM_VECTOR 7 | ||
66 | #define DF_VECTOR 8 | 67 | #define DF_VECTOR 8 |
67 | #define TS_VECTOR 10 | 68 | #define TS_VECTOR 10 |
68 | #define NP_VECTOR 11 | 69 | #define NP_VECTOR 11 |
@@ -301,6 +302,7 @@ struct kvm_vcpu { | |||
301 | char fx_buf[FX_BUF_SIZE]; | 302 | char fx_buf[FX_BUF_SIZE]; |
302 | char *host_fx_image; | 303 | char *host_fx_image; |
303 | char *guest_fx_image; | 304 | char *guest_fx_image; |
305 | int fpu_active; | ||
304 | 306 | ||
305 | int mmio_needed; | 307 | int mmio_needed; |
306 | int mmio_read_completed; | 308 | int mmio_read_completed; |
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index 644efc5381ad..2a7a0390bfb1 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c | |||
@@ -587,6 +587,7 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu) | |||
587 | init_vmcb(vcpu->svm->vmcb); | 587 | init_vmcb(vcpu->svm->vmcb); |
588 | 588 | ||
589 | fx_init(vcpu); | 589 | fx_init(vcpu); |
590 | vcpu->fpu_active = 1; | ||
590 | vcpu->apic_base = 0xfee00000 | | 591 | vcpu->apic_base = 0xfee00000 | |
591 | /*for vcpu 0*/ MSR_IA32_APICBASE_BSP | | 592 | /*for vcpu 0*/ MSR_IA32_APICBASE_BSP | |
592 | MSR_IA32_APICBASE_ENABLE; | 593 | MSR_IA32_APICBASE_ENABLE; |
@@ -756,6 +757,11 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) | |||
756 | } | 757 | } |
757 | } | 758 | } |
758 | #endif | 759 | #endif |
760 | if ((vcpu->cr0 & CR0_TS_MASK) && !(cr0 & CR0_TS_MASK)) { | ||
761 | vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); | ||
762 | vcpu->fpu_active = 1; | ||
763 | } | ||
764 | |||
759 | vcpu->cr0 = cr0; | 765 | vcpu->cr0 = cr0; |
760 | cr0 |= CR0_PG_MASK | CR0_WP_MASK; | 766 | cr0 |= CR0_PG_MASK | CR0_WP_MASK; |
761 | cr0 &= ~(CR0_CD_MASK | CR0_NW_MASK); | 767 | cr0 &= ~(CR0_CD_MASK | CR0_NW_MASK); |
@@ -928,6 +934,16 @@ static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
928 | return 0; | 934 | return 0; |
929 | } | 935 | } |
930 | 936 | ||
937 | static int nm_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | ||
938 | { | ||
939 | vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); | ||
940 | if (!(vcpu->cr0 & CR0_TS_MASK)) | ||
941 | vcpu->svm->vmcb->save.cr0 &= ~CR0_TS_MASK; | ||
942 | vcpu->fpu_active = 1; | ||
943 | |||
944 | return 1; | ||
945 | } | ||
946 | |||
931 | static int shutdown_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | 947 | static int shutdown_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) |
932 | { | 948 | { |
933 | /* | 949 | /* |
@@ -1292,6 +1308,7 @@ static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu, | |||
1292 | [SVM_EXIT_WRITE_DR5] = emulate_on_interception, | 1308 | [SVM_EXIT_WRITE_DR5] = emulate_on_interception, |
1293 | [SVM_EXIT_WRITE_DR7] = emulate_on_interception, | 1309 | [SVM_EXIT_WRITE_DR7] = emulate_on_interception, |
1294 | [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception, | 1310 | [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception, |
1311 | [SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception, | ||
1295 | [SVM_EXIT_INTR] = nop_on_interception, | 1312 | [SVM_EXIT_INTR] = nop_on_interception, |
1296 | [SVM_EXIT_NMI] = nop_on_interception, | 1313 | [SVM_EXIT_NMI] = nop_on_interception, |
1297 | [SVM_EXIT_SMI] = nop_on_interception, | 1314 | [SVM_EXIT_SMI] = nop_on_interception, |
@@ -1481,8 +1498,10 @@ again: | |||
1481 | load_db_regs(vcpu->svm->db_regs); | 1498 | load_db_regs(vcpu->svm->db_regs); |
1482 | } | 1499 | } |
1483 | 1500 | ||
1484 | fx_save(vcpu->host_fx_image); | 1501 | if (vcpu->fpu_active) { |
1485 | fx_restore(vcpu->guest_fx_image); | 1502 | fx_save(vcpu->host_fx_image); |
1503 | fx_restore(vcpu->guest_fx_image); | ||
1504 | } | ||
1486 | 1505 | ||
1487 | asm volatile ( | 1506 | asm volatile ( |
1488 | #ifdef CONFIG_X86_64 | 1507 | #ifdef CONFIG_X86_64 |
@@ -1593,8 +1612,10 @@ again: | |||
1593 | #endif | 1612 | #endif |
1594 | : "cc", "memory" ); | 1613 | : "cc", "memory" ); |
1595 | 1614 | ||
1596 | fx_save(vcpu->guest_fx_image); | 1615 | if (vcpu->fpu_active) { |
1597 | fx_restore(vcpu->host_fx_image); | 1616 | fx_save(vcpu->guest_fx_image); |
1617 | fx_restore(vcpu->host_fx_image); | ||
1618 | } | ||
1598 | 1619 | ||
1599 | if ((vcpu->svm->vmcb->save.dr7 & 0xff)) | 1620 | if ((vcpu->svm->vmcb->save.dr7 & 0xff)) |
1600 | load_db_regs(vcpu->svm->host_db_regs); | 1621 | load_db_regs(vcpu->svm->host_db_regs); |
@@ -1664,6 +1685,12 @@ static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root) | |||
1664 | { | 1685 | { |
1665 | vcpu->svm->vmcb->save.cr3 = root; | 1686 | vcpu->svm->vmcb->save.cr3 = root; |
1666 | force_new_asid(vcpu); | 1687 | force_new_asid(vcpu); |
1688 | |||
1689 | if (vcpu->fpu_active) { | ||
1690 | vcpu->svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR); | ||
1691 | vcpu->svm->vmcb->save.cr0 |= CR0_TS_MASK; | ||
1692 | vcpu->fpu_active = 0; | ||
1693 | } | ||
1667 | } | 1694 | } |
1668 | 1695 | ||
1669 | static void svm_inject_page_fault(struct kvm_vcpu *vcpu, | 1696 | static void svm_inject_page_fault(struct kvm_vcpu *vcpu, |