]> git.baikalelectronics.ru Git - kernel.git/commitdiff
KVM: x86: Make sure KVM_CPUID_FEATURES really are KVM_CPUID_FEATURES
authorPaul Durrant <pdurrant@amazon.com>
Fri, 5 Nov 2021 09:51:01 +0000 (09:51 +0000)
committerPaolo Bonzini <pbonzini@redhat.com>
Thu, 11 Nov 2021 15:56:21 +0000 (10:56 -0500)
Currently when kvm_update_cpuid_runtime() runs, it assumes that the
KVM_CPUID_FEATURES leaf is located at 0x40000001. This is not true,
however, if Hyper-V support is enabled. In this case the KVM leaves will
be offset.

This patch introdues as new 'kvm_cpuid_base' field into struct
kvm_vcpu_arch to track the location of the KVM leaves and function
kvm_update_kvm_cpuid_base() (called from kvm_set_cpuid()) to locate the
leaves using the 'KVMKVMKVM\0\0\0' signature (which is now given a
definition in kvm_para.h). Adjustment of KVM_CPUID_FEATURES will hence now
target the correct leaf.

NOTE: A new for_each_possible_hypervisor_cpuid_base() macro is intoduced
      into processor.h to avoid having duplicate code for the iteration
      over possible hypervisor base leaves.

Signed-off-by: Paul Durrant <pdurrant@amazon.com>
Message-Id: <20211105095101.5384-3-pdurrant@amazon.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/processor.h
arch/x86/include/uapi/asm/kvm_para.h
arch/x86/kernel/kvm.c
arch/x86/kvm/cpuid.c

index b71023c64b83a8e8fbe141b9e01e35b37200e308..c343cfcc1ec6aecbb34cb5d4c0f668e0b5d16fcf 100644 (file)
@@ -725,6 +725,7 @@ struct kvm_vcpu_arch {
 
        int cpuid_nent;
        struct kvm_cpuid_entry2 *cpuid_entries;
+       u32 kvm_cpuid_base;
 
        u64 reserved_gpa_bits;
        int maxphyaddr;
index 9ad2acaaae9b84be5bece5730bfb8e7c746cc892..726318cda082471abb6610e7d7e28a92cf2a6f9e 100644 (file)
@@ -807,11 +807,14 @@ static inline u32 amd_get_nodes_per_socket(void)  { return 0; }
 static inline u32 amd_get_highest_perf(void)           { return 0; }
 #endif
 
+#define for_each_possible_hypervisor_cpuid_base(function) \
+       for (function = 0x40000000; function < 0x40010000; function += 0x100)
+
 static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves)
 {
        uint32_t base, eax, signature[3];
 
-       for (base = 0x40000000; base < 0x40010000; base += 0x100) {
+       for_each_possible_hypervisor_cpuid_base(base) {
                cpuid(base, &eax, &signature[0], &signature[1], &signature[2]);
 
                if (!memcmp(sig, signature, 12) &&
index 5146bbab84d4ca820d41d178dc463d17e5ef9d28..6e64b27b2c1ee0b7ac49bcb7c20c60caf7f3314c 100644 (file)
@@ -8,6 +8,7 @@
  * should be used to determine that a VM is running under KVM.
  */
 #define KVM_CPUID_SIGNATURE    0x40000000
+#define KVM_SIGNATURE "KVMKVMKVM\0\0\0"
 
 /* This CPUID returns two feature bitmaps in eax, edx. Before enabling
  * a particular paravirtualization, the appropriate feature bit should
index b656456c3a94461df54fcf05df2a8b53df801101..c97859170286cf801171b4a529183d6af2ff6ab5 100644 (file)
@@ -755,7 +755,7 @@ static noinline uint32_t __kvm_cpuid_base(void)
                return 0;       /* So we don't blow up on old processors */
 
        if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
-               return hypervisor_cpuid_base("KVMKVMKVM\0\0\0", 0);
+               return hypervisor_cpuid_base(KVM_SIGNATURE, 0);
 
        return 0;
 }
index 41529c168e91d80a021975eef6bd5ef22010cb65..e19dabf1848b449e1d02a3dfcab17d027634bfc0 100644 (file)
@@ -99,11 +99,45 @@ static int kvm_check_cpuid(struct kvm_cpuid_entry2 *entries, int nent)
        return 0;
 }
 
-void kvm_update_pv_runtime(struct kvm_vcpu *vcpu)
+static void kvm_update_kvm_cpuid_base(struct kvm_vcpu *vcpu)
 {
-       struct kvm_cpuid_entry2 *best;
+       u32 function;
+       struct kvm_cpuid_entry2 *entry;
+
+       vcpu->arch.kvm_cpuid_base = 0;
+
+       for_each_possible_hypervisor_cpuid_base(function) {
+               entry = kvm_find_cpuid_entry(vcpu, function, 0);
+
+               if (entry) {
+                       u32 signature[3];
+
+                       signature[0] = entry->ebx;
+                       signature[1] = entry->ecx;
+                       signature[2] = entry->edx;
+
+                       BUILD_BUG_ON(sizeof(signature) > sizeof(KVM_SIGNATURE));
+                       if (!memcmp(signature, KVM_SIGNATURE, sizeof(signature))) {
+                               vcpu->arch.kvm_cpuid_base = function;
+                               break;
+                       }
+               }
+       }
+}
+
+struct kvm_cpuid_entry2 *kvm_find_kvm_cpuid_features(struct kvm_vcpu *vcpu)
+{
+       u32 base = vcpu->arch.kvm_cpuid_base;
+
+       if (!base)
+               return NULL;
+
+       return kvm_find_cpuid_entry(vcpu, base | KVM_CPUID_FEATURES, 0);
+}
 
-       best = kvm_find_cpuid_entry(vcpu, KVM_CPUID_FEATURES, 0);
+void kvm_update_pv_runtime(struct kvm_vcpu *vcpu)
+{
+       struct kvm_cpuid_entry2 *best = kvm_find_kvm_cpuid_features(vcpu);
 
        /*
         * save the feature bitmap to avoid cpuid lookup for every PV
@@ -142,7 +176,7 @@ void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu)
                     cpuid_entry_has(best, X86_FEATURE_XSAVEC)))
                best->ebx = xstate_required_size(vcpu->arch.xcr0, true);
 
-       best = kvm_find_cpuid_entry(vcpu, KVM_CPUID_FEATURES, 0);
+       best = kvm_find_kvm_cpuid_features(vcpu);
        if (kvm_hlt_in_guest(vcpu->kvm) && best &&
                (best->eax & (1 << KVM_FEATURE_PV_UNHALT)))
                best->eax &= ~(1 << KVM_FEATURE_PV_UNHALT);
@@ -252,6 +286,7 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
     vcpu->arch.cpuid_entries = e2;
     vcpu->arch.cpuid_nent = nent;
 
+    kvm_update_kvm_cpuid_base(vcpu);
     kvm_update_cpuid_runtime(vcpu);
     kvm_vcpu_after_set_cpuid(vcpu);
 
@@ -872,8 +907,7 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
                }
                break;
        case KVM_CPUID_SIGNATURE: {
-               static const char signature[12] = "KVMKVMKVM\0\0";
-               const u32 *sigptr = (const u32 *)signature;
+               const u32 *sigptr = (const u32 *)KVM_SIGNATURE;
                entry->eax = KVM_CPUID_FEATURES;
                entry->ebx = sigptr[0];
                entry->ecx = sigptr[1];