]> git.itanic.dy.fi Git - linux-stable/commitdiff
KVM: nVMX: hyper-v: Enable L2 TLB flush
authorVitaly Kuznetsov <vkuznets@redhat.com>
Tue, 1 Nov 2022 14:54:04 +0000 (15:54 +0100)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 18 Nov 2022 17:59:17 +0000 (12:59 -0500)
Enable L2 TLB flush feature on nVMX when:
- Enlightened VMCS is in use.
- The feature flag is enabled in eVMCS.
- The feature flag is enabled in partition assist page.

Perform synthetic vmexit to L1 after processing TLB flush call upon
request (HV_VMX_SYNTHETIC_EXIT_REASON_TRAP_AFTER_FLUSH).

Note: nested_evmcs_l2_tlb_flush_enabled() uses cached VP assist page copy
which gets updated from nested_vmx_handle_enlightened_vmptrld(). This is
also guaranteed to happen post migration with eVMCS backed L2 running.

Reviewed-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20221101145426.251680-27-vkuznets@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/include/asm/hyperv-tlfs.h
arch/x86/kvm/vmx/hyperv.c
arch/x86/kvm/vmx/hyperv.h
arch/x86/kvm/vmx/nested.c

index 6639979302ab70258403501fc6320e585dc10751..b25c6792d409ca7127992da3b67d362ef2d16a02 100644 (file)
@@ -600,6 +600,15 @@ struct hv_enlightened_vmcs {
 
 #define HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL                     0xFFFF
 
+/*
+ * Note, Hyper-V isn't actually stealing bit 28 from Intel, just abusing it by
+ * pairing it with architecturally impossible exit reasons.  Bit 28 is set only
+ * on SMI exits to a SMI transfer monitor (STM) and if and only if a MTF VM-Exit
+ * is pending.  I.e. it will never be set by hardware for non-SMI exits (there
+ * are only three), nor will it ever be set unless the VMM is an STM.
+ */
+#define HV_VMX_SYNTHETIC_EXIT_REASON_TRAP_AFTER_FLUSH          0x10000031
+
 /*
  * Hyper-V uses the software reserved 32 bytes in VMCB control area to expose
  * SVM enlightenments to guests.
index bceca1a99804fdac96d5ca582f68ad9daba2d4fa..04a0bba58c7deb69c6a1b63d3739e6d0e124bab3 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "../cpuid.h"
 #include "hyperv.h"
+#include "nested.h"
 #include "vmcs.h"
 #include "vmx.h"
 #include "trace.h"
@@ -500,6 +501,22 @@ int nested_enable_evmcs(struct kvm_vcpu *vcpu,
        return 0;
 }
 
+bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu)
+{
+       struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       struct hv_enlightened_vmcs *evmcs = vmx->nested.hv_evmcs;
+
+       if (!hv_vcpu || !evmcs)
+               return false;
+
+       if (!evmcs->hv_enlightenments_control.nested_flush_hypercall)
+               return false;
+
+       return hv_vcpu->vp_assist_page.nested_control.features.directhypercall;
+}
+
 void vmx_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu)
 {
+       nested_vmx_vmexit(vcpu, HV_VMX_SYNTHETIC_EXIT_REASON_TRAP_AFTER_FLUSH, 0, 0);
 }
index 8bf366730d333cda68b4963683011f5c66733e22..571e7929d14e7b83058228291158f0e96933bf68 100644 (file)
@@ -243,6 +243,7 @@ int nested_enable_evmcs(struct kvm_vcpu *vcpu,
                        uint16_t *vmcs_version);
 void nested_evmcs_filter_control_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
 int nested_evmcs_check_controls(struct vmcs12 *vmcs12);
+bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu);
 void vmx_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu);
 
 #endif /* __KVM_X86_VMX_HYPERV_H */
index 38e6cb8abe62736d56b7600cf11146e6975caa4d..b28be793de298860b70b2c9f6ad65746853332b0 100644 (file)
@@ -1132,6 +1132,15 @@ static void nested_vmx_transition_tlb_flush(struct kvm_vcpu *vcpu,
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
+       /*
+        * KVM_REQ_HV_TLB_FLUSH flushes entries from either L1's VP_ID or
+        * L2's VP_ID upon request from the guest. Make sure we check for
+        * pending entries in the right FIFO upon L1/L2 transition as these
+        * requests are put by other vCPUs asynchronously.
+        */
+       if (to_hv_vcpu(vcpu) && enable_ept)
+               kvm_make_request(KVM_REQ_HV_TLB_FLUSH, vcpu);
+
        /*
         * If vmcs12 doesn't use VPID, L1 expects linear and combined mappings
         * for *all* contexts to be flushed on VM-Enter/VM-Exit, i.e. it's a
@@ -3267,6 +3276,12 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
 
 static bool vmx_get_nested_state_pages(struct kvm_vcpu *vcpu)
 {
+       /*
+        * Note: nested_get_evmcs_page() also updates 'vp_assist_page' copy
+        * in 'struct kvm_vcpu_hv' in case eVMCS is in use, this is mandatory
+        * to make nested_evmcs_l2_tlb_flush_enabled() work correctly post
+        * migration.
+        */
        if (!nested_get_evmcs_page(vcpu)) {
                pr_debug_ratelimited("%s: enlightened vmptrld failed\n",
                                     __func__);
@@ -6144,6 +6159,11 @@ static bool nested_vmx_l0_wants_exit(struct kvm_vcpu *vcpu,
                 * Handle L2's bus locks in L0 directly.
                 */
                return true;
+       case EXIT_REASON_VMCALL:
+               /* Hyper-V L2 TLB flush hypercall is handled by L0 */
+               return guest_hv_cpuid_has_l2_tlb_flush(vcpu) &&
+                       nested_evmcs_l2_tlb_flush_enabled(vcpu) &&
+                       kvm_hv_is_tlb_flush_hcall(vcpu);
        default:
                break;
        }