qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC 0/6] x86 CPU subclasses, v4
@ 2013-01-04 19:56 Eduardo Habkost
  2013-01-04 19:56 ` [Qemu-devel] [RFC 1/6] target-i386: Move CPU object creation to cpu.c Eduardo Habkost
                   ` (6 more replies)
  0 siblings, 7 replies; 9+ messages in thread
From: Eduardo Habkost @ 2013-01-04 19:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: Igor Mammedov, Andreas Färber

This is a new RFC for the x86 CPU subclasses. This version handles the "host"
subclass differently, and I believe this made the code much simpler.

However, a few tricks were necessary:

 - To keep the "default_kvm_features" compat functions working (this shouldn't
   be necessary once we start using global properties for the compat code).
 - For the vendor property setting (because it depends on a kvm_enabled() check,
   that can't be made on class_init). I don't know how we will be able to
   convert that logic using global properties/defaults in the future.
 - To keep the original model names in the "-cpu ?" output, for compatibility.

This series depends on multiple series:
 - pc-1.4 kvm_mmu_opt disable series I sent today;
 - -cpu "enforce" fix series I sent today;
 - A experimental rebased version of Igor's "wave 2" x86 CPU init cleanup.

Because of the tricky dependencies, I recommend you use the git tree for testing:
  git://github.com/ehabkost/qemu-hacks.git x86-cpu-model-classes.RFC.v4
  https://github.com/ehabkost/qemu-hacks/tree/x86-cpu-model-classes.RFC.v4

Eduardo Habkost (6):
  target-i386: Move CPU object creation to cpu.c
  target-i386: Make cpu_x86_create() get Error argument
  target-i386: Simplify cpu_x86_find_by_name() logic
  target-i386: Set feature string parsing results directly on CPU
    object
  target-i386: Move kvm_features/hypervisor initialization to
    cpu_x86_find_by_name()
  target-i386: CPU model subclasses

 include/sysemu/kvm.h  |    3 +
 target-i386/cpu-qom.h |   26 +
 target-i386/cpu.c     | 1548 ++++++++++++++++++++++++++++++-------------------
 target-i386/cpu.h     |    4 +-
 target-i386/helper.c  |   26 +-
 target-i386/kvm.c     |    2 +
 6 files changed, 988 insertions(+), 621 deletions(-)

-- 
1.7.11.7

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Qemu-devel] [RFC 1/6] target-i386: Move CPU object creation to cpu.c
  2013-01-04 19:56 [Qemu-devel] [RFC 0/6] x86 CPU subclasses, v4 Eduardo Habkost
@ 2013-01-04 19:56 ` Eduardo Habkost
  2013-01-04 19:56 ` [Qemu-devel] [RFC 2/6] target-i386: Make cpu_x86_create() get Error argument Eduardo Habkost
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Eduardo Habkost @ 2013-01-04 19:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: Igor Mammedov, Andreas Färber

As we will need to create the CPU object after splitting the CPU model
string (because we're going to use different subclasses for each CPU
model), move the CPU object creation to cpu_x86_register(), and at the
same time rename cpu_x86_register() to cpu_x86_create().

This will also simplify the CPU creation code to a trivial
cpu_x86_create()+cpu_x86_realize() sequence. This will be useful for
code that have to set additional properties before cpu_x86_realize() is
called (e.g. the PC CPU initialization code, that needs to set APIC IDs
depending on the CPU cores/threads topology).

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
Changes v2:
 - Move CPU creation code after cpu_model split (as we will eventually
   use just the "model name" part to find the right CPU class)
 - Small update on comment about feature string before cpu_x86_create()
   function
---
 target-i386/cpu.c    | 18 +++++++++++++++---
 target-i386/cpu.h    |  2 +-
 target-i386/helper.c |  9 ++-------
 3 files changed, 18 insertions(+), 11 deletions(-)

diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index e308987..243ea3e 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -1519,8 +1519,13 @@ static void filter_features_for_kvm(X86CPU *cpu)
 }
 #endif
 
-int cpu_x86_register(X86CPU *cpu, const char *cpu_model)
+/* Create and initialize a X86CPU object, based on the full CPU model string
+ * (that may include "+feature,-feature,feature=xxx,feature" feature strings)
+ */
+X86CPU *cpu_x86_create(const char *cpu_model)
 {
+    X86CPU *cpu = NULL;
+    CPUX86State *env;
     x86_def_t def1, *def = &def1;
     QDict *props = NULL;
     Error *error = NULL;
@@ -1542,6 +1547,10 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model)
         goto out;
     }
 
+    cpu = X86_CPU(object_new(TYPE_X86_CPU));
+    env = &cpu->env;
+    env->cpu_model_str = cpu_model;
+
     def->kvm_features |= kvm_default_features;
     add_flagname_to_bitmaps("hypervisor", &def->features,
                             &def->ext_features, &def->ext2_features,
@@ -1562,9 +1571,12 @@ out:
     if (error) {
         fprintf(stderr, "%s\n", error_get_pretty(error));
         error_free(error);
-        return -1;
+        if (cpu) {
+            object_delete(OBJECT(cpu));
+        }
+        return NULL;
     }
-    return 0;
+    return cpu;
 }
 
 #if !defined(CONFIG_USER_ONLY)
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 4fbfdc8..c0ac8c7 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -981,7 +981,7 @@ int cpu_x86_signal_handler(int host_signum, void *pinfo,
 void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
                    uint32_t *eax, uint32_t *ebx,
                    uint32_t *ecx, uint32_t *edx);
