diff mbox series

[v3,13/20] KVM: nVMX: initialize vmcs02 constant exactly once (per VMCS)

Message ID 20180926162358.10741-14-sean.j.christopherson@intel.com (mailing list archive)
State New, archived
Headers show
Series KVM: nVMX: add option to perform early consistency checks via H/W | expand

Commit Message

Sean Christopherson Sept. 26, 2018, 4:23 p.m. UTC
Add a dedicated flag to track if vmcs02 has been initialized, i.e.
the constant state for vmcs02 has been written to the backing VMCS.
The launched flag (in struct loaded_vmcs) gets cleared on logical
CPU migration to mirror hardware behavior[1], i.e. using the launched
flag to determine whether or not vmcs02 constant state needs to be
initialized results in unnecessarily re-initializing the VMCS when
migrating between logical CPUS.

[1] The active VMCS needs to be VMCLEARed before it can be migrated
    to a different logical CPU.  Hardware's VMCS cache is per-CPU
    and is not coherent between CPUs.  VMCLEAR flushes the cache so
    that any dirty data is written back to memory.  A side effect
    of VMCLEAR is that it also clears the VMCS's internal launch
    flag, which KVM must mirror because VMRESUME must be used to
    run a previously launched VMCS.

Suggested-by: Jim Mattson <jmattson@google.com>
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
---
 arch/x86/kvm/vmx.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

Comments

Jim Mattson Sept. 26, 2018, 4:57 p.m. UTC | #1
On Wed, Sep 26, 2018 at 9:23 AM, Sean Christopherson
<sean.j.christopherson@intel.com> wrote:
> Add a dedicated flag to track if vmcs02 has been initialized, i.e.
> the constant state for vmcs02 has been written to the backing VMCS.
> The launched flag (in struct loaded_vmcs) gets cleared on logical
> CPU migration to mirror hardware behavior[1], i.e. using the launched
> flag to determine whether or not vmcs02 constant state needs to be
> initialized results in unnecessarily re-initializing the VMCS when
> migrating between logical CPUS.
>
> [1] The active VMCS needs to be VMCLEARed before it can be migrated
>     to a different logical CPU.  Hardware's VMCS cache is per-CPU
>     and is not coherent between CPUs.  VMCLEAR flushes the cache so
>     that any dirty data is written back to memory.  A side effect
>     of VMCLEAR is that it also clears the VMCS's internal launch
>     flag, which KVM must mirror because VMRESUME must be used to
>     run a previously launched VMCS.
>
> Suggested-by: Jim Mattson <jmattson@google.com>
> Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
Reviewed-by: Jim Mattson <jmattson@google.com>
diff mbox series

Patch

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 702d4f51fa53..5a2566ee4975 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -833,6 +833,13 @@  struct nested_vmx {
 	bool sync_shadow_vmcs;
 	bool dirty_vmcs12;
 
+	/*
+	 * vmcs02 has been initialized, i.e. state that is constant for
+	 * vmcs02 has been written to the backing VMCS.  Initialization
+	 * is delayed until L1 actually attempts to run a nested VM.
+	 */
+	bool vmcs02_initialized;
+
 	bool change_vmcs01_virtual_apic_mode;
 
 	/* L2 must run next, and mustn't decide to exit to L1. */
@@ -8278,6 +8285,7 @@  static int enter_vmx_operation(struct kvm_vcpu *vcpu)
 
 	vmx->nested.vpid02 = allocate_vpid();
 
+	vmx->nested.vmcs02_initialized = false;
 	vmx->nested.vmxon = true;
 	return 0;
 
@@ -11907,13 +11915,14 @@  static u64 nested_vmx_calc_efer(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
 static void prepare_vmcs02_constant_state(struct vcpu_vmx *vmx)
 {
 	/*
-	 * If we have never launched vmcs02, set the constant vmcs02 state
+	 * If vmcs02 hasn't been initialized, set the constant vmcs02 state
 	 * according to L0's settings (vmcs12 is irrelevant here).  Host
 	 * fields that come from L0 and are not constant, e.g. HOST_CR3,
 	 * will be set as needed prior to VMLAUNCH/VMRESUME.
 	 */
-	if (vmx->nested.vmcs02.launched)
+	if (vmx->nested.vmcs02_initialized)
 		return;
+	vmx->nested.vmcs02_initialized = true;
 
 	/* All VMFUNCs are currently emulated through L0 vmexits.  */
 	if (cpu_has_vmx_vmfunc())