aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2017-12-13 08:16:30 -0500
committerRadim Krčmář <rkrcmar@redhat.com>2018-01-16 10:52:52 -0500
commitc992384bde84fb2f0318bdb4f6c710605dd7a217 (patch)
tree60f91e72baf56050435eccd642b4e04067e8bbb9
parent1f6e5b25643e539e55a4c7553e4be6562c88fb76 (diff)
KVM: vmx: speed up MSR bitmap merge
The bulk of the MSR bitmap is either immutable, or can be copied from the L1 bitmap. By initializing it at VMXON time, and copying the mutable parts one long at a time on vmentry (rather than one bit), about 4000 clock cycles (30%) can be saved on a nested VMLAUNCH/VMRESUME. The resulting for loop only has four iterations, so it is cheap enough to reinitialize the MSR write bitmaps on every iteration, and it makes the code simpler. Suggested-by: Jim Mattson <jmattson@google.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
-rw-r--r--arch/x86/kvm/vmx.c78
1 files changed, 42 insertions, 36 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 1f4a3037b99e..71b2c9354423 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -4972,11 +4972,6 @@ static void nested_vmx_disable_intercept_for_msr(unsigned long *msr_bitmap_l1,
4972{ 4972{
4973 int f = sizeof(unsigned long); 4973 int f = sizeof(unsigned long);
4974 4974
4975 if (!cpu_has_vmx_msr_bitmap()) {
4976 WARN_ON(1);
4977 return;
4978 }
4979
4980 /* 4975 /*
4981 * See Intel PRM Vol. 3, 20.6.9 (MSR-Bitmap Address). Early manuals 4976 * See Intel PRM Vol. 3, 20.6.9 (MSR-Bitmap Address). Early manuals
4982 * have the write-low and read-high bitmap offsets the wrong way round. 4977 * have the write-low and read-high bitmap offsets the wrong way round.
@@ -7177,6 +7172,7 @@ static int enter_vmx_operation(struct kvm_vcpu *vcpu)
7177 (unsigned long *)__get_free_page(GFP_KERNEL); 7172 (unsigned long *)__get_free_page(GFP_KERNEL);
7178 if (!vmx->nested.msr_bitmap) 7173 if (!vmx->nested.msr_bitmap)
7179 goto out_msr_bitmap; 7174 goto out_msr_bitmap;
7175 memset(vmx->nested.msr_bitmap, 0xff, PAGE_SIZE);
7180 } 7176 }
7181 7177
7182 vmx->nested.cached_vmcs12 = kmalloc(VMCS12_SIZE, GFP_KERNEL); 7178 vmx->nested.cached_vmcs12 = kmalloc(VMCS12_SIZE, GFP_KERNEL);
@@ -9844,8 +9840,8 @@ static void vmx_inject_page_fault_nested(struct kvm_vcpu *vcpu,
9844 } 9840 }
9845} 9841}
9846 9842
9847static inline bool nested_vmx_merge_msr_bitmap(struct kvm_vcpu *vcpu, 9843static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
9848 struct vmcs12 *vmcs12); 9844 struct vmcs12 *vmcs12);
9849 9845
9850static void nested_get_vmcs12_pages(struct kvm_vcpu *vcpu, 9846static void nested_get_vmcs12_pages(struct kvm_vcpu *vcpu,
9851 struct vmcs12 *vmcs12) 9847 struct vmcs12 *vmcs12)
@@ -9934,11 +9930,7 @@ static void nested_get_vmcs12_pages(struct kvm_vcpu *vcpu,
9934 (unsigned long)(vmcs12->posted_intr_desc_addr & 9930 (unsigned long)(vmcs12->posted_intr_desc_addr &
9935 (PAGE_SIZE - 1))); 9931 (PAGE_SIZE - 1)));
9936 } 9932 }
9937 if (cpu_has_vmx_msr_bitmap() && 9933 if (!nested_vmx_prepare_msr_bitmap(vcpu, vmcs12))
9938 nested_cpu_has(vmcs12, CPU_BASED_USE_MSR_BITMAPS) &&
9939 nested_vmx_merge_msr_bitmap(vcpu, vmcs12))
9940 ;
9941 else
9942 vmcs_clear_bits(CPU_BASED_VM_EXEC_CONTROL, 9934 vmcs_clear_bits(CPU_BASED_VM_EXEC_CONTROL,
9943 CPU_BASED_USE_MSR_BITMAPS); 9935 CPU_BASED_USE_MSR_BITMAPS);
9944} 9936}
@@ -10006,14 +9998,19 @@ static int nested_vmx_check_tpr_shadow_controls(struct kvm_vcpu *vcpu,
10006 * Merge L0's and L1's MSR bitmap, return false to indicate that 9998 * Merge L0's and L1's MSR bitmap, return false to indicate that
10007 * we do not use the hardware. 9999 * we do not use the hardware.
10008 */ 10000 */
10009static inline bool nested_vmx_merge_msr_bitmap(struct kvm_vcpu *vcpu, 10001static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
10010 struct vmcs12 *vmcs12) 10002 struct vmcs12 *vmcs12)
10011{ 10003{
10012 int msr; 10004 int msr;
10013 struct page *page; 10005 struct page *page;
10014 unsigned long *msr_bitmap_l1; 10006 unsigned long *msr_bitmap_l1;
10015 unsigned long *msr_bitmap_l0 = to_vmx(vcpu)->nested.msr_bitmap; 10007 unsigned long *msr_bitmap_l0 = to_vmx(vcpu)->nested.msr_bitmap;
10016 10008
10009 /* Nothing to do if the MSR bitmap is not in use. */
10010 if (!cpu_has_vmx_msr_bitmap() ||
10011 !nested_cpu_has(vmcs12, CPU_BASED_USE_MSR_BITMAPS))
10012 return false;
10013
10017 /* This shortcut is ok because we support only x2APIC MSRs so far. */ 10014 /* This shortcut is ok because we support only x2APIC MSRs so far. */
10018 if (!nested_cpu_has_virt_x2apic_mode(vmcs12)) 10015 if (!nested_cpu_has_virt_x2apic_mode(vmcs12))
10019 return false; 10016 return false;
@@ -10021,32 +10018,41 @@ static inline bool nested_vmx_merge_msr_bitmap(struct kvm_vcpu *vcpu,
10021 page = kvm_vcpu_gpa_to_page(vcpu, vmcs12->msr_bitmap); 10018 page = kvm_vcpu_gpa_to_page(vcpu, vmcs12->msr_bitmap);
10022 if (is_error_page(page)) 10019 if (is_error_page(page))
10023 return false; 10020 return false;
10024 msr_bitmap_l1 = (unsigned long *)kmap(page);
10025 10021
10026 memset(msr_bitmap_l0, 0xff, PAGE_SIZE); 10022 msr_bitmap_l1 = (unsigned long *)kmap(page);
10023 if (nested_cpu_has_apic_reg_virt(vmcs12)) {
10024 /*
10025 * L0 need not intercept reads for MSRs between 0x800 and 0x8ff, it
10026 * just lets the processor take the value from the virtual-APIC page;
10027 * take those 256 bits directly from the L1 bitmap.
10028 */
10029 for (msr = 0x800; msr <= 0x8ff; msr += BITS_PER_LONG) {
10030 unsigned word = msr / BITS_PER_LONG;
10031 msr_bitmap_l0[word] = msr_bitmap_l1[word];
10032 msr_bitmap_l0[word + (0x800 / sizeof(long))] = ~0;
10033 }
10034 } else {
10035 for (msr = 0x800; msr <= 0x8ff; msr += BITS_PER_LONG) {
10036 unsigned word = msr / BITS_PER_LONG;
10037 msr_bitmap_l0[word] = ~0;
10038 msr_bitmap_l0[word + (0x800 / sizeof(long))] = ~0;
10039 }
10040 }
10027 10041
10028 if (nested_cpu_has_virt_x2apic_mode(vmcs12)) { 10042 nested_vmx_disable_intercept_for_msr(
10029 if (nested_cpu_has_apic_reg_virt(vmcs12)) 10043 msr_bitmap_l1, msr_bitmap_l0,
10030 for (msr = 0x800; msr <= 0x8ff; msr++) 10044 APIC_BASE_MSR + (APIC_TASKPRI >> 4),
10031 nested_vmx_disable_intercept_for_msr( 10045 MSR_TYPE_W);
10032 msr_bitmap_l1, msr_bitmap_l0,
10033 msr, MSR_TYPE_R);
10034 10046
10047 if (nested_cpu_has_vid(vmcs12)) {
10035 nested_vmx_disable_intercept_for_msr( 10048 nested_vmx_disable_intercept_for_msr(
10036 msr_bitmap_l1, msr_bitmap_l0, 10049 msr_bitmap_l1, msr_bitmap_l0,
10037 APIC_BASE_MSR + (APIC_TASKPRI >> 4), 10050 APIC_BASE_MSR + (APIC_EOI >> 4),
10038 MSR_TYPE_R | MSR_TYPE_W); 10051 MSR_TYPE_W);
10039 10052 nested_vmx_disable_intercept_for_msr(
10040 if (nested_cpu_has_vid(vmcs12)) { 10053 msr_bitmap_l1, msr_bitmap_l0,
10041 nested_vmx_disable_intercept_for_msr( 10054 APIC_BASE_MSR + (APIC_SELF_IPI >> 4),
10042 msr_bitmap_l1, msr_bitmap_l0, 10055 MSR_TYPE_W);
10043 APIC_BASE_MSR + (APIC_EOI >> 4),
10044 MSR_TYPE_W);
10045 nested_vmx_disable_intercept_for_msr(
10046 msr_bitmap_l1, msr_bitmap_l0,
10047 APIC_BASE_MSR + (APIC_SELF_IPI >> 4),
10048 MSR_TYPE_W);
10049 }
10050 } 10056 }
10051 kunmap(page); 10057 kunmap(page);
10052 kvm_release_page_clean(page); 10058 kvm_release_page_clean(page);