KVM: nVMX: Unconditionally validate CR3 during nested transitions
authorSean Christopherson <sean.j.christopherson@intel.com>
Sat, 2 May 2020 04:32:26 +0000 (21:32 -0700)
committerPaolo Bonzini <pbonzini@redhat.com>
Wed, 13 May 2020 16:15:09 +0000 (12:15 -0400)
Unconditionally check the validity of the incoming CR3 during nested
VM-Enter/VM-Exit to avoid invoking kvm_read_cr3() in the common case
where the guest isn't using PAE paging.  If vmcs.GUEST_CR3 hasn't yet
been cached (common case), kvm_read_cr3() will trigger a VMREAD.  The
VMREAD (~30 cycles) alone is likely slower than nested_cr3_valid()
(~5 cycles if vcpu->arch.maxphyaddr gets a cache hit), and the poor
exchange only gets worse when retpolines are enabled as the call to
kvm_x86_ops.cache_reg() will incur a retpoline (60+ cycles).

Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
Message-Id: <20200502043234.12481-3-sean.j.christopherson@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/vmx/nested.c

index b69f5a2fa362b789bcb431e210ece30d7bc9ace2..90ba278dd572d915ee7ce68913d2359faa2d3187 100644 (file)
@@ -1119,21 +1119,20 @@ static bool nested_vmx_transition_mmu_sync(struct kvm_vcpu *vcpu)
 static int nested_vmx_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3, bool nested_ept,
                               u32 *entry_failure_code)
 {
-       if (cr3 != kvm_read_cr3(vcpu) || (!nested_ept && pdptrs_changed(vcpu))) {
-               if (CC(!nested_cr3_valid(vcpu, cr3))) {
-                       *entry_failure_code = ENTRY_FAIL_DEFAULT;
-                       return -EINVAL;
-               }
+       if (CC(!nested_cr3_valid(vcpu, cr3))) {
+               *entry_failure_code = ENTRY_FAIL_DEFAULT;
+               return -EINVAL;
+       }
 
-               /*
-                * If PAE paging and EPT are both on, CR3 is not used by the CPU and
-                * must not be dereferenced.
-                */
-               if (is_pae_paging(vcpu) && !nested_ept) {
-                       if (CC(!load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3))) {
-                               *entry_failure_code = ENTRY_FAIL_PDPTE;
-                               return -EINVAL;
-                       }
+       /*
+        * If PAE paging and EPT are both on, CR3 is not used by the CPU and
+        * must not be dereferenced.
+        */
+       if (!nested_ept && is_pae_paging(vcpu) &&
+           (cr3 != kvm_read_cr3(vcpu) || pdptrs_changed(vcpu))) {
+               if (CC(!load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3))) {
+                       *entry_failure_code = ENTRY_FAIL_PDPTE;
+                       return -EINVAL;
                }
        }