From 49cb3c9f3cc3a567ce2e6159bf27328c64b6601d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 23 Mar 2022 12:33:25 +0100 Subject: [PATCH 10/10] KVM: x86: workaround invalid CPUID[0xD,9] info on some AMD processors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit from mainline-v7.0.0-rc2 commit 58f7db26f21c690cf9a669c314cfd7371506084a category: feature feature: SPR AMX support for Qemu bugzilla: https://gitee.com/openeuler/intel-qemu/issues/I5VHOB Intel-SIG: commit 58f7db26f21c ("KVM: x86: workaround invalid CPUID[0xD,9] info on some AMD processors") ---------------------------------------------------------------- KVM: x86: workaround invalid CPUID[0xD,9] info on some AMD processors Some AMD processors expose the PKRU extended save state even if they do not have the related PKU feature in CPUID. Worse, when they do they report a size of 64, whereas the expected size of the PKRU extended save state is 8, therefore the esa->size == eax assertion does not hold. The state is already ignored by KVM_GET_SUPPORTED_CPUID because it was not enabled in the host XCR0. However, QEMU kvm_cpu_xsave_init() runs before QEMU invokes arch_prctl() to enable dynamically-enabled save states such as XTILEDATA, and KVM_GET_SUPPORTED_CPUID hides save states that have yet to be enabled. Therefore, kvm_cpu_xsave_init() needs to consult the host CPUID instead of KVM_GET_SUPPORTED_CPUID, and dies with an assertion failure. When setting up the ExtSaveArea array to match the host, ignore features that KVM does not report as supported. This will cause QEMU to skip the incorrect CPUID leaf instead of tripping the assertion. Closes: https://gitlab.com/qemu-project/qemu/-/issues/916 Reported-by: Daniel P. Berrangé Analyzed-by: Yang Zhong Reported-by: Peter Krempa Tested-by: Daniel P. Berrangé Signed-off-by: Paolo Bonzini Signed-off-by: Jason Zeng --- target/i386/cpu.c | 4 ++-- target/i386/cpu.h | 2 ++ target/i386/kvm/kvm-cpu.c | 19 ++++++++++++------- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 1bc03d3eef..551b47ab1e 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -4973,8 +4973,8 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) return cpu_list; } -static uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, - bool migratable_only) +uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + bool migratable_only) { FeatureWordInfo *wi = &feature_word_info[w]; uint64_t r = 0; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index eaa99c302f..290f1beaea 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -605,6 +605,8 @@ typedef enum FeatureWord { } FeatureWord; typedef uint64_t FeatureWordArray[FEATURE_WORDS]; +uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, + bool migratable_only); /* cpuid_features bits */ #define CPUID_FP87 (1U << 0) diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c index a35a1bf9fe..5eb955ce9a 100644 --- a/target/i386/kvm/kvm-cpu.c +++ b/target/i386/kvm/kvm-cpu.c @@ -99,13 +99,18 @@ static void kvm_cpu_xsave_init(void) for (i = XSTATE_SSE_BIT + 1; i < XSAVE_STATE_AREA_COUNT; i++) { ExtSaveArea *esa = &x86_ext_save_areas[i]; - if (esa->size) { - host_cpuid(0xd, i, &eax, &ebx, &ecx, &edx); - if (eax != 0) { - assert(esa->size == eax); - esa->offset = ebx; - esa->ecx = ecx; - } + if (!esa->size) { + continue; + } + if ((x86_cpu_get_supported_feature_word(esa->feature, false) & esa->bits) + != esa->bits) { + continue; + } + host_cpuid(0xd, i, &eax, &ebx, &ecx, &edx); + if (eax != 0) { + assert(esa->size == eax); + esa->offset = ebx; + esa->ecx = ecx; } } } -- 2.27.0