-int cpu_x86_register(X86CPU *cpu, const char *cpu_model);
+X86CPU *cpu_x86_create(const char *cpu_model);
 void cpu_clear_apic_feature(CPUX86State *env);
 void host_cpuid(uint32_t function, uint32_t count,
                 uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
diff --git a/target-i386/helper.c b/target-i386/helper.c
index dca1360..7482c97 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -1240,15 +1240,10 @@ int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector,
 X86CPU *cpu_x86_init(const char *cpu_model)
 {
     X86CPU *cpu;
-    CPUX86State *env;
     Error *error = NULL;
 
-    cpu = X86_CPU(object_new(TYPE_X86_CPU));
-    env = &cpu->env;
-    env->cpu_model_str = cpu_model;
-
-    if (cpu_x86_register(cpu, cpu_model) < 0) {
-        object_delete(OBJECT(cpu));
+    cpu = cpu_x86_create(cpu_model);
+    if (!cpu) {
         return NULL;
     }
 
-- 
1.7.11.7

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [RFC 2/6] target-i386: Make cpu_x86_create() get Error argument
  2013-01-04 19:56 [Qemu-devel] [RFC 0/6] x86 CPU subclasses, v4 Eduardo Habkost
  2013-01-04 19:56 ` [Qemu-devel] [RFC 1/6] target-i386: Move CPU object creation to cpu.c Eduardo Habkost
@ 2013-01-04 19:56 ` Eduardo Habkost
  2013-01-04 19:56 ` [Qemu-devel] [RFC 3/6] target-i386: Simplify cpu_x86_find_by_name() logic Eduardo Habkost
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Eduardo Habkost @ 2013-01-04 19:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: Igor Mammedov, Andreas Färber

Instead of forcing the caller to guess what went wrong while creating
the CPU object, return error information in a Error argument.

Also, as cpu_x86_create() won't print error messages itself anymore,
change cpu_x86_init() to print any error returned by cpu_x86_create()
or cpu_x86_realize().

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
Changes v2:
 - Fix include "qemu-error.h" to use the new "qemu/error-report.h"
 - Remove bogus error_free() call just after error_propagate()
---
 target-i386/cpu.c    |  5 ++---
 target-i386/cpu.h    |  2 +-
 target-i386/helper.c | 21 ++++++++++++++-------
 3 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 243ea3e..6c75327 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -1522,7 +1522,7 @@ static void filter_features_for_kvm(X86CPU *cpu)
 /* Create and initialize a X86CPU object, based on the full CPU model string
  * (that may include "+feature,-feature,feature=xxx,feature" feature strings)
  */
-X86CPU *cpu_x86_create(const char *cpu_model)
+X86CPU *cpu_x86_create(const char *cpu_model, Error **errp)
 {
     X86CPU *cpu = NULL;
     CPUX86State *env;
@@ -1569,8 +1569,7 @@ out:
     QDECREF(props);
     g_strfreev(model_pieces);
     if (error) {
-        fprintf(stderr, "%s\n", error_get_pretty(error));
-        error_free(error);
+        error_propagate(errp, error);
         if (cpu) {
             object_delete(OBJECT(cpu));
         }
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index c0ac8c7..91091bf 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -981,7 +981,7 @@ int cpu_x86_signal_handler(int host_signum, void *pinfo,
 void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
                    uint32_t *eax, uint32_t *ebx,
                    uint32_t *ecx, uint32_t *edx);
-X86CPU *cpu_x86_create(const char *cpu_model);
+X86CPU *cpu_x86_create(const char *cpu_model, Error **errp);
 void cpu_clear_apic_feature(CPUX86State *env);
 void host_cpuid(uint32_t function, uint32_t count,
                 uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 7482c97..8b6b4da 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -23,6 +23,7 @@
 #include "sysemu/sysemu.h"
 #include "monitor/monitor.h"
 #endif
+#include "qemu/error-report.h"
 
 //#define DEBUG_MMU
 
@@ -1239,21 +1240,27 @@ int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector,
 
 X86CPU *cpu_x86_init(const char *cpu_model)
 {
-    X86CPU *cpu;
+    X86CPU *cpu = NULL;
     Error *error = NULL;
 
-    cpu = cpu_x86_create(cpu_model);
-    if (!cpu) {
-        return NULL;
+    cpu = cpu_x86_create(cpu_model, &error);
+    if (error) {
+        goto error;
     }
 
     x86_cpu_realize(OBJECT(cpu), &error);
     if (error) {
-        error_free(error);
-        object_delete(OBJECT(cpu));
-        return NULL;
+        goto error;
     }
     return cpu;
+
+error:
+    if (cpu) {
+        object_delete(OBJECT(cpu));
+    }
+    error_report("%s", error_get_pretty(error));
+    error_free(error);
+    return NULL;
 }
 
 #if !defined(CONFIG_USER_ONLY)
-- 
1.7.11.7

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [RFC 3/6] target-i386: Simplify cpu_x86_find_by_name() logic
  2013-01-04 19:56 [Qemu-devel] [RFC 0/6] x86 CPU subclasses, v4 Eduardo Habkost
  2013-01-04 19:56 ` [Qemu-devel] [RFC 1/6] target-i386: Move CPU object creation to cpu.c Eduardo Habkost
  2013-01-04 19:56 ` [Qemu-devel] [RFC 2/6] target-i386: Make cpu_x86_create() get Error argument Eduardo Habkost
@ 2013-01-04 19:56 ` Eduardo Habkost
  2013-01-04 19:56 ` [Qemu-devel] [RFC 4/6] target-i386: Set feature string parsing results directly on CPU object Eduardo Habkost
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Eduardo Habkost @ 2013-01-04 19:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: Igor Mammedov, Andreas Färber

Move the check for "host" to beginning of function, so instead of a
confusing if/else-if/else mess we now have just two obvious if/else
blocks:

1) Special case for "host";
2) General case for CPU model lookup on x86_defs list.

This way, we will be able to easily move those two parts to separate
class instance_init functions.

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
 target-i386/cpu.c | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 6c75327..a2ac3c3 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -1250,20 +1250,24 @@ static void cpudef_2_x86_cpu(X86CPU *cpu, x86_def_t *def, Error **errp)
 
 static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name)
 {
-    x86_def_t *def;
 
-    for (def = x86_defs; def; def = def->next) {
-        if (name && !strcmp(name, def->name)) {
-            break;
-        }
-    }
     if (kvm_enabled() && name && strcmp(name, "host") == 0) {
 #ifdef CONFIG_KVM
         kvm_cpu_fill_host(x86_cpu_def);
 #endif
-    } else if (!def) {
-        return -1;
     } else {
+        x86_def_t *def;
+
+        for (def = x86_defs; def; def = def->next) {
+            if (name && !strcmp(name, def->name)) {
+                break;
+            }
+        }
+
+        if (!def) {
+            return -1;
+        }
+
         memcpy(x86_cpu_def, def, sizeof(*def));
         /* sysenter isn't supported on compatibility mode on AMD, syscall
          * isn't supported in compatibility mode on Intel.
-- 
1.7.11.7

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [RFC 4/6] target-i386: Set feature string parsing results directly on CPU object
  2013-01-04 19:56 [Qemu-devel] [RFC 0/6] x86 CPU subclasses, v4 Eduardo Habkost
                   ` (2 preceding siblings ...)
  2013-01-04 19:56 ` [Qemu-devel] [RFC 3/6] target-i386: Simplify cpu_x86_find_by_name() logic Eduardo Habkost
@ 2013-01-04 19:56 ` Eduardo Habkost
  2013-01-04 19:56 ` [Qemu-devel] [RFC 5/6] target-i386: Move kvm_features/hypervisor initialization to cpu_x86_find_by_name() Eduardo Habkost
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Eduardo Habkost @ 2013-01-04 19:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: Igor Mammedov, Andreas Färber

Note that this is temporary: just like we would eventually kill usage of
x86_def_t inside cpu_x86_parse_featurestr(), we will eventually kill
usage of X86CPU inside that function as well.

This will help us keep the x86_def_t usage restricted to the CPU object
creation code.

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
 target-i386/cpu.c | 37 +++++++++++++++++++------------------
 1 file changed, 19 insertions(+), 18 deletions(-)

diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index a2ac3c3..54be18c 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -1303,7 +1303,7 @@ static void cpu_x86_set_props(X86CPU *cpu, QDict *features, Error **errp)
 
 /* Parse "+feature,-feature,feature=foo" CPU feature string
  */
-static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features,
+static int cpu_x86_parse_featurestr(X86CPU *cpu, char *features,
                                     QDict **props)
 {
     char *featurestr; /* Single 'key=value" string being parsed */
@@ -1374,7 +1374,7 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features,
                     fprintf(stderr, "bad numerical value %s\n", val);
                     goto error;
                 }
-                x86_cpu_def->tsc_khz = tsc_freq / 1000;
+                cpu->env.tsc_khz = tsc_freq / 1000;
             } else if (!strcmp(featurestr, "hv_spinlocks")) {
                 char *err;
                 numvalue = strtoul(val, &err, 0);
@@ -1400,20 +1400,20 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features,
             goto error;
         }
     }
-    x86_cpu_def->features |= plus_features;
-    x86_cpu_def->ext_features |= plus_ext_features;
-    x86_cpu_def->ext2_features |= plus_ext2_features;
-    x86_cpu_def->ext3_features |= plus_ext3_features;
-    x86_cpu_def->kvm_features |= plus_kvm_features;
-    x86_cpu_def->svm_features |= plus_svm_features;
-    x86_cpu_def->cpuid_7_0_ebx_features |= plus_7_0_ebx_features;
-    x86_cpu_def->features &= ~minus_features;
-    x86_cpu_def->ext_features &= ~minus_ext_features;
-    x86_cpu_def->ext2_features &= ~minus_ext2_features;
-    x86_cpu_def->ext3_features &= ~minus_ext3_features;
-    x86_cpu_def->kvm_features &= ~minus_kvm_features;
-    x86_cpu_def->svm_features &= ~minus_svm_features;
-    x86_cpu_def->cpuid_7_0_ebx_features &= ~minus_7_0_ebx_features;
+    cpu->env.cpuid_features |= plus_features;
+    cpu->env.cpuid_ext_features |= plus_ext_features;
+    cpu->env.cpuid_ext2_features |= plus_ext2_features;
+    cpu->env.cpuid_ext3_features |= plus_ext3_features;
+    cpu->env.cpuid_kvm_features |= plus_kvm_features;
+    cpu->env.cpuid_svm_features |= plus_svm_features;
+    cpu->env.cpuid_7_0_ebx_features |= plus_7_0_ebx_features;
+    cpu->env.cpuid_features &= ~minus_features;
+    cpu->env.cpuid_ext_features &= ~minus_ext_features;
+    cpu->env.cpuid_ext2_features &= ~minus_ext2_features;
+    cpu->env.cpuid_ext3_features &= ~minus_ext3_features;
+    cpu->env.cpuid_kvm_features &= ~minus_kvm_features;
+    cpu->env.cpuid_svm_features &= ~minus_svm_features;
+    cpu->env.cpuid_7_0_ebx_features &= ~minus_7_0_ebx_features;
     g_strfreev(feat_array);
     return 0;
 
@@ -1561,12 +1561,13 @@ X86CPU *cpu_x86_create(const char *cpu_model, Error **errp)
                             &def->ext3_features, &def->kvm_features,
                             &def->svm_features, &def->cpuid_7_0_ebx_features);
 
-    if (cpu_x86_parse_featurestr(def, features, &props) < 0) {
+    cpudef_2_x86_cpu(cpu, def, &error);
+
+    if (cpu_x86_parse_featurestr(cpu, features, &props) < 0) {
         error_setg(&error, "Invalid cpu_model string format: %s", cpu_model);
         goto out;
     }
 
-    cpudef_2_x86_cpu(cpu, def, &error);
     cpu_x86_set_props(cpu, props, &error);
 
 out:
-- 
1.7.11.7

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [RFC 5/6] target-i386: Move kvm_features/hypervisor initialization to cpu_x86_find_by_name()
  2013-01-04 19:56 [Qemu-devel] [RFC 0/6] x86 CPU subclasses, v4 Eduardo Habkost
                   ` (3 preceding siblings ...)
  2013-01-04 19:56 ` [Qemu-devel] [RFC 4/6] target-i386: Set feature string parsing results directly on CPU object Eduardo Habkost
@ 2013-01-04 19:56 ` Eduardo Habkost
  2013-01-04 19:56 ` [Qemu-devel] [RFC 6/6] target-i386: CPU model subclasses Eduardo Habkost
  2013-01-04 22:07 ` [Qemu-devel] [RFC 0/6] x86 CPU subclasses, v4 Eduardo Habkost
  6 siblings, 0 replies; 9+ messages in thread
From: Eduardo Habkost @ 2013-01-04 19:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: Igor Mammedov, Andreas Färber

Move the initialization to the cpu_x86_find_by_name(), inside the block
for predefined CPU models.

That code is not necessary for -cpu "host", because:

- kvm_features doesn't need to be set because kvm_cpu_fill_host()
  already sets all bits supported by the host.
- the CPUID_EXT_HYPERVISOR flag doesn't need to be manually set because
  kvm_arch_get_supported_cpuid() already sets it.

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
 target-i386/cpu.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 54be18c..03b7f55 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -1281,6 +1281,15 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name)
             host_cpuid(0, 0, NULL, &ebx, &ecx, &edx);
             x86cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx);
         }
+
+        x86_cpu_def->kvm_features |= kvm_default_features;
+        add_flagname_to_bitmaps("hypervisor", &x86_cpu_def->features,
+                                &x86_cpu_def->ext_features,
+                                &x86_cpu_def->ext2_features,
+                                &x86_cpu_def->ext3_features,
+                                &x86_cpu_def->kvm_features,
+                                &x86_cpu_def->svm_features,
+                                &x86_cpu_def->cpuid_7_0_ebx_features);
     }
 
     return 0;
@@ -1555,12 +1564,6 @@ X86CPU *cpu_x86_create(const char *cpu_model, Error **errp)
     env = &cpu->env;
     env->cpu_model_str = cpu_model;
 
