Signed-off-by: Andreas Färber <afaer...@suse.de>
---
 target-ppc/cpu-qom.h        |   84 ++++++++++++++
 target-ppc/cpu.h            |   25 +----
 target-ppc/helper.c         |   72 ++----------
 target-ppc/kvm.c            |   29 +++--
 target-ppc/kvm_ppc.h        |    6 -
 target-ppc/translate.c      |    2 +-
 target-ppc/translate_init.c |  264 ++++++++++++++++++++++++++++++++++++-------
 7 files changed, 342 insertions(+), 140 deletions(-)
 create mode 100644 target-ppc/cpu-qom.h

diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h
new file mode 100644
index 0000000..9236dcc
--- /dev/null
+++ b/target-ppc/cpu-qom.h
@@ -0,0 +1,84 @@
+/*
+ * QEMU PowerPC CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+#ifndef QEMU_PPC_CPU_QOM_H
+#define QEMU_PPC_CPU_QOM_H
+
+#include "qemu/cpu.h"
+#include "cpu.h"
+
+#define TYPE_POWERPC_CPU "powerpc-cpu"
+
+#define POWERPC_CPU_CLASS(klass) \
+    OBJECT_CLASS_CHECK(PowerPCCPUClass, (klass), TYPE_POWERPC_CPU)
+#define POWERPC_CPU(obj) \
+    OBJECT_CHECK(PowerPCCPU, (obj), TYPE_POWERPC_CPU)
+#define POWERPC_CPU_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(PowerPCCPUClass, (obj), TYPE_POWERPC_CPU)
+
+/**
+ * PowerPCCPUClass:
+ * @parent_reset: The parent class' reset handler.
+ *
+ * A PowerPC CPU model.
+ */
+typedef struct PowerPCCPUClass {
+    /*< private >*/
+    CPUClass parent_class;
+    /*< public >*/
+
+    void (*parent_reset)(CPUState *cpu);
+
+    uint32_t pvr;
+    uint32_t svr;
+    uint64_t insns_flags;
+    uint64_t insns_flags2;
+    uint64_t msr_mask;
+    powerpc_mmu_t   mmu_model;
+    powerpc_excp_t  excp_model;
+    powerpc_input_t bus_model;
+    uint32_t flags;
+    int bfd_mach;
+    void (*init_proc)(CPUPPCState *env);
+    int  (*check_pow)(CPUPPCState *env);
+} PowerPCCPUClass;
+
+/**
+ * PowerPCCPU:
+ * @env: Legacy CPU state.
+ *
+ * A PowerPC CPU.
+ */
+typedef struct PowerPCCPU {
+    /*< private >*/
+    CPUState parent_obj;
+    /*< public >*/
+
+    CPUPPCState env;
+} PowerPCCPU;
+
+static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
+{
+    return POWERPC_CPU(container_of(env, PowerPCCPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(ppc_env_get_cpu(e))
+
+
+#endif
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index ad09cbe..ff28843 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -305,7 +305,6 @@ enum powerpc_input_t {
 #define PPC_INPUT(env) (env->bus_model)
 
 /*****************************************************************************/
-typedef struct ppc_def_t ppc_def_t;
 typedef struct opc_handler_t opc_handler_t;
 
 /*****************************************************************************/
@@ -877,22 +876,6 @@ enum {
 /* The whole PowerPC CPU context */
 #define NB_MMU_MODES 3
 
-struct ppc_def_t {
-    const char *name;
-    uint32_t pvr;
-    uint32_t svr;
-    uint64_t insns_flags;
-    uint64_t insns_flags2;
-    uint64_t msr_mask;
-    powerpc_mmu_t   mmu_model;
-    powerpc_excp_t  excp_model;
-    powerpc_input_t bus_model;
-    uint32_t flags;
-    int bfd_mach;
-    void (*init_proc)(CPUPPCState *env);
-    int  (*check_pow)(CPUPPCState *env);
-};
-
 struct CPUPPCState {
     /* First are the most commonly used resources
      * during translated code execution
@@ -1096,6 +1079,8 @@ struct mmu_ctx_t {
 };
 #endif
 
+#include "cpu-qom.h"
+
 /*****************************************************************************/
 CPUPPCState *cpu_ppc_init (const char *cpu_model);
 void ppc_translate_init(void);
@@ -1142,9 +1127,9 @@ void ppc_store_msr (CPUPPCState *env, target_ulong value);
 
 void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf);
 
-const ppc_def_t *ppc_find_by_pvr(uint32_t pvr);
-const ppc_def_t *cpu_ppc_find_by_name (const char *name);
-int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def);
+void ppc_cpu_initfn(Object *obj);
+const char *ppc_find_by_pvr(uint32_t pvr);
+PowerPCCPU *cpu_ppc_find_by_name(const char *name);
 
 /* Time-base and decrementer management */
 #ifndef NO_CPU_IO_DEFS
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index bd711b6..7d26cb5 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -3138,85 +3138,31 @@ void cpu_dump_rfi (target_ulong RA, target_ulong msr)
 
 void cpu_state_reset(CPUPPCState *env)
 {
-    target_ulong msr;
-
-    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
-        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
-        log_cpu_state(env, 0);
-    }
-
-    msr = (target_ulong)0;
-    if (0) {
-        /* XXX: find a suitable condition to enable the hypervisor mode */
-        msr |= (target_ulong)MSR_HVB;
-    }
-    msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */
-    msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */
-    msr |= (target_ulong)1 << MSR_EP;
-#if defined (DO_SINGLE_STEP) && 0
-    /* Single step trace mode */
-    msr |= (target_ulong)1 << MSR_SE;
-    msr |= (target_ulong)1 << MSR_BE;
-#endif
-#if defined(CONFIG_USER_ONLY)
-    msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */
-    msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
-    msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
-    msr |= (target_ulong)1 << MSR_PR;
-#else
-    env->excp_prefix = env->hreset_excp_prefix;
-    env->nip = env->hreset_vector | env->excp_prefix;
-    if (env->mmu_model != POWERPC_MMU_REAL)
-        ppc_tlb_invalidate_all(env);
-#endif
-    env->msr = msr & env->msr_mask;
-#if defined(TARGET_PPC64)
-    if (env->mmu_model & POWERPC_MMU_64)
-        env->msr |= (1ULL << MSR_SF);
-#endif
-    hreg_compute_hflags(env);
-    env->reserve_addr = (target_ulong)-1ULL;
-    /* Be sure no exception or interrupt is pending */
-    env->pending_interrupts = 0;
-    env->exception_index = POWERPC_EXCP_NONE;
-    env->error_code = 0;
-    /* Flush all TLBs */
-    tlb_flush(env, 1);
+    cpu_reset(ENV_GET_CPU(env));
 }
 
-CPUPPCState *cpu_ppc_init (const char *cpu_model)
+CPUPPCState *cpu_ppc_init(const char *cpu_model)
 {
+    PowerPCCPU *cpu;
     CPUPPCState *env;
-    const ppc_def_t *def;
 
-    def = cpu_ppc_find_by_name(cpu_model);
-    if (!def)
+    cpu = cpu_ppc_find_by_name(cpu_model);
+    if (cpu == NULL) {
         return NULL;
+    }
+    env = &cpu->env;
 
-    env = g_malloc0(sizeof(CPUPPCState));
-    cpu_exec_init(env);
     if (tcg_enabled()) {
         ppc_translate_init();
     }
-    /* Adjust cpu index for SMT */
-#if !defined(CONFIG_USER_ONLY)
-    if (kvm_enabled()) {
-        int smt = kvmppc_smt_threads();
-
-        env->cpu_index = (env->cpu_index / smp_threads)*smt
-            + (env->cpu_index % smp_threads);
-    }
-#endif /* !CONFIG_USER_ONLY */
-    env->cpu_model_str = cpu_model;
-    cpu_ppc_register_internal(env, def);
 
     qemu_init_vcpu(env);
 
     return env;
 }
 
-void cpu_ppc_close (CPUPPCState *env)
+void cpu_ppc_close(CPUPPCState *env)
 {
     /* Should also remove all opcode tables... */
-    g_free(env);
+    object_delete(OBJECT(ppc_env_get_cpu(env)));
 }
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index aeb3de9..2ee5bc0 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -902,19 +902,12 @@ static void alter_insns(uint64_t *word, uint64_t flags, 
bool on)
     }
 }
 
-const ppc_def_t *kvmppc_host_cpu_def(void)
+static void kvmppc_host_cpu_class_init(ObjectClass *klass, void *data)
 {
-    uint32_t host_pvr = mfpvr();
-    const ppc_def_t *base_spec;
-    ppc_def_t *spec;
+    PowerPCCPUClass *spec = POWERPC_CPU_CLASS(klass);
     uint32_t vmx = kvmppc_get_vmx();
     uint32_t dfp = kvmppc_get_dfp();
 
-    base_spec = ppc_find_by_pvr(host_pvr);
-
-    spec = g_malloc0(sizeof(*spec));
-    memcpy(spec, base_spec, sizeof(*spec));
-
     /* Now fix up the spec with information we can query from the host */
 
     if (vmx != -1) {
@@ -926,8 +919,6 @@ const ppc_def_t *kvmppc_host_cpu_def(void)
         /* Only override when we know what the host supports */
         alter_insns(&spec->insns_flags2, PPC2_DFP, dfp);
     }
-
-    return spec;
 }
 
 bool kvm_arch_stop_on_emulation_error(CPUPPCState *env)
@@ -944,3 +935,19 @@ int kvm_arch_on_sigbus(int code, void *addr)
 {
     return 1;
 }
+
+static void kvmppc_register_types(void)
+{
+    TypeInfo type = {
+        .name = "host",
+        .instance_size = sizeof(PowerPCCPU),
+        .instance_init = ppc_cpu_initfn,
+        .class_size = sizeof(PowerPCCPUClass),
+        .class_init = kvmppc_host_cpu_class_init,
+    };
+    uint32_t host_pvr = mfpvr();
+    type.parent = ppc_find_by_pvr(host_pvr);
+    type_register_static(&type);
+}
+
+type_init(kvmppc_register_types)
diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
index 8f1267c..ce5be6e 100644
--- a/target-ppc/kvm_ppc.h
+++ b/target-ppc/kvm_ppc.h
@@ -28,7 +28,6 @@ off_t kvmppc_alloc_rma(const char *name, MemoryRegion 
*sysmem);
 void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd);
 int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
 #endif /* !CONFIG_USER_ONLY */
-const ppc_def_t *kvmppc_host_cpu_def(void);
 
 #else
 
@@ -90,11 +89,6 @@ static inline int kvmppc_remove_spapr_tce(void *table, int 
pfd,
 }
 #endif /* !CONFIG_USER_ONLY */
 
-static inline const ppc_def_t *kvmppc_host_cpu_def(void)
-{
-    return NULL;
-}
-
 #endif
 
 #ifndef CONFIG_KVM
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 3ec59a7..e43160d 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -9272,8 +9272,8 @@ GEN_SPEOP_LDST(evstwwe, 0x1C, 2),
 GEN_SPEOP_LDST(evstwwo, 0x1E, 2),
 };
 
-#include "translate_init.c"
 #include "helper_regs.h"
+#include "translate_init.c"
 
 /*****************************************************************************/
 /* Misc PowerPC helpers */
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 1ec6f42..52264c8 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -3,6 +3,7 @@
  *
  *  Copyright (c) 2003-2007 Jocelyn Mayer
  *  Copyright 2011 Freescale Semiconductor, Inc.
+ *  Copyright (c) 2012 SUSE LINUX Products GmbH
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -27,6 +28,7 @@
 #include "gdbstub.h"
 #include <kvm.h>
 #include "kvm_ppc.h"
+#include "cpus.h"
 
 //#define PPC_DUMP_CPU
 //#define PPC_DEBUG_SPR
