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