qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v2 12/21] cpuid: Fix multicore setup on Intel


From: Andre Przywara
Subject: [Qemu-devel] [PATCH v2 12/21] cpuid: Fix multicore setup on Intel
Date: Fri, 18 Sep 2009 13:48:05 +0200

The multicore CPUID code detects whether the guest is an Intel or an
AMD CPU, because the Linux kernel is picky about the CmpLegacy bit.
KVM by default passes through the host's vendor, which was not
catched by the code. So fork out the vendor determining bits into a
separate function to be used from both places and always get the real
vendor.
This fixes KVM's multicore setup on Intel CPUs.

Signed-off-by: Andre Przywara <address@hidden>
Reported-by: Dietmar Maurer <address@hidden>
---
 target-i386/cpuid.c |   49 +++++++++++++++++++++++++++++++------------------
 1 files changed, 31 insertions(+), 18 deletions(-)

diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
index 4f2b359..e76457c 100644
--- a/target-i386/cpuid.c
+++ b/target-i386/cpuid.c
@@ -615,6 +615,24 @@ int cpu_x86_register (CPUX86State *env, const char 
*cpu_model)
     return 0;
 }
 
+static void get_cpuid_vendor(CPUX86State *env, uint32_t *ebx,
+                             uint32_t *ecx, uint32_t *edx)
+{
+    *ebx = env->cpuid_vendor1;
+    *edx = env->cpuid_vendor2;
+    *ecx = env->cpuid_vendor3;
+
+    /* sysenter isn't supported on compatibility mode on AMD, syscall
+     * isn't supported in compatibility mode on Intel.
+     * Normally we advertise the actual cpu vendor, but you can override
+     * this if you want to use KVM's sysenter/syscall emulation
+     * in compatibility mode and when doing cross vendor migration
+     */
+    if (kvm_enabled() && 
+        (env->cpuid_flags & CPUID_FLAGS_VENDOR_OVERRIDE) == 0)
+        host_cpuid(0, 0, NULL, ebx, ecx, edx);
+}
+
 #define CPUID_LEAF_PROPAGATE ((1 << 0x02) | (1 << 0x04) | (1 << 0x05) |\
                              (1 << 0x0D))
 #define CPUID_LEAF_PROPAGATE_EXTENDED ((1 << 0x05) | (1 << 0x06) |\
@@ -646,19 +664,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, 
uint32_t count,
     switch(index) {
     case 0:
         *eax = env->cpuid_level;
-        *ebx = env->cpuid_vendor1;
-        *edx = env->cpuid_vendor2;
-        *ecx = env->cpuid_vendor3;
-
-        /* sysenter isn't supported on compatibility mode on AMD, syscall
-         * isn't supported in compatibility mode on Intel.
-         * Normally we advertise the actual cpu vendor, but you can override
-         * this if you want to use KVM's sysenter/syscall emulation
-         * in compatibility mode and when doing cross vendor migration
-         */
-        if (kvm_enabled() && 
-            (env->cpuid_flags & CPUID_FLAGS_VENDOR_OVERRIDE) == 0)
-            host_cpuid(0, 0, NULL, ebx, ecx, edx);
+        get_cpuid_vendor(env, ebx, ecx, edx);
         break;
     case 1:
         *eax = env->cpuid_version;
@@ -755,11 +761,18 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, 
uint32_t count,
         *ecx = env->cpuid_ext3_features;
         *edx = env->cpuid_ext2_features;
 
-        if (env->nr_cores * env->nr_threads > 1 &&
-            env->cpuid_vendor1 == CPUID_VENDOR_AMD_1 &&
-            env->cpuid_vendor2 == CPUID_VENDOR_AMD_2 &&
-            env->cpuid_vendor3 == CPUID_VENDOR_AMD_3) {
-            *ecx |= 1 << 1;    /* CmpLegacy bit */
+        /* The Linux kernel checks for the CMPLegacy bit and
+         * discards multiple thread information if it is set.
+         * So dont set it here for Intel to make Linux guests happy.
+         */
+        if (env->nr_cores * env->nr_threads > 1) {
+            uint32_t tebx, tecx, tedx;
+            get_cpuid_vendor(env, &tebx, &tecx, &tedx);
+            if (tebx != CPUID_VENDOR_INTEL_1 ||
+                tedx != CPUID_VENDOR_INTEL_2 ||
+                tecx != CPUID_VENDOR_INTEL_3) {
+                *ecx |= 1 << 1;    /* CmpLegacy bit */
+            }
         }
 
         if (kvm_enabled()) {
-- 
1.6.1.3






reply via email to

[Prev in Thread] Current Thread [Next in Thread]