From e82aa4bcebf4f14782c20f20d9bacf0c352adbc6 Mon Sep 17 00:00:00 2001 From: Radim Krcmar Date: Fri, 28 Mar 2014 18:00:08 +0100 Subject: [PATCH 22/30] x86: cpuid: reconstruct leaf 0Dh data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RH-Author: Radim Krcmar Message-id: <1396029608-8095-3-git-send-email-rkrcmar@redhat.com> Patchwork-id: 58277 O-Subject: [RHEL6.6 qemu-kvm PATCH 2/2] x86: cpuid: reconstruct leaf 0Dh data Bugzilla: 1023268 RH-Acked-by: Andrew Jones RH-Acked-by: Eduardo Habkost RH-Acked-by: Igor Mammedov The data in leaf 0Dh depends on information from other feature bits. Instead of passing it blindly from the host, compute it based on whether these feature bits are enabled. Signed-off-by: Paolo Bonzini Signed-off-by: Gleb Natapov (backported from commit 2560f19f426aceb4f2e809d860b93e7573cb1c4e) Changes: - 'features[FEAT_1_ECX]' -> 'cpuid_ext_features' - we don't have nicely abstracted cpu extensions yet, so this patch uses a function where two variables sufficed upstream ('offsetof()' looked too hacky.) - squashed with a cosmetic change: commit 33f373d7c56350fd2ec3e31f4f2c46cb49464911 Author: Liu Jinsong Date: Tue Dec 3 04:17:50 2013 +0800 target-i386: fix cpuid leaf 0x0d Fix cpuid leaf 0x0d which incorrectly parsed eax and ebx. However, before this patch the CPUID worked fine -- the .offset field contained the size _and_ was stored in the register that is supposed to hold the size (eax), and likewise the .size field contained the offset _and_ was stored in the register trhat is supposed to hold the offset (ebx). Signed-off-by: Liu Jinsong Signed-off-by: Paolo Bonzini - removed explicit "!= 0" in boolean conditions [OCD] (Resisted an urge to remove all extraneous parentheses too.) Signed-off-by: Radim Krčmář --- Minipoll: Which one do you prefer? (1) if (esa->detect(env) && (kvm_mask & (1 << count)) != 0) { (2) if (esa->detect(env) && (kvm_mask & (1 << count))) { (3) if (esa->detect(env) && kvm_mask & (1 << count)) { (4) if (esa->detect(env) && kvm_mask & 1 << count) { ('!=' having higher precedence that '&' is a bug in C, bit too late to fix it though.) target-i386/cpuid.c | 68 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 17 deletions(-) Signed-off-by: Miroslav Rezanina --- target-i386/cpuid.c | 68 ++++++++++++++++++++++++++++++++++++++------------ 1 files changed, 51 insertions(+), 17 deletions(-) diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c index 0f4c7a6..de1a620 100644 --- a/target-i386/cpuid.c +++ b/target-i386/cpuid.c @@ -81,6 +81,20 @@ static const char *cpuid_7_0_ebx_feature_name[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; +typedef struct ExtSaveArea { + bool (*enabled)(const CPUX86State *); + uint32_t offset, size; +} ExtSaveArea; + +static bool cpu_has_avx(const CPUX86State *env) +{ + return env->cpuid_ext_features & CPUID_EXT_AVX; +} + +static const ExtSaveArea ext_save_areas[] = { + [2] = { .enabled = cpu_has_avx, .offset = 0x240, .size = 0x100 }, +}; + /* collects per-function cpuid data */ typedef struct model_features_t { @@ -1369,29 +1383,49 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *edx = 0; } break; - case 0xD: + case 0xD: { + KVMState *s = env->kvm_state; + uint64_t kvm_mask; + int i; + /* Processor Extended State */ - if (!(env->cpuid_ext_features & CPUID_EXT_XSAVE)) { - *eax = 0; - *ebx = 0; - *ecx = 0; - *edx = 0; + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; + if (!(env->cpuid_ext_features & CPUID_EXT_XSAVE) || !kvm_enabled()) { break; } - if (kvm_enabled()) { - KVMState *s = env->kvm_state; + kvm_mask = + kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EAX) | + ((uint64_t)kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EDX) << 32); - *eax = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EAX); - *ebx = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EBX); - *ecx = kvm_arch_get_supported_cpuid(s, 0xd, count, R_ECX); - *edx = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EDX); - } else { - *eax = 0; - *ebx = 0; - *ecx = 0; - *edx = 0; + if (count == 0) { + *ecx = 0x240; + for (i = 2; i < ARRAY_SIZE(ext_save_areas); i++) { + const ExtSaveArea *esa = &ext_save_areas[i]; + if (esa->enabled(env) && kvm_mask & (1 << i)) { + if (i < 32) { + *eax |= 1 << i; + } else { + *edx |= 1 << (i - 32); + } + *ecx = MAX(*ecx, esa->offset + esa->size); + } + } + *eax |= kvm_mask & (XSTATE_FP | XSTATE_SSE); + *ebx = *ecx; + } else if (count == 1) { + *eax = kvm_arch_get_supported_cpuid(s, 0xd, 1, R_EAX); + } else if (count < ARRAY_SIZE(ext_save_areas)) { + const ExtSaveArea *esa = &ext_save_areas[count]; + if (esa->enabled(env) && kvm_mask & (1 << count)) { + *eax = esa->size; + *ebx = esa->offset; + } } break; + } case 0x80000000: *eax = env->cpuid_xlevel; *ebx = env->cpuid_vendor1; -- 1.7.1