-    def->kvm_features |= kvm_default_features;
-    add_flagname_to_bitmaps("hypervisor", &def->features,
-                            &def->ext_features, &def->ext2_features,
-                            &def->ext3_features, &def->kvm_features,
-                            &def->svm_features, &def->cpuid_7_0_ebx_features);
-
     cpudef_2_x86_cpu(cpu, def, &error);
 
     if (cpu_x86_parse_featurestr(cpu, features, &props) < 0) {
-- 
1.7.11.7

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [RFC 6/6] target-i386: CPU model subclasses
  2013-01-04 19:56 [Qemu-devel] [RFC 0/6] x86 CPU subclasses, v4 Eduardo Habkost
                   ` (4 preceding siblings ...)
  2013-01-04 19:56 ` [Qemu-devel] [RFC 5/6] target-i386: Move kvm_features/hypervisor initialization to cpu_x86_find_by_name() Eduardo Habkost
@ 2013-01-04 19:56 ` Eduardo Habkost
  2013-01-04 22:08   ` Eduardo Habkost
  2013-01-04 22:07 ` [Qemu-devel] [RFC 0/6] x86 CPU subclasses, v4 Eduardo Habkost
  6 siblings, 1 reply; 9+ messages in thread
From: Eduardo Habkost @ 2013-01-04 19:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: Igor Mammedov, Andreas Färber

This requires a small hack for -cpu host: the definition of -cpu host
requires KVM to be initialized, so there's a small hook added to
kvm_arch_init() so that the full CPU model data can be added to the
"host" CPU class after KVM is initialized, and a kvm_required field was
added to X86CPUClass to make sure we won't try to use the "host" CPU
model if KVM is not initialized.

The x86_def_t structs were mechanically translated into class_init
functions for each class. Note that the feature bit initialization uses
"|=" so it will be easier to change that code to reuse definitions set
in other functions or other classes.

The qemu_get_version() hacks inside x86_cpudef_setup() were moved to the
class_init functions of qemu64, qemu32, and athlon CPU models.

The additional feature initialization steps inside
cpu_x86_find_by_name() were moved as follows:

 - The KVM-specific vendor string initialization is now inside
   x86_cpu_initfn(), as it requires a kvm_enabled() check.
 - The setting of the "hypervisor" flag is now inside the common
   x86_cpu_class_init() function.
 - The initialization of kvm_features is a bit complicated, because:
   - kvm_default_features may be changed by the machine init functions,
     that may be called after class_init is called;
   - The "host" CPU model doesn't use kvm_default_features.

The solution is to make kvm_features a pointer. Most CPU models will
point to &kvm_default_features, but the "host" CPU model will point to
another static variable that will carry the host CPU features. The
pointer won't be necessary anymore once we start using global properties
for the KVM features machine-type compatibility code.

The "-cpu ?" output is not printing the full class name to not break the
libvirt parsing.

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
 include/sysemu/kvm.h  |    3 +
 target-i386/cpu-qom.h |   26 +
 target-i386/cpu.c     | 1505 ++++++++++++++++++++++++++++++-------------------
 target-i386/cpu.h     |    2 -
 target-i386/kvm.c     |    2 +
 5 files changed, 942 insertions(+), 596 deletions(-)

diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 3db19ff..69edeed 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -131,6 +131,9 @@ void *kvm_arch_vmalloc(ram_addr_t size);
 void kvm_setup_guest_memory(void *start, size_t size);
 
 void kvm_flush_coalesced_mmio_buffer(void);
+
+void x86_cpu_finish_host_class_init(KVMState *s);
+
 #endif
 
 int kvm_insert_breakpoint(CPUArchState *current_env, target_ulong addr,
diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
index 332916a..618a41a 100644
--- a/target-i386/cpu-qom.h
+++ b/target-i386/cpu-qom.h
@@ -49,6 +49,32 @@ typedef struct X86CPUClass {
     /*< public >*/
 
     void (*parent_reset)(CPUState *cpu);
+
+    /* Original model name for -cpu ? listing */
+    const char *model_name;
+
+    /* CPU model definition information: */
+    uint32_t level;
+    char vendor[CPUID_VENDOR_SZ + 1];
+    int family;
+    int model;
+    int stepping;
+    int tsc_khz;
+    uint32_t features, ext_features, ext2_features, ext3_features;
+    /* KVM features are a pointer because currently we change the default
+     * set of features using compatibility functions on the machine init
+     * function, and those may be called after class_init.
+     */
+    uint32_t *kvm_features;
+    uint32_t svm_features;
+    uint32_t xlevel;
+    char model_id[48];
+    /* 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;
+    bool kvm_required;
 } X86CPUClass;
 
 /**
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 03b7f55..506a1d3 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -299,26 +299,6 @@ static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features,
             fprintf(stderr, "CPU feature %s not found\n", flagname);
 }
 
-typedef struct x86_def_t {
-    struct x86_def_t *next;
-    const char *name;
-    uint32_t level;
-    char vendor[CPUID_VENDOR_SZ + 1];
-    int family;
-    int model;
-    int stepping;
-    int tsc_khz;
-    uint32_t features, ext_features, ext2_features, ext3_features;
-    uint32_t kvm_features, svm_features;
-    uint32_t xlevel;
-    char model_id[48];
-    /* 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)
 #define PENTIUM_FEATURES (I486_FEATURES | CPUID_DE | CPUID_TSC | \
           CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_MMX | CPUID_APIC)
@@ -357,473 +337,769 @@ typedef struct x86_def_t {
 #define TCG_SVM_FEATURES 0
 #define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP)
 
-/* maintains list of cpu model definitions
- */
-static x86_def_t *x86_defs = {NULL};
 
-/* built-in cpu model definitions (deprecated)
+/* CPU class name definitions: */
+
+#define X86_CPU_CLASS_SUFFIX "-" TYPE_X86_CPU
+#define CPU_CLASS_NAME(name) (name X86_CPU_CLASS_SUFFIX)
+
+/* -cpu "host" */
+#define TYPE_X86_HOST_CPU CPU_CLASS_NAME("host")
+
+/* Return X86CPUClass for a CPU model name */
+static X86CPUClass *x86_cpu_class_by_name(const char *name)
+{
+    X86CPUClass *cc;
+    char *class_name = g_strdup_printf(CPU_CLASS_NAME("%s"), name);
+    cc =  X86_CPU_CLASS(object_class_by_name(class_name));
+    g_free(class_name);
+    return cc;
+}
+
+/* Return the simple model name for a X86CPUClass
+ *
+ * The caller is responsible for freeing the returned string using g_free().
  */
-static x86_def_t builtin_x86_defs[] = {
-    {
-        .name = "qemu64",
-        .level = 4,
-        .vendor = CPUID_VENDOR_AMD,
-        .family = 6,
-        .model = 2,
-        .stepping = 3,
-        .features = PPRO_FEATURES |
+static char *x86_cpu_class_get_model_name(X86CPUClass *cc)
+{
+    const char *class_name = object_class_get_name(OBJECT_CLASS(cc));
+    if (g_str_has_suffix(class_name, X86_CPU_CLASS_SUFFIX)) {
+        return g_strndup(class_name,
+                         strlen(class_name) - strlen(X86_CPU_CLASS_SUFFIX));
+    } else {
+        return g_strdup(class_name);
+    }
+}
+
+
+static void x86_cpu_class_init_qemu64(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 4;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_AMD);
+    cc->family = 6;
+    cc->model = 2;
+    cc->stepping = 3;
+    cc->features |= PPRO_FEATURES |
             CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
-            CPUID_PSE36,
-        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_CX16 | CPUID_EXT_POPCNT,
-        .ext2_features = (PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) |
-            CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
-        .ext3_features = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
-            CPUID_EXT3_ABM | CPUID_EXT3_SSE4A,
-        .xlevel = 0x8000000A,
-    },
-    {
-        .name = "phenom",
-        .level = 5,
-        .vendor = CPUID_VENDOR_AMD,
-        .family = 16,
-        .model = 2,
-        .stepping = 3,
-        .features = PPRO_FEATURES |
+            CPUID_PSE36;
+    cc->ext_features |= CPUID_EXT_SSE3 | CPUID_EXT_CX16 | CPUID_EXT_POPCNT;
+    cc->ext2_features |= (PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) |
+            CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX;
+    cc->ext3_features |= CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
+            CPUID_EXT3_ABM | CPUID_EXT3_SSE4A;
+    cc->xlevel = 0x8000000A;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "QEMU Virtual CPU version ");
+    pstrcat(cc->model_id, sizeof(cc->model_id), qemu_get_version());
+}
+
+static const TypeInfo x86_cpu_qemu64_type_info = {
+    .name = CPU_CLASS_NAME("qemu64"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_qemu64,
+};
+
+static void x86_cpu_class_init_phenom(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 5;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_AMD);
+    cc->family = 16;
+    cc->model = 2;
+    cc->stepping = 3;
+    cc->features |= PPRO_FEATURES |
             CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
-            CPUID_PSE36 | CPUID_VME | CPUID_HT,
-        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_CX16 |
-            CPUID_EXT_POPCNT,
-        .ext2_features = (PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) |
+            CPUID_PSE36 | CPUID_VME | CPUID_HT;
+    cc->ext_features |= CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_CX16 |
+            CPUID_EXT_POPCNT;
+    cc->ext2_features |= (PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) |
             CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX |
             CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_MMXEXT |
-            CPUID_EXT2_FFXSR | CPUID_EXT2_PDPE1GB | CPUID_EXT2_RDTSCP,
-        /* Missing: CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC,
-                    CPUID_EXT3_CR8LEG,
-                    CPUID_EXT3_MISALIGNSSE, CPUID_EXT3_3DNOWPREFETCH,
+            CPUID_EXT2_FFXSR | CPUID_EXT2_PDPE1GB | CPUID_EXT2_RDTSCP;
+        /* Missing: CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC;
+                    CPUID_EXT3_CR8LEG;
+                    CPUID_EXT3_MISALIGNSSE, CPUID_EXT3_3DNOWPREFETCH;
                     CPUID_EXT3_OSVW, CPUID_EXT3_IBS */
-        .ext3_features = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
-            CPUID_EXT3_ABM | CPUID_EXT3_SSE4A,
-        .svm_features = CPUID_SVM_NPT | CPUID_SVM_LBRV,
-        .xlevel = 0x8000001A,
-        .model_id = "AMD Phenom(tm) 9550 Quad-Core Processor"
-    },
-    {
-        .name = "core2duo",
-        .level = 10,
-        .vendor = CPUID_VENDOR_INTEL,
-        .family = 6,
-        .model = 15,
-        .stepping = 11,
-        .features = PPRO_FEATURES |
+    cc->ext3_features |= CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
+            CPUID_EXT3_ABM | CPUID_EXT3_SSE4A;
+    cc->svm_features |= CPUID_SVM_NPT | CPUID_SVM_LBRV;
+    cc->xlevel = 0x8000001A;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "AMD Phenom(tm) 9550 Quad-Core Processor");
+}
+
+static const TypeInfo x86_cpu_phenom_type_info = {
+    .name = CPU_CLASS_NAME("phenom"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_phenom,
+};
+
+static void x86_cpu_class_init_core2duo(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 10;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_INTEL);
+    cc->family = 6;
+    cc->model = 15;
+    cc->stepping = 11;
+    cc->features |= PPRO_FEATURES |
             CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
             CPUID_PSE36 | CPUID_VME | CPUID_DTS | CPUID_ACPI | CPUID_SS |
-            CPUID_HT | CPUID_TM | CPUID_PBE,
-        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 |
+            CPUID_HT | CPUID_TM | CPUID_PBE;
+    cc->ext_features |= CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 |
             CPUID_EXT_DTES64 | CPUID_EXT_DSCPL | CPUID_EXT_VMX | CPUID_EXT_EST |
-            CPUID_EXT_TM2 | CPUID_EXT_CX16 | CPUID_EXT_XTPR | CPUID_EXT_PDCM,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
-        .ext3_features = CPUID_EXT3_LAHF_LM,
-        .xlevel = 0x80000008,
-        .model_id = "Intel(R) Core(TM)2 Duo CPU     T7700  @ 2.40GHz",
-    },
-    {
-        .name = "kvm64",
-        .level = 5,
-        .vendor = CPUID_VENDOR_INTEL,
-        .family = 15,
-        .model = 6,
-        .stepping = 1,
+            CPUID_EXT_TM2 | CPUID_EXT_CX16 | CPUID_EXT_XTPR | CPUID_EXT_PDCM;
+    cc->ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX;
+    cc->ext3_features |= CPUID_EXT3_LAHF_LM;
+    cc->xlevel = 0x80000008;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "Intel(R) Core(TM)2 Duo CPU     T7700  @ 2.40GHz");
+}
+
+static const TypeInfo x86_cpu_core2duo_type_info = {
+    .name = CPU_CLASS_NAME("core2duo"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_core2duo,
+};
+
+static void x86_cpu_class_init_kvm64(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 5;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_INTEL);
+    cc->family = 15;
+    cc->model = 6;
+    cc->stepping = 1;
         /* Missing: CPUID_VME, CPUID_HT */
-        .features = PPRO_FEATURES |
+    cc->features |= PPRO_FEATURES |
             CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
-            CPUID_PSE36,
+            CPUID_PSE36;
         /* Missing: CPUID_EXT_POPCNT, CPUID_EXT_MONITOR */
-        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_CX16,
+    cc->ext_features |= CPUID_EXT_SSE3 | CPUID_EXT_CX16;
         /* Missing: CPUID_EXT2_PDPE1GB, CPUID_EXT2_RDTSCP */
-        .ext2_features = (PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) |
-            CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
-        /* Missing: CPUID_EXT3_LAHF_LM, CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC,
-                    CPUID_EXT3_CR8LEG, CPUID_EXT3_ABM, CPUID_EXT3_SSE4A,
-                    CPUID_EXT3_MISALIGNSSE, CPUID_EXT3_3DNOWPREFETCH,
+    cc->ext2_features |= (PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) |
+            CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX;
+        /* Missing: CPUID_EXT3_LAHF_LM, CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC;
+                    CPUID_EXT3_CR8LEG, CPUID_EXT3_ABM, CPUID_EXT3_SSE4A;
+                    CPUID_EXT3_MISALIGNSSE, CPUID_EXT3_3DNOWPREFETCH;
                     CPUID_EXT3_OSVW, CPUID_EXT3_IBS, CPUID_EXT3_SVM */
-        .ext3_features = 0,
-        .xlevel = 0x80000008,
-        .model_id = "Common KVM processor"
-    },
-    {
-        .name = "qemu32",
-        .level = 4,
-        .vendor = CPUID_VENDOR_INTEL,
-        .family = 6,
-        .model = 3,
-        .stepping = 3,
-        .features = PPRO_FEATURES,
-        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_POPCNT,
-        .xlevel = 0x80000004,
-    },
-    {
-        .name = "kvm32",
-        .level = 5,
-        .vendor = CPUID_VENDOR_INTEL,
-        .family = 15,
-        .model = 6,
-        .stepping = 1,
-        .features = PPRO_FEATURES |
-            CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_PSE36,
-        .ext_features = CPUID_EXT_SSE3,
-        .ext2_features = PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES,
-        .ext3_features = 0,
-        .xlevel = 0x80000008,
-        .model_id = "Common 32-bit KVM processor"
-    },
-    {
-        .name = "coreduo",
-        .level = 10,
-        .vendor = CPUID_VENDOR_INTEL,
-        .family = 6,
-        .model = 14,
-        .stepping = 8,
-        .features = PPRO_FEATURES | CPUID_VME |
+    cc->ext3_features |= 0;
+    cc->xlevel = 0x80000008;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "Common KVM processor");
+}
+
+static const TypeInfo x86_cpu_kvm64_type_info = {
+    .name = CPU_CLASS_NAME("kvm64"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_kvm64,
+};
+
+static void x86_cpu_class_init_qemu32(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 4;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_INTEL);
+    cc->family = 6;
+    cc->model = 3;
+    cc->stepping = 3;
+    cc->features |= PPRO_FEATURES;
+    cc->ext_features |= CPUID_EXT_SSE3 | CPUID_EXT_POPCNT;
+    cc->xlevel = 0x80000004;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "QEMU Virtual CPU version ");
+    pstrcat(cc->model_id, sizeof(cc->model_id), qemu_get_version());
+}
+
+static const TypeInfo x86_cpu_qemu32_type_info = {
+    .name = CPU_CLASS_NAME("qemu32"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_qemu32,
+};
+
+static void x86_cpu_class_init_kvm32(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 5;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_INTEL);
+    cc->family = 15;
+    cc->model = 6;
+    cc->stepping = 1;
+    cc->features |= PPRO_FEATURES |
+            CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_PSE36;
+    cc->ext_features |= CPUID_EXT_SSE3;
+    cc->ext2_features |= PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES;
+    cc->ext3_features |= 0;
+    cc->xlevel = 0x80000008;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "Common 32-bit KVM processor");
+}
+
+static const TypeInfo x86_cpu_kvm32_type_info = {
+    .name = CPU_CLASS_NAME("kvm32"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_kvm32,
+};
+
+static void x86_cpu_class_init_coreduo(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 10;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_INTEL);
+    cc->family = 6;
+    cc->model = 14;
+    cc->stepping = 8;
+    cc->features |= PPRO_FEATURES | CPUID_VME |
             CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_DTS | CPUID_ACPI |
-            CPUID_SS | CPUID_HT | CPUID_TM | CPUID_PBE,
-        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_VMX |
-            CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_XTPR | CPUID_EXT_PDCM,
-        .ext2_features = CPUID_EXT2_NX,
-        .xlevel = 0x80000008,
-        .model_id = "Genuine Intel(R) CPU           T2600  @ 2.16GHz",
-    },
-    {
-        .name = "486",
-        .level = 1,
-        .vendor = CPUID_VENDOR_INTEL,
-        .family = 4,
-        .model = 0,
-        .stepping = 0,
-        .features = I486_FEATURES,
-        .xlevel = 0,
-    },
-    {
-        .name = "pentium",
-        .level = 1,
-        .vendor = CPUID_VENDOR_INTEL,
-        .family = 5,
-        .model = 4,
-        .stepping = 3,
-        .features = PENTIUM_FEATURES,
-        .xlevel = 0,
-    },
-    {
-        .name = "pentium2",
-        .level = 2,
-        .vendor = CPUID_VENDOR_INTEL,
-        .family = 6,
-        .model = 5,
-        .stepping = 2,
-        .features = PENTIUM2_FEATURES,
-        .xlevel = 0,
-    },
-    {
-        .name = "pentium3",
-        .level = 2,
-        .vendor = CPUID_VENDOR_INTEL,
-        .family = 6,
-        .model = 7,
-        .stepping = 3,
-        .features = PENTIUM3_FEATURES,
-        .xlevel = 0,
-    },
-    {
-        .name = "athlon",
-        .level = 2,
-        .vendor = CPUID_VENDOR_AMD,
-        .family = 6,
-        .model = 2,
-        .stepping = 3,
-        .features = PPRO_FEATURES | CPUID_PSE36 | CPUID_VME | CPUID_MTRR |
-            CPUID_MCA,
-        .ext2_features = (PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) |
-            CPUID_EXT2_MMXEXT | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT,
-        .xlevel = 0x80000008,
-    },
-    {
-        .name = "n270",
+            CPUID_SS | CPUID_HT | CPUID_TM | CPUID_PBE;
+    cc->ext_features |= CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_VMX |
+            CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_XTPR | CPUID_EXT_PDCM;
+    cc->ext2_features |= CPUID_EXT2_NX;
+    cc->xlevel = 0x80000008;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "Genuine Intel(R) CPU           T2600  @ 2.16GHz");
+}
+
+static const TypeInfo x86_cpu_coreduo_type_info = {
+    .name = CPU_CLASS_NAME("coreduo"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_coreduo,
+};
+
+static void x86_cpu_class_init_486(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 1;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_INTEL);
+    cc->family = 4;
+    cc->model = 0;
+    cc->stepping = 0;
+    cc->features |= I486_FEATURES;
+    cc->xlevel = 0;
+}
+
+static const TypeInfo x86_cpu_486_type_info = {
+    .name = CPU_CLASS_NAME("486"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_486,
+};
+
+static void x86_cpu_class_init_pentium(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 1;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_INTEL);
+    cc->family = 5;
+    cc->model = 4;
+    cc->stepping = 3;
+    cc->features |= PENTIUM_FEATURES;
+    cc->xlevel = 0;
+}
+
+static const TypeInfo x86_cpu_pentium_type_info = {
+    .name = CPU_CLASS_NAME("pentium"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_pentium,
+};
+
+static void x86_cpu_class_init_pentium2(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 2;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_INTEL);
+    cc->family = 6;
+    cc->model = 5;
+    cc->stepping = 2;
+    cc->features |= PENTIUM2_FEATURES;
+    cc->xlevel = 0;
+}
+
+static const TypeInfo x86_cpu_pentium2_type_info = {
+    .name = CPU_CLASS_NAME("pentium2"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_pentium2,
+};
+
+static void x86_cpu_class_init_pentium3(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 2;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_INTEL);
+    cc->family = 6;
+    cc->model = 7;
+    cc->stepping = 3;
+    cc->features |= PENTIUM3_FEATURES;
+    cc->xlevel = 0;
+}
+
+static const TypeInfo x86_cpu_pentium3_type_info = {
+    .name = CPU_CLASS_NAME("pentium3"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_pentium3,
+};
+
+static void x86_cpu_class_init_athlon(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 2;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_AMD);
+    cc->family = 6;
+    cc->model = 2;
+    cc->stepping = 3;
+    cc->features |= PPRO_FEATURES | CPUID_PSE36 | CPUID_VME | CPUID_MTRR |
+            CPUID_MCA;
+    cc->ext2_features |= (PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) |
+            CPUID_EXT2_MMXEXT | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT;
+    cc->xlevel = 0x80000008;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "QEMU Virtual CPU version ");
+    pstrcat(cc->model_id, sizeof(cc->model_id), qemu_get_version());
+}
+
+static const TypeInfo x86_cpu_athlon_type_info = {
+    .name = CPU_CLASS_NAME("athlon"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_athlon,
+};
+
+static void x86_cpu_class_init_n270(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
         /* original is on level 10 */
-        .level = 5,
-        .vendor = CPUID_VENDOR_INTEL,
-        .family = 6,
-        .model = 28,
-        .stepping = 2,
-        .features = PPRO_FEATURES |
+    cc->level = 5;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_INTEL);
+    cc->family = 6;
+    cc->model = 28;
+    cc->stepping = 2;
+    cc->features |= PPRO_FEATURES |
             CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_VME | CPUID_DTS |
-            CPUID_ACPI | CPUID_SS | CPUID_HT | CPUID_TM | CPUID_PBE,
+            CPUID_ACPI | CPUID_SS | CPUID_HT | CPUID_TM | CPUID_PBE;
             /* Some CPUs got no CPUID_SEP */
-        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 |
-            CPUID_EXT_DSCPL | CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_XTPR,
-        .ext2_features = (PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) |
-            CPUID_EXT2_NX,
-        .ext3_features = CPUID_EXT3_LAHF_LM,
-        .xlevel = 0x8000000A,
-        .model_id = "Intel(R) Atom(TM) CPU N270   @ 1.60GHz",
-    },
-    {
-        .name = "Conroe",
-        .level = 2,
-        .vendor = CPUID_VENDOR_INTEL,
-        .family = 6,
-        .model = 2,
-        .stepping = 3,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+    cc->ext_features |= CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 |
+            CPUID_EXT_DSCPL | CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_XTPR;
+    cc->ext2_features |= (PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) |
+            CPUID_EXT2_NX;
+    cc->ext3_features |= CPUID_EXT3_LAHF_LM;
+    cc->xlevel = 0x8000000A;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "Intel(R) Atom(TM) CPU N270   @ 1.60GHz");
+}
+
+static const TypeInfo x86_cpu_n270_type_info = {
+    .name = CPU_CLASS_NAME("n270"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_n270,
+};
+
+static void x86_cpu_class_init_Conroe(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 2;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_INTEL);
+    cc->family = 6;
+    cc->model = 2;
+    cc->stepping = 3;
+    cc->features |= CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
              CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
              CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
              CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_SSSE3 | CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
-        .ext3_features = CPUID_EXT3_LAHF_LM,
-        .xlevel = 0x8000000A,
-        .model_id = "Intel Celeron_4x0 (Conroe/Merom Class Core 2)",
-    },
-    {
-        .name = "Penryn",
-        .level = 2,
-        .vendor = CPUID_VENDOR_INTEL,
-        .family = 6,
-        .model = 2,
-        .stepping = 3,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+             CPUID_DE | CPUID_FP87;
+    cc->ext_features |= CPUID_EXT_SSSE3 | CPUID_EXT_SSE3;
+    cc->ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL;
+    cc->ext3_features |= CPUID_EXT3_LAHF_LM;
+    cc->xlevel = 0x8000000A;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "Intel Celeron_4x0 (Conroe/Merom Class Core 2)");
+}
+
+static const TypeInfo x86_cpu_Conroe_type_info = {
+    .name = CPU_CLASS_NAME("Conroe"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_Conroe,
+};
+
+static void x86_cpu_class_init_Penryn(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 2;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_INTEL);
+    cc->family = 6;
+    cc->model = 2;
+    cc->stepping = 3;
+    cc->features |= CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
              CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
              CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
              CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
-             CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
-        .ext3_features = CPUID_EXT3_LAHF_LM,
-        .xlevel = 0x8000000A,
-        .model_id = "Intel Core 2 Duo P9xxx (Penryn Class Core 2)",
-    },
-    {
-        .name = "Nehalem",
-        .level = 2,
-        .vendor = CPUID_VENDOR_INTEL,
-        .family = 6,
-        .model = 2,
-        .stepping = 3,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+             CPUID_DE | CPUID_FP87;
+    cc->ext_features |= CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
+             CPUID_EXT_SSE3;
+    cc->ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL;
+    cc->ext3_features |= CPUID_EXT3_LAHF_LM;
+    cc->xlevel = 0x8000000A;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "Intel Core 2 Duo P9xxx (Penryn Class Core 2)");
+}
+
+static const TypeInfo x86_cpu_Penryn_type_info = {
+    .name = CPU_CLASS_NAME("Penryn"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_Penryn,
+};
+
+static void x86_cpu_class_init_Nehalem(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 2;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_INTEL);
+    cc->family = 6;
+    cc->model = 2;
+    cc->stepping = 3;
+    cc->features |= CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
              CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
              CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
              CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_POPCNT | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
-             CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
-        .ext3_features = CPUID_EXT3_LAHF_LM,
-        .xlevel = 0x8000000A,
-        .model_id = "Intel Core i7 9xx (Nehalem Class Core i7)",
-    },
-    {
-        .name = "Westmere",
-        .level = 11,
-        .vendor = CPUID_VENDOR_INTEL,
-        .family = 6,
-        .model = 44,
-        .stepping = 1,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+             CPUID_DE | CPUID_FP87;
+    cc->ext_features |= CPUID_EXT_POPCNT | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
+             CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_SSE3;
+    cc->ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX;
+    cc->ext3_features |= CPUID_EXT3_LAHF_LM;
+    cc->xlevel = 0x8000000A;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "Intel Core i7 9xx (Nehalem Class Core i7)");
+}
+
+static const TypeInfo x86_cpu_Nehalem_type_info = {
+    .name = CPU_CLASS_NAME("Nehalem"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_Nehalem,
+};
+
+static void x86_cpu_class_init_Westmere(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 11;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_INTEL);
+    cc->family = 6;
+    cc->model = 44;
+    cc->stepping = 1;
+    cc->features |= CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
              CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
              CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
              CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_AES | CPUID_EXT_POPCNT | CPUID_EXT_SSE42 |
+             CPUID_DE | CPUID_FP87;
+    cc->ext_features |= CPUID_EXT_AES | CPUID_EXT_POPCNT | CPUID_EXT_SSE42 |
              CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
-             CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
-        .ext3_features = CPUID_EXT3_LAHF_LM,
-        .xlevel = 0x8000000A,
-        .model_id = "Westmere E56xx/L56xx/X56xx (Nehalem-C)",
-    },
-    {
-        .name = "SandyBridge",
-        .level = 0xd,
-        .vendor = CPUID_VENDOR_INTEL,
-        .family = 6,
-        .model = 42,
-        .stepping = 1,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+             CPUID_EXT_SSE3;
+    cc->ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX;
+    cc->ext3_features |= CPUID_EXT3_LAHF_LM;
+    cc->xlevel = 0x8000000A;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "Westmere E56xx/L56xx/X56xx (Nehalem-C)");
+}
+
+static const TypeInfo x86_cpu_Westmere_type_info = {
+    .name = CPU_CLASS_NAME("Westmere"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_Westmere,
+};
+
+static void x86_cpu_class_init_SandyBridge(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 0xd;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_INTEL);
+    cc->family = 6;
+    cc->model = 42;
+    cc->stepping = 1;
+    cc->features |= CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
              CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
              CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
              CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
+             CPUID_DE | CPUID_FP87;
+    cc->ext_features |= CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
              CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_POPCNT |
              CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
              CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ |
-             CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
-             CPUID_EXT2_SYSCALL,
-        .ext3_features = CPUID_EXT3_LAHF_LM,
-        .xlevel = 0x8000000A,
-        .model_id = "Intel Xeon E312xx (Sandy Bridge)",
-    },
-    {
-        .name = "Haswell",
-        .level = 0xd,
-        .vendor = CPUID_VENDOR_INTEL,
-        .family = 6,
-        .model = 60,
-        .stepping = 1,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+             CPUID_EXT_SSE3;
+    cc->ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
+             CPUID_EXT2_SYSCALL;
+    cc->ext3_features |= CPUID_EXT3_LAHF_LM;
+    cc->xlevel = 0x8000000A;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "Intel Xeon E312xx (Sandy Bridge)");
+}
+
+static const TypeInfo x86_cpu_SandyBridge_type_info = {
+    .name = CPU_CLASS_NAME("SandyBridge"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_SandyBridge,
+};
+
+static void x86_cpu_class_init_Haswell(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 0xd;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_INTEL);
+    cc->family = 6;
+    cc->model = 60;
+    cc->stepping = 1;
+    cc->features |= CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
              CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
              CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
              CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
+             CPUID_DE | CPUID_FP87;
+    cc->ext_features |= CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
              CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
              CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
              CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
              CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
-             CPUID_EXT_PCID,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
-             CPUID_EXT2_SYSCALL,
-        .ext3_features = CPUID_EXT3_LAHF_LM,
-        .cpuid_7_0_ebx_features = CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
+             CPUID_EXT_PCID;
+    cc->ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
+             CPUID_EXT2_SYSCALL;
+    cc->ext3_features |= CPUID_EXT3_LAHF_LM;
+    cc->cpuid_7_0_ebx_features |= CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
             CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
             CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
-            CPUID_7_0_EBX_RTM,
-        .xlevel = 0x8000000A,
-        .model_id = "Intel Core Processor (Haswell)",
-    },
-    {
-        .name = "Opteron_G1",
-        .level = 5,
-        .vendor = CPUID_VENDOR_AMD,
-        .family = 15,
-        .model = 6,
-        .stepping = 1,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+            CPUID_7_0_EBX_RTM;
+    cc->xlevel = 0x8000000A;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "Intel Core Processor (Haswell)");
+}
+
+static const TypeInfo x86_cpu_Haswell_type_info = {
+    .name = CPU_CLASS_NAME("Haswell"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_Haswell,
+};
+
+static void x86_cpu_class_init_Opteron_G1(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 5;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_AMD);
+    cc->family = 15;
+    cc->model = 6;
+    cc->stepping = 1;
+    cc->features |= CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
              CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
              CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
              CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_FXSR | CPUID_EXT2_MMX |
+             CPUID_DE | CPUID_FP87;
+    cc->ext_features |= CPUID_EXT_SSE3;
+    cc->ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_FXSR | CPUID_EXT2_MMX |
              CPUID_EXT2_NX | CPUID_EXT2_PSE36 | CPUID_EXT2_PAT |
              CPUID_EXT2_CMOV | CPUID_EXT2_MCA | CPUID_EXT2_PGE |
              CPUID_EXT2_MTRR | CPUID_EXT2_SYSCALL | CPUID_EXT2_APIC |
              CPUID_EXT2_CX8 | CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR |
-             CPUID_EXT2_TSC | CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU,
-        .xlevel = 0x80000008,
-        .model_id = "AMD Opteron 240 (Gen 1 Class Opteron)",
-    },
-    {
-        .name = "Opteron_G2",
-        .level = 5,
-        .vendor = CPUID_VENDOR_AMD,
-        .family = 15,
-        .model = 6,
-        .stepping = 1,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+             CPUID_EXT2_TSC | CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU;
+    cc->xlevel = 0x80000008;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "AMD Opteron 240 (Gen 1 Class Opteron)");
+}
+
+static const TypeInfo x86_cpu_Opteron_G1_type_info = {
+    .name = CPU_CLASS_NAME("Opteron_G1"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_Opteron_G1,
+};
+
+static void x86_cpu_class_init_Opteron_G2(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 5;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_AMD);
+    cc->family = 15;
+    cc->model = 6;
+    cc->stepping = 1;
+    cc->features |= CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
              CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
              CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
              CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_CX16 | CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_FXSR |
+             CPUID_DE | CPUID_FP87;
+    cc->ext_features |= CPUID_EXT_CX16 | CPUID_EXT_SSE3;
+    cc->ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_FXSR |
              CPUID_EXT2_MMX | CPUID_EXT2_NX | CPUID_EXT2_PSE36 |
              CPUID_EXT2_PAT | CPUID_EXT2_CMOV | CPUID_EXT2_MCA |
              CPUID_EXT2_PGE | CPUID_EXT2_MTRR | CPUID_EXT2_SYSCALL |
              CPUID_EXT2_APIC | CPUID_EXT2_CX8 | CPUID_EXT2_MCE |
              CPUID_EXT2_PAE | CPUID_EXT2_MSR | CPUID_EXT2_TSC | CPUID_EXT2_PSE |
-             CPUID_EXT2_DE | CPUID_EXT2_FPU,
-        .ext3_features = CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM,
-        .xlevel = 0x80000008,
-        .model_id = "AMD Opteron 22xx (Gen 2 Class Opteron)",
-    },
-    {
-        .name = "Opteron_G3",
-        .level = 5,
-        .vendor = CPUID_VENDOR_AMD,
-        .family = 15,
-        .model = 6,
-        .stepping = 1,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+             CPUID_EXT2_DE | CPUID_EXT2_FPU;
+    cc->ext3_features |= CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM;
+    cc->xlevel = 0x80000008;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "AMD Opteron 22xx (Gen 2 Class Opteron)");
+}
+
+static const TypeInfo x86_cpu_Opteron_G2_type_info = {
+    .name = CPU_CLASS_NAME("Opteron_G2"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_Opteron_G2,
+};
+
+static void x86_cpu_class_init_Opteron_G3(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 5;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_AMD);
+    cc->family = 15;
+    cc->model = 6;
+    cc->stepping = 1;
+    cc->features |= CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
              CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
              CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
              CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_POPCNT | CPUID_EXT_CX16 | CPUID_EXT_MONITOR |
-             CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_FXSR |
+             CPUID_DE | CPUID_FP87;
+    cc->ext_features |= CPUID_EXT_POPCNT | CPUID_EXT_CX16 | CPUID_EXT_MONITOR |
+             CPUID_EXT_SSE3;
+    cc->ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_FXSR |
              CPUID_EXT2_MMX | CPUID_EXT2_NX | CPUID_EXT2_PSE36 |
              CPUID_EXT2_PAT | CPUID_EXT2_CMOV | CPUID_EXT2_MCA |
              CPUID_EXT2_PGE | CPUID_EXT2_MTRR | CPUID_EXT2_SYSCALL |
              CPUID_EXT2_APIC | CPUID_EXT2_CX8 | CPUID_EXT2_MCE |
              CPUID_EXT2_PAE | CPUID_EXT2_MSR | CPUID_EXT2_TSC | CPUID_EXT2_PSE |
-             CPUID_EXT2_DE | CPUID_EXT2_FPU,
-        .ext3_features = CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A |
-             CPUID_EXT3_ABM | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM,
-        .xlevel = 0x80000008,
-        .model_id = "AMD Opteron 23xx (Gen 3 Class Opteron)",
-    },
-    {
-        .name = "Opteron_G4",
-        .level = 0xd,
-        .vendor = CPUID_VENDOR_AMD,
-        .family = 21,
-        .model = 1,
-        .stepping = 2,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+             CPUID_EXT2_DE | CPUID_EXT2_FPU;
+    cc->ext3_features |= CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A |
+             CPUID_EXT3_ABM | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM;
+    cc->xlevel = 0x80000008;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "AMD Opteron 23xx (Gen 3 Class Opteron)");
+}
+
+static const TypeInfo x86_cpu_Opteron_G3_type_info = {
+    .name = CPU_CLASS_NAME("Opteron_G3"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_Opteron_G3,
+};
+
+static void x86_cpu_class_init_Opteron_G4(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 0xd;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_AMD);
+    cc->family = 21;
+    cc->model = 1;
+    cc->stepping = 2;
+    cc->features |= CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
              CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
              CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
              CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
+             CPUID_DE | CPUID_FP87;
+    cc->ext_features |= CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
              CPUID_EXT_POPCNT | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
              CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ |
-             CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_RDTSCP |
+             CPUID_EXT_SSE3;
+    cc->ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_RDTSCP |
              CPUID_EXT2_PDPE1GB | CPUID_EXT2_FXSR | CPUID_EXT2_MMX |
              CPUID_EXT2_NX | CPUID_EXT2_PSE36 | CPUID_EXT2_PAT |
              CPUID_EXT2_CMOV | CPUID_EXT2_MCA | CPUID_EXT2_PGE |
              CPUID_EXT2_MTRR | CPUID_EXT2_SYSCALL | CPUID_EXT2_APIC |
              CPUID_EXT2_CX8 | CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR |
-             CPUID_EXT2_TSC | CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU,
-        .ext3_features = CPUID_EXT3_FMA4 | CPUID_EXT3_XOP |
+             CPUID_EXT2_TSC | CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU;
+    cc->ext3_features |= CPUID_EXT3_FMA4 | CPUID_EXT3_XOP |
              CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_MISALIGNSSE |
              CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | CPUID_EXT3_SVM |
-             CPUID_EXT3_LAHF_LM,
-        .xlevel = 0x8000001A,
-        .model_id = "AMD Opteron 62xx class CPU",
-    },
-    {
-        .name = "Opteron_G5",
-        .level = 0xd,
-        .vendor = CPUID_VENDOR_AMD,
-        .family = 21,
-        .model = 2,
-        .stepping = 0,
-        .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+             CPUID_EXT3_LAHF_LM;
+    cc->xlevel = 0x8000001A;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "AMD Opteron 62xx class CPU");
+}
+
+static const TypeInfo x86_cpu_Opteron_G4_type_info = {
+    .name = CPU_CLASS_NAME("Opteron_G4"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_Opteron_G4,
+};
+
+static void x86_cpu_class_init_Opteron_G5(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->level = 0xd;
+    pstrcpy(cc->vendor, sizeof(cc->vendor), CPUID_VENDOR_AMD);
+    cc->family = 21;
+    cc->model = 2;
+    cc->stepping = 0;
+    cc->features |= CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
              CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
              CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
              CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
-             CPUID_DE | CPUID_FP87,
-        .ext_features = CPUID_EXT_F16C | CPUID_EXT_AVX | CPUID_EXT_XSAVE |
+             CPUID_DE | CPUID_FP87;
+    cc->ext_features |= CPUID_EXT_F16C | CPUID_EXT_AVX | CPUID_EXT_XSAVE |
              CPUID_EXT_AES | CPUID_EXT_POPCNT | CPUID_EXT_SSE42 |
              CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_FMA |
-             CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3,
-        .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_RDTSCP |
+             CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3;
+    cc->ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_RDTSCP |
              CPUID_EXT2_PDPE1GB | CPUID_EXT2_FXSR | CPUID_EXT2_MMX |
              CPUID_EXT2_NX | CPUID_EXT2_PSE36 | CPUID_EXT2_PAT |
              CPUID_EXT2_CMOV | CPUID_EXT2_MCA | CPUID_EXT2_PGE |
              CPUID_EXT2_MTRR | CPUID_EXT2_SYSCALL | CPUID_EXT2_APIC |
              CPUID_EXT2_CX8 | CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR |
-             CPUID_EXT2_TSC | CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU,
-        .ext3_features = CPUID_EXT3_TBM | CPUID_EXT3_FMA4 | CPUID_EXT3_XOP |
+             CPUID_EXT2_TSC | CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU;
+    cc->ext3_features |= CPUID_EXT3_TBM | CPUID_EXT3_FMA4 | CPUID_EXT3_XOP |
              CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_MISALIGNSSE |
              CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | CPUID_EXT3_SVM |
-             CPUID_EXT3_LAHF_LM,
-        .xlevel = 0x8000001A,
-        .model_id = "AMD Opteron 63xx class CPU",
-    },
+             CPUID_EXT3_LAHF_LM;
+    cc->xlevel = 0x8000001A;
+    pstrcpy(cc->model_id, sizeof(cc->model_id), "AMD Opteron 63xx class CPU");
+}
+
+static const TypeInfo x86_cpu_Opteron_G5_type_info = {
+    .name = CPU_CLASS_NAME("Opteron_G5"),
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .abstract = false,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_class_init_Opteron_G5,
 };
 
 static void x86cpu_vendor_words2str(char *dst, uint32_t ebx, uint32_t ecx,
@@ -854,67 +1130,6 @@ static int cpu_x86_fill_model_id(char *str)
     return 0;
 }
 
-/* Fill a x86_def_t struct with information about the host CPU, and
- * the CPU features supported by the host hardware + host kernel
- *
- * This function may be called only if KVM is enabled.
- */
-static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def)
-{
-    KVMState *s = kvm_state;
-    uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
-
-    assert(kvm_enabled());
-
-    x86_cpu_def->name = "host";
-    host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
-    x86cpu_vendor_words2str(x86_cpu_def->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;
-
-    x86_cpu_def->level = kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
-    x86_cpu_def->features = kvm_arch_get_supported_cpuid(s, 0x1, 0, R_EDX);
-    x86_cpu_def->ext_features = kvm_arch_get_supported_cpuid(s, 0x1, 0, R_ECX);
-
-    if (x86_cpu_def->level >= 7) {
-        x86_cpu_def->cpuid_7_0_ebx_features =
-                    kvm_arch_get_supported_cpuid(s, 0x7, 0, R_EBX);
-    } else {
-        x86_cpu_def->cpuid_7_0_ebx_features = 0;
-    }
-
-    x86_cpu_def->xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX);
-    x86_cpu_def->ext2_features =
-                kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_EDX);
-    x86_cpu_def->ext3_features =
-                kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_ECX);
-
-    cpu_x86_fill_model_id(x86_cpu_def->model_id);
-
-    /* Call Centaur's CPUID instruction. */
-    if (!strcmp(x86_cpu_def->vendor, CPUID_VENDOR_VIA)) {
-        host_cpuid(0xC0000000, 0, &eax, &ebx, &ecx, &edx);
-        eax = kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
-        if (eax >= 0xC0000001) {
-            /* Support VIA max extended level */
-            x86_cpu_def->xlevel2 = eax;
-            host_cpuid(0xC0000001, 0, &eax, &ebx, &ecx, &edx);
-            x86_cpu_def->ext4_features =
-                    kvm_arch_get_supported_cpuid(s, 0xC0000001, 0, R_EDX);
-        }
-    }
-
-    /* Other KVM-specific feature fields: */
-    x86_cpu_def->svm_features =
-        kvm_arch_get_supported_cpuid(s, 0x8000000A, 0, R_EDX);
-    x86_cpu_def->kvm_features =
-        kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX);
-
-}
-
 static int unavailable_host_feature(struct model_features_t *f, uint32_t mask)
 {
     int i;
@@ -940,31 +1155,30 @@ static int unavailable_host_feature(struct model_features_t *f, uint32_t mask)
 static int kvm_check_features_against_host(X86CPU *cpu)
 {
     CPUX86State *env = &cpu->env;
-    x86_def_t host_def;
+    X86CPUClass *host_class = x86_cpu_class_by_name("host");
     uint32_t mask;
     int rv, i;
     struct model_features_t ft[] = {
-        {&env->cpuid_features, &host_def.features,
+        {&env->cpuid_features, &host_class->features,
             feature_name, 0x00000001, R_EDX},
-        {&env->cpuid_ext_features, &host_def.ext_features,
+        {&env->cpuid_ext_features, &host_class->ext_features,
             ext_feature_name, 0x00000001, R_ECX},
-        {&env->cpuid_ext2_features, &host_def.ext2_features,
+        {&env->cpuid_ext2_features, &host_class->ext2_features,
             ext2_feature_name, 0x80000001, R_EDX},
-        {&env->cpuid_ext3_features, &host_def.ext3_features,
+        {&env->cpuid_ext3_features, &host_class->ext3_features,
             ext3_feature_name, 0x80000001, R_ECX},
-        {&env->cpuid_ext4_features, &host_def.ext4_features,
+        {&env->cpuid_ext4_features, &host_class->ext4_features,
             NULL, 0xC0000001, R_EDX},
-        {&env->cpuid_7_0_ebx_features, &host_def.cpuid_7_0_ebx_features,
+        {&env->cpuid_7_0_ebx_features, &host_class->cpuid_7_0_ebx_features,
             cpuid_7_0_ebx_feature_name, 7, R_EBX},
-        {&env->cpuid_svm_features, &host_def.svm_features,
+        {&env->cpuid_svm_features, &host_class->svm_features,
             svm_feature_name, 0x8000000A, R_EDX},
-        {&env->cpuid_kvm_features, &host_def.kvm_features,
+        {&env->cpuid_kvm_features, host_class->kvm_features,
             kvm_feature_name, KVM_CPUID_FEATURES, R_EAX},
     };
 
     assert(kvm_enabled());
 
-    kvm_cpu_fill_host(&host_def);
     for (rv = 0, i = 0; i < ARRAY_SIZE(ft); ++i)
         for (mask = 1; mask; mask <<= 1)
             if (*ft[i].guest_feat & mask &&
@@ -1223,78 +1437,6 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, void *opaque,
     cpu->env.tsc_khz = value / 1000;
 }
 
-static void cpudef_2_x86_cpu(X86CPU *cpu, x86_def_t *def, Error **errp)
-{
-    CPUX86State *env = &cpu->env;
-
-    assert(def->vendor[0]);
-    object_property_set_str(OBJECT(cpu), def->vendor, "vendor", errp);
-    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);
-    object_property_set_int(OBJECT(cpu), def->stepping, "stepping", errp);
-    env->cpuid_features = def->features;
-    env->cpuid_ext_features = def->ext_features;
-    env->cpuid_ext2_features = def->ext2_features;
-    env->cpuid_ext3_features = def->ext3_features;
-    object_property_set_int(OBJECT(cpu), def->xlevel, "xlevel", errp);
-    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_features = 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", errp);
-    object_property_set_str(OBJECT(cpu), def->model_id, "model-id", errp);
-}
-
-static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name)
-{
-
-    if (kvm_enabled() && name && strcmp(name, "host") == 0) {
-#ifdef CONFIG_KVM
-        kvm_cpu_fill_host(x86_cpu_def);
-#endif
-    } else {
-        x86_def_t *def;
-
-        for (def = x86_defs; def; def = def->next) {
-            if (name && !strcmp(name, def->name)) {
-                break;
-            }
-        }
-
-        if (!def) {
-            return -1;
-        }
-
-        memcpy(x86_cpu_def, def, sizeof(*def));
-        /* 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 using the 'vendor' property if you want to use KVM's
-         * sysenter/syscall emulation in compatibility mode and when doing
-         * cross vendor migration
-         */
-        if (kvm_enabled()) {
-            uint32_t  ebx = 0, ecx = 0, edx = 0;
-            host_cpuid(0, 0, NULL, &ebx, &ecx, &edx);
-            x86cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx);
-        }
-
-        x86_cpu_def->kvm_features |= kvm_default_features;
-        add_flagname_to_bitmaps("hypervisor", &x86_cpu_def->features,
-                                &x86_cpu_def->ext_features,
-                                &x86_cpu_def->ext2_features,
-                                &x86_cpu_def->ext3_features,
-                                &x86_cpu_def->kvm_features,
-                                &x86_cpu_def->svm_features,
-                                &x86_cpu_def->cpuid_7_0_ebx_features);
-    }
-
-    return 0;
-}
-
 /* Set features on X86CPU object based on a provide key,value list */
 static void cpu_x86_set_props(X86CPU *cpu, QDict *features, Error **errp)
 {
@@ -1461,19 +1603,61 @@ static void listflags(char *buf, int bufsize, uint32_t fbits,
         }
 }
 
-/* generate CPU information. */
+/* Sort alphabetically by type name, listing kvm_required models last. */
+static gint x86_cpu_list_compare(gconstpointer a, gconstpointer b)
+{
+    ObjectClass *class_a = (ObjectClass *)a;
+    ObjectClass *class_b = (ObjectClass *)b;
+    X86CPUClass *cc_a = X86_CPU_CLASS(class_a);
+    X86CPUClass *cc_b = X86_CPU_CLASS(class_b);
+    const char *name_a, *name_b;
+
+    if (cc_a->kvm_required != cc_b->kvm_required) {
+        /* kvm_required items go last */
+        return cc_a->kvm_required ? 1 : -1;
+    } else {
+        name_a = object_class_get_name(class_a);
+        name_b = object_class_get_name(class_b);
+        return strcmp(name_a, name_b);
+    }
+}
+
+static GSList *get_sorted_cpu_model_list(void)
+{
+    GSList *list;
+
+    list = object_class_get_list(TYPE_X86_CPU, false);
+    list = g_slist_sort(list, x86_cpu_list_compare);
+    return list;
+}
+
+static void x86_cpu_list_entry(gpointer data, gpointer user_data)
+{
+    ObjectClass *oc = data;
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    CPUListState *s = user_data;
+    char *name = x86_cpu_class_get_model_name(cc);
+
+    (*s->cpu_fprintf)(s->file, "x86 %16s  %-48s\n",
+                      name, cc->model_id);
+    g_free(name);
+}
+
+/* list available CPU models and flags */
 void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 {
-    x86_def_t *def;
+    CPUListState s = {
+        .file = f,
+        .cpu_fprintf = cpu_fprintf,
+    };
+    GSList *list;
     char buf[256];
 
-    for (def = x86_defs; def; def = def->next) {
-        snprintf(buf, sizeof(buf), "%s", def->name);
-        (*cpu_fprintf)(f, "x86 %16s  %-48s\n", buf, def->model_id);
-    }
-    if (kvm_enabled()) {
-        (*cpu_fprintf)(f, "x86 %16s\n", "[host]");
-    }
+    (*cpu_fprintf)(f, "Available CPUs:\n");
+    list = get_sorted_cpu_model_list();
+    g_slist_foreach(list, x86_cpu_list_entry, &s);
+    g_slist_free(list);
+
     (*cpu_fprintf)(f, "\nRecognized CPUID flags:\n");
     listflags(buf, sizeof(buf), (uint32_t)~0, feature_name, 1);
     (*cpu_fprintf)(f, "  %s\n", buf);
@@ -1485,24 +1669,31 @@ void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf)
     (*cpu_fprintf)(f, "  %s\n", buf);
 }
 
+static void x86_cpu_definition_entry(gpointer data, gpointer user_data)
+{
+    ObjectClass *oc = data;
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    CpuDefinitionInfoList **cpu_list = user_data;
+    CpuDefinitionInfoList *entry;
+    CpuDefinitionInfo *info;
+
+    info = g_malloc0(sizeof(*info));
+    info->name = x86_cpu_class_get_model_name(cc);
+
+    entry = g_malloc0(sizeof(*entry));
+    entry->value = info;
+    entry->next = *cpu_list;
+    *cpu_list = entry;
+}
+
 CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
 {
     CpuDefinitionInfoList *cpu_list = NULL;
-    x86_def_t *def;
-
-    for (def = x86_defs; def; def = def->next) {
-        CpuDefinitionInfoList *entry;
-        CpuDefinitionInfo *info;
-
-        info = g_malloc0(sizeof(*info));
-        info->name = g_strdup(def->name);
-
-        entry = g_malloc0(sizeof(*entry));
-        entry->value = info;
-        entry->next = cpu_list;
-        cpu_list = entry;
-    }
+    GSList *list;
 
+    list = get_sorted_cpu_model_list();
+    g_slist_foreach(list, x86_cpu_definition_entry, &cpu_list);
+    g_slist_free(list);
     return cpu_list;
 }
 
@@ -1538,15 +1729,13 @@ static void filter_features_for_kvm(X86CPU *cpu)
 X86CPU *cpu_x86_create(const char *cpu_model, Error **errp)
 {
     X86CPU *cpu = NULL;
+    X86CPUClass *cc;
     CPUX86State *env;
-    x86_def_t def1, *def = &def1;
     QDict *props = NULL;
     Error *error = NULL;
     char *name, *features;
     gchar **model_pieces;
 
-    memset(def, 0, sizeof(*def));
-
     model_pieces = g_strsplit(cpu_model, ",", 2);
     if (!model_pieces[0]) {
         error_setg(&error, "Invalid/empty CPU model name");
@@ -1555,17 +1744,21 @@ X86CPU *cpu_x86_create(const char *cpu_model, Error **errp)
     name = model_pieces[0];
     features = model_pieces[1];
 
-    if (cpu_x86_find_by_name(def, name) < 0) {
+    cc = x86_cpu_class_by_name(name);
+    if (!cc) {
         error_setg(&error, "Unable to find CPU definition: %s", name);
         goto out;
     }
 
-    cpu = X86_CPU(object_new(TYPE_X86_CPU));
+    if (cc->kvm_required && !kvm_enabled()) {
+        error_setg(&error, "CPU model '%s' requires KVM", name);
+        goto out;
+    }
+
+    cpu = X86_CPU(object_new(object_class_get_name(OBJECT_CLASS(cc))));
     env = &cpu->env;
     env->cpu_model_str = cpu_model;
 
-    cpudef_2_x86_cpu(cpu, def, &error);
-
     if (cpu_x86_parse_featurestr(cpu, features, &props) < 0) {
         error_setg(&error, "Invalid cpu_model string format: %s", cpu_model);
         goto out;
@@ -1595,33 +1788,6 @@ void cpu_clear_apic_feature(CPUX86State *env)
 
 #endif /* !CONFIG_USER_ONLY */
 
-/* Initialize list of CPU models, filling some non-static fields if necessary
- */
-void x86_cpudef_setup(void)
-{
-    int i, j;
-    static const char *model_with_versions[] = { "qemu32", "qemu64", "athlon" };
-
-    for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) {
-        x86_def_t *def = &builtin_x86_defs[i];
-        def->next = x86_defs;
-
-        /* 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], def->name) == 0) {
-                pstrcpy(def->model_id, sizeof(def->model_id),
-                        "QEMU Virtual CPU version ");
-                pstrcat(def->model_id, sizeof(def->model_id),
-                        qemu_get_version());
-                break;
-            }
-        }
-
-        x86_defs = def;
-    }
-}
-
 static void get_cpuid_vendor(CPUX86State *env, uint32_t *ebx,
                              uint32_t *ecx, uint32_t *edx)
 {
@@ -2134,7 +2300,10 @@ void x86_cpu_realize(Object *obj, Error **errp)
 static void x86_cpu_initfn(Object *obj)
 {
     X86CPU *cpu = X86_CPU(obj);
+    X86CPUClass *cc = X86_CPU_GET_CLASS(cpu);
+    Error *error = NULL;
     CPUX86State *env = &cpu->env;
+    char vendor[CPUID_VENDOR_SZ + 1];
     static int inited;
 
     cpu_exec_init(env);
@@ -2174,6 +2343,48 @@ static void x86_cpu_initfn(Object *obj)
         cpu_set_debug_excp_handler(breakpoint_handler);
 #endif
     }
+
+    /* 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 using the 'vendor' property if you want to use KVM's
+     * sysenter/syscall emulation in compatibility mode and when doing
+     * cross vendor migration
+     */
+    if (kvm_enabled()) {
+        uint32_t  ebx = 0, ecx = 0, edx = 0;
+        host_cpuid(0, 0, NULL, &ebx, &ecx, &edx);
+        x86cpu_vendor_words2str(vendor, ebx, edx, ecx);
+        object_property_set_str(OBJECT(cpu), vendor, "vendor", &error);
+    } else {
+        assert(cc->vendor[0]);
+        object_property_set_str(OBJECT(cpu), cc->vendor, "vendor", &error);
+    }
+
+    object_property_set_int(OBJECT(cpu), cc->level, "level", &error);
+    object_property_set_int(OBJECT(cpu), cc->family, "family", &error);
+    object_property_set_int(OBJECT(cpu), cc->model, "model", &error);
+    object_property_set_int(OBJECT(cpu), cc->stepping, "stepping", &error);
+    env->cpuid_features = cc->features;
+    env->cpuid_ext_features = cc->ext_features;
+    env->cpuid_ext2_features = cc->ext2_features;
+    env->cpuid_ext3_features = cc->ext3_features;
+    object_property_set_int(OBJECT(cpu), cc->xlevel, "xlevel", &error);
+    env->cpuid_kvm_features = *cc->kvm_features;
+    env->cpuid_svm_features = cc->svm_features;
+    env->cpuid_ext4_features = cc->ext4_features;
+    env->cpuid_7_0_ebx_features = cc->cpuid_7_0_ebx_features;
+    env->cpuid_xlevel2 = cc->xlevel2;
+    object_property_set_int(OBJECT(cpu), (int64_t)cc->tsc_khz * 1000,
+                            "tsc-frequency", &error);
+    object_property_set_str(OBJECT(cpu), cc->model_id, "model-id", &error);
+
+
+    if (error) {
+        error_report("cpu_init: %s", error_get_pretty(error));
+        exit(1);
+    }
+
 }
 
 static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
@@ -2183,6 +2394,9 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
 
     xcc->parent_reset = cc->reset;
     cc->reset = x86_cpu_reset;
+
+    xcc->ext_features |= CPUID_EXT_HYPERVISOR;
+    xcc->kvm_features = &kvm_default_features;
 }
 
 static const TypeInfo x86_cpu_type_info = {
@@ -2190,14 +2404,117 @@ 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,
 };
 
+#ifdef CONFIG_KVM
+
+/* Called by kvm_init() so the "host" CPU class can finish the KVM-dependent
+ * part of its initialization.
+ */
+void x86_cpu_finish_host_class_init(KVMState *s)
+{
+    X86CPUClass *cc = x86_cpu_class_by_name("host");
+    uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
+    static uint32_t host_kvm_features;
+
+    assert(kvm_enabled());
+
+    host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
+    x86cpu_vendor_words2str(cc->vendor, ebx, edx, ecx);
+
+    host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
+    cc->family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
+    cc->model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
+    cc->stepping = eax & 0x0F;
+
+    cc->level = kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
+    cc->features = kvm_arch_get_supported_cpuid(s, 0x1, 0, R_EDX);
+    cc->ext_features = kvm_arch_get_supported_cpuid(s, 0x1, 0, R_ECX);
+
+    if (cc->level >= 7) {
+        cc->cpuid_7_0_ebx_features =
+                    kvm_arch_get_supported_cpuid(s, 0x7, 0, R_EBX);
+    } else {
+        cc->cpuid_7_0_ebx_features = 0;
+    }
+
+    cc->xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX);
+    cc->ext2_features =
+                kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_EDX);
+    cc->ext3_features =
+                kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_ECX);
+
+    cpu_x86_fill_model_id(cc->model_id);
+
+    /* Call Centaur's CPUID instruction. */
+    if (!strcmp(cc->vendor, CPUID_VENDOR_VIA)) {
+        host_cpuid(0xC0000000, 0, &eax, &ebx, &ecx, &edx);
+        eax = kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
+        if (eax >= 0xC0000001) {
+            /* Support VIA max extended level */
+            cc->xlevel2 = eax;
+            host_cpuid(0xC0000001, 0, &eax, &ebx, &ecx, &edx);
+            cc->ext4_features =
+                    kvm_arch_get_supported_cpuid(s, 0xC0000001, 0, R_EDX);
+        }
+    }
+
+    /* Other KVM-specific feature fields: */
+    cc->svm_features =
+        kvm_arch_get_supported_cpuid(s, 0x8000000A, 0, R_EDX);
+    host_kvm_features =
+        kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX);
+    cc->kvm_features = &host_kvm_features;
+}
+
+static void x86_cpu_host_class_init(ObjectClass *oc, void *data)
+{
+    X86CPUClass *cc = X86_CPU_CLASS(oc);
+    cc->kvm_required = true;
+}
+
+static const TypeInfo x86_host_cpu_type_info = {
+    .name = TYPE_X86_HOST_CPU,
+    .parent = TYPE_X86_CPU,
+    .class_init = x86_cpu_host_class_init,
+};
+
+#endif /* CONFIG_KVM */
+
+
 static void x86_cpu_register_types(void)
 {
     type_register_static(&x86_cpu_type_info);
+#ifdef CONFIG_KVM
+    type_register_static(&x86_host_cpu_type_info);
+#endif
+    type_register_static(&x86_cpu_qemu64_type_info);
+    type_register_static(&x86_cpu_phenom_type_info);
+    type_register_static(&x86_cpu_core2duo_type_info);
+    type_register_static(&x86_cpu_kvm64_type_info);
+    type_register_static(&x86_cpu_qemu32_type_info);
+    type_register_static(&x86_cpu_kvm32_type_info);
+    type_register_static(&x86_cpu_coreduo_type_info);
+    type_register_static(&x86_cpu_486_type_info);
+    type_register_static(&x86_cpu_pentium_type_info);
+    type_register_static(&x86_cpu_pentium2_type_info);
+    type_register_static(&x86_cpu_pentium3_type_info);
+    type_register_static(&x86_cpu_athlon_type_info);
+    type_register_static(&x86_cpu_n270_type_info);
+    type_register_static(&x86_cpu_Conroe_type_info);
+    type_register_static(&x86_cpu_Penryn_type_info);
+    type_register_static(&x86_cpu_Nehalem_type_info);
+    type_register_static(&x86_cpu_Westmere_type_info);
+    type_register_static(&x86_cpu_SandyBridge_type_info);
+    type_register_static(&x86_cpu_Haswell_type_info);
+    type_register_static(&x86_cpu_Opteron_G1_type_info);
+    type_register_static(&x86_cpu_Opteron_G2_type_info);
+    type_register_static(&x86_cpu_Opteron_G3_type_info);
+    type_register_static(&x86_cpu_Opteron_G4_type_info);
+    type_register_static(&x86_cpu_Opteron_G5_type_info);
 }
 
 type_init(x86_cpu_register_types)
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 91091bf..3714cca 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -866,7 +866,6 @@ typedef struct CPUX86State {
 X86CPU *cpu_x86_init(const char *cpu_model);
 int cpu_x86_exec(CPUX86State *s);
 void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf);
-void x86_cpudef_setup(void);
 int cpu_x86_support_mca_broadcast(CPUX86State *env);
 
 int cpu_get_pic_interrupt(CPUX86State *s);
@@ -1048,7 +1047,6 @@ static inline CPUX86State *cpu_init(const char *cpu_model)
 #define cpu_gen_code cpu_x86_gen_code
 #define cpu_signal_handler cpu_x86_signal_handler
 #define cpu_list x86_cpu_list
-#define cpudef_setup	x86_cpudef_setup
 
 #define CPU_SAVE_VERSION 12
 
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 3acff40..f4cc8a5 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -767,6 +767,8 @@ int kvm_arch_init(KVMState *s)
             }
         }
     }
+
+    x86_cpu_finish_host_class_init(s);
     return 0;
 }
 
-- 
1.7.11.7

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] [RFC 0/6] x86 CPU subclasses, v4
  2013-01-04 19:56 [Qemu-devel] [RFC 0/6] x86 CPU subclasses, v4 Eduardo Habkost
                   ` (5 preceding siblings ...)
  2013-01-04 19:56 ` [Qemu-devel] [RFC 6/6] target-i386: CPU model subclasses Eduardo Habkost
@ 2013-01-04 22:07 ` Eduardo Habkost
  6 siblings, 0 replies; 9+ messages in thread
From: Eduardo Habkost @ 2013-01-04 22:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Igor Mammedov, Andreas Färber

On Fri, Jan 04, 2013 at 05:56:16PM -0200, Eduardo Habkost wrote:
> This is a new RFC for the x86 CPU subclasses. This version handles the "host"
> subclass differently, and I believe this made the code much simpler.
> 
> However, a few tricks were necessary:
> 
>  - To keep the "default_kvm_features" compat functions working (this shouldn't
>    be necessary once we start using global properties for the compat code).
>  - For the vendor property setting (because it depends on a kvm_enabled() check,
>    that can't be made on class_init). I don't know how we will be able to
>    convert that logic using global properties/defaults in the future.
>  - To keep the original model names in the "-cpu ?" output, for compatibility.
> 
> This series depends on multiple series:
>  - pc-1.4 kvm_mmu_opt disable series I sent today;
>  - -cpu "enforce" fix series I sent today;
>  - A experimental rebased version of Igor's "wave 2" x86 CPU init cleanup.
> 
> Because of the tricky dependencies, I recommend you use the git tree for testing:
>   git://github.com/ehabkost/qemu-hacks.git x86-cpu-model-classes.RFC.v4
>   https://github.com/ehabkost/qemu-hacks/tree/x86-cpu-model-classes.RFC.v4

I submitted newer versions of the dependencies. There's a git branch of
this RFC rebased on top of the newer dependencies, here:

   git://github.com/ehabkost/qemu-hacks.git x86-cpu-model-classes.RFC.v5
   https://github.com/ehabkost/qemu-hacks/tree/x86-cpu-model-classes.RFC.v5

> 
> Eduardo Habkost (6):
>   target-i386: Move CPU object creation to cpu.c
>   target-i386: Make cpu_x86_create() get Error argument
>   target-i386: Simplify cpu_x86_find_by_name() logic
>   target-i386: Set feature string parsing results directly on CPU
>     object
>   target-i386: Move kvm_features/hypervisor initialization to
>     cpu_x86_find_by_name()
>   target-i386: CPU model subclasses
> 
>  include/sysemu/kvm.h  |    3 +
>  target-i386/cpu-qom.h |   26 +
>  target-i386/cpu.c     | 1548 ++++++++++++++++++++++++++++++-------------------
>  target-i386/cpu.h     |    4 +-
>  target-i386/helper.c  |   26 +-
>  target-i386/kvm.c     |    2 +
>  6 files changed, 988 insertions(+), 621 deletions(-)
> 
> -- 
> 1.7.11.7
> 
> 

-- 
Eduardo

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] [RFC 6/6] target-i386: CPU model subclasses
  2013-01-04 19:56 ` [Qemu-devel] [RFC 6/6] target-i386: CPU model subclasses Eduardo Habkost
@ 2013-01-04 22:08   ` Eduardo Habkost
  0 siblings, 0 replies; 9+ messages in thread
From: Eduardo Habkost @ 2013-01-04 22:08 UTC (permalink / raw)
  To: qemu-devel; +Cc: Igor Mammedov, Andreas Färber

On Fri, Jan 04, 2013 at 05:56:22PM -0200, Eduardo Habkost wrote:
> +    /* Original model name for -cpu ? listing */
> +    const char *model_name;

This is a leftover of a test I was making. It will be removed.

-- 
Eduardo

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2013-01-04 22:07 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-01-04 19:56 [Qemu-devel] [RFC 0/6] x86 CPU subclasses, v4 Eduardo Habkost
2013-01-04 19:56 ` [Qemu-devel] [RFC 1/6] target-i386: Move CPU object creation to cpu.c Eduardo Habkost
2013-01-04 19:56 ` [Qemu-devel] [RFC 2/6] target-i386: Make cpu_x86_create() get Error argument Eduardo Habkost
2013-01-04 19:56 ` [Qemu-devel] [RFC 3/6] target-i386: Simplify cpu_x86_find_by_name() logic Eduardo Habkost
2013-01-04 19:56 ` [Qemu-devel] [RFC 4/6] target-i386: Set feature string parsing results directly on CPU object Eduardo Habkost
2013-01-04 19:56 ` [Qemu-devel] [RFC 5/6] target-i386: Move kvm_features/hypervisor initialization to cpu_x86_find_by_name() Eduardo Habkost
2013-01-04 19:56 ` [Qemu-devel] [RFC 6/6] target-i386: CPU model subclasses Eduardo Habkost
2013-01-04 22:08   ` Eduardo Habkost
2013-01-04 22:07 ` [Qemu-devel] [RFC 0/6] x86 CPU subclasses, v4 Eduardo Habkost

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).