KVM: x86: Snapshot if a vCPU's vendor model is AMD vs. Intel compatible
authorSean Christopherson <seanjc@google.com>
Fri, 5 Apr 2024 23:55:54 +0000 (16:55 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 27 Apr 2024 15:05:28 +0000 (17:05 +0200)
commit fd706c9b1674e2858766bfbf7430534c2b26fbef upstream.

Add kvm_vcpu_arch.is_amd_compatible to cache if a vCPU's vendor model is
compatible with AMD, i.e. if the vCPU vendor is AMD or Hygon, along with
helpers to check if a vCPU is compatible AMD vs. Intel.  To handle Intel
vs. AMD behavior related to masking the LVTPC entry, KVM will need to
check for vendor compatibility on every PMI injection, i.e. querying for
AMD will soon be a moderately hot path.

Note!  This subtly (or maybe not-so-subtly) makes "Intel compatible" KVM's
default behavior, both if userspace omits (or never sets) CPUID 0x0 and if
userspace sets a completely unknown vendor.  One could argue that KVM
should treat such vCPUs as not being compatible with Intel *or* AMD, but
that would add useless complexity to KVM.

KVM needs to do *something* in the face of vendor specific behavior, and
so unless KVM conjured up a magic third option, choosing to treat unknown
vendors as neither Intel nor AMD means that checks on AMD compatibility
would yield Intel behavior, and checks for Intel compatibility would yield
AMD behavior.  And that's far worse as it would effectively yield random
behavior depending on whether KVM checked for AMD vs. Intel vs. !AMD vs.
!Intel.  And practically speaking, all x86 CPUs follow either Intel or AMD
architecture, i.e. "supporting" an unknown third architecture adds no
value.

Deliberately don't convert any of the existing guest_cpuid_is_intel()
checks, as the Intel side of things is messier due to some flows explicitly
checking for exactly vendor==Intel, versus some flows assuming anything
that isn't "AMD compatible" gets Intel behavior.  The Intel code will be
cleaned up in the future.

Cc: stable@vger.kernel.org
Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-ID: <20240405235603.1173076-2-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/cpuid.c
arch/x86/kvm/cpuid.h
arch/x86/kvm/mmu/mmu.c
arch/x86/kvm/x86.c

index 08cfc26ee7c67a2278f779bbd1f695db9fe698b3..f779facd82460181e2fbbf6f8df9f02d5d368dec 100644 (file)
@@ -732,6 +732,7 @@ struct kvm_vcpu_arch {
 
        int cpuid_nent;
        struct kvm_cpuid_entry2 *cpuid_entries;
+       bool is_amd_compatible;
 
        u64 reserved_gpa_bits;
        int maxphyaddr;
index 537e826205cece8f8e3ec6c5b9320a514bb4fdd7..6222aa3221f5216778bbf554dcdd723c6a058900 100644 (file)
@@ -189,6 +189,7 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
 
        kvm_update_pv_runtime(vcpu);
 
+       vcpu->arch.is_amd_compatible = guest_cpuid_is_amd_or_hygon(vcpu);
        vcpu->arch.maxphyaddr = cpuid_query_maxphyaddr(vcpu);
        vcpu->arch.reserved_gpa_bits = kvm_vcpu_reserved_gpa_bits_raw(vcpu);
 
index c99edfff7f824369d063533adb7b64ef5d32331f..3c0b2dddc989c805156acc612c2a5af471eb5303 100644 (file)
@@ -121,6 +121,16 @@ static inline bool guest_cpuid_is_intel(struct kvm_vcpu *vcpu)
        return best && is_guest_vendor_intel(best->ebx, best->ecx, best->edx);
 }
 
+static inline bool guest_cpuid_is_amd_compatible(struct kvm_vcpu *vcpu)
+{
+       return vcpu->arch.is_amd_compatible;
+}
+
+static inline bool guest_cpuid_is_intel_compatible(struct kvm_vcpu *vcpu)
+{
+       return !guest_cpuid_is_amd_compatible(vcpu);
+}
+
 static inline int guest_cpuid_family(struct kvm_vcpu *vcpu)
 {
        struct kvm_cpuid_entry2 *best;
index 4724289c8a7f80f44e02ac07c9261a12af553cf0..acb9193fc06a4c4dc703f47c882405d683db73fa 100644 (file)
@@ -4351,7 +4351,7 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu,
                                context->root_level, is_efer_nx(context),
                                guest_can_use_gbpages(vcpu),
                                is_cr4_pse(context),
-                               guest_cpuid_is_amd_or_hygon(vcpu));
+                               guest_cpuid_is_amd_compatible(vcpu));
 }
 
 static void
index 57a1484e257fa421943e136690f90f1fb3567936..f781ba5d421d1c372f8c36ee479c51fcc4cf93ed 100644 (file)
@@ -3107,7 +3107,7 @@ static void kvmclock_sync_fn(struct work_struct *work)
 static bool can_set_mci_status(struct kvm_vcpu *vcpu)
 {
        /* McStatusWrEn enabled? */
-       if (guest_cpuid_is_amd_or_hygon(vcpu))
+       if (guest_cpuid_is_amd_compatible(vcpu))
                return !!(vcpu->arch.msr_hwcr & BIT_ULL(18));
 
        return false;