KVM: nVMX: Use kvm_{read,write}_guest_cached() for shadow_vmcs12
authorDavid Woodhouse <dwmw@amazon.co.uk>
Mon, 15 Nov 2021 16:50:24 +0000 (16:50 +0000)
committerPaolo Bonzini <pbonzini@redhat.com>
Thu, 18 Nov 2021 07:03:42 +0000 (02:03 -0500)
Using kvm_vcpu_map() for reading from the guest is entirely gratuitous,
when all we do is a single memcpy and unmap it again. Fix it up to use
kvm_read_guest()... but in fact I couldn't bring myself to do that
without also making it use a gfn_to_hva_cache for both that *and* the
copy in the other direction.

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Message-Id: <20211115165030.7422-5-dwmw2@infradead.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/vmx/vmx.h

index e307d3c1d26b4202e5d9cfb0d2828bc6fbe14ca5..fff6b326dc2b2d00ceb34225c8033b5570eea4ac 100644 (file)
@@ -670,33 +670,39 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
 static void nested_cache_shadow_vmcs12(struct kvm_vcpu *vcpu,
                                       struct vmcs12 *vmcs12)
 {
-       struct kvm_host_map map;
-       struct vmcs12 *shadow;
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       struct gfn_to_hva_cache *ghc = &vmx->nested.shadow_vmcs12_cache;
 
        if (!nested_cpu_has_shadow_vmcs(vmcs12) ||
            vmcs12->vmcs_link_pointer == INVALID_GPA)
                return;
 
-       shadow = get_shadow_vmcs12(vcpu);
-
-       if (kvm_vcpu_map(vcpu, gpa_to_gfn(vmcs12->vmcs_link_pointer), &map))
+       if (ghc->gpa != vmcs12->vmcs_link_pointer &&
+           kvm_gfn_to_hva_cache_init(vcpu->kvm, ghc,
+                                     vmcs12->vmcs_link_pointer, VMCS12_SIZE))
                return;
 
-       memcpy(shadow, map.hva, VMCS12_SIZE);
-       kvm_vcpu_unmap(vcpu, &map, false);
+       kvm_read_guest_cached(vmx->vcpu.kvm, ghc, get_shadow_vmcs12(vcpu),
+                             VMCS12_SIZE);
 }
 
 static void nested_flush_cached_shadow_vmcs12(struct kvm_vcpu *vcpu,
                                              struct vmcs12 *vmcs12)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
+       struct gfn_to_hva_cache *ghc = &vmx->nested.shadow_vmcs12_cache;
 
        if (!nested_cpu_has_shadow_vmcs(vmcs12) ||
            vmcs12->vmcs_link_pointer == INVALID_GPA)
                return;
 
-       kvm_write_guest(vmx->vcpu.kvm, vmcs12->vmcs_link_pointer,
-                       get_shadow_vmcs12(vcpu), VMCS12_SIZE);
+       if (ghc->gpa != vmcs12->vmcs_link_pointer &&
+           kvm_gfn_to_hva_cache_init(vcpu->kvm, ghc,
+                                     vmcs12->vmcs_link_pointer, VMCS12_SIZE))
+               return;
+
+       kvm_write_guest_cached(vmx->vcpu.kvm, ghc, get_shadow_vmcs12(vcpu),
+                              VMCS12_SIZE);
 }
 
 /*
index a4ead6023133a6b0984aa6771b8a547fc8a46a6c..cdadbd5dc0ca0cb2899f29fd92e8dbb8f977206e 100644 (file)
@@ -141,6 +141,11 @@ struct nested_vmx {
         */
        struct vmcs12 *cached_shadow_vmcs12;
 
+       /*
+        * GPA to HVA cache for accessing vmcs12->vmcs_link_pointer
+        */
+       struct gfn_to_hva_cache shadow_vmcs12_cache;
+
        /*
         * Indicates if the shadow vmcs or enlightened vmcs must be updated
         * with the data held by struct vmcs12.