]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: x86: Add a macro to init CPUID features that ignore host kernel support
authorSean Christopherson <seanjc@google.com>
Thu, 28 Nov 2024 01:33:56 +0000 (17:33 -0800)
committerSean Christopherson <seanjc@google.com>
Wed, 18 Dec 2024 22:19:52 +0000 (14:19 -0800)
Add a macro for use in kvm_set_cpu_caps() to automagically initialize
features that KVM wants to support based solely on the CPU's capabilities,
e.g. KVM advertises LA57 support if it's available in hardware, even if
the host kernel isn't utilizing 57-bit virtual addresses.

Track a features that are passed through to userspace (from hardware) in
a local variable, and simply OR them in *after* adjusting the capabilities
that came from boot_cpu_data.

Note, eliminating the open-coded call to cpuid_ecx() also fixes a largely
benign bug where KVM could incorrectly report LA57 support on Intel CPUs
whose max supported CPUID is less than 7, i.e. if the max supported leaf
(<7) happened to have bit 16 set.  In practice, barring a funky virtual
machine setup, the bug is benign as all known CPUs that support VMX also
support leaf 7.

Link: https://lore.kernel.org/r/20241128013424.4096668-30-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/kvm/cpuid.c

index 88ab264b4280c526645d2e48e17ee186ba1f8401..67514cb4e000024b92a50e6a50d24182a7a19545 100644 (file)
@@ -631,12 +631,14 @@ static __always_inline u32 raw_cpuid_get(struct cpuid_reg cpuid)
 do {                                                                   \
        const struct cpuid_reg cpuid = x86_feature_cpuid(leaf * 32);    \
        const u32 __maybe_unused kvm_cpu_cap_init_in_progress = leaf;   \
+       u32 kvm_cpu_cap_passthrough = 0;                                \
                                                                        \
        if (leaf < NCAPINTS)                                            \
                kvm_cpu_caps[leaf] &= (mask);                           \
        else                                                            \
                kvm_cpu_caps[leaf] = (mask);                            \
                                                                        \
+       kvm_cpu_caps[leaf] |= kvm_cpu_cap_passthrough;                  \
        kvm_cpu_caps[leaf] &= raw_cpuid_get(cpuid);                     \
 } while (0)
 
@@ -673,6 +675,18 @@ do {                                                                       \
        (IS_ENABLED(CONFIG_X86_64) ? F(name) : 0);              \
 })
 
+/*
+ * Passthrough Feature - For features that KVM supports based purely on raw
+ * hardware CPUID, i.e. that KVM virtualizes even if the host kernel doesn't
+ * use the feature.  Simply force set the feature in KVM's capabilities, raw
+ * CPUID support will be factored in by kvm_cpu_cap_mask().
+ */
+#define PASSTHROUGH_F(name)                                    \
+({                                                             \
+       kvm_cpu_cap_passthrough |= F(name);                     \
+       F(name);                                                \
+})
+
 /*
  * Aliased Features - For features in 0x8000_0001.EDX that are duplicates of
  * identical 0x1.EDX features, and thus are aliased from 0x1 to 0x8000_0001.
@@ -798,7 +812,7 @@ void kvm_set_cpu_caps(void)
 
        kvm_cpu_cap_init(CPUID_7_ECX,
                F(AVX512VBMI) |
-               F(LA57) |
+               PASSTHROUGH_F(LA57) |
                F(PKU) |
                0 /*OSPKE*/ |
                F(RDPID) |
@@ -817,9 +831,6 @@ void kvm_set_cpu_caps(void)
                F(SGX_LC) |
                F(BUS_LOCK_DETECT)
        );
-       /* Set LA57 based on hardware capability. */
-       if (cpuid_ecx(7) & feature_bit(LA57))
-               kvm_cpu_cap_set(X86_FEATURE_LA57);
 
        /*
         * PKU not yet implemented for shadow paging and requires OSPKE
@@ -1097,6 +1108,7 @@ EXPORT_SYMBOL_GPL(kvm_set_cpu_caps);
 #undef F
 #undef SF
 #undef X86_64_F
+#undef PASSTHROUGH_F
 #undef ALIASED_1_EDX_F
 
 struct kvm_cpuid_array {