aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2009-09-07 04:14:12 -0400
committerAvi Kivity <avi@redhat.com>2009-12-03 02:32:22 -0500
commit26bb0981b3ff00b9177d61fe55806db978862b3c (patch)
treec64237caadf82729ca0d8aa9a9a66bdce27e66be /arch/x86
parent18863bdd60f895f3b3ba16b15e8331aee781e8ec (diff)
KVM: VMX: Use shared msr infrastructure
Instead of reloading syscall MSRs on every preemption, use the new shared msr infrastructure to reload them at the last possible minute (just before exit to userspace). Improves vcpu/idle/vcpu switches by about 2000 cycles (when EFER needs to be reloaded as well). [jan: fix slot index missing indirection] Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/kvm/vmx.c112
1 files changed, 42 insertions, 70 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 32512519e1ac..bf46253149c3 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -86,6 +86,11 @@ struct vmcs {
86 char data[0]; 86 char data[0];
87}; 87};
88 88
89struct shared_msr_entry {
90 unsigned index;
91 u64 data;
92};
93
89struct vcpu_vmx { 94struct vcpu_vmx {
90 struct kvm_vcpu vcpu; 95 struct kvm_vcpu vcpu;
91 struct list_head local_vcpus_link; 96 struct list_head local_vcpus_link;
@@ -93,8 +98,7 @@ struct vcpu_vmx {
93 int launched; 98 int launched;
94 u8 fail; 99 u8 fail;
95 u32 idt_vectoring_info; 100 u32 idt_vectoring_info;
96 struct kvm_msr_entry *guest_msrs; 101 struct shared_msr_entry *guest_msrs;
97 struct kvm_msr_entry *host_msrs;
98 int nmsrs; 102 int nmsrs;
99 int save_nmsrs; 103 int save_nmsrs;
100 int msr_offset_efer; 104 int msr_offset_efer;
@@ -108,7 +112,6 @@ struct vcpu_vmx {
108 u16 fs_sel, gs_sel, ldt_sel; 112 u16 fs_sel, gs_sel, ldt_sel;
109 int gs_ldt_reload_needed; 113 int gs_ldt_reload_needed;
110 int fs_reload_needed; 114 int fs_reload_needed;
111 int guest_efer_loaded;
112 } host_state; 115 } host_state;
113 struct { 116 struct {
114 int vm86_active; 117 int vm86_active;
@@ -195,6 +198,8 @@ static struct kvm_vmx_segment_field {
195 VMX_SEGMENT_FIELD(LDTR), 198 VMX_SEGMENT_FIELD(LDTR),
196}; 199};
197 200
201static u64 host_efer;
202
198static void ept_save_pdptrs(struct kvm_vcpu *vcpu); 203static void ept_save_pdptrs(struct kvm_vcpu *vcpu);
199 204
200/* 205/*
@@ -209,22 +214,6 @@ static const u32 vmx_msr_index[] = {
209}; 214};
210#define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index) 215#define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index)
211 216
212static void load_msrs(struct kvm_msr_entry *e, int n)
213{
214 int i;
215
216 for (i = 0; i < n; ++i)
217 wrmsrl(e[i].index, e[i].data);
218}
219
220static void save_msrs(struct kvm_msr_entry *e, int n)
221{
222 int i;
223
224 for (i = 0; i < n; ++i)
225 rdmsrl(e[i].index, e[i].data);
226}
227
228static inline int is_page_fault(u32 intr_info) 217static inline int is_page_fault(u32 intr_info)
229{ 218{
230 return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK | 219 return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
@@ -373,7 +362,7 @@ static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr)
373 int i; 362 int i;
374 363
375 for (i = 0; i < vmx->nmsrs; ++i) 364 for (i = 0; i < vmx->nmsrs; ++i)
376 if (vmx->guest_msrs[i].index == msr) 365 if (vmx_msr_index[vmx->guest_msrs[i].index] == msr)
377 return i; 366 return i;
378 return -1; 367 return -1;
379} 368}
@@ -404,7 +393,7 @@ static inline void __invept(int ext, u64 eptp, gpa_t gpa)
404 : : "a" (&operand), "c" (ext) : "cc", "memory"); 393 : : "a" (&operand), "c" (ext) : "cc", "memory");
405} 394}
406 395
407static struct kvm_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr) 396static struct shared_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr)
408{ 397{
409 int i; 398 int i;
410 399
@@ -595,17 +584,15 @@ static void reload_tss(void)
595 load_TR_desc(); 584 load_TR_desc();
596} 585}
597 586
598static void load_transition_efer(struct vcpu_vmx *vmx) 587static bool update_transition_efer(struct vcpu_vmx *vmx)
599{ 588{
600 int efer_offset = vmx->msr_offset_efer; 589 int efer_offset = vmx->msr_offset_efer;
601 u64 host_efer;
602 u64 guest_efer; 590 u64 guest_efer;
603 u64 ignore_bits; 591 u64 ignore_bits;
604 592
605 if (efer_offset < 0) 593 if (efer_offset < 0)
606 return; 594 return false;
607 host_efer = vmx->host_msrs[efer_offset].data; 595 guest_efer = vmx->vcpu.arch.shadow_efer;
608 guest_efer = vmx->guest_msrs[efer_offset].data;
609 596
610 /* 597 /*
611 * NX is emulated; LMA and LME handled by hardware; SCE meaninless 598 * NX is emulated; LMA and LME handled by hardware; SCE meaninless
@@ -619,26 +606,18 @@ static void load_transition_efer(struct vcpu_vmx *vmx)
619 ignore_bits &= ~(u64)EFER_SCE; 606 ignore_bits &= ~(u64)EFER_SCE;
620#endif 607#endif
621 if ((guest_efer & ~ignore_bits) == (host_efer & ~ignore_bits)) 608 if ((guest_efer & ~ignore_bits) == (host_efer & ~ignore_bits))
622 return; 609 return false;
623 610
624 vmx->host_state.guest_efer_loaded = 1;
625 guest_efer &= ~ignore_bits; 611 guest_efer &= ~ignore_bits;
626 guest_efer |= host_efer & ignore_bits; 612 guest_efer |= host_efer & ignore_bits;
627 wrmsrl(MSR_EFER, guest_efer); 613 vmx->guest_msrs[efer_offset].data = guest_efer;
628 vmx->vcpu.stat.efer_reload++; 614 return true;
629}
630
631static void reload_host_efer(struct vcpu_vmx *vmx)
632{
633 if (vmx->host_state.guest_efer_loaded) {
634 vmx->host_state.guest_efer_loaded = 0;
635 load_msrs(vmx->host_msrs + vmx->msr_offset_efer, 1);
636 }
637} 615}
638 616
639static void vmx_save_host_state(struct kvm_vcpu *vcpu) 617static void vmx_save_host_state(struct kvm_vcpu *vcpu)
640{ 618{
641 struct vcpu_vmx *vmx = to_vmx(vcpu); 619 struct vcpu_vmx *vmx = to_vmx(vcpu);
620 int i;
642 621
643 if (vmx->host_state.loaded) 622 if (vmx->host_state.loaded)
644 return; 623 return;
@@ -680,8 +659,9 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu)
680 wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base); 659 wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
681 } 660 }
682#endif 661#endif
683 load_msrs(vmx->guest_msrs, vmx->save_nmsrs); 662 for (i = 0; i < vmx->save_nmsrs; ++i)
684 load_transition_efer(vmx); 663 kvm_set_shared_msr(vmx->guest_msrs[i].index,
664 vmx->guest_msrs[i].data);
685} 665}
686 666
687static void __vmx_load_host_state(struct vcpu_vmx *vmx) 667static void __vmx_load_host_state(struct vcpu_vmx *vmx)
@@ -709,9 +689,6 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx)
709 local_irq_restore(flags); 689 local_irq_restore(flags);
710 } 690 }
711 reload_tss(); 691 reload_tss();
712 save_msrs(vmx->guest_msrs, vmx->save_nmsrs);
713 load_msrs(vmx->host_msrs, vmx->save_nmsrs);
714 reload_host_efer(vmx);
715#ifdef CONFIG_X86_64 692#ifdef CONFIG_X86_64
716 if (is_long_mode(&vmx->vcpu)) { 693 if (is_long_mode(&vmx->vcpu)) {
717 rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base); 694 rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
@@ -908,19 +885,14 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
908/* 885/*
909 * Swap MSR entry in host/guest MSR entry array. 886 * Swap MSR entry in host/guest MSR entry array.
910 */ 887 */
911#ifdef CONFIG_X86_64
912static void move_msr_up(struct vcpu_vmx *vmx, int from, int to) 888static void move_msr_up(struct vcpu_vmx *vmx, int from, int to)
913{ 889{
914 struct kvm_msr_entry tmp; 890 struct shared_msr_entry tmp;
915 891
916 tmp = vmx->guest_msrs[to]; 892 tmp = vmx->guest_msrs[to];
917 vmx->guest_msrs[to] = vmx->guest_msrs[from]; 893 vmx->guest_msrs[to] = vmx->guest_msrs[from];
918 vmx->guest_msrs[from] = tmp; 894 vmx->guest_msrs[from] = tmp;
919 tmp = vmx->host_msrs[to];
920 vmx->host_msrs[to] = vmx->host_msrs[from];
921 vmx->host_msrs[from] = tmp;
922} 895}
923#endif
924 896
925/* 897/*
926 * Set up the vmcs to automatically save and restore system 898 * Set up the vmcs to automatically save and restore system
@@ -929,15 +901,13 @@ static void move_msr_up(struct vcpu_vmx *vmx, int from, int to)
929 */ 901 */
930static void setup_msrs(struct vcpu_vmx *vmx) 902static void setup_msrs(struct vcpu_vmx *vmx)
931{ 903{
932 int save_nmsrs; 904 int save_nmsrs, index;
933 unsigned long *msr_bitmap; 905 unsigned long *msr_bitmap;
934 906
935 vmx_load_host_state(vmx); 907 vmx_load_host_state(vmx);
936 save_nmsrs = 0; 908 save_nmsrs = 0;
937#ifdef CONFIG_X86_64 909#ifdef CONFIG_X86_64
938 if (is_long_mode(&vmx->vcpu)) { 910 if (is_long_mode(&vmx->vcpu)) {
939 int index;
940
941 index = __find_msr_index(vmx, MSR_SYSCALL_MASK); 911 index = __find_msr_index(vmx, MSR_SYSCALL_MASK);
942 if (index >= 0) 912 if (index >= 0)
943 move_msr_up(vmx, index, save_nmsrs++); 913 move_msr_up(vmx, index, save_nmsrs++);
@@ -956,9 +926,11 @@ static void setup_msrs(struct vcpu_vmx *vmx)
956 move_msr_up(vmx, index, save_nmsrs++); 926 move_msr_up(vmx, index, save_nmsrs++);
957 } 927 }
958#endif 928#endif
959 vmx->save_nmsrs = save_nmsrs; 929 vmx->msr_offset_efer = index = __find_msr_index(vmx, MSR_EFER);
930 if (index >= 0 && update_transition_efer(vmx))
931 move_msr_up(vmx, index, save_nmsrs++);
960 932
961 vmx->msr_offset_efer = __find_msr_index(vmx, MSR_EFER); 933 vmx->save_nmsrs = save_nmsrs;
962 934
963 if (cpu_has_vmx_msr_bitmap()) { 935 if (cpu_has_vmx_msr_bitmap()) {
964 if (is_long_mode(&vmx->vcpu)) 936 if (is_long_mode(&vmx->vcpu))
@@ -1000,7 +972,7 @@ static void guest_write_tsc(u64 guest_tsc, u64 host_tsc)
1000static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) 972static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
1001{ 973{
1002 u64 data; 974 u64 data;
1003 struct kvm_msr_entry *msr; 975 struct shared_msr_entry *msr;
1004 976
1005 if (!pdata) { 977 if (!pdata) {
1006 printk(KERN_ERR "BUG: get_msr called with NULL pdata\n"); 978 printk(KERN_ERR "BUG: get_msr called with NULL pdata\n");
@@ -1019,9 +991,9 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
1019 vmx_load_host_state(to_vmx(vcpu)); 991 vmx_load_host_state(to_vmx(vcpu));
1020 data = to_vmx(vcpu)->msr_guest_kernel_gs_base; 992 data = to_vmx(vcpu)->msr_guest_kernel_gs_base;
1021 break; 993 break;
994#endif
1022 case MSR_EFER: 995 case MSR_EFER:
1023 return kvm_get_msr_common(vcpu, msr_index, pdata); 996 return kvm_get_msr_common(vcpu, msr_index, pdata);
1024#endif
1025 case MSR_IA32_TSC: 997 case MSR_IA32_TSC:
1026 data = guest_read_tsc(); 998 data = guest_read_tsc();
1027 break; 999 break;
@@ -1035,6 +1007,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
1035 data = vmcs_readl(GUEST_SYSENTER_ESP); 1007 data = vmcs_readl(GUEST_SYSENTER_ESP);
1036 break; 1008 break;
1037 default: 1009 default:
1010 vmx_load_host_state(to_vmx(vcpu));
1038 msr = find_msr_entry(to_vmx(vcpu), msr_index); 1011 msr = find_msr_entry(to_vmx(vcpu), msr_index);
1039 if (msr) { 1012 if (msr) {
1040 vmx_load_host_state(to_vmx(vcpu)); 1013 vmx_load_host_state(to_vmx(vcpu));
@@ -1056,7 +1029,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
1056static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) 1029static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
1057{ 1030{
1058 struct vcpu_vmx *vmx = to_vmx(vcpu); 1031 struct vcpu_vmx *vmx = to_vmx(vcpu);
1059 struct kvm_msr_entry *msr; 1032 struct shared_msr_entry *msr;
1060 u64 host_tsc; 1033 u64 host_tsc;
1061 int ret = 0; 1034 int ret = 0;
1062 1035
@@ -1565,7 +1538,10 @@ continue_rmode:
1565static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer) 1538static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer)
1566{ 1539{
1567 struct vcpu_vmx *vmx = to_vmx(vcpu); 1540 struct vcpu_vmx *vmx = to_vmx(vcpu);
1568 struct kvm_msr_entry *msr = find_msr_entry(vmx, MSR_EFER); 1541 struct shared_msr_entry *msr = find_msr_entry(vmx, MSR_EFER);
1542
1543 if (!msr)
1544 return;
1569 1545
1570 /* 1546 /*
1571 * Force kernel_gs_base reloading before EFER changes, as control 1547 * Force kernel_gs_base reloading before EFER changes, as control
@@ -2417,10 +2393,8 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
2417 if (wrmsr_safe(index, data_low, data_high) < 0) 2393 if (wrmsr_safe(index, data_low, data_high) < 0)
2418 continue; 2394 continue;
2419 data = data_low | ((u64)data_high << 32); 2395 data = data_low | ((u64)data_high << 32);
2420 vmx->host_msrs[j].index = index; 2396 vmx->guest_msrs[j].index = i;
2421 vmx->host_msrs[j].reserved = 0; 2397 vmx->guest_msrs[j].data = 0;
2422 vmx->host_msrs[j].data = data;
2423 vmx->guest_msrs[j] = vmx->host_msrs[j];
2424 ++vmx->nmsrs; 2398 ++vmx->nmsrs;
2425 } 2399 }
2426 2400
@@ -3821,7 +3795,6 @@ static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
3821 __clear_bit(vmx->vpid, vmx_vpid_bitmap); 3795 __clear_bit(vmx->vpid, vmx_vpid_bitmap);
3822 spin_unlock(&vmx_vpid_lock); 3796 spin_unlock(&vmx_vpid_lock);
3823 vmx_free_vmcs(vcpu); 3797 vmx_free_vmcs(vcpu);
3824 kfree(vmx->host_msrs);
3825 kfree(vmx->guest_msrs); 3798 kfree(vmx->guest_msrs);
3826 kvm_vcpu_uninit(vcpu); 3799 kvm_vcpu_uninit(vcpu);
3827 kmem_cache_free(kvm_vcpu_cache, vmx); 3800 kmem_cache_free(kvm_vcpu_cache, vmx);
@@ -3848,10 +3821,6 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
3848 goto uninit_vcpu; 3821 goto uninit_vcpu;
3849 } 3822 }
3850 3823
3851 vmx->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
3852 if (!vmx->host_msrs)
3853 goto free_guest_msrs;
3854
3855 vmx->vmcs = alloc_vmcs(); 3824 vmx->vmcs = alloc_vmcs();
3856 if (!vmx->vmcs) 3825 if (!vmx->vmcs)
3857 goto free_msrs; 3826 goto free_msrs;
@@ -3882,8 +3851,6 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
3882free_vmcs: 3851free_vmcs:
3883 free_vmcs(vmx->vmcs); 3852 free_vmcs(vmx->vmcs);
3884free_msrs: 3853free_msrs:
3885 kfree(vmx->host_msrs);
3886free_guest_msrs:
3887 kfree(vmx->guest_msrs); 3854 kfree(vmx->guest_msrs);
3888uninit_vcpu: 3855uninit_vcpu:
3889 kvm_vcpu_uninit(&vmx->vcpu); 3856 kvm_vcpu_uninit(&vmx->vcpu);
@@ -4033,7 +4000,12 @@ static struct kvm_x86_ops vmx_x86_ops = {
4033 4000
4034static int __init vmx_init(void) 4001static int __init vmx_init(void)
4035{ 4002{
4036 int r; 4003 int r, i;
4004
4005 rdmsrl_safe(MSR_EFER, &host_efer);
4006
4007 for (i = 0; i < NR_VMX_MSR; ++i)
4008 kvm_define_shared_msr(i, vmx_msr_index[i]);
4037 4009
4038 vmx_io_bitmap_a = (unsigned long *)__get_free_page(GFP_KERNEL); 4010 vmx_io_bitmap_a = (unsigned long *)__get_free_page(GFP_KERNEL);
4039 if (!vmx_io_bitmap_a) 4011 if (!vmx_io_bitmap_a)