]> git.proxmox.com Git - qemu.git/blobdiff - target-i386/cpu.c
Merge branch 'x86cpu_qom_tcg_v2' of git://github.com/imammedo/qemu
[qemu.git] / target-i386 / cpu.c
index 65d9af6ac7cd5c8435766fd9c9efdb53b589660b..880cfea3f8babe84baab03f321c235e34156580c 100644 (file)
@@ -31,6 +31,8 @@
 
 #include "hyperv.h"
 
+#include "hw/hw.h"
+
 /* feature flags taken from "Intel Processor Identification and the CPUID
  * Instruction" and AMD's "CPUID Specification".  In cases of disagreement
  * between feature naming conventions, aliases may be added.
@@ -50,7 +52,7 @@ static const char *ext_feature_name[] = {
     "ds_cpl", "vmx", "smx", "est",
     "tm2", "ssse3", "cid", NULL,
     "fma", "cx16", "xtpr", "pdcm",
-    NULL, NULL, "dca", "sse4.1|sse4_1",
+    NULL, "pcid", "dca", "sse4.1|sse4_1",
     "sse4.2|sse4_2", "x2apic", "movbe", "popcnt",
     "tsc-deadline", "aes", "xsave", "osxsave",
     "avx", NULL, NULL, "hypervisor",
@@ -77,7 +79,7 @@ static const char *ext3_feature_name[] = {
 };
 
 static const char *kvm_feature_name[] = {
-    "kvmclock", "kvm_nopiodelay", "kvm_mmu", "kvmclock", "kvm_asyncpf", NULL, NULL, NULL,
+    "kvmclock", "kvm_nopiodelay", "kvm_mmu", "kvmclock", "kvm_asyncpf", NULL, "kvm_pv_eoi", NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -238,6 +240,8 @@ typedef struct x86_def_t {
     /* Store the results of Centaur's CPUID instructions */
     uint32_t ext4_features;
     uint32_t xlevel2;
+    /* The feature bits on CPUID[EAX=7,ECX=0].EBX */
+    uint32_t cpuid_7_0_ebx_features;
 } x86_def_t;
 
 #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
@@ -303,7 +307,6 @@ static x86_def_t builtin_x86_defs[] = {
         .ext3_features = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
             CPUID_EXT3_ABM | CPUID_EXT3_SSE4A,
         .xlevel = 0x8000000A,
-        .model_id = "QEMU Virtual CPU version " QEMU_VERSION,
     },
     {
         .name = "phenom",
@@ -386,7 +389,6 @@ static x86_def_t builtin_x86_defs[] = {
         .features = PPRO_FEATURES,
         .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_POPCNT,
         .xlevel = 0x80000004,
-        .model_id = "QEMU Virtual CPU version " QEMU_VERSION,
     },
     {
         .name = "kvm32",
@@ -465,8 +467,6 @@ static x86_def_t builtin_x86_defs[] = {
         .features = PPRO_FEATURES | CPUID_PSE36 | CPUID_VME | CPUID_MTRR | CPUID_MCA,
         .ext2_features = (PPRO_FEATURES & EXT2_FEATURE_MASK) | CPUID_EXT2_MMXEXT | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT,
         .xlevel = 0x80000008,
-        /* XXX: put another string ? */
-        .model_id = "QEMU Virtual CPU version " QEMU_VERSION,
     },
     {
         .name = "n270",
@@ -521,6 +521,12 @@ static int cpu_x86_fill_host(x86_def_t *x86_cpu_def)
     x86_cpu_def->ext_features = ecx;
     x86_cpu_def->features = edx;
 
+    if (kvm_enabled() && x86_cpu_def->level >= 7) {
+        x86_cpu_def->cpuid_7_0_ebx_features = kvm_arch_get_supported_cpuid(kvm_state, 0x7, 0, R_EBX);
+    } else {
+        x86_cpu_def->cpuid_7_0_ebx_features = 0;
+    }
+
     host_cpuid(0x80000000, 0, &eax, &ebx, &ecx, &edx);
     x86_cpu_def->xlevel = eax;
 
@@ -715,66 +721,32 @@ static void x86_cpuid_get_level(Object *obj, Visitor *v, void *opaque,
                                 const char *name, Error **errp)
 {
     X86CPU *cpu = X86_CPU(obj);
-    int64_t value;
 
-    value = cpu->env.cpuid_level;
-    /* TODO Use visit_type_uint32() once available */
-    visit_type_int(v, &value, name, errp);
+    visit_type_uint32(v, &cpu->env.cpuid_level, name, errp);
 }
 
 static void x86_cpuid_set_level(Object *obj, Visitor *v, void *opaque,
                                 const char *name, Error **errp)
 {
     X86CPU *cpu = X86_CPU(obj);
-    const int64_t min = 0;
-    const int64_t max = UINT32_MAX;
-    int64_t value;
 
-    /* TODO Use visit_type_uint32() once available */
-    visit_type_int(v, &value, name, errp);
-    if (error_is_set(errp)) {
-        return;
-    }
-    if (value < min || value > max) {
-        error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
-                  name ? name : "null", value, min, max);
-        return;
-    }
-
-    cpu->env.cpuid_level = value;
+    visit_type_uint32(v, &cpu->env.cpuid_level, name, errp);
 }
 
 static void x86_cpuid_get_xlevel(Object *obj, Visitor *v, void *opaque,
                                  const char *name, Error **errp)
 {
     X86CPU *cpu = X86_CPU(obj);
-    int64_t value;
 
-    value = cpu->env.cpuid_xlevel;
-    /* TODO Use visit_type_uint32() once available */
-    visit_type_int(v, &value, name, errp);
+    visit_type_uint32(v, &cpu->env.cpuid_xlevel, name, errp);
 }
 
 static void x86_cpuid_set_xlevel(Object *obj, Visitor *v, void *opaque,
                                  const char *name, Error **errp)
 {
     X86CPU *cpu = X86_CPU(obj);
-    const int64_t min = 0;
-    const int64_t max = UINT32_MAX;
-    int64_t value;
-
-    /* TODO Use visit_type_uint32() once available */
-    visit_type_int(v, &value, name, errp);
-    if (error_is_set(errp)) {
-        return;
-    }
-    if (value < min || value > max) {
-        error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
-                  name ? name : "null", value, min, max);
-        return;
-    }
 
-    cpu->env.cpuid_xlevel = value;
+    visit_type_uint32(v, &cpu->env.cpuid_xlevel, name, errp);
 }
 
 static char *x86_cpuid_get_vendor(Object *obj, Error **errp)
@@ -1185,6 +1157,7 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model)
     env->cpuid_kvm_features = def->kvm_features;
     env->cpuid_svm_features = def->svm_features;
     env->cpuid_ext4_features = def->ext4_features;
+    env->cpuid_7_0_ebx = def->cpuid_7_0_ebx_features;
     env->cpuid_xlevel2 = def->xlevel2;
     object_property_set_int(OBJECT(cpu), (int64_t)def->tsc_khz * 1000,
                             "tsc-frequency", &error);
@@ -1324,11 +1297,23 @@ void cpu_clear_apic_feature(CPUX86State *env)
  */
 void x86_cpudef_setup(void)
 {
-    int i;
+    int i, j;
+    static const char *model_with_versions[] = { "qemu32", "qemu64", "athlon" };
 
     for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) {
         builtin_x86_defs[i].next = x86_defs;
         builtin_x86_defs[i].flags = 1;
+
+        /* Look for specific "cpudef" models that */
+        /* have the QEMU version in .model_id */
+        for (j = 0; j < ARRAY_SIZE(model_with_versions); j++) {
+            if (strcmp(model_with_versions[j], builtin_x86_defs[i].name) == 0) {
+                pstrcpy(builtin_x86_defs[i].model_id, sizeof(builtin_x86_defs[i].model_id), "QEMU Virtual CPU version ");
+                pstrcat(builtin_x86_defs[i].model_id, sizeof(builtin_x86_defs[i].model_id), qemu_get_version());
+                break;
+            }
+        }
+
         x86_defs = &builtin_x86_defs[i];
     }
 #if !defined(CONFIG_USER_ONLY)
@@ -1451,13 +1436,12 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
         *edx = 0;
         break;
     case 7:
-        if (kvm_enabled()) {
-            KVMState *s = env->kvm_state;
-
-            *eax = kvm_arch_get_supported_cpuid(s, 0x7, count, R_EAX);
-            *ebx = kvm_arch_get_supported_cpuid(s, 0x7, count, R_EBX);
-            *ecx = kvm_arch_get_supported_cpuid(s, 0x7, count, R_ECX);
-            *edx = kvm_arch_get_supported_cpuid(s, 0x7, count, R_EDX);
+        /* Structured Extended Feature Flags Enumeration Leaf */
+        if (count == 0) {
+            *eax = 0; /* Maximum ECX value for sub-leaves */
+            *ebx = env->cpuid_7_0_ebx; /* Feature flags */
+            *ecx = 0; /* Reserved */
+            *edx = 0; /* Reserved */
         } else {
             *eax = 0;
             *ebx = 0;
@@ -1704,8 +1688,31 @@ static void x86_cpu_reset(CPUState *s)
     env->dr[7] = DR7_FIXED_1;
     cpu_breakpoint_remove_all(env, BP_CPU);
     cpu_watchpoint_remove_all(env, BP_CPU);
+
+#if !defined(CONFIG_USER_ONLY)
+    /* We hard-wire the BSP to the first CPU. */
+    if (env->cpu_index == 0) {
+        apic_designate_bsp(env->apic_state);
+    }
+
+    env->halted = !cpu_is_bsp(cpu);
+#endif
+}
+
+#ifndef CONFIG_USER_ONLY
+bool cpu_is_bsp(X86CPU *cpu)
+{
+    return cpu_get_apic_base(cpu->env.apic_state) & MSR_IA32_APICBASE_BSP;
 }
 
+/* TODO: remove me, when reset over QOM tree is implemented */
+static void x86_cpu_machine_reset_cb(void *opaque)
+{
+    X86CPU *cpu = opaque;
+    cpu_reset(CPU(cpu));
+}
+#endif
+
 static void mce_init(X86CPU *cpu)
 {
     CPUX86State *cenv = &cpu->env;
@@ -1722,10 +1729,24 @@ static void mce_init(X86CPU *cpu)
     }
 }
 
+void x86_cpu_realize(Object *obj, Error **errp)
+{
+    X86CPU *cpu = X86_CPU(obj);
+
+#ifndef CONFIG_USER_ONLY
+    qemu_register_reset(x86_cpu_machine_reset_cb, cpu);
+#endif
+
+    mce_init(cpu);
+    qemu_init_vcpu(&cpu->env);
+    cpu_reset(CPU(cpu));
+}
+
 static void x86_cpu_initfn(Object *obj)
 {
     X86CPU *cpu = X86_CPU(obj);
     CPUX86State *env = &cpu->env;
+    static int inited;
 
     cpu_exec_init(env);
 
@@ -1755,7 +1776,15 @@ static void x86_cpu_initfn(Object *obj)
                         x86_cpuid_set_tsc_freq, NULL, NULL, NULL);
 
     env->cpuid_apic_id = env->cpu_index;
-    mce_init(cpu);
+
+    /* init various static tables used in TCG mode */
+    if (tcg_enabled() && !inited) {
+        inited = 1;
+        optimize_flags_init();
+#ifndef CONFIG_USER_ONLY
+        cpu_set_debug_excp_handler(breakpoint_handler);
+#endif
+    }
 }
 
 static void x86_cpu_common_class_init(ObjectClass *oc, void *data)