Commit 9d6105b2 authored by Sean Christopherson's avatar Sean Christopherson Committed by Paolo Bonzini

KVM: nVMX: initialize vmcs02 constant exactly once (per VMCS)

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: default avatarJim Mattson <jmattson@google.com>
Signed-off-by: default avatarSean Christopherson <sean.j.christopherson@intel.com>
Reviewed-by: default avatarJim Mattson <jmattson@google.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 09abe320
...@@ -833,6 +833,13 @@ struct nested_vmx { ...@@ -833,6 +833,13 @@ struct nested_vmx {
bool sync_shadow_vmcs; bool sync_shadow_vmcs;
bool dirty_vmcs12; 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; bool change_vmcs01_virtual_apic_mode;
/* L2 must run next, and mustn't decide to exit to L1. */ /* 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) ...@@ -8278,6 +8285,7 @@ static int enter_vmx_operation(struct kvm_vcpu *vcpu)
vmx->nested.vpid02 = allocate_vpid(); vmx->nested.vpid02 = allocate_vpid();
vmx->nested.vmcs02_initialized = false;
vmx->nested.vmxon = true; vmx->nested.vmxon = true;
return 0; return 0;
...@@ -11982,13 +11990,14 @@ static u64 nested_vmx_calc_efer(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12) ...@@ -11982,13 +11990,14 @@ static u64 nested_vmx_calc_efer(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
static void prepare_vmcs02_constant_state(struct vcpu_vmx *vmx) 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 * according to L0's settings (vmcs12 is irrelevant here). Host
* fields that come from L0 and are not constant, e.g. HOST_CR3, * fields that come from L0 and are not constant, e.g. HOST_CR3,
* will be set as needed prior to VMLAUNCH/VMRESUME. * will be set as needed prior to VMLAUNCH/VMRESUME.
*/ */
if (vmx->nested.vmcs02.launched) if (vmx->nested.vmcs02_initialized)
return; return;
vmx->nested.vmcs02_initialized = true;
/* All VMFUNCs are currently emulated through L0 vmexits. */ /* All VMFUNCs are currently emulated through L0 vmexits. */
if (cpu_has_vmx_vmfunc()) if (cpu_has_vmx_vmfunc())
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment