qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [RFC] target-i386: register a class for each CPU model


From: Eduardo Habkost
Subject: [Qemu-devel] [RFC] target-i386: register a class for each CPU model
Date: Mon, 12 Nov 2012 19:48:40 -0200

This creates the following class hierarchy:

- TYPE_X86_CPU ("<arch>-cpu")
 - TYPE_X86_DEFCPU "<arch>-cpu-predefined": abstract base class for the
   predefined CPU models
   - "<arch>-cpu-model-<model>": a class for each predefined CPU model
 - TYPE_X86_HOST_CPU ("<arch>-cpu-model-host"): class for the "-cpu host" CPU
   model

On TARGET_X86_64, "<arch>" is "x86_64", on TARGET_I386, "<arch>" is
"i386".

The trick here is to replace exactly what's implemented in the
cpu_x86_find_cpudef() logic and nothing else. So, the only difference in
relation to the previous code is that instead of looking at the CPU model table
on cpu_x86_find_cpudef(), we just use the right CPU class, that will fill the
X86CPUDefinition struct on a ->init_cpudef() method.

The init_cpudef() method was added jut to not require us to kill the
X86CPUDefinition array in the same patch. But the X86CPUDefinition
struct may eventually go away, and all the default-value initialization
for each CPU model can become just different defaults set on
instance_init() or class_init().

Signed-off-by: Eduardo Habkost <address@hidden>
---
I am using those class names because I don't want the CPU model names to live
in the same namespace as all device names. I want to avoid doing the same
mistake that was done in the arm code, that registers a QOM class named "any".
Some CPU model names, like "qemu64", don't make any sense unless you already
know it is a CPU model name.

As an alternative to the complex naming above, I was considering simply using
"cpu-<model>" as the class name. I don't know what others think.

This patch depends on the "[PATCH 00/17] target-i386: CPU init cleanup for CPU
classes/properties" series I have just sent.

Changes v1 -> v2:
 - Rebase on top of CPU properties series
 - Use a static type (with a different class init function) for the
   "-cpu host" class

Changes v2 -> v3:
 - Fix the "device not found" error to use the CPU model name, not
   the full -cpu string
 - kill cpudef_init() and cpudef_setup(), as we don't need a
   cpudef-specific initialization function, anymore
 - Instead of keeping a copy of a X86CPUDefinition struct inside
   X86CPUClass, keep only a pointer
 - Add a init_cpudef() class method, used to fill the X86CPUDefinition
   struct for the CPU
 - Use separate subclass for "-cpu host", that uses cpu_x86_fill_host()
   on init_cpudef()

Changes v3 -> v4:
 - Rebase on top of qemu.git master, without the CPU properties series
 - Rename CPU classes to "<arch>-cpu-model<model>"
---
 arch_init.c           |   7 --
 arch_init.h           |   1 -
 bsd-user/main.c       |   3 -
 linux-user/main.c     |   3 -
 target-i386/cpu-qom.h |  22 +++++-
 target-i386/cpu.c     | 208 +++++++++++++++++++++++++++++++++++++++++---------
 target-i386/cpu.h     |   2 -
 vl.c                  |   7 --
 8 files changed, 192 insertions(+), 61 deletions(-)

diff --git a/arch_init.c b/arch_init.c
index e6effe8..bea1b9c 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -1124,13 +1124,6 @@ void do_smbios_option(const char *optarg)
 #endif
 }
 
-void cpudef_init(void)
-{
-#if defined(cpudef_setup)
-    cpudef_setup(); /* parse cpu definitions in target config file */
-#endif
-}
-
 int audio_available(void)
 {
 #ifdef HAS_AUDIO
diff --git a/arch_init.h b/arch_init.h
index 5fc780c..84a7f9a 100644
--- a/arch_init.h
+++ b/arch_init.h
@@ -27,7 +27,6 @@ extern const uint32_t arch_type;
 void select_soundhw(const char *optarg);
 void do_acpitable_option(const char *optarg);
 void do_smbios_option(const char *optarg);
-void cpudef_init(void);
 int audio_available(void);
 void audio_init(ISABus *isa_bus, PCIBus *pci_bus);
 int tcg_available(void);
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 095ae8e..cf0a345 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -762,9 +762,6 @@ int main(int argc, char **argv)
     }
 
     cpu_model = NULL;
-#if defined(cpudef_setup)
-    cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
-#endif
 
     optind = 1;
     for(;;) {
diff --git a/linux-user/main.c b/linux-user/main.c
index 25e35cd..e881fcf 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3426,9 +3426,6 @@ int main(int argc, char **argv, char **envp)
     }
 
     cpu_model = NULL;
-#if defined(cpudef_setup)
-    cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
-#endif
 
     /* init debug */
     cpu_set_log_filename(log_file);
diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
index 5901140..01ea9de 100644
--- a/target-i386/cpu-qom.h
+++ b/target-i386/cpu-qom.h
@@ -37,19 +37,37 @@
 #define X86_CPU_GET_CLASS(obj) \
     OBJECT_GET_CLASS(X86CPUClass, (obj), TYPE_X86_CPU)
 
+
+struct X86CPUDefinition;
+typedef struct X86CPUDefinition X86CPUDefinition;
+
+struct X86CPUClass;
+typedef struct X86CPUClass X86CPUClass;
+
 /**
  * X86CPUClass:
  * @parent_reset: The parent class' reset handler.
+ * @init_cpudef: initialize X86CPUDefinition struct for CPU class
  *
  * An x86 CPU model or family.
  */
-typedef struct X86CPUClass {
+struct X86CPUClass {
     /*< private >*/
     CPUClass parent_class;
     /*< public >*/
 
     void (*parent_reset)(CPUState *cpu);
-} X86CPUClass;
+
+    /* Init a X86CPUDefinition struct.
+     * This method should eventually go away when we make all info from
+     * X86CPUDefinition be settable using properties inside instance_init().
+     *
+     * We can't just store a X86CPUDefinition pointer on the X86CPUClass
+     * struct because the "-cpu host" class needs KVM to be initialized,
+     * to probe host CPU/KVM capabilities.
+     */
+    int (*init_cpudef)(X86CPUClass *xcc, X86CPUDefinition *def, Error **errp);
+};
 
 /**
  * X86CPU:
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 5f2ce7d..7b13987 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -271,7 +271,11 @@ static void add_flagname_to_bitmaps(const char *flagname, 
uint32_t *features,
             fprintf(stderr, "CPU feature %s not found\n", flagname);
 }
 
-typedef struct X86CPUDefinition {
+/* This struct should eventually go away and just become multiple series of
+ * properties and values to set by default on CPU objects, one for each CPU
+ * class.
+ */
+struct X86CPUDefinition {
     struct X86CPUDefinition *next;
     const char *name;
     uint32_t level;
@@ -290,7 +294,7 @@ typedef struct X86CPUDefinition {
     uint32_t xlevel2;
     /* The feature bits on CPUID[EAX=7,ECX=0].EBX */
     uint32_t cpuid_7_0_ebx_features;
-} X86CPUDefinition;
+};
 
 #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
 #define PENTIUM_FEATURES (I486_FEATURES | CPUID_DE | CPUID_TSC | \
@@ -1146,33 +1150,6 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor 
*v, void *opaque,
     cpu->env.tsc_khz = value / 1000;
 }
 
-/* Find a CPU model definition and put the result on a X86CPUDefinition struct
- */
-static int cpu_x86_find_cpudef(const char *name,
-                               X86CPUDefinition *result,
-                               Error **errp)
-{
-    X86CPUDefinition *def;
-
-    for (def = x86_defs; def; def = def->next)
-        if (name && !strcmp(name, def->name))
-            break;
-    if (kvm_enabled() && name && strcmp(name, "host") == 0) {
-        kvm_cpu_fill_host(result);
-    } else if (!def) {
-        goto error;
-    } else {
-        memcpy(result, def, sizeof(*def));
-    }
-    return 0;
-
-error:
-    if (!error_is_set(errp)) {
-        error_set(errp, QERR_INVALID_PARAMETER_COMBINATION);
-    }
-    return -1;
-}
-
 static int cpu_x86_parse_featurestr(X86CPUDefinition *x86_cpu_def,
                                     char *features, Error **errp)
 {
@@ -1503,29 +1480,54 @@ static int cpudef_2_x86_cpu(X86CPU *cpu, 
X86CPUDefinition *def, Error **errp)
     return 0;
 }
 
+/* Build class name for specific CPU model:
+ *
+ * The CPU class names are in the form <arch>-cpu-model-<model>.
+ */
+
+/* For statically-defined class names (e.g. TYPE_X86_CPU_HOST) */
+#define STATIC_CPU_CLASS_NAME(model) (TYPE_X86_CPU "-model-" model)
+
+/* For dynamically-defined class names (built from the cpudef array) */
+static char *build_cpu_class_name(const char *model)
+{
+    return g_strdup_printf("%s-model-%s", TYPE_X86_CPU, model);
+}
+
 X86CPU *cpu_x86_init(const char *cpu_string)
 {
     X86CPU *cpu = NULL;
+    ObjectClass *obj_class;
+    X86CPUClass *cpu_class;
     CPUX86State *env;
     Error *error = NULL;
     X86CPUDefinition def;
-    char *name, *features;
+    char *model_name, *features;
     gchar **model_pieces;
+    char *class_name = NULL;
 
     model_pieces = g_strsplit(cpu_string, ",", 2);
     if (!model_pieces[0]) {
         goto error;
     }
-    name = model_pieces[0];
+    model_name = model_pieces[0];
     features = model_pieces[1];
 
-    cpu = X86_CPU(object_new(TYPE_X86_CPU));
+    class_name = build_cpu_class_name(model_name);
+    obj_class = object_class_by_name(class_name);
+    if (!obj_class) {
+        error_set(&error, QERR_DEVICE_NOT_FOUND, model_name);
+        goto error;
+    }
+
+    cpu = X86_CPU(object_new(class_name));
     env = &cpu->env;
     env->cpu_model_str = cpu_string;
 
     memset(&def, 0, sizeof(def));
 
-    if (cpu_x86_find_cpudef(name, &def, &error) < 0) {
+    cpu_class = X86_CPU_GET_CLASS(cpu);
+    if (cpu_class->init_cpudef(cpu_class, &def, &error) < 0) {
         goto error;
     }
 
@@ -1543,9 +1545,11 @@ X86CPU *cpu_x86_init(const char *cpu_string)
     }
 
     g_strfreev(model_pieces);
+    g_free(class_name);
     return cpu;
 error:
     g_strfreev(model_pieces);
+    g_free(class_name);
     if (cpu) {
         object_delete(OBJECT(cpu));
     }
@@ -1567,7 +1571,7 @@ void cpu_clear_apic_feature(CPUX86State *env)
 
 /* Initialize list of CPU models, filling some non-static fields if necessary
  */
-void x86_cpudef_setup(void)
+static void x86_cpudef_setup(void)
 {
     int i, j;
     static const char *model_with_versions[] = { "qemu32", "qemu64", "athlon" 
};
@@ -2123,15 +2127,147 @@ static const TypeInfo x86_cpu_type_info = {
     .name = TYPE_X86_CPU,
     .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,
 };
 
+/* TYPE_X86_DEFCPU: abstract class for predefined CPU models */
+
+#define TYPE_X86_DEFCPU (TYPE_X86_CPU "-predefined")
+
+#define X86_DEFCPU_CLASS(klass) \
+    OBJECT_CLASS_CHECK(X86DEFCPUClass, (klass), TYPE_X86_DEFCPU)
+#define X86_DEFCPU(obj) \
+    OBJECT_CHECK(X86DEFCPU, (obj), TYPE_X86_DEFCPU)
+#define X86_DEFCPU_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(X86DEFCPUClass, (obj), TYPE_X86_DEFCPU)
+
+/**
+ * X86DEFCPUClass:
+ * @cpudef: pointer to X86CPUDefinition for CPU model
+ *
+ * A predefined CPU model, pointing to a X86CPUDefinition struct.
+ */
+typedef struct X86DEFCPUClass {
+    /*< private >*/
+    X86CPUClass parent_class;
+
+    /*< public >*/
+    X86CPUDefinition *cpudef;
+} X86DEFCPUClass;
+
+/* The init_cpudef() method for children of TYPE_X86_DEFCPU */
+static int x86_predef_cpu_init_cpudef(X86CPUClass *xcc, X86CPUDefinition *def,
+                                       Error **errp)
+{
+    X86DEFCPUClass *defclass = X86_DEFCPU_CLASS(xcc);
+    memcpy(def, defclass->cpudef, sizeof(X86CPUDefinition));
+    return 0;
+}
+
+/* The class_init() method for children of TYPE_X86_DEFCPU
+ *
+ * Note that this is the class_init() method for _children_ of TYPE_X86_DEFCPU,
+ * not for TYPE_X86_DEFCPU itself, because we need the class-specific
+ * class_data pointer.
+ */
+static void x86_predef_cpu_class_init(ObjectClass *oc, void *data)
+{
+    X86CPUClass *xcc = X86_CPU_CLASS(oc);
+    X86DEFCPUClass *xdcc = X86_DEFCPU_CLASS(xcc);
+    X86CPUDefinition *def = data;
+
+    xcc->init_cpudef = x86_predef_cpu_init_cpudef;
+    xdcc->cpudef = def;
+}
+
+static TypeInfo x86_predef_cpu_type_info = {
+    .name = TYPE_X86_DEFCPU,
+    .parent = TYPE_X86_CPU,
+    .abstract = true,
+    .class_size = sizeof(X86DEFCPUClass),
+};
+
+/* Register a CPU class for a specific X86CPUDefinintion
+ *
+ * The class will be a child of TYPE_X86_DEFCPU.
+ */
+static void x86_cpu_register_class(const char *name, X86CPUDefinition *def)
+{
+    char *class_name = build_cpu_class_name(name);
+    TypeInfo type = {
+        .name = class_name,
+        .parent = TYPE_X86_DEFCPU,
+        .instance_size = sizeof(X86CPU),
+        .instance_init = x86_cpu_initfn,
+        .class_size = sizeof(X86DEFCPUClass),
+        .class_init = x86_predef_cpu_class_init,
+        .class_data = def,
+    };
+    type_register(&type);
+    g_free(class_name);
+}
+
+
+/* TYPE_X86_HOST_CPU:
+ *
+ * X86CPU subclass for "-cpu host"
+ */
+
+#define TYPE_X86_HOST_CPU STATIC_CPU_CLASS_NAME("host")
+
+/* The init_cpudef() method for TYPE_X86_HOST_CPU */
+static int x86_host_cpu_init_cpudef(X86CPUClass *xcc, X86CPUDefinition *def,
+                                     Error **errp)
+{
+    if (!kvm_enabled()) {
+        error_set(errp, ERROR_CLASS_GENERIC_ERROR,
+                  "-cpu host is available only when using KVM");
+        return -1;
+    }
+    memset(def, 0, sizeof(*def));
+    kvm_cpu_fill_host(def);
+    return 0;
+}
+
+/* The class_init() method for TYPE_X86_HOST_CPU */
+static void x86_cpu_host_class_init(ObjectClass *oc, void *data)
+{
+    X86CPUClass *xcc = X86_CPU_CLASS(oc);
+
+    xcc->init_cpudef = x86_host_cpu_init_cpudef;
+}
+
+static TypeInfo x86_cpu_host_type_info = {
+    .name = TYPE_X86_HOST_CPU,
+    .parent = TYPE_X86_CPU,
+    .instance_size = sizeof(X86CPU),
+    .instance_init = x86_cpu_initfn,
+    .class_size = sizeof(X86CPUClass),
+    .class_init = x86_cpu_host_class_init,
+};
+
 static void x86_cpu_register_types(void)
 {
+    X86CPUDefinition *def;
+
+    x86_cpudef_setup();
+
+    /* Abstract X86CPU class */
     type_register_static(&x86_cpu_type_info);
+
+    /* -cpu host class */
+    type_register_static(&x86_cpu_host_type_info);
+
+    /* Abstract class for predefined CPU models */
+    type_register_static(&x86_predef_cpu_type_info);
+
+    /* One class for each CPU model: */
+    for (def = x86_defs; def; def = def->next) {
+        x86_cpu_register_class(def->name, def);
+    }
+
 }
 
 type_init(x86_cpu_register_types)
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 4d5510e..dba4f66 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -841,7 +841,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);
@@ -1022,7 +1021,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/vl.c b/vl.c
index 4f03a72..997d92a 100644
--- a/vl.c
+++ b/vl.c
@@ -3508,13 +3508,6 @@ int main(int argc, char **argv, char **envp)
         qemu_set_version(machine->hw_version);
     }
 
-    /* Init CPU def lists, based on config
-     * - Must be called after all the qemu_read_config_file() calls
-     * - Must be called before list_cpus()
-     * - Must be called before machine->init()
-     */
-    cpudef_init();
-
     if (cpu_model && is_help_option(cpu_model)) {
         list_cpus(stdout, &fprintf, cpu_model);
         exit(0);
-- 
1.7.11.7




reply via email to

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