]> git.proxmox.com Git - mirror_qemu.git/blobdiff - target-i386/cpu.c
target-i386: X86CPU model subclasses
[mirror_qemu.git] / target-i386 / cpu.c
index 9f5c78ede0ba70352737d4b1e34d90046903e480..0e69383cf53747dd62008e505f2d8a238789cdb1 100644 (file)
@@ -490,16 +490,35 @@ static void add_flagname_to_bitmaps(const char *flagname,
     }
 }
 
+/* CPU class name definitions: */
+
+#define X86_CPU_TYPE_SUFFIX "-" TYPE_X86_CPU
+#define X86_CPU_TYPE_NAME(name) (name X86_CPU_TYPE_SUFFIX)
+
+/* Return type name for a given CPU model name
+ * Caller is responsible for freeing the returned string.
+ */
+static char *x86_cpu_type_name(const char *model_name)
+{
+    return g_strdup_printf(X86_CPU_TYPE_NAME("%s"), model_name);
+}
+
 static ObjectClass *x86_cpu_class_by_name(const char *cpu_model)
 {
+    ObjectClass *oc;
+    char *typename;
+
     if (cpu_model == NULL) {
         return NULL;
     }
 
-    return object_class_by_name(TYPE_X86_CPU);
+    typename = x86_cpu_type_name(cpu_model);
+    oc = object_class_by_name(typename);
+    g_free(typename);
+    return oc;
 }
 
-typedef struct X86CPUDefinition {
+struct X86CPUDefinition {
     const char *name;
     uint32_t level;
     uint32_t xlevel;
@@ -512,7 +531,7 @@ typedef struct X86CPUDefinition {
     FeatureWordArray features;
     char model_id[48];
     bool cache_info_passthrough;
-} X86CPUDefinition;
+};
 
 #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
 #define PENTIUM_FEATURES (I486_FEATURES | CPUID_DE | CPUID_TSC | \
@@ -562,8 +581,6 @@ typedef struct X86CPUDefinition {
           CPUID_7_0_EBX_ERMS, CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM,
           CPUID_7_0_EBX_RDSEED */
 
-/* built-in CPU model definitions
- */
 static X86CPUDefinition builtin_x86_defs[] = {
     {
         .name = "qemu64",
@@ -1134,6 +1151,8 @@ void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w,
     }
 }
 
+#ifdef CONFIG_KVM
+
 static int cpu_x86_fill_model_id(char *str)
 {
     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
@@ -1149,44 +1168,68 @@ static int cpu_x86_fill_model_id(char *str)
     return 0;
 }
 
-/* Fill a X86CPUDefinition struct with information about the host CPU, and
- * the CPU features supported by the host hardware + host kernel
+static X86CPUDefinition host_cpudef;
+
+/* class_init for the "host" CPU model
  *
- * This function may be called only if KVM is enabled.
+ * This function may be called before KVM is initialized.
  */
-static void kvm_cpu_fill_host(X86CPUDefinition *x86_cpu_def)
+static void host_x86_cpu_class_init(ObjectClass *oc, void *data)
 {
-    KVMState *s = kvm_state;
+    X86CPUClass *xcc = X86_CPU_CLASS(oc);
     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
-    FeatureWord w;
 
-    assert(kvm_enabled());
+    xcc->kvm_required = true;
 
-    x86_cpu_def->name = "host";
-    x86_cpu_def->cache_info_passthrough = true;
     host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
-    x86_cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx);
+    x86_cpu_vendor_words2str(host_cpudef.vendor, ebx, edx, ecx);
 
     host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
-    x86_cpu_def->family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
-    x86_cpu_def->model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
-    x86_cpu_def->stepping = eax & 0x0F;
+    host_cpudef.family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
+    host_cpudef.model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
+    host_cpudef.stepping = eax & 0x0F;
 
-    x86_cpu_def->level = kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
-    x86_cpu_def->xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX);
-    x86_cpu_def->xlevel2 =
-        kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
+    cpu_x86_fill_model_id(host_cpudef.model_id);
 
-    cpu_x86_fill_model_id(x86_cpu_def->model_id);
+    xcc->cpu_def = &host_cpudef;
+    host_cpudef.cache_info_passthrough = true;
+
+    /* level, xlevel, xlevel2, and the feature words are initialized on
+     * instance_init, because they require KVM to be initialized.
+     */
+}
+
+static void host_x86_cpu_initfn(Object *obj)
+{
+    X86CPU *cpu = X86_CPU(obj);
+    CPUX86State *env = &cpu->env;
+    KVMState *s = kvm_state;
+    FeatureWord w;
+
+    assert(kvm_enabled());
+
+    env->cpuid_level = kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
+    env->cpuid_xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX);
+    env->cpuid_xlevel2 = kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
 
     for (w = 0; w < FEATURE_WORDS; w++) {
         FeatureWordInfo *wi = &feature_word_info[w];
-        x86_cpu_def->features[w] =
+        env->features[w] =
             kvm_arch_get_supported_cpuid(s, wi->cpuid_eax, wi->cpuid_ecx,
                                          wi->cpuid_reg);
     }
+    object_property_set_bool(OBJECT(cpu), true, "pmu", &error_abort);
 }
 
+static const TypeInfo host_x86_cpu_type_info = {
+    .name = X86_CPU_TYPE_NAME("host"),
+    .parent = TYPE_X86_CPU,
+    .instance_init = host_x86_cpu_initfn,
+    .class_init = host_x86_cpu_class_init,
+};
+
+#endif
+
 static int unavailable_host_feature(FeatureWordInfo *f, uint32_t mask)
 {
     int i;
@@ -1597,32 +1640,6 @@ static PropertyInfo qdev_prop_spinlocks = {
     .set   = x86_set_hv_spinlocks,
 };
 
-static int cpu_x86_find_by_name(X86CPU *cpu, X86CPUDefinition *x86_cpu_def,
-                                const char *name)
-{
-    X86CPUDefinition *def;
-    int i;
-
-    if (name == NULL) {
-        return -1;
-    }
-    if (kvm_enabled() && strcmp(name, "host") == 0) {
-        kvm_cpu_fill_host(x86_cpu_def);
-        object_property_set_bool(OBJECT(cpu), true, "pmu", &error_abort);
-        return 0;
-    }
-
-    for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
-        def = &builtin_x86_defs[i];
-        if (strcmp(name, def->name) == 0) {
-            memcpy(x86_cpu_def, def, sizeof(*def));
-            return 0;
-        }
-    }
-
-    return -1;
-}
-
 /* Convert all '_' in a feature string option name to '-', to make feature
  * name conform to QOM property naming rule, which uses '-' instead of '_'.
  */
@@ -1832,22 +1849,14 @@ static void filter_features_for_kvm(X86CPU *cpu)
     }
 }
 
-/* Load CPU definition for a given CPU model name
+/* Load data from X86CPUDefinition
  */
-static void x86_cpu_load_def(X86CPU *cpu, const char *name, Error **errp)
+static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp)
 {
     CPUX86State *env = &cpu->env;
-    X86CPUDefinition def1, *def = &def1;
     const char *vendor;
     char host_vendor[CPUID_VENDOR_SZ + 1];
 
-    memset(def, 0, sizeof(*def));
-
-    if (cpu_x86_find_by_name(cpu, def, name) < 0) {
-        error_setg(errp, "Unable to find CPU definition: %s", name);
-        return;
-    }
-
     object_property_set_int(OBJECT(cpu), def->level, "level", errp);
     object_property_set_int(OBJECT(cpu), def->family, "family", errp);
     object_property_set_int(OBJECT(cpu), def->model, "model", errp);
@@ -1899,10 +1908,10 @@ X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge,
                        Error **errp)
 {
     X86CPU *cpu = NULL;
+    X86CPUClass *xcc;
     ObjectClass *oc;
     gchar **model_pieces;
     char *name, *features;
-    char *typename;
     Error *error = NULL;
 
     model_pieces = g_strsplit(cpu_model, ",", 2);
@@ -1918,12 +1927,15 @@ X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge,
         error_setg(&error, "Unable to find CPU definition: %s", name);
         goto out;
     }
-    cpu = X86_CPU(object_new(object_class_get_name(oc)));
-    x86_cpu_load_def(cpu, name, &error);
-    if (error) {
+    xcc = X86_CPU_CLASS(oc);
+
+    if (xcc->kvm_required && !kvm_enabled()) {
+        error_setg(&error, "CPU model '%s' requires KVM", name);
         goto out;
     }
 
+    cpu = X86_CPU(object_new(object_class_get_name(oc)));
+
 #ifndef CONFIG_USER_ONLY
     if (icc_bridge == NULL) {
         error_setg(&error, "Invalid icc-bridge value");
@@ -1933,14 +1945,6 @@ X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge,
     object_unref(OBJECT(cpu));
 #endif
 
-    /* Emulate per-model subclasses for global properties */
-    typename = g_strdup_printf("%s-" TYPE_X86_CPU, name);
-    qdev_prop_set_globals_for_type(DEVICE(cpu), typename, &error);
-    g_free(typename);
-    if (error) {
-        goto out;
-    }
-
     cpu_x86_parse_featurestr(cpu, features, &error);
     if (error) {
         goto out;
@@ -1982,6 +1986,28 @@ out:
     return cpu;
 }
 
+static void x86_cpu_cpudef_class_init(ObjectClass *oc, void *data)
+{
+    X86CPUDefinition *cpudef = data;
+    X86CPUClass *xcc = X86_CPU_CLASS(oc);
+
+    xcc->cpu_def = cpudef;
+}
+
+static void x86_register_cpudef_type(X86CPUDefinition *def)
+{
+    char *typename = x86_cpu_type_name(def->name);
+    TypeInfo ti = {
+        .name = typename,
+        .parent = TYPE_X86_CPU,
+        .class_init = x86_cpu_cpudef_class_init,
+        .class_data = def,
+    };
+
+    type_register(&ti);
+    g_free(typename);
+}
+
 #if !defined(CONFIG_USER_ONLY)
 
 void cpu_clear_apic_feature(CPUX86State *env)
@@ -2643,6 +2669,7 @@ static void x86_cpu_initfn(Object *obj)
 {
     CPUState *cs = CPU(obj);
     X86CPU *cpu = X86_CPU(obj);
+    X86CPUClass *xcc = X86_CPU_GET_CLASS(obj);
     CPUX86State *env = &cpu->env;
     static int inited;
 
@@ -2686,6 +2713,8 @@ static void x86_cpu_initfn(Object *obj)
     cpu->hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY;
     env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index);
 
+    x86_cpu_load_def(cpu, xcc->cpu_def, &error_abort);
+
     /* init various static tables used in TCG mode */
     if (tcg_enabled() && !inited) {
         inited = 1;
@@ -2792,14 +2821,22 @@ static const TypeInfo x86_cpu_type_info = {
     .parent = TYPE_CPU,
     .instance_size = sizeof(X86CPU),
     .instance_init = x86_cpu_initfn,
-    .abstract = false,
+    .abstract = true,
     .class_size = sizeof(X86CPUClass),
     .class_init = x86_cpu_common_class_init,
 };
 
 static void x86_cpu_register_types(void)
 {
+    int i;
+
     type_register_static(&x86_cpu_type_info);
+    for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
+        x86_register_cpudef_type(&builtin_x86_defs[i]);
+    }
+#ifdef CONFIG_KVM
+    type_register_static(&host_x86_cpu_type_info);
+#endif
 }
 
 type_init(x86_cpu_register_types)