KVM: x86: Allow vendor code to disable quirks
authorPaolo Bonzini <pbonzini@redhat.com>
Mon, 3 Mar 2025 16:18:38 +0000 (11:18 -0500)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 14 Mar 2025 18:20:58 +0000 (14:20 -0400)
In some cases, the handling of quirks is split between platform-specific
code and generic code, or it is done entirely in generic code, but the
relevant bug does not trigger on some platforms; for example,
this will be the case for "ignore guest PAT".  Allow unaffected vendor
modules to disable handling of a quirk for all VMs via a new entry in
kvm_caps.

Such quirks remain available in KVM_CAP_DISABLE_QUIRKS2, because that API
tells userspace that KVM *knows* that some of its past behavior was bogus
or just undesirable.  In other words, it's plausible for userspace to
refuse to run if a quirk is not listed by KVM_CAP_DISABLE_QUIRKS2, so
preserve that and make it part of the API.

As an example, mark KVM_X86_QUIRK_CD_NW_CLEARED as auto-disabled on
Intel systems.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/svm/svm.c
arch/x86/kvm/x86.c
arch/x86/kvm/x86.h

index 7fdbe84..bf1dc79 100644 (file)
@@ -2422,6 +2422,9 @@ int memslot_rmap_alloc(struct kvm_memory_slot *slot, unsigned long npages);
         KVM_X86_QUIRK_SLOT_ZAP_ALL |           \
         KVM_X86_QUIRK_STUFF_FEATURE_MSRS)
 
+#define KVM_X86_CONDITIONAL_QUIRKS             \
+        KVM_X86_QUIRK_CD_NW_CLEARED
+
 /*
  * KVM previously used a u32 field in kvm_run to indicate the hypercall was
  * initiated from long mode. KVM now sets bit 0 to indicate long mode, but the
index e67de78..92c1b0f 100644 (file)
@@ -5472,6 +5472,7 @@ static __init int svm_hardware_setup(void)
         */
        allow_smaller_maxphyaddr = !npt_enabled;
 
+       kvm_caps.inapplicable_quirks &= ~KVM_X86_QUIRK_CD_NW_CLEARED;
        return 0;
 
 err:
index cdc9c7b..93168a4 100644 (file)
@@ -9783,6 +9783,7 @@ int kvm_x86_vendor_init(struct kvm_x86_init_ops *ops)
                kvm_host.xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
                kvm_caps.supported_xcr0 = kvm_host.xcr0 & KVM_SUPPORTED_XCR0;
        }
+       kvm_caps.inapplicable_quirks = KVM_X86_CONDITIONAL_QUIRKS;
 
        rdmsrl_safe(MSR_EFER, &kvm_host.efer);
 
@@ -12733,6 +12734,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
        /* Decided by the vendor code for other VM types.  */
        kvm->arch.pre_fault_allowed =
                type == KVM_X86_DEFAULT_VM || type == KVM_X86_SW_PROTECTED_VM;
+       kvm->arch.disabled_quirks = kvm_caps.inapplicable_quirks;
 
        ret = kvm_page_track_init(kvm);
        if (ret)
index 8ce6da9..2217787 100644 (file)
@@ -34,6 +34,7 @@ struct kvm_caps {
        u64 supported_xcr0;
        u64 supported_xss;
        u64 supported_perf_cap;
+       u64 inapplicable_quirks;
 };
 
 struct kvm_host_values {