aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2009-12-30 05:40:26 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2010-03-01 10:35:50 -0500
commit02daab21d94dc4cf01b2fd09863d59a436900322 (patch)
treee7caff282dd9019e1b19cd549609c6b991f29152 /arch
parente8467fda83cdc9de53972fee0cd2e6916cf66f41 (diff)
KVM: Lazify fpu activation and deactivation
Defer fpu deactivation as much as possible - if the guest fpu is loaded, keep it loaded until the next heavyweight exit (where we are forced to unload it). This reduces unnecessary exits. We also defer fpu activation on clts; while clts signals the intent to use the fpu, we can't be sure the guest will actually use it. Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/kvm_host.h1
-rw-r--r--arch/x86/kvm/svm.c35
-rw-r--r--arch/x86/kvm/vmx.c25
-rw-r--r--arch/x86/kvm/x86.c7
4 files changed, 37 insertions, 31 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 693046a7a12d..93bee7abb71c 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -506,6 +506,7 @@ struct kvm_x86_ops {
506 void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg); 506 void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg);
507 unsigned long (*get_rflags)(struct kvm_vcpu *vcpu); 507 unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
508 void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags); 508 void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags);
509 void (*fpu_deactivate)(struct kvm_vcpu *vcpu);
509 510
510 void (*tlb_flush)(struct kvm_vcpu *vcpu); 511 void (*tlb_flush)(struct kvm_vcpu *vcpu);
511 512
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 3899c2d19830..5b336a80f31e 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -984,17 +984,11 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
984 if (npt_enabled) 984 if (npt_enabled)
985 goto set; 985 goto set;
986 986
987 if (kvm_read_cr0_bits(vcpu, X86_CR0_TS) && !(cr0 & X86_CR0_TS)) {
988 svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
989 vcpu->fpu_active = 1;
990 }
991
992 vcpu->arch.cr0 = cr0; 987 vcpu->arch.cr0 = cr0;
993 cr0 |= X86_CR0_PG | X86_CR0_WP; 988 cr0 |= X86_CR0_PG | X86_CR0_WP;
994 if (!vcpu->fpu_active) { 989
995 svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR); 990 if (!vcpu->fpu_active)
996 cr0 |= X86_CR0_TS; 991 cr0 |= X86_CR0_TS;
997 }
998set: 992set:
999 /* 993 /*
1000 * re-enable caching here because the QEMU bios 994 * re-enable caching here because the QEMU bios
@@ -1250,6 +1244,8 @@ static int nm_interception(struct vcpu_svm *svm)
1250 svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); 1244 svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
1251 if (!kvm_read_cr0_bits(&svm->vcpu, X86_CR0_TS)) 1245 if (!kvm_read_cr0_bits(&svm->vcpu, X86_CR0_TS))
1252 svm->vmcb->save.cr0 &= ~X86_CR0_TS; 1246 svm->vmcb->save.cr0 &= ~X86_CR0_TS;
1247 else
1248 svm->vmcb->save.cr0 |= X86_CR0_TS;
1253 svm->vcpu.fpu_active = 1; 1249 svm->vcpu.fpu_active = 1;
1254 1250
1255 return 1; 1251 return 1;
@@ -2586,6 +2582,8 @@ static void svm_flush_tlb(struct kvm_vcpu *vcpu)
2586 2582
2587static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu) 2583static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu)
2588{ 2584{
2585 if (npt_enabled)
2586 vcpu->fpu_active = 1;
2589} 2587}
2590 2588
2591static inline void sync_cr8_to_lapic(struct kvm_vcpu *vcpu) 2589static inline void sync_cr8_to_lapic(struct kvm_vcpu *vcpu)
@@ -2805,12 +2803,6 @@ static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root)
2805 2803
2806 svm->vmcb->save.cr3 = root; 2804 svm->vmcb->save.cr3 = root;
2807 force_new_asid(vcpu); 2805 force_new_asid(vcpu);
2808
2809 if (vcpu->fpu_active) {
2810 svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR);
2811 svm->vmcb->save.cr0 |= X86_CR0_TS;
2812 vcpu->fpu_active = 0;
2813 }
2814} 2806}
2815 2807
2816static int is_disabled(void) 2808static int is_disabled(void)
@@ -2926,6 +2918,20 @@ static bool svm_rdtscp_supported(void)
2926 return false; 2918 return false;
2927} 2919}
2928 2920
2921static void svm_fpu_deactivate(struct kvm_vcpu *vcpu)
2922{
2923 struct vcpu_svm *svm = to_svm(vcpu);
2924
2925 if (npt_enabled) {
2926 /* hack: npt requires active fpu at this time */
2927 vcpu->fpu_active = 1;
2928 return;
2929 }
2930
2931 svm->vmcb->control.intercept_exceptions |= 1 << NM_VECTOR;
2932 svm->vmcb->save.cr0 |= X86_CR0_TS;
2933}
2934
2929static struct kvm_x86_ops svm_x86_ops = { 2935static struct kvm_x86_ops svm_x86_ops = {
2930 .cpu_has_kvm_support = has_svm, 2936 .cpu_has_kvm_support = has_svm,
2931 .disabled_by_bios = is_disabled, 2937 .disabled_by_bios = is_disabled,
@@ -2967,6 +2973,7 @@ static struct kvm_x86_ops svm_x86_ops = {
2967 .cache_reg = svm_cache_reg, 2973 .cache_reg = svm_cache_reg,
2968 .get_rflags = svm_get_rflags, 2974 .get_rflags = svm_get_rflags,
2969 .set_rflags = svm_set_rflags, 2975 .set_rflags = svm_set_rflags,
2976 .fpu_deactivate = svm_fpu_deactivate,
2970 2977
2971 .tlb_flush = svm_flush_tlb, 2978 .tlb_flush = svm_flush_tlb,
2972 2979
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index dbcdb55094f7..d11be3fb7c80 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -66,7 +66,7 @@ module_param(emulate_invalid_guest_state, bool, S_IRUGO);
66#define KVM_GUEST_CR0_MASK \ 66#define KVM_GUEST_CR0_MASK \
67 (KVM_GUEST_CR0_MASK_UNRESTRICTED_GUEST | X86_CR0_PG | X86_CR0_PE) 67 (KVM_GUEST_CR0_MASK_UNRESTRICTED_GUEST | X86_CR0_PG | X86_CR0_PE)
68#define KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST \ 68#define KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST \
69 (X86_CR0_WP | X86_CR0_NE | X86_CR0_TS | X86_CR0_MP) 69 (X86_CR0_WP | X86_CR0_NE | X86_CR0_MP)
70#define KVM_VM_CR0_ALWAYS_ON \ 70#define KVM_VM_CR0_ALWAYS_ON \
71 (KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST | X86_CR0_PG | X86_CR0_PE) 71 (KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST | X86_CR0_PG | X86_CR0_PE)
72#define KVM_CR4_GUEST_OWNED_BITS \ 72#define KVM_CR4_GUEST_OWNED_BITS \
@@ -579,9 +579,8 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu)
579{ 579{
580 u32 eb; 580 u32 eb;
581 581
582 eb = (1u << PF_VECTOR) | (1u << UD_VECTOR) | (1u << MC_VECTOR); 582 eb = (1u << PF_VECTOR) | (1u << UD_VECTOR) | (1u << MC_VECTOR)
583 if (!vcpu->fpu_active) 583 | (1u << NM_VECTOR);
584 eb |= 1u << NM_VECTOR;
585 /* 584 /*
586 * Unconditionally intercept #DB so we can maintain dr6 without 585 * Unconditionally intercept #DB so we can maintain dr6 without
587 * reading it every exit. 586 * reading it every exit.
@@ -595,6 +594,8 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu)
595 eb = ~0; 594 eb = ~0;
596 if (enable_ept) 595 if (enable_ept)
597 eb &= ~(1u << PF_VECTOR); /* bypass_guest_pf = 0 */ 596 eb &= ~(1u << PF_VECTOR); /* bypass_guest_pf = 0 */
597 if (vcpu->fpu_active)
598 eb &= ~(1u << NM_VECTOR);
598 vmcs_write32(EXCEPTION_BITMAP, eb); 599 vmcs_write32(EXCEPTION_BITMAP, eb);
599} 600}
600 601
@@ -806,9 +807,6 @@ static void vmx_fpu_activate(struct kvm_vcpu *vcpu)
806 807
807static void vmx_fpu_deactivate(struct kvm_vcpu *vcpu) 808static void vmx_fpu_deactivate(struct kvm_vcpu *vcpu)
808{ 809{
809 if (!vcpu->fpu_active)
810 return;
811 vcpu->fpu_active = 0;
812 vmcs_set_bits(GUEST_CR0, X86_CR0_TS); 810 vmcs_set_bits(GUEST_CR0, X86_CR0_TS);
813 update_exception_bitmap(vcpu); 811 update_exception_bitmap(vcpu);
814} 812}
@@ -1737,8 +1735,6 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
1737 else 1735 else
1738 hw_cr0 = (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON; 1736 hw_cr0 = (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON;
1739 1737
1740 vmx_fpu_deactivate(vcpu);
1741
1742 if (vmx->rmode.vm86_active && (cr0 & X86_CR0_PE)) 1738 if (vmx->rmode.vm86_active && (cr0 & X86_CR0_PE))
1743 enter_pmode(vcpu); 1739 enter_pmode(vcpu);
1744 1740
@@ -1757,12 +1753,12 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
1757 if (enable_ept) 1753 if (enable_ept)
1758 ept_update_paging_mode_cr0(&hw_cr0, cr0, vcpu); 1754 ept_update_paging_mode_cr0(&hw_cr0, cr0, vcpu);
1759 1755
1756 if (!vcpu->fpu_active)
1757 hw_cr0 |= X86_CR0_TS;
1758
1760 vmcs_writel(CR0_READ_SHADOW, cr0); 1759 vmcs_writel(CR0_READ_SHADOW, cr0);
1761 vmcs_writel(GUEST_CR0, hw_cr0); 1760 vmcs_writel(GUEST_CR0, hw_cr0);
1762 vcpu->arch.cr0 = cr0; 1761 vcpu->arch.cr0 = cr0;
1763
1764 if (!(cr0 & X86_CR0_TS) || !(cr0 & X86_CR0_PE))
1765 vmx_fpu_activate(vcpu);
1766} 1762}
1767 1763
1768static u64 construct_eptp(unsigned long root_hpa) 1764static u64 construct_eptp(unsigned long root_hpa)
@@ -1793,8 +1789,6 @@ static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
1793 1789
1794 vmx_flush_tlb(vcpu); 1790 vmx_flush_tlb(vcpu);
1795 vmcs_writel(GUEST_CR3, guest_cr3); 1791 vmcs_writel(GUEST_CR3, guest_cr3);
1796 if (kvm_read_cr0_bits(vcpu, X86_CR0_PE))
1797 vmx_fpu_deactivate(vcpu);
1798} 1792}
1799 1793
1800static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) 1794static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
@@ -3002,11 +2996,9 @@ static int handle_cr(struct kvm_vcpu *vcpu)
3002 }; 2996 };
3003 break; 2997 break;
3004 case 2: /* clts */ 2998 case 2: /* clts */
3005 vmx_fpu_deactivate(vcpu);
3006 vcpu->arch.cr0 &= ~X86_CR0_TS; 2999 vcpu->arch.cr0 &= ~X86_CR0_TS;
3007 vmcs_writel(CR0_READ_SHADOW, kvm_read_cr0(vcpu)); 3000 vmcs_writel(CR0_READ_SHADOW, kvm_read_cr0(vcpu));
3008 trace_kvm_cr_write(0, kvm_read_cr0(vcpu)); 3001 trace_kvm_cr_write(0, kvm_read_cr0(vcpu));
3009 vmx_fpu_activate(vcpu);
3010 skip_emulated_instruction(vcpu); 3002 skip_emulated_instruction(vcpu);
3011 return 1; 3003 return 1;
3012 case 1: /*mov from cr*/ 3004 case 1: /*mov from cr*/
@@ -4127,6 +4119,7 @@ static struct kvm_x86_ops vmx_x86_ops = {
4127 .cache_reg = vmx_cache_reg, 4119 .cache_reg = vmx_cache_reg,
4128 .get_rflags = vmx_get_rflags, 4120 .get_rflags = vmx_get_rflags,
4129 .set_rflags = vmx_set_rflags, 4121 .set_rflags = vmx_set_rflags,
4122 .fpu_deactivate = vmx_fpu_deactivate,
4130 4123
4131 .tlb_flush = vmx_flush_tlb, 4124 .tlb_flush = vmx_flush_tlb,
4132 4125
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 748b15d8e46d..1de2ad7a004d 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1509,8 +1509,8 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
1509 1509
1510void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) 1510void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
1511{ 1511{
1512 kvm_x86_ops->vcpu_put(vcpu);
1513 kvm_put_guest_fpu(vcpu); 1512 kvm_put_guest_fpu(vcpu);
1513 kvm_x86_ops->vcpu_put(vcpu);
1514} 1514}
1515 1515
1516static int is_efer_nx(void) 1516static int is_efer_nx(void)
@@ -4006,6 +4006,10 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
4006 r = 0; 4006 r = 0;
4007 goto out; 4007 goto out;
4008 } 4008 }
4009 if (test_and_clear_bit(KVM_REQ_DEACTIVATE_FPU, &vcpu->requests)) {
4010 vcpu->fpu_active = 0;
4011 kvm_x86_ops->fpu_deactivate(vcpu);
4012 }
4009 } 4013 }
4010 4014
4011 preempt_disable(); 4015 preempt_disable();
@@ -5075,6 +5079,7 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
5075 kvm_fx_save(&vcpu->arch.guest_fx_image); 5079 kvm_fx_save(&vcpu->arch.guest_fx_image);
5076 kvm_fx_restore(&vcpu->arch.host_fx_image); 5080 kvm_fx_restore(&vcpu->arch.host_fx_image);
5077 ++vcpu->stat.fpu_reload; 5081 ++vcpu->stat.fpu_reload;
5082 set_bit(KVM_REQ_DEACTIVATE_FPU, &vcpu->requests);
5078} 5083}
5079EXPORT_SYMBOL_GPL(kvm_put_guest_fpu); 5084EXPORT_SYMBOL_GPL(kvm_put_guest_fpu);
5080 5085