From: David Woodhouse <[email protected]>

With APICv live on plane-0 vCPUs while their plane-1 twins use
software injection, the twins trip the APICv coherency checks: stale
vcpu-vs-VM activation state at vcpu_enter_guest(), and timer interrupt
injection against a vCPU that is not the running one. Cross-plane
event delivery (forced VTL entry, twin kicks, NMI folding) depends on
software-injection bookkeeping that hardware acceleration bypasses.

Add APICV_INHIBIT_REASON_PLANES, set it when a plane above 0 is
created, and include it in the VMX and AVIC required-inhibit masks;
__kvm_set_or_clear_apicv_inhibit() silently ignores a reason the
vendor mask does not carry. The reference VSM hypervisor likewise
force-disables APICv when VTLs are enabled.

Signed-off-by: David Woodhouse <[email protected]>
Assisted-by: LLM
---
 arch/x86/include/asm/kvm_host.h | 10 +++++++++-
 arch/x86/kvm/svm/svm.h          |  3 ++-
 arch/x86/kvm/vmx/main.c         |  3 ++-
 arch/x86/kvm/x86.c              | 10 ++++++++++
 4 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 1ba77d9375cd..5945b57c091d 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1436,6 +1436,13 @@ enum kvm_apicv_inhibit {
         */
        APICV_INHIBIT_REASON_PHYSICAL_ID_TOO_BIG,
 
+       /*
+        * APICv is inhibited when the VM has multiple planes (Hyper-V VTLs).
+        * Cross-plane event delivery relies on software injection; hardware
+        * acceleration on one twin would bypass it.
+        */
+       APICV_INHIBIT_REASON_PLANES,
+
        NR_APICV_INHIBIT_REASONS,
 };
 
@@ -1455,7 +1462,8 @@ enum kvm_apicv_inhibit {
        __APICV_INHIBIT_REASON(PIT_REINJ),              \
        __APICV_INHIBIT_REASON(SEV),                    \
        __APICV_INHIBIT_REASON(LOGICAL_ID_ALIASED),     \
-       __APICV_INHIBIT_REASON(PHYSICAL_ID_TOO_BIG)
+       __APICV_INHIBIT_REASON(PHYSICAL_ID_TOO_BIG),    \
+       __APICV_INHIBIT_REASON(PLANES)
 
 struct kvm_possible_nx_huge_pages {
        /*
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 7a1bf4f5b8e0..64438317d148 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -925,7 +925,8 @@ extern struct kvm_x86_nested_ops svm_nested_ops;
        BIT(APICV_INHIBIT_REASON_APIC_ID_MODIFIED) |    \
        BIT(APICV_INHIBIT_REASON_APIC_BASE_MODIFIED) |  \
        BIT(APICV_INHIBIT_REASON_LOGICAL_ID_ALIASED) |  \
-       BIT(APICV_INHIBIT_REASON_PHYSICAL_ID_TOO_BIG)   \
+       BIT(APICV_INHIBIT_REASON_PHYSICAL_ID_TOO_BIG) | \
+       BIT(APICV_INHIBIT_REASON_PLANES)                \
 )
 
 bool __init avic_hardware_setup(void);
diff --git a/arch/x86/kvm/vmx/main.c b/arch/x86/kvm/vmx/main.c
index 572921bdfb32..81a8d398068b 100644
--- a/arch/x86/kvm/vmx/main.c
+++ b/arch/x86/kvm/vmx/main.c
@@ -876,7 +876,8 @@ static int vt_gmem_max_mapping_level(struct kvm *kvm, 
kvm_pfn_t pfn,
         BIT(APICV_INHIBIT_REASON_BLOCKIRQ) |                   \
         BIT(APICV_INHIBIT_REASON_PHYSICAL_ID_ALIASED) |        \
         BIT(APICV_INHIBIT_REASON_APIC_ID_MODIFIED) |           \
-        BIT(APICV_INHIBIT_REASON_APIC_BASE_MODIFIED))
+        BIT(APICV_INHIBIT_REASON_APIC_BASE_MODIFIED) | \
+        BIT(APICV_INHIBIT_REASON_PLANES))
 
 struct kvm_x86_ops vt_x86_ops __initdata = {
        .name = KBUILD_MODNAME,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 3e2465b2fa2b..052821799120 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -13979,6 +13979,16 @@ int kvm_arch_plane_init(struct kvm *kvm, struct 
kvm_plane *plane,
 {
        mutex_init(&plane->arch.apic_map_lock);
 
+       /*
+        * Cross-plane event delivery (forced VTL entry, twin kicks, NMI
+        * folding) relies on software injection via KVM_REQ_EVENT; hardware
+        * APIC virtualization on one twin would bypass the bookkeeping the
+        * other twin's plane depends on.  Mirrors the reference VSM
+        * hypervisor, which force-disables APICv when VTLs are enabled.
+        */
+       if (plane_level > 0)
+               kvm_set_apicv_inhibit(kvm, APICV_INHIBIT_REASON_PLANES);
+
        return 0;
 }
 
-- 
2.50.1


Reply via email to