diff options
author | Wincy Van <fanwenyi0529@gmail.com> | 2015-02-03 10:56:03 -0500 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2015-02-03 11:06:17 -0500 |
commit | f2b93280edee5c7e95eecba48707a4e4a19b17c8 (patch) | |
tree | 6b4ac484f00e60309f5878a17833dbd881ebb90f | |
parent | 3af18d9c5fe95a6b377dca7b9ff9c6d3ab7f0969 (diff) |
KVM: nVMX: Enable nested virtualize x2apic mode
When L2 is using x2apic, we can use virtualize x2apic mode to
gain higher performance, especially in apicv case.
This patch also introduces nested_vmx_check_apicv_controls
for the nested apicv patches.
Signed-off-by: Wincy Van <fanwenyi0529@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | arch/x86/kvm/vmx.c | 114 |
1 files changed, 112 insertions, 2 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 6d1d26f017c1..25984e7e8a4d 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -1115,6 +1115,11 @@ static inline bool nested_cpu_has_xsaves(struct vmcs12 *vmcs12) | |||
1115 | vmx_xsaves_supported(); | 1115 | vmx_xsaves_supported(); |
1116 | } | 1116 | } |
1117 | 1117 | ||
1118 | static inline bool nested_cpu_has_virt_x2apic_mode(struct vmcs12 *vmcs12) | ||
1119 | { | ||
1120 | return nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE); | ||
1121 | } | ||
1122 | |||
1118 | static inline bool is_exception(u32 intr_info) | 1123 | static inline bool is_exception(u32 intr_info) |
1119 | { | 1124 | { |
1120 | return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK)) | 1125 | return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK)) |
@@ -2402,6 +2407,7 @@ static __init void nested_vmx_setup_ctls_msrs(void) | |||
2402 | nested_vmx_secondary_ctls_low = 0; | 2407 | nested_vmx_secondary_ctls_low = 0; |
2403 | nested_vmx_secondary_ctls_high &= | 2408 | nested_vmx_secondary_ctls_high &= |
2404 | SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | | 2409 | SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | |
2410 | SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | | ||
2405 | SECONDARY_EXEC_WBINVD_EXITING | | 2411 | SECONDARY_EXEC_WBINVD_EXITING | |
2406 | SECONDARY_EXEC_XSAVES; | 2412 | SECONDARY_EXEC_XSAVES; |
2407 | 2413 | ||
@@ -4163,6 +4169,52 @@ static void __vmx_enable_intercept_for_msr(unsigned long *msr_bitmap, | |||
4163 | } | 4169 | } |
4164 | } | 4170 | } |
4165 | 4171 | ||
4172 | /* | ||
4173 | * If a msr is allowed by L0, we should check whether it is allowed by L1. | ||
4174 | * The corresponding bit will be cleared unless both of L0 and L1 allow it. | ||
4175 | */ | ||
4176 | static void nested_vmx_disable_intercept_for_msr(unsigned long *msr_bitmap_l1, | ||
4177 | unsigned long *msr_bitmap_nested, | ||
4178 | u32 msr, int type) | ||
4179 | { | ||
4180 | int f = sizeof(unsigned long); | ||
4181 | |||
4182 | if (!cpu_has_vmx_msr_bitmap()) { | ||
4183 | WARN_ON(1); | ||
4184 | return; | ||
4185 | } | ||
4186 | |||
4187 | /* | ||
4188 | * See Intel PRM Vol. 3, 20.6.9 (MSR-Bitmap Address). Early manuals | ||
4189 | * have the write-low and read-high bitmap offsets the wrong way round. | ||
4190 | * We can control MSRs 0x00000000-0x00001fff and 0xc0000000-0xc0001fff. | ||
4191 | */ | ||
4192 | if (msr <= 0x1fff) { | ||
4193 | if (type & MSR_TYPE_R && | ||
4194 | !test_bit(msr, msr_bitmap_l1 + 0x000 / f)) | ||
4195 | /* read-low */ | ||
4196 | __clear_bit(msr, msr_bitmap_nested + 0x000 / f); | ||
4197 | |||
4198 | if (type & MSR_TYPE_W && | ||
4199 | !test_bit(msr, msr_bitmap_l1 + 0x800 / f)) | ||
4200 | /* write-low */ | ||
4201 | __clear_bit(msr, msr_bitmap_nested + 0x800 / f); | ||
4202 | |||
4203 | } else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) { | ||
4204 | msr &= 0x1fff; | ||
4205 | if (type & MSR_TYPE_R && | ||
4206 | !test_bit(msr, msr_bitmap_l1 + 0x400 / f)) | ||
4207 | /* read-high */ | ||
4208 | __clear_bit(msr, msr_bitmap_nested + 0x400 / f); | ||
4209 | |||
4210 | if (type & MSR_TYPE_W && | ||
4211 | !test_bit(msr, msr_bitmap_l1 + 0xc00 / f)) | ||
4212 | /* write-high */ | ||
4213 | __clear_bit(msr, msr_bitmap_nested + 0xc00 / f); | ||
4214 | |||
4215 | } | ||
4216 | } | ||
4217 | |||
4166 | static void vmx_disable_intercept_for_msr(u32 msr, bool longmode_only) | 4218 | static void vmx_disable_intercept_for_msr(u32 msr, bool longmode_only) |
4167 | { | 4219 | { |
4168 | if (!longmode_only) | 4220 | if (!longmode_only) |
@@ -8500,7 +8552,59 @@ static int nested_vmx_check_msr_bitmap_controls(struct kvm_vcpu *vcpu, | |||
8500 | static inline bool nested_vmx_merge_msr_bitmap(struct kvm_vcpu *vcpu, | 8552 | static inline bool nested_vmx_merge_msr_bitmap(struct kvm_vcpu *vcpu, |
8501 | struct vmcs12 *vmcs12) | 8553 | struct vmcs12 *vmcs12) |
8502 | { | 8554 | { |
8503 | return false; | 8555 | struct page *page; |
8556 | unsigned long *msr_bitmap; | ||
8557 | |||
8558 | if (!nested_cpu_has_virt_x2apic_mode(vmcs12)) | ||
8559 | return false; | ||
8560 | |||
8561 | page = nested_get_page(vcpu, vmcs12->msr_bitmap); | ||
8562 | if (!page) { | ||
8563 | WARN_ON(1); | ||
8564 | return false; | ||
8565 | } | ||
8566 | msr_bitmap = (unsigned long *)kmap(page); | ||
8567 | if (!msr_bitmap) { | ||
8568 | nested_release_page_clean(page); | ||
8569 | WARN_ON(1); | ||
8570 | return false; | ||
8571 | } | ||
8572 | |||
8573 | if (nested_cpu_has_virt_x2apic_mode(vmcs12)) { | ||
8574 | /* TPR is allowed */ | ||
8575 | nested_vmx_disable_intercept_for_msr(msr_bitmap, | ||
8576 | vmx_msr_bitmap_nested, | ||
8577 | APIC_BASE_MSR + (APIC_TASKPRI >> 4), | ||
8578 | MSR_TYPE_R | MSR_TYPE_W); | ||
8579 | } else | ||
8580 | __vmx_enable_intercept_for_msr( | ||
8581 | vmx_msr_bitmap_nested, | ||
8582 | APIC_BASE_MSR + (APIC_TASKPRI >> 4), | ||
8583 | MSR_TYPE_R | MSR_TYPE_W); | ||
8584 | kunmap(page); | ||
8585 | nested_release_page_clean(page); | ||
8586 | |||
8587 | return true; | ||
8588 | } | ||
8589 | |||
8590 | static int nested_vmx_check_apicv_controls(struct kvm_vcpu *vcpu, | ||
8591 | struct vmcs12 *vmcs12) | ||
8592 | { | ||
8593 | if (!nested_cpu_has_virt_x2apic_mode(vmcs12)) | ||
8594 | return 0; | ||
8595 | |||
8596 | /* | ||
8597 | * If virtualize x2apic mode is enabled, | ||
8598 | * virtualize apic access must be disabled. | ||
8599 | */ | ||
8600 | if (nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)) | ||
8601 | return -EINVAL; | ||
8602 | |||
8603 | /* tpr shadow is needed by all apicv features. */ | ||
8604 | if (!nested_cpu_has(vmcs12, CPU_BASED_TPR_SHADOW)) | ||
8605 | return -EINVAL; | ||
8606 | |||
8607 | return 0; | ||
8504 | } | 8608 | } |
8505 | 8609 | ||
8506 | static int nested_vmx_check_msr_switch(struct kvm_vcpu *vcpu, | 8610 | static int nested_vmx_check_msr_switch(struct kvm_vcpu *vcpu, |
@@ -8796,7 +8900,8 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) | |||
8796 | else | 8900 | else |
8797 | vmcs_write64(APIC_ACCESS_ADDR, | 8901 | vmcs_write64(APIC_ACCESS_ADDR, |
8798 | page_to_phys(vmx->nested.apic_access_page)); | 8902 | page_to_phys(vmx->nested.apic_access_page)); |
8799 | } else if (vm_need_virtualize_apic_accesses(vmx->vcpu.kvm)) { | 8903 | } else if (!(nested_cpu_has_virt_x2apic_mode(vmcs12)) && |
8904 | (vm_need_virtualize_apic_accesses(vmx->vcpu.kvm))) { | ||
8800 | exec_control |= | 8905 | exec_control |= |
8801 | SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; | 8906 | SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; |
8802 | kvm_vcpu_reload_apic_access_page(vcpu); | 8907 | kvm_vcpu_reload_apic_access_page(vcpu); |
@@ -9007,6 +9112,11 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) | |||
9007 | return 1; | 9112 | return 1; |
9008 | } | 9113 | } |
9009 | 9114 | ||
9115 | if (nested_vmx_check_apicv_controls(vcpu, vmcs12)) { | ||
9116 | nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD); | ||
9117 | return 1; | ||
9118 | } | ||
9119 | |||
9010 | if (nested_vmx_check_msr_switch_controls(vcpu, vmcs12)) { | 9120 | if (nested_vmx_check_msr_switch_controls(vcpu, vmcs12)) { |
9011 | nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD); | 9121 | nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD); |
9012 | return 1; | 9122 | return 1; |