@@ -7583,6 +7585,51 @@ enum {
 
 /*****************************************************************************/
 /* PowerPC CPU definitions                                                   */
+
+typedef struct PowerPCCPUInfo PowerPCCPUInfo;
+
+struct PowerPCCPUInfo {
+    const char *name;
+    uint32_t pvr;
+    uint32_t svr;
+    uint64_t insns_flags;
+    uint64_t insns_flags2;
+    uint64_t msr_mask;
+    powerpc_mmu_t   mmu_model;
+    powerpc_excp_t  excp_model;
+    powerpc_input_t bus_model;
+    uint32_t flags;
+    int bfd_mach;
+    void (*init_proc)(CPUPPCState *env);
+    int  (*check_pow)(CPUPPCState *env);
+};
+
+static void ppc_cpu_reset(CPUState *cpu);
+
+static void ppc_cpu_class_init(ObjectClass *klass, void *data)
+{
+    CPUClass *cpu_class = CPU_CLASS(klass);
+    PowerPCCPUClass *k = POWERPC_CPU_CLASS(klass);
+    const PowerPCCPUInfo *info = data;
+
+    k->parent_reset = cpu_class->reset;
+    cpu_class->reset = ppc_cpu_reset;
+
+    k->pvr = info->pvr;
+    k->svr = info->svr;
+    k->insns_flags = info->insns_flags;
+    k->insns_flags2 = info->insns_flags2;
+    k->msr_mask = info->msr_mask;
+    k->mmu_model = info->mmu_model;
+    k->excp_model = info->excp_model;
+    k->bus_model = info->bus_model;
+    k->flags = info->flags;
+    k->bfd_mach = info->bfd_mach;
+
+    k->init_proc = info->init_proc;
+    k->check_pow = info->check_pow;
+}
+
 #define POWERPC_DEF_SVR(_name, _pvr, _svr, _type)                             \
     {                                                                         \
         .name         = _name,                                                \
@@ -7602,7 +7649,7 @@ enum {
 #define POWERPC_DEF(_name, _pvr, _type)                                       \
 POWERPC_DEF_SVR(_name, _pvr, POWERPC_SVR_NONE, _type)
 
-static const ppc_def_t ppc_defs[] = {
+static const PowerPCCPUInfo ppc_cpus[] = {
     /* Embedded PowerPC                                                      */
     /* PowerPC 401 family                                                    */
     /* Generic PowerPC 401 */
@@ -9280,7 +9327,7 @@ static const ppc_def_t ppc_defs[] = {
 
 /*****************************************************************************/
 /* Generic CPU instantiation routine                                         */
-static void init_ppc_proc (CPUPPCState *env, const ppc_def_t *def)
+static void init_ppc_proc(CPUPPCState *env, PowerPCCPUClass *def)
 {
 #if !defined(CONFIG_USER_ONLY)
     int i;
@@ -9672,7 +9719,7 @@ static void fix_opcode_tables (opc_handler_t 
**ppc_opcodes)
 }
 
 /*****************************************************************************/
-static int create_ppc_opcodes (CPUPPCState *env, const ppc_def_t *def)
+static int create_ppc_opcodes(CPUPPCState *env, const PowerPCCPUClass *def)
 {
     opcode_t *opc;
 
@@ -9884,8 +9931,26 @@ static int gdb_set_spe_reg(CPUPPCState *env, uint8_t 
*mem_buf, int n)
     return 0;
 }
 
-int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
+void ppc_cpu_initfn(Object *obj)
 {
+    PowerPCCPU *cpu = POWERPC_CPU(obj);
+    PowerPCCPUClass *def = POWERPC_CPU_GET_CLASS(cpu);
+    CPUPPCState *env = &cpu->env;
+
+    memset(env, 0, sizeof(*env));
+    cpu_exec_init(env);
+    env->cpu_model_str = object_get_typename(obj);
+
+    /* Adjust cpu index for SMT */
+#if !defined(CONFIG_USER_ONLY)
+    if (kvm_enabled()) {
+        int smt = kvmppc_smt_threads();
+
+        env->cpu_index = (env->cpu_index / smp_threads) * smt
+            + (env->cpu_index % smp_threads);
+    }
+#endif /* !CONFIG_USER_ONLY */
+
     env->msr_mask = def->msr_mask;
     env->mmu_model = def->mmu_model;
     env->excp_model = def->excp_model;
@@ -9911,8 +9976,9 @@ int cpu_ppc_register_internal (CPUPPCState *env, const 
ppc_def_t *def)
     env->flags = def->flags;
     env->bfd_mach = def->bfd_mach;
     env->check_pow = def->check_pow;
-    if (create_ppc_opcodes(env, def) < 0)
-        return -1;
+    if (create_ppc_opcodes(env, def) < 0) {
+        abort();
+    }
     init_ppc_proc(env, def);
 
     if (def->insns_flags & PPC_FLOAT) {
@@ -10089,11 +10155,64 @@ int cpu_ppc_register_internal (CPUPPCState *env, 
const ppc_def_t *def)
     dump_ppc_sprs(env);
     fflush(stdout);
 #endif
+}
 
-    return 0;
+static void ppc_cpu_reset(CPUState *c)
+{
+    PowerPCCPU *cpu = POWERPC_CPU(c);
+    PowerPCCPUClass *klass = POWERPC_CPU_GET_CLASS(cpu);
+    CPUPPCState *env = &cpu->env;
+    target_ulong msr;
+
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, 0);
+    }
+
+    klass->parent_reset(c);
+
+    msr = (target_ulong)0;
+    if (0) {
+        /* XXX: find a suitable condition to enable the hypervisor mode */
+        msr |= (target_ulong)MSR_HVB;
+    }
+    msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */
+    msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */
+    msr |= (target_ulong)1 << MSR_EP;
+#if defined(DO_SINGLE_STEP) && 0
+    /* Single step trace mode */
+    msr |= (target_ulong)1 << MSR_SE;
+    msr |= (target_ulong)1 << MSR_BE;
+#endif
+#if defined(CONFIG_USER_ONLY)
+    msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */
+    msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
+    msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
+    msr |= (target_ulong)1 << MSR_PR;
+#else
+    env->excp_prefix = env->hreset_excp_prefix;
+    env->nip = env->hreset_vector | env->excp_prefix;
+    if (env->mmu_model != POWERPC_MMU_REAL) {
+        ppc_tlb_invalidate_all(env);
+    }
+#endif
+    env->msr = msr & env->msr_mask;
+#if defined(TARGET_PPC64)
+    if (env->mmu_model & POWERPC_MMU_64) {
+        env->msr |= (1ULL << MSR_SF);
+    }
+#endif
+    hreg_compute_hflags(env);
+    env->reserve_addr = (target_ulong)-1ULL;
+    /* Be sure no exception or interrupt is pending */
+    env->pending_interrupts = 0;
+    env->exception_index = POWERPC_EXCP_NONE;
+    env->error_code = 0;
+    /* Flush all TLBs */
+    tlb_flush(env, 1);
 }
 
-static bool ppc_cpu_usable(const ppc_def_t *def)
+static bool ppc_cpu_usable(const PowerPCCPUInfo *def)
 {
 #if defined(TARGET_PPCEMB)
     /* When using the ppcemb target, we only support 440 style cores */
@@ -10105,18 +10224,18 @@ static bool ppc_cpu_usable(const ppc_def_t *def)
     return true;
 }
 
-const ppc_def_t *ppc_find_by_pvr(uint32_t pvr)
+const char *ppc_find_by_pvr(uint32_t pvr)
 {
     int i;
 
-    for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) {
-        if (!ppc_cpu_usable(&ppc_defs[i])) {
+    for (i = 0; i < ARRAY_SIZE(ppc_cpus); i++) {
+        if (!ppc_cpu_usable(&ppc_cpus[i])) {
             continue;
         }
 
         /* If we have an exact match, we're done */
-        if (pvr == ppc_defs[i].pvr) {
-            return &ppc_defs[i];
+        if (pvr == ppc_cpus[i].pvr) {
+            return ppc_cpus[i].name;
         }
     }
 
@@ -10125,14 +10244,13 @@ const ppc_def_t *ppc_find_by_pvr(uint32_t pvr)
 
 #include <ctype.h>
 
-const ppc_def_t *cpu_ppc_find_by_name (const char *name)
+PowerPCCPU *cpu_ppc_find_by_name(const char *name)
 {
-    const ppc_def_t *ret;
     const char *p;
-    int i, max, len;
+    int i, len;
 
-    if (kvm_enabled() && (strcasecmp(name, "host") == 0)) {
-        return kvmppc_host_cpu_def();
+    if (!kvm_enabled() && (strcasecmp(name, "host") == 0)) {
+        return NULL;
     }
 
     /* Check if the given name is a PVR */
@@ -10147,36 +10265,104 @@ const ppc_def_t *cpu_ppc_find_by_name (const char 
*name)
             if (!qemu_isxdigit(*p++))
                 break;
         }
-        if (i == 8)
-            return ppc_find_by_pvr(strtoul(name, NULL, 16));
-    }
-    ret = NULL;
-    max = ARRAY_SIZE(ppc_defs);
-    for (i = 0; i < max; i++) {
-        if (!ppc_cpu_usable(&ppc_defs[i])) {
-            continue;
+        if (i == 8) {
+            name = ppc_find_by_pvr(strtoul(name, NULL, 16));
+            if (name == NULL) {
+                return NULL;
+            }
         }
+    }
 
-        if (strcasecmp(name, ppc_defs[i].name) == 0) {
-            ret = &ppc_defs[i];
-            break;
-        }
+    if (object_class_by_name(name) == NULL) {
+        return NULL;
     }
+    return POWERPC_CPU(object_new(name));
+}
 
-    return ret;
+typedef struct PowerPCCPUListState {
+    FILE *file;
+    fprintf_function cpu_fprintf;
+} PowerPCCPUListState;
+
+/* Sort by PVR and alphabetically. */
+static gint ppc_cpu_list_compare(gconstpointer a, gconstpointer b)
+{
+    PowerPCCPUClass *class_a = POWERPC_CPU_CLASS(a);
+    PowerPCCPUClass *class_b = POWERPC_CPU_CLASS(b);
+
+    if (class_a->pvr == class_b->pvr) {
+        return strcasecmp(object_class_get_name(OBJECT_CLASS(class_a)),
+                          object_class_get_name(OBJECT_CLASS(class_b)));
+    } else if (class_a->pvr > class_b->pvr) {
+        return 1;
+    } else {
+        return -1;
+    }
+}
+
+static void ppc_cpu_list_entry(gpointer data, gpointer user_data)
+{
+    ObjectClass *klass = data;
+    PowerPCCPUClass *k = POWERPC_CPU_CLASS(klass);
+    PowerPCCPUListState *s = user_data;
+    const char *name;
+
+    name = object_class_get_name(klass);
+    if (strcmp(name, "host") == 0) {
+        return;
+    }
+    (*s->cpu_fprintf)(s->file, "PowerPC %-16s PVR %08x\n",
+                      name, k->pvr);
+}
+
+void ppc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    PowerPCCPUListState s = {
+        .file = f,
+        .cpu_fprintf = cpu_fprintf,
+    };
+    GSList *list;
+
+    list = object_class_get_list(TYPE_POWERPC_CPU, false);
+    list = g_slist_sort(list, ppc_cpu_list_compare);
+    g_slist_foreach(list, ppc_cpu_list_entry, &s);
+    g_slist_free(list);
+}
+
+static void ppc_register_cpu(const PowerPCCPUInfo *info)
+{
+    TypeInfo type = {
+        .name = info->name,
+        .parent = TYPE_POWERPC_CPU,
+        .instance_size = sizeof(PowerPCCPU),
+        .instance_init = ppc_cpu_initfn,
+        .class_size = sizeof(PowerPCCPUClass),
+        .class_init = ppc_cpu_class_init,
+        .class_data = (void *)info,
+    };
+
+    type_register_static(&type);
 }
 
-void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf)
+static TypeInfo ppc_cpu_type_info = {
+    .name = TYPE_POWERPC_CPU,
+    .parent = TYPE_CPU,
+    .instance_size = sizeof(PowerPCCPU),
+    .abstract = true,
+    .class_size = sizeof(PowerPCCPUClass),
+};
+
+static void ppc_cpu_register_types(void)
 {
-    int i, max;
+    int i;
 
-    max = ARRAY_SIZE(ppc_defs);
-    for (i = 0; i < max; i++) {
-        if (!ppc_cpu_usable(&ppc_defs[i])) {
+    type_register_static(&ppc_cpu_type_info);
+    for (i = 0; i < ARRAY_SIZE(ppc_cpus); i++) {
+        if (!ppc_cpu_usable(&ppc_cpus[i])) {
             continue;
         }
-
-        (*cpu_fprintf)(f, "PowerPC %-16s PVR %08x\n",
-                       ppc_defs[i].name, ppc_defs[i].pvr);
+        ppc_register_cpu(&ppc_cpus[i]);
     }
 }
+
+type_init(ppc_cpu_register_types)
-- 
1.7.7


Reply via email to