diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2007-04-27 02:29:49 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-05-03 03:52:31 -0400 |
commit | 2ab455ccceb07945368709ba852e49f4c3119331 (patch) | |
tree | de79805085d8dfcf5714c45e7873116c110bd182 /drivers/kvm | |
parent | 25c4c2762e31a75403eca0dd59f2cab85e3a2532 (diff) |
KVM: VMX: Add lazy FPU support for VT
Only save/restore the FPU host state when the guest is actually using the
FPU.
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/vmx.c | 61 |
1 files changed, 56 insertions, 5 deletions
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index 09608114e29a..5a2a68dec6bf 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c | |||
@@ -101,6 +101,13 @@ static inline int is_page_fault(u32 intr_info) | |||
101 | (INTR_TYPE_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK); | 101 | (INTR_TYPE_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK); |
102 | } | 102 | } |
103 | 103 | ||
104 | static inline int is_no_device(u32 intr_info) | ||
105 | { | ||
106 | return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK | | ||
107 | INTR_INFO_VALID_MASK)) == | ||
108 | (INTR_TYPE_EXCEPTION | NM_VECTOR | INTR_INFO_VALID_MASK); | ||
109 | } | ||
110 | |||
104 | static inline int is_external_interrupt(u32 intr_info) | 111 | static inline int is_external_interrupt(u32 intr_info) |
105 | { | 112 | { |
106 | return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK)) | 113 | return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK)) |
@@ -216,6 +223,16 @@ static void vmcs_write64(unsigned long field, u64 value) | |||
216 | #endif | 223 | #endif |
217 | } | 224 | } |
218 | 225 | ||
226 | static void vmcs_clear_bits(unsigned long field, u32 mask) | ||
227 | { | ||
228 | vmcs_writel(field, vmcs_readl(field) & ~mask); | ||
229 | } | ||
230 | |||
231 | static void vmcs_set_bits(unsigned long field, u32 mask) | ||
232 | { | ||
233 | vmcs_writel(field, vmcs_readl(field) | mask); | ||
234 | } | ||
235 | |||
219 | /* | 236 | /* |
220 | * Switches to specified vcpu, until a matching vcpu_put(), but assumes | 237 | * Switches to specified vcpu, until a matching vcpu_put(), but assumes |
221 | * vcpu mutex is already taken. | 238 | * vcpu mutex is already taken. |
@@ -833,6 +850,11 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) | |||
833 | } | 850 | } |
834 | #endif | 851 | #endif |
835 | 852 | ||
853 | if (!(cr0 & CR0_TS_MASK)) { | ||
854 | vcpu->fpu_active = 1; | ||
855 | vmcs_clear_bits(EXCEPTION_BITMAP, CR0_TS_MASK); | ||
856 | } | ||
857 | |||
836 | vmcs_writel(CR0_READ_SHADOW, cr0); | 858 | vmcs_writel(CR0_READ_SHADOW, cr0); |
837 | vmcs_writel(GUEST_CR0, | 859 | vmcs_writel(GUEST_CR0, |
838 | (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON); | 860 | (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON); |
@@ -842,6 +864,12 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) | |||
842 | static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) | 864 | static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) |
843 | { | 865 | { |
844 | vmcs_writel(GUEST_CR3, cr3); | 866 | vmcs_writel(GUEST_CR3, cr3); |
867 | |||
868 | if (!(vcpu->cr0 & CR0_TS_MASK)) { | ||
869 | vcpu->fpu_active = 0; | ||
870 | vmcs_set_bits(GUEST_CR0, CR0_TS_MASK); | ||
871 | vmcs_set_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR); | ||
872 | } | ||
845 | } | 873 | } |
846 | 874 | ||
847 | static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) | 875 | static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) |
@@ -1368,6 +1396,15 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1368 | asm ("int $2"); | 1396 | asm ("int $2"); |
1369 | return 1; | 1397 | return 1; |
1370 | } | 1398 | } |
1399 | |||
1400 | if (is_no_device(intr_info)) { | ||
1401 | vcpu->fpu_active = 1; | ||
1402 | vmcs_clear_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR); | ||
1403 | if (!(vcpu->cr0 & CR0_TS_MASK)) | ||
1404 | vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK); | ||
1405 | return 1; | ||
1406 | } | ||
1407 | |||
1371 | error_code = 0; | 1408 | error_code = 0; |
1372 | rip = vmcs_readl(GUEST_RIP); | 1409 | rip = vmcs_readl(GUEST_RIP); |
1373 | if (intr_info & INTR_INFO_DELIEVER_CODE_MASK) | 1410 | if (intr_info & INTR_INFO_DELIEVER_CODE_MASK) |
@@ -1556,7 +1593,11 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1556 | break; | 1593 | break; |
1557 | case 2: /* clts */ | 1594 | case 2: /* clts */ |
1558 | vcpu_load_rsp_rip(vcpu); | 1595 | vcpu_load_rsp_rip(vcpu); |
1559 | set_cr0(vcpu, vcpu->cr0 & ~CR0_TS_MASK); | 1596 | vcpu->fpu_active = 1; |
1597 | vmcs_clear_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR); | ||
1598 | vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK); | ||
1599 | vcpu->cr0 &= ~CR0_TS_MASK; | ||
1600 | vmcs_writel(CR0_READ_SHADOW, vcpu->cr0); | ||
1560 | skip_emulated_instruction(vcpu); | 1601 | skip_emulated_instruction(vcpu); |
1561 | return 1; | 1602 | return 1; |
1562 | case 1: /*mov from cr*/ | 1603 | case 1: /*mov from cr*/ |
@@ -1806,8 +1847,14 @@ again: | |||
1806 | if (vcpu->guest_debug.enabled) | 1847 | if (vcpu->guest_debug.enabled) |
1807 | kvm_guest_debug_pre(vcpu); | 1848 | kvm_guest_debug_pre(vcpu); |
1808 | 1849 | ||
1809 | fx_save(vcpu->host_fx_image); | 1850 | if (vcpu->fpu_active) { |
1810 | fx_restore(vcpu->guest_fx_image); | 1851 | fx_save(vcpu->host_fx_image); |
1852 | fx_restore(vcpu->guest_fx_image); | ||
1853 | } | ||
1854 | /* | ||
1855 | * Loading guest fpu may have cleared host cr0.ts | ||
1856 | */ | ||
1857 | vmcs_writel(HOST_CR0, read_cr0()); | ||
1811 | 1858 | ||
1812 | #ifdef CONFIG_X86_64 | 1859 | #ifdef CONFIG_X86_64 |
1813 | if (is_long_mode(vcpu)) { | 1860 | if (is_long_mode(vcpu)) { |
@@ -1965,8 +2012,11 @@ again: | |||
1965 | } | 2012 | } |
1966 | #endif | 2013 | #endif |
1967 | 2014 | ||
1968 | fx_save(vcpu->guest_fx_image); | 2015 | if (vcpu->fpu_active) { |
1969 | fx_restore(vcpu->host_fx_image); | 2016 | fx_save(vcpu->guest_fx_image); |
2017 | fx_restore(vcpu->host_fx_image); | ||
2018 | } | ||
2019 | |||
1970 | vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0; | 2020 | vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0; |
1971 | 2021 | ||
1972 | asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); | 2022 | asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); |
@@ -2078,6 +2128,7 @@ static int vmx_create_vcpu(struct kvm_vcpu *vcpu) | |||
2078 | vmcs_clear(vmcs); | 2128 | vmcs_clear(vmcs); |
2079 | vcpu->vmcs = vmcs; | 2129 | vcpu->vmcs = vmcs; |
2080 | vcpu->launched = 0; | 2130 | vcpu->launched = 0; |
2131 | vcpu->fpu_active = 1; | ||
2081 | 2132 | ||
2082 | return 0; | 2133 | return 0; |
2083 | 2134 | ||