From: Paul Durrant <pdurrant@xxxxxxxxxx> 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_cpuid_base() (called from kvm_update_cpuid_runtime()) to locate the leaves using the 'KVMKVMKVM\0\0\0' signature. Adjustment of KVM_CPUID_FEATURES will hence now target the correct leaf. Signed-off-by: Paul Durrant <pdurrant@xxxxxxxxxx> --- Cc: Paolo Bonzini <pbonzini@xxxxxxxxxx> Cc: Sean Christopherson <seanjc@xxxxxxxxxx> Cc: Vitaly Kuznetsov <vkuznets@xxxxxxxxxx> Cc: Wanpeng Li <wanpengli@xxxxxxxxxxx> Cc: Jim Mattson <jmattson@xxxxxxxxxx> Cc: Joerg Roedel <joro@xxxxxxxxxx> --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/cpuid.c | 50 +++++++++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 88fce6ab4bbd..21133ffa23e9 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -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; diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 2d70edb0f323..2cfb8ec4f570 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -99,11 +99,46 @@ static int kvm_check_cpuid(struct kvm_cpuid_entry2 *entries, int nent) return 0; } +static void kvm_update_cpuid_base(struct kvm_vcpu *vcpu) +{ + u32 function; + + for (function = 0x40000000; function < 0x40010000; function += 0x100) { + struct kvm_cpuid_entry2 *best = kvm_find_cpuid_entry(vcpu, function, 0); + + if (best) { + char signature[12]; + + *(u32 *)&signature[0] = best->ebx; + *(u32 *)&signature[4] = best->ecx; + *(u32 *)&signature[8] = best->edx; + + if (!memcmp(signature, "KVMKVMKVM\0\0\0", 12)) + break; + } + } + vcpu->arch.kvm_cpuid_base = function; +} + +static inline bool kvm_get_cpuid_base(struct kvm_vcpu *vcpu, u32 *function) +{ + if (vcpu->arch.kvm_cpuid_base < 0x40000000 || + vcpu->arch.kvm_cpuid_base >= 0x40010000) + return false; + + *function = vcpu->arch.kvm_cpuid_base; + return true; +} + void kvm_update_pv_runtime(struct kvm_vcpu *vcpu) { + u32 base; struct kvm_cpuid_entry2 *best; - best = kvm_find_cpuid_entry(vcpu, KVM_CPUID_FEATURES, 0); + if (!kvm_get_cpuid_base(vcpu, &base)) + return; + + best = kvm_find_cpuid_entry(vcpu, base + KVM_CPUID_FEATURES, 0); /* * save the feature bitmap to avoid cpuid lookup for every PV @@ -116,6 +151,7 @@ void kvm_update_pv_runtime(struct kvm_vcpu *vcpu) void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu) { struct kvm_cpuid_entry2 *best; + u32 base; best = kvm_find_cpuid_entry(vcpu, 1, 0); if (best) { @@ -142,10 +178,14 @@ 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); - if (kvm_hlt_in_guest(vcpu->kvm) && best && - (best->eax & (1 << KVM_FEATURE_PV_UNHALT))) - best->eax &= ~(1 << KVM_FEATURE_PV_UNHALT); + kvm_update_cpuid_base(vcpu); + + if (kvm_get_cpuid_base(vcpu, &base)) { + best = kvm_find_cpuid_entry(vcpu, base + KVM_CPUID_FEATURES, 0); + if (kvm_hlt_in_guest(vcpu->kvm) && best && + (best->eax & (1 << KVM_FEATURE_PV_UNHALT))) + best->eax &= ~(1 << KVM_FEATURE_PV_UNHALT); + } if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT)) { best = kvm_find_cpuid_entry(vcpu, 0x1, 0); -- 2.20.1