aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWanpeng Li <wanpeng.li@hotmail.com>2015-10-13 12:18:36 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2015-10-16 04:30:35 -0400
commit5c614b3583e7b6dab0c86356fa36c2bcbb8322a0 (patch)
treeba785911c804f0771dd09021311a12a9b44bf154
parent99b83ac893b84ed1a62ad6d1f2b6cc32026b9e85 (diff)
KVM: nVMX: nested VPID emulation
VPID is used to tag address space and avoid a TLB flush. Currently L0 use the same VPID to run L1 and all its guests. KVM flushes VPID when switching between L1 and L2. This patch advertises VPID to the L1 hypervisor, then address space of L1 and L2 can be separately treated and avoid TLB flush when swithing between L1 and L2. For each nested vmentry, if vpid12 is changed, reuse shadow vpid w/ an invvpid. Performance: run lmbench on L2 w/ 3.5 kernel. Context switching - times in microseconds - smaller is better ------------------------------------------------------------------------- Host OS 2p/0K 2p/16K 2p/64K 8p/16K 8p/64K 16p/16K 16p/64K ctxsw ctxsw ctxsw ctxsw ctxsw ctxsw ctxsw --------- ------------- ------ ------ ------ ------ ------ ------- ------- kernel Linux 3.5.0-1 1.2200 1.3700 1.4500 4.7800 2.3300 5.60000 2.88000 nested VPID kernel Linux 3.5.0-1 1.2600 1.4300 1.5600 12.7 12.9 3.49000 7.46000 vanilla Reviewed-by: Jan Kiszka <jan.kiszka@siemens.com> Reviewed-by: Wincy Van <fanwenyi0529@gmail.com> Signed-off-by: Wanpeng Li <wanpeng.li@hotmail.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--arch/x86/kvm/vmx.c39
1 files changed, 32 insertions, 7 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 9b6ab311d0bd..bea552204aa2 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -426,6 +426,9 @@ struct nested_vmx {
426 /* to migrate it to L2 if VM_ENTRY_LOAD_DEBUG_CONTROLS is off */ 426 /* to migrate it to L2 if VM_ENTRY_LOAD_DEBUG_CONTROLS is off */
427 u64 vmcs01_debugctl; 427 u64 vmcs01_debugctl;
428 428
429 u16 vpid02;
430 u16 last_vpid;
431
429 u32 nested_vmx_procbased_ctls_low; 432 u32 nested_vmx_procbased_ctls_low;
430 u32 nested_vmx_procbased_ctls_high; 433 u32 nested_vmx_procbased_ctls_high;
431 u32 nested_vmx_true_procbased_ctls_low; 434 u32 nested_vmx_true_procbased_ctls_low;
@@ -1213,6 +1216,11 @@ static inline bool nested_cpu_has_virt_x2apic_mode(struct vmcs12 *vmcs12)
1213 return nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE); 1216 return nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE);
1214} 1217}
1215 1218
1219static inline bool nested_cpu_has_vpid(struct vmcs12 *vmcs12)
1220{
1221 return nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_VPID);
1222}
1223
1216static inline bool nested_cpu_has_apic_reg_virt(struct vmcs12 *vmcs12) 1224static inline bool nested_cpu_has_apic_reg_virt(struct vmcs12 *vmcs12)
1217{ 1225{
1218 return nested_cpu_has2(vmcs12, SECONDARY_EXEC_APIC_REGISTER_VIRT); 1226 return nested_cpu_has2(vmcs12, SECONDARY_EXEC_APIC_REGISTER_VIRT);
@@ -2590,6 +2598,7 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
2590 SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | 2598 SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES |
2591 SECONDARY_EXEC_RDTSCP | 2599 SECONDARY_EXEC_RDTSCP |
2592 SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | 2600 SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE |
2601 SECONDARY_EXEC_ENABLE_VPID |
2593 SECONDARY_EXEC_APIC_REGISTER_VIRT | 2602 SECONDARY_EXEC_APIC_REGISTER_VIRT |
2594 SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | 2603 SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY |
2595 SECONDARY_EXEC_WBINVD_EXITING | 2604 SECONDARY_EXEC_WBINVD_EXITING |
@@ -6818,6 +6827,7 @@ static void free_nested(struct vcpu_vmx *vmx)
6818 return; 6827 return;
6819 6828
6820 vmx->nested.vmxon = false; 6829 vmx->nested.vmxon = false;
6830 free_vpid(vmx->nested.vpid02);
6821 nested_release_vmcs12(vmx); 6831 nested_release_vmcs12(vmx);
6822 if (enable_shadow_vmcs) 6832 if (enable_shadow_vmcs)
6823 free_vmcs(vmx->nested.current_shadow_vmcs); 6833 free_vmcs(vmx->nested.current_shadow_vmcs);
@@ -7379,7 +7389,7 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
7379 VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID); 7389 VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
7380 return 1; 7390 return 1;
7381 } 7391 }
7382 vmx_flush_tlb(vcpu); 7392 __vmx_flush_tlb(vcpu, to_vmx(vcpu)->nested.vpid02);
7383 nested_vmx_succeed(vcpu); 7393 nested_vmx_succeed(vcpu);
7384 break; 7394 break;
7385 default: 7395 default:
@@ -8759,8 +8769,10 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
8759 goto free_vmcs; 8769 goto free_vmcs;
8760 } 8770 }
8761 8771
8762 if (nested) 8772 if (nested) {
8763 nested_vmx_setup_ctls_msrs(vmx); 8773 nested_vmx_setup_ctls_msrs(vmx);
8774 vmx->nested.vpid02 = allocate_vpid();
8775 }
8764 8776
8765 vmx->nested.posted_intr_nv = -1; 8777 vmx->nested.posted_intr_nv = -1;
8766 vmx->nested.current_vmptr = -1ull; 8778 vmx->nested.current_vmptr = -1ull;
@@ -8781,6 +8793,7 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
8781 return &vmx->vcpu; 8793 return &vmx->vcpu;
8782 8794
8783free_vmcs: 8795free_vmcs:
8796 free_vpid(vmx->nested.vpid02);
8784 free_loaded_vmcs(vmx->loaded_vmcs); 8797 free_loaded_vmcs(vmx->loaded_vmcs);
8785free_msrs: 8798free_msrs:
8786 kfree(vmx->guest_msrs); 8799 kfree(vmx->guest_msrs);
@@ -9665,12 +9678,24 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
9665 9678
9666 if (enable_vpid) { 9679 if (enable_vpid) {
9667 /* 9680 /*
9668 * Trivially support vpid by letting L2s share their parent 9681 * There is no direct mapping between vpid02 and vpid12, the
9669 * L1's vpid. TODO: move to a more elaborate solution, giving 9682 * vpid02 is per-vCPU for L0 and reused while the value of
9670 * each L2 its own vpid and exposing the vpid feature to L1. 9683 * vpid12 is changed w/ one invvpid during nested vmentry.
9684 * The vpid12 is allocated by L1 for L2, so it will not
9685 * influence global bitmap(for vpid01 and vpid02 allocation)
9686 * even if spawn a lot of nested vCPUs.
9671 */ 9687 */
9672 vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid); 9688 if (nested_cpu_has_vpid(vmcs12) && vmx->nested.vpid02) {
9673 vmx_flush_tlb(vcpu); 9689 vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->nested.vpid02);
9690 if (vmcs12->virtual_processor_id != vmx->nested.last_vpid) {
9691 vmx->nested.last_vpid = vmcs12->virtual_processor_id;
9692 __vmx_flush_tlb(vcpu, to_vmx(vcpu)->nested.vpid02);
9693 }
9694 } else {
9695 vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid);
9696 vmx_flush_tlb(vcpu);
9697 }
9698
9674 } 9699 }
9675 9700
9676 if (nested_cpu_has_ept(vmcs12)) { 9701 if (nested_cpu_has_ept(vmcs12)) {