diff options
Diffstat (limited to 'drivers/kvm')
-rw-r--r-- | drivers/kvm/vmx.c | 58 |
1 files changed, 42 insertions, 16 deletions
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index 3745e6ccc5b4..6270df58e055 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c | |||
@@ -80,6 +80,9 @@ static const u32 vmx_msr_index[] = { | |||
80 | 80 | ||
81 | #ifdef CONFIG_X86_64 | 81 | #ifdef CONFIG_X86_64 |
82 | static unsigned msr_offset_kernel_gs_base; | 82 | static unsigned msr_offset_kernel_gs_base; |
83 | #define NR_64BIT_MSRS 4 | ||
84 | #else | ||
85 | #define NR_64BIT_MSRS 0 | ||
83 | #endif | 86 | #endif |
84 | 87 | ||
85 | static inline int is_page_fault(u32 intr_info) | 88 | static inline int is_page_fault(u32 intr_info) |
@@ -301,6 +304,32 @@ static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code) | |||
301 | } | 304 | } |
302 | 305 | ||
303 | /* | 306 | /* |
307 | * Set up the vmcs to automatically save and restore system | ||
308 | * msrs. Don't touch the 64-bit msrs if the guest is in legacy | ||
309 | * mode, as fiddling with msrs is very expensive. | ||
310 | */ | ||
311 | static void setup_msrs(struct kvm_vcpu *vcpu) | ||
312 | { | ||
313 | int nr_skip, nr_good_msrs; | ||
314 | |||
315 | if (is_long_mode(vcpu)) | ||
316 | nr_skip = NR_BAD_MSRS; | ||
317 | else | ||
318 | nr_skip = NR_64BIT_MSRS; | ||
319 | nr_good_msrs = vcpu->nmsrs - nr_skip; | ||
320 | |||
321 | vmcs_writel(VM_ENTRY_MSR_LOAD_ADDR, | ||
322 | virt_to_phys(vcpu->guest_msrs + nr_skip)); | ||
323 | vmcs_writel(VM_EXIT_MSR_STORE_ADDR, | ||
324 | virt_to_phys(vcpu->guest_msrs + nr_skip)); | ||
325 | vmcs_writel(VM_EXIT_MSR_LOAD_ADDR, | ||
326 | virt_to_phys(vcpu->host_msrs + nr_skip)); | ||
327 | vmcs_write32(VM_EXIT_MSR_STORE_COUNT, nr_good_msrs); /* 22.2.2 */ | ||
328 | vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */ | ||
329 | vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */ | ||
330 | } | ||
331 | |||
332 | /* | ||
304 | * reads and returns guest's timestamp counter "register" | 333 | * reads and returns guest's timestamp counter "register" |
305 | * guest_tsc = host_tsc + tsc_offset -- 21.3 | 334 | * guest_tsc = host_tsc + tsc_offset -- 21.3 |
306 | */ | 335 | */ |
@@ -825,6 +854,7 @@ static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer) | |||
825 | 854 | ||
826 | msr->data = efer & ~EFER_LME; | 855 | msr->data = efer & ~EFER_LME; |
827 | } | 856 | } |
857 | setup_msrs(vcpu); | ||
828 | } | 858 | } |
829 | 859 | ||
830 | #endif | 860 | #endif |
@@ -988,7 +1018,6 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) | |||
988 | struct descriptor_table dt; | 1018 | struct descriptor_table dt; |
989 | int i; | 1019 | int i; |
990 | int ret = 0; | 1020 | int ret = 0; |
991 | int nr_good_msrs; | ||
992 | extern asmlinkage void kvm_vmx_return(void); | 1021 | extern asmlinkage void kvm_vmx_return(void); |
993 | 1022 | ||
994 | if (!init_rmode_tss(vcpu->kvm)) { | 1023 | if (!init_rmode_tss(vcpu->kvm)) { |
@@ -1140,19 +1169,10 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) | |||
1140 | ++vcpu->nmsrs; | 1169 | ++vcpu->nmsrs; |
1141 | } | 1170 | } |
1142 | 1171 | ||
1143 | nr_good_msrs = vcpu->nmsrs - NR_BAD_MSRS; | 1172 | setup_msrs(vcpu); |
1144 | vmcs_writel(VM_ENTRY_MSR_LOAD_ADDR, | 1173 | |
1145 | virt_to_phys(vcpu->guest_msrs + NR_BAD_MSRS)); | ||
1146 | vmcs_writel(VM_EXIT_MSR_STORE_ADDR, | ||
1147 | virt_to_phys(vcpu->guest_msrs + NR_BAD_MSRS)); | ||
1148 | vmcs_writel(VM_EXIT_MSR_LOAD_ADDR, | ||
1149 | virt_to_phys(vcpu->host_msrs + NR_BAD_MSRS)); | ||
1150 | vmcs_write32_fixedbits(MSR_IA32_VMX_EXIT_CTLS, VM_EXIT_CONTROLS, | 1174 | vmcs_write32_fixedbits(MSR_IA32_VMX_EXIT_CTLS, VM_EXIT_CONTROLS, |
1151 | (HOST_IS_64 << 9)); /* 22.2,1, 20.7.1 */ | 1175 | (HOST_IS_64 << 9)); /* 22.2,1, 20.7.1 */ |
1152 | vmcs_write32(VM_EXIT_MSR_STORE_COUNT, nr_good_msrs); /* 22.2.2 */ | ||
1153 | vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */ | ||
1154 | vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */ | ||
1155 | |||
1156 | 1176 | ||
1157 | /* 22.2.1, 20.8.1 */ | 1177 | /* 22.2.1, 20.8.1 */ |
1158 | vmcs_write32_fixedbits(MSR_IA32_VMX_ENTRY_CTLS, | 1178 | vmcs_write32_fixedbits(MSR_IA32_VMX_ENTRY_CTLS, |
@@ -1769,9 +1789,11 @@ again: | |||
1769 | fx_restore(vcpu->guest_fx_image); | 1789 | fx_restore(vcpu->guest_fx_image); |
1770 | 1790 | ||
1771 | #ifdef CONFIG_X86_64 | 1791 | #ifdef CONFIG_X86_64 |
1772 | save_msrs(vcpu->host_msrs + msr_offset_kernel_gs_base, 1); | 1792 | if (is_long_mode(vcpu)) { |
1793 | save_msrs(vcpu->host_msrs + msr_offset_kernel_gs_base, 1); | ||
1794 | load_msrs(vcpu->guest_msrs, NR_BAD_MSRS); | ||
1795 | } | ||
1773 | #endif | 1796 | #endif |
1774 | load_msrs(vcpu->guest_msrs, NR_BAD_MSRS); | ||
1775 | 1797 | ||
1776 | asm ( | 1798 | asm ( |
1777 | /* Store host registers */ | 1799 | /* Store host registers */ |
@@ -1915,8 +1937,12 @@ again: | |||
1915 | } | 1937 | } |
1916 | ++kvm_stat.exits; | 1938 | ++kvm_stat.exits; |
1917 | 1939 | ||
1918 | save_msrs(vcpu->guest_msrs, NR_BAD_MSRS); | 1940 | #ifdef CONFIG_X86_64 |
1919 | load_msrs(vcpu->host_msrs, NR_BAD_MSRS); | 1941 | if (is_long_mode(vcpu)) { |
1942 | save_msrs(vcpu->guest_msrs, NR_BAD_MSRS); | ||
1943 | load_msrs(vcpu->host_msrs, NR_BAD_MSRS); | ||
1944 | } | ||
1945 | #endif | ||
1920 | 1946 | ||
1921 | fx_save(vcpu->guest_fx_image); | 1947 | fx_save(vcpu->guest_fx_image); |
1922 | fx_restore(vcpu->host_fx_image); | 1948 | fx_restore(vcpu->host_fx_image); |