From mboxrd@z Thu Jan 1 00:00:00 1970 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Subject: [RFC 06/12] target-ppc: QOM'ify CPU Date: Wed, 14 Mar 2012 18:53:30 +0100 Message-ID: <1331747617-7837-7-git-send-email-afaerber@suse.de> References: <1330893156-26569-1-git-send-email-afaerber@suse.de> <1331747617-7837-1-git-send-email-afaerber@suse.de> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Cc: =?UTF-8?q?Andreas=20F=C3=A4rber?= , Alexander Graf (maintainer:PowerPC), Avi Kivity (supporter:Overall), Marcelo Tosatti (supporter:Overall), qemu-ppc@nongnu.org (open list:PowerPC), kvm@vger.kernel.org (open list:Overall) To: qemu-devel@nongnu.org Return-path: Received: from cantor2.suse.de ([195.135.220.15]:51017 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1760810Ab2CNRxn (ORCPT ); Wed, 14 Mar 2012 13:53:43 -0400 In-Reply-To: <1331747617-7837-1-git-send-email-afaerber@suse.de> Sender: kvm-owner@vger.kernel.org List-ID: Signed-off-by: Andreas F=C3=A4rber --- 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 + * + */ +#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) =20 /*********************************************************************= ********/ -typedef struct ppc_def_t ppc_def_t; typedef struct opc_handler_t opc_handler_t; =20 /*********************************************************************= ********/ @@ -877,22 +876,6 @@ enum { /* The whole PowerPC CPU context */ #define NB_MMU_MODES 3 =20 -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 =20 +#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_ulon= g value); =20 void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf); =20 -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); =20 /* 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_ulon= g msr) =20 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 =3D (target_ulong)0; - if (0) { - /* XXX: find a suitable condition to enable the hypervisor mod= e */ - msr |=3D (target_ulong)MSR_HVB; - } - msr |=3D (target_ulong)0 << MSR_AP; /* TO BE CHECKED */ - msr |=3D (target_ulong)0 << MSR_SA; /* TO BE CHECKED */ - msr |=3D (target_ulong)1 << MSR_EP; -#if defined (DO_SINGLE_STEP) && 0 - /* Single step trace mode */ - msr |=3D (target_ulong)1 << MSR_SE; - msr |=3D (target_ulong)1 << MSR_BE; -#endif -#if defined(CONFIG_USER_ONLY) - msr |=3D (target_ulong)1 << MSR_FP; /* Allow floating point usage = */ - msr |=3D (target_ulong)1 << MSR_VR; /* Allow altivec usage */ - msr |=3D (target_ulong)1 << MSR_SPE; /* Allow SPE usage */ - msr |=3D (target_ulong)1 << MSR_PR; -#else - env->excp_prefix =3D env->hreset_excp_prefix; - env->nip =3D env->hreset_vector | env->excp_prefix; - if (env->mmu_model !=3D POWERPC_MMU_REAL) - ppc_tlb_invalidate_all(env); -#endif - env->msr =3D msr & env->msr_mask; -#if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) - env->msr |=3D (1ULL << MSR_SF); -#endif - hreg_compute_hflags(env); - env->reserve_addr =3D (target_ulong)-1ULL; - /* Be sure no exception or interrupt is pending */ - env->pending_interrupts =3D 0; - env->exception_index =3D POWERPC_EXCP_NONE; - env->error_code =3D 0; - /* Flush all TLBs */ - tlb_flush(env, 1); + cpu_reset(ENV_GET_CPU(env)); } =20 -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; =20 - def =3D cpu_ppc_find_by_name(cpu_model); - if (!def) + cpu =3D cpu_ppc_find_by_name(cpu_model); + if (cpu =3D=3D NULL) { return NULL; + } + env =3D &cpu->env; =20 - env =3D 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 =3D kvmppc_smt_threads(); - - env->cpu_index =3D (env->cpu_index / smp_threads)*smt - + (env->cpu_index % smp_threads); - } -#endif /* !CONFIG_USER_ONLY */ - env->cpu_model_str =3D cpu_model; - cpu_ppc_register_internal(env, def); =20 qemu_init_vcpu(env); =20 return env; } =20 -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) } } =20 -const ppc_def_t *kvmppc_host_cpu_def(void) +static void kvmppc_host_cpu_class_init(ObjectClass *klass, void *data) { - uint32_t host_pvr =3D mfpvr(); - const ppc_def_t *base_spec; - ppc_def_t *spec; + PowerPCCPUClass *spec =3D POWERPC_CPU_CLASS(klass); uint32_t vmx =3D kvmppc_get_vmx(); uint32_t dfp =3D kvmppc_get_dfp(); =20 - base_spec =3D ppc_find_by_pvr(host_pvr); - - spec =3D g_malloc0(sizeof(*spec)); - memcpy(spec, base_spec, sizeof(*spec)); - /* Now fix up the spec with information we can query from the host= */ =20 if (vmx !=3D -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; } =20 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 =3D { + .name =3D "host", + .instance_size =3D sizeof(PowerPCCPU), + .instance_init =3D ppc_cpu_initfn, + .class_size =3D sizeof(PowerPCCPUClass), + .class_init =3D kvmppc_host_cpu_class_init, + }; + uint32_t host_pvr =3D mfpvr(); + type.parent =3D 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, in= t *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); =20 #else =20 @@ -90,11 +89,6 @@ static inline int kvmppc_remove_spapr_tce(void *tabl= e, int pfd, } #endif /* !CONFIG_USER_ONLY */ =20 -static inline const ppc_def_t *kvmppc_host_cpu_def(void) -{ - return NULL; -} - #endif =20 #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), }; =20 -#include "translate_init.c" #include "helper_regs.h" +#include "translate_init.c" =20 /*********************************************************************= ********/ /* 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 #include "kvm_ppc.h" +#include "cpus.h" =20 //#define PPC_DUMP_CPU //#define PPC_DEBUG_SPR @@ -7583,6 +7585,51 @@ enum { =20 /*********************************************************************= ********/ /* 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 =3D CPU_CLASS(klass); + PowerPCCPUClass *k =3D POWERPC_CPU_CLASS(klass); + const PowerPCCPUInfo *info =3D data; + + k->parent_reset =3D cpu_class->reset; + cpu_class->reset =3D ppc_cpu_reset; + + k->pvr =3D info->pvr; + k->svr =3D info->svr; + k->insns_flags =3D info->insns_flags; + k->insns_flags2 =3D info->insns_flags2; + k->msr_mask =3D info->msr_mask; + k->mmu_model =3D info->mmu_model; + k->excp_model =3D info->excp_model; + k->bus_model =3D info->bus_model; + k->flags =3D info->flags; + k->bfd_mach =3D info->bfd_mach; + + k->init_proc =3D info->init_proc; + k->check_pow =3D info->check_pow; +} + #define POWERPC_DEF_SVR(_name, _pvr, _svr, _type) = \ { = \ .name =3D _name, = \ @@ -7602,7 +7649,7 @@ enum { #define POWERPC_DEF(_name, _pvr, _type) = \ POWERPC_DEF_SVR(_name, _pvr, POWERPC_SVR_NONE, _type) =20 -static const ppc_def_t ppc_defs[] =3D { +static const PowerPCCPUInfo ppc_cpus[] =3D { /* Embedded PowerPC = */ /* PowerPC 401 family = */ /* Generic PowerPC 401 */ @@ -9280,7 +9327,7 @@ static const ppc_def_t ppc_defs[] =3D { =20 /*********************************************************************= ********/ /* 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 **pp= c_opcodes) } =20 /*********************************************************************= ********/ -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; =20 @@ -9884,8 +9931,26 @@ static int gdb_set_spe_reg(CPUPPCState *env, uin= t8_t *mem_buf, int n) return 0; } =20 -int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) +void ppc_cpu_initfn(Object *obj) { + PowerPCCPU *cpu =3D POWERPC_CPU(obj); + PowerPCCPUClass *def =3D POWERPC_CPU_GET_CLASS(cpu); + CPUPPCState *env =3D &cpu->env; + + memset(env, 0, sizeof(*env)); + cpu_exec_init(env); + env->cpu_model_str =3D object_get_typename(obj); + + /* Adjust cpu index for SMT */ +#if !defined(CONFIG_USER_ONLY) + if (kvm_enabled()) { + int smt =3D kvmppc_smt_threads(); + + env->cpu_index =3D (env->cpu_index / smp_threads) * smt + + (env->cpu_index % smp_threads); + } +#endif /* !CONFIG_USER_ONLY */ + env->msr_mask =3D def->msr_mask; env->mmu_model =3D def->mmu_model; env->excp_model =3D def->excp_model; @@ -9911,8 +9976,9 @@ int cpu_ppc_register_internal (CPUPPCState *env, = const ppc_def_t *def) env->flags =3D def->flags; env->bfd_mach =3D def->bfd_mach; env->check_pow =3D 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); =20 if (def->insns_flags & PPC_FLOAT) { @@ -10089,11 +10155,64 @@ int cpu_ppc_register_internal (CPUPPCState *e= nv, const ppc_def_t *def) dump_ppc_sprs(env); fflush(stdout); #endif +} =20 - return 0; +static void ppc_cpu_reset(CPUState *c) +{ + PowerPCCPU *cpu =3D POWERPC_CPU(c); + PowerPCCPUClass *klass =3D POWERPC_CPU_GET_CLASS(cpu); + CPUPPCState *env =3D &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 =3D (target_ulong)0; + if (0) { + /* XXX: find a suitable condition to enable the hypervisor mod= e */ + msr |=3D (target_ulong)MSR_HVB; + } + msr |=3D (target_ulong)0 << MSR_AP; /* TO BE CHECKED */ + msr |=3D (target_ulong)0 << MSR_SA; /* TO BE CHECKED */ + msr |=3D (target_ulong)1 << MSR_EP; +#if defined(DO_SINGLE_STEP) && 0 + /* Single step trace mode */ + msr |=3D (target_ulong)1 << MSR_SE; + msr |=3D (target_ulong)1 << MSR_BE; +#endif +#if defined(CONFIG_USER_ONLY) + msr |=3D (target_ulong)1 << MSR_FP; /* Allow floating point usage = */ + msr |=3D (target_ulong)1 << MSR_VR; /* Allow altivec usage */ + msr |=3D (target_ulong)1 << MSR_SPE; /* Allow SPE usage */ + msr |=3D (target_ulong)1 << MSR_PR; +#else + env->excp_prefix =3D env->hreset_excp_prefix; + env->nip =3D env->hreset_vector | env->excp_prefix; + if (env->mmu_model !=3D POWERPC_MMU_REAL) { + ppc_tlb_invalidate_all(env); + } +#endif + env->msr =3D msr & env->msr_mask; +#if defined(TARGET_PPC64) + if (env->mmu_model & POWERPC_MMU_64) { + env->msr |=3D (1ULL << MSR_SF); + } +#endif + hreg_compute_hflags(env); + env->reserve_addr =3D (target_ulong)-1ULL; + /* Be sure no exception or interrupt is pending */ + env->pending_interrupts =3D 0; + env->exception_index =3D POWERPC_EXCP_NONE; + env->error_code =3D 0; + /* Flush all TLBs */ + tlb_flush(env, 1); } =20 -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 *d= ef) return true; } =20 -const ppc_def_t *ppc_find_by_pvr(uint32_t pvr) +const char *ppc_find_by_pvr(uint32_t pvr) { int i; =20 - for (i =3D 0; i < ARRAY_SIZE(ppc_defs); i++) { - if (!ppc_cpu_usable(&ppc_defs[i])) { + for (i =3D 0; i < ARRAY_SIZE(ppc_cpus); i++) { + if (!ppc_cpu_usable(&ppc_cpus[i])) { continue; } =20 /* If we have an exact match, we're done */ - if (pvr =3D=3D ppc_defs[i].pvr) { - return &ppc_defs[i]; + if (pvr =3D=3D ppc_cpus[i].pvr) { + return ppc_cpus[i].name; } } =20 @@ -10125,14 +10244,13 @@ const ppc_def_t *ppc_find_by_pvr(uint32_t pvr= ) =20 #include =20 -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; =20 - if (kvm_enabled() && (strcasecmp(name, "host") =3D=3D 0)) { - return kvmppc_host_cpu_def(); + if (!kvm_enabled() && (strcasecmp(name, "host") =3D=3D 0)) { + return NULL; } =20 /* 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 =3D=3D 8) - return ppc_find_by_pvr(strtoul(name, NULL, 16)); - } - ret =3D NULL; - max =3D ARRAY_SIZE(ppc_defs); - for (i =3D 0; i < max; i++) { - if (!ppc_cpu_usable(&ppc_defs[i])) { - continue; + if (i =3D=3D 8) { + name =3D ppc_find_by_pvr(strtoul(name, NULL, 16)); + if (name =3D=3D NULL) { + return NULL; + } } + } =20 - if (strcasecmp(name, ppc_defs[i].name) =3D=3D 0) { - ret =3D &ppc_defs[i]; - break; - } + if (object_class_by_name(name) =3D=3D NULL) { + return NULL; } + return POWERPC_CPU(object_new(name)); +} =20 - 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 =3D POWERPC_CPU_CLASS(a); + PowerPCCPUClass *class_b =3D POWERPC_CPU_CLASS(b); + + if (class_a->pvr =3D=3D 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 =3D data; + PowerPCCPUClass *k =3D POWERPC_CPU_CLASS(klass); + PowerPCCPUListState *s =3D user_data; + const char *name; + + name =3D object_class_get_name(klass); + if (strcmp(name, "host") =3D=3D 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 =3D { + .file =3D f, + .cpu_fprintf =3D cpu_fprintf, + }; + GSList *list; + + list =3D object_class_get_list(TYPE_POWERPC_CPU, false); + list =3D 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 =3D { + .name =3D info->name, + .parent =3D TYPE_POWERPC_CPU, + .instance_size =3D sizeof(PowerPCCPU), + .instance_init =3D ppc_cpu_initfn, + .class_size =3D sizeof(PowerPCCPUClass), + .class_init =3D ppc_cpu_class_init, + .class_data =3D (void *)info, + }; + + type_register_static(&type); } =20 -void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf) +static TypeInfo ppc_cpu_type_info =3D { + .name =3D TYPE_POWERPC_CPU, + .parent =3D TYPE_CPU, + .instance_size =3D sizeof(PowerPCCPU), + .abstract =3D true, + .class_size =3D sizeof(PowerPCCPUClass), +}; + +static void ppc_cpu_register_types(void) { - int i, max; + int i; =20 - max =3D ARRAY_SIZE(ppc_defs); - for (i =3D 0; i < max; i++) { - if (!ppc_cpu_usable(&ppc_defs[i])) { + type_register_static(&ppc_cpu_type_info); + for (i =3D 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) --=20 1.7.7 From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:56851) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S7sOn-0006HO-1p for qemu-devel@nongnu.org; Wed, 14 Mar 2012 13:54:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1S7sON-0002d9-FU for qemu-devel@nongnu.org; Wed, 14 Mar 2012 13:54:08 -0400 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 14 Mar 2012 18:53:30 +0100 Message-Id: <1331747617-7837-7-git-send-email-afaerber@suse.de> In-Reply-To: <1331747617-7837-1-git-send-email-afaerber@suse.de> References: <1330893156-26569-1-git-send-email-afaerber@suse.de> <1331747617-7837-1-git-send-email-afaerber@suse.de> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [RFC 06/12] target-ppc: QOM'ify CPU List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: "open list:Overall" , Marcelo Tosatti , Alexander Graf , "open list:PowerPC" , Avi Kivity , =?UTF-8?q?Andreas=20F=C3=A4rber?= Signed-off-by: Andreas F=C3=A4rber --- 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 + * + */ +#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) =20 /***********************************************************************= ******/ -typedef struct ppc_def_t ppc_def_t; typedef struct opc_handler_t opc_handler_t; =20 /***********************************************************************= ******/ @@ -877,22 +876,6 @@ enum { /* The whole PowerPC CPU context */ #define NB_MMU_MODES 3 =20 -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 =20 +#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); =20 void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf); =20 -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); =20 /* 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) =20 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 =3D (target_ulong)0; - if (0) { - /* XXX: find a suitable condition to enable the hypervisor mode = */ - msr |=3D (target_ulong)MSR_HVB; - } - msr |=3D (target_ulong)0 << MSR_AP; /* TO BE CHECKED */ - msr |=3D (target_ulong)0 << MSR_SA; /* TO BE CHECKED */ - msr |=3D (target_ulong)1 << MSR_EP; -#if defined (DO_SINGLE_STEP) && 0 - /* Single step trace mode */ - msr |=3D (target_ulong)1 << MSR_SE; - msr |=3D (target_ulong)1 << MSR_BE; -#endif -#if defined(CONFIG_USER_ONLY) - msr |=3D (target_ulong)1 << MSR_FP; /* Allow floating point usage */ - msr |=3D (target_ulong)1 << MSR_VR; /* Allow altivec usage */ - msr |=3D (target_ulong)1 << MSR_SPE; /* Allow SPE usage */ - msr |=3D (target_ulong)1 << MSR_PR; -#else - env->excp_prefix =3D env->hreset_excp_prefix; - env->nip =3D env->hreset_vector | env->excp_prefix; - if (env->mmu_model !=3D POWERPC_MMU_REAL) - ppc_tlb_invalidate_all(env); -#endif - env->msr =3D msr & env->msr_mask; -#if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) - env->msr |=3D (1ULL << MSR_SF); -#endif - hreg_compute_hflags(env); - env->reserve_addr =3D (target_ulong)-1ULL; - /* Be sure no exception or interrupt is pending */ - env->pending_interrupts =3D 0; - env->exception_index =3D POWERPC_EXCP_NONE; - env->error_code =3D 0; - /* Flush all TLBs */ - tlb_flush(env, 1); + cpu_reset(ENV_GET_CPU(env)); } =20 -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; =20 - def =3D cpu_ppc_find_by_name(cpu_model); - if (!def) + cpu =3D cpu_ppc_find_by_name(cpu_model); + if (cpu =3D=3D NULL) { return NULL; + } + env =3D &cpu->env; =20 - env =3D 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 =3D kvmppc_smt_threads(); - - env->cpu_index =3D (env->cpu_index / smp_threads)*smt - + (env->cpu_index % smp_threads); - } -#endif /* !CONFIG_USER_ONLY */ - env->cpu_model_str =3D cpu_model; - cpu_ppc_register_internal(env, def); =20 qemu_init_vcpu(env); =20 return env; } =20 -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 fl= ags, bool on) } } =20 -const ppc_def_t *kvmppc_host_cpu_def(void) +static void kvmppc_host_cpu_class_init(ObjectClass *klass, void *data) { - uint32_t host_pvr =3D mfpvr(); - const ppc_def_t *base_spec; - ppc_def_t *spec; + PowerPCCPUClass *spec =3D POWERPC_CPU_CLASS(klass); uint32_t vmx =3D kvmppc_get_vmx(); uint32_t dfp =3D kvmppc_get_dfp(); =20 - base_spec =3D ppc_find_by_pvr(host_pvr); - - spec =3D g_malloc0(sizeof(*spec)); - memcpy(spec, base_spec, sizeof(*spec)); - /* Now fix up the spec with information we can query from the host *= / =20 if (vmx !=3D -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; } =20 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 =3D { + .name =3D "host", + .instance_size =3D sizeof(PowerPCCPU), + .instance_init =3D ppc_cpu_initfn, + .class_size =3D sizeof(PowerPCCPUClass), + .class_init =3D kvmppc_host_cpu_class_init, + }; + uint32_t host_pvr =3D mfpvr(); + type.parent =3D 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); =20 #else =20 @@ -90,11 +89,6 @@ static inline int kvmppc_remove_spapr_tce(void *table,= int pfd, } #endif /* !CONFIG_USER_ONLY */ =20 -static inline const ppc_def_t *kvmppc_host_cpu_def(void) -{ - return NULL; -} - #endif =20 #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), }; =20 -#include "translate_init.c" #include "helper_regs.h" +#include "translate_init.c" =20 /***********************************************************************= ******/ /* 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 #include "kvm_ppc.h" +#include "cpus.h" =20 //#define PPC_DUMP_CPU //#define PPC_DEBUG_SPR @@ -7583,6 +7585,51 @@ enum { =20 /***********************************************************************= ******/ /* 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 =3D CPU_CLASS(klass); + PowerPCCPUClass *k =3D POWERPC_CPU_CLASS(klass); + const PowerPCCPUInfo *info =3D data; + + k->parent_reset =3D cpu_class->reset; + cpu_class->reset =3D ppc_cpu_reset; + + k->pvr =3D info->pvr; + k->svr =3D info->svr; + k->insns_flags =3D info->insns_flags; + k->insns_flags2 =3D info->insns_flags2; + k->msr_mask =3D info->msr_mask; + k->mmu_model =3D info->mmu_model; + k->excp_model =3D info->excp_model; + k->bus_model =3D info->bus_model; + k->flags =3D info->flags; + k->bfd_mach =3D info->bfd_mach; + + k->init_proc =3D info->init_proc; + k->check_pow =3D info->check_pow; +} + #define POWERPC_DEF_SVR(_name, _pvr, _svr, _type) = \ { = \ .name =3D _name, = \ @@ -7602,7 +7649,7 @@ enum { #define POWERPC_DEF(_name, _pvr, _type) = \ POWERPC_DEF_SVR(_name, _pvr, POWERPC_SVR_NONE, _type) =20 -static const ppc_def_t ppc_defs[] =3D { +static const PowerPCCPUInfo ppc_cpus[] =3D { /* Embedded PowerPC = */ /* PowerPC 401 family = */ /* Generic PowerPC 401 */ @@ -9280,7 +9327,7 @@ static const ppc_def_t ppc_defs[] =3D { =20 /***********************************************************************= ******/ /* 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) } =20 /***********************************************************************= ******/ -static int create_ppc_opcodes (CPUPPCState *env, const ppc_def_t *def) +static int create_ppc_opcodes(CPUPPCState *env, const PowerPCCPUClass *d= ef) { opcode_t *opc; =20 @@ -9884,8 +9931,26 @@ static int gdb_set_spe_reg(CPUPPCState *env, uint8= _t *mem_buf, int n) return 0; } =20 -int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) +void ppc_cpu_initfn(Object *obj) { + PowerPCCPU *cpu =3D POWERPC_CPU(obj); + PowerPCCPUClass *def =3D POWERPC_CPU_GET_CLASS(cpu); + CPUPPCState *env =3D &cpu->env; + + memset(env, 0, sizeof(*env)); + cpu_exec_init(env); + env->cpu_model_str =3D object_get_typename(obj); + + /* Adjust cpu index for SMT */ +#if !defined(CONFIG_USER_ONLY) + if (kvm_enabled()) { + int smt =3D kvmppc_smt_threads(); + + env->cpu_index =3D (env->cpu_index / smp_threads) * smt + + (env->cpu_index % smp_threads); + } +#endif /* !CONFIG_USER_ONLY */ + env->msr_mask =3D def->msr_mask; env->mmu_model =3D def->mmu_model; env->excp_model =3D def->excp_model; @@ -9911,8 +9976,9 @@ int cpu_ppc_register_internal (CPUPPCState *env, co= nst ppc_def_t *def) env->flags =3D def->flags; env->bfd_mach =3D def->bfd_mach; env->check_pow =3D 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); =20 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 +} =20 - return 0; +static void ppc_cpu_reset(CPUState *c) +{ + PowerPCCPU *cpu =3D POWERPC_CPU(c); + PowerPCCPUClass *klass =3D POWERPC_CPU_GET_CLASS(cpu); + CPUPPCState *env =3D &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 =3D (target_ulong)0; + if (0) { + /* XXX: find a suitable condition to enable the hypervisor mode = */ + msr |=3D (target_ulong)MSR_HVB; + } + msr |=3D (target_ulong)0 << MSR_AP; /* TO BE CHECKED */ + msr |=3D (target_ulong)0 << MSR_SA; /* TO BE CHECKED */ + msr |=3D (target_ulong)1 << MSR_EP; +#if defined(DO_SINGLE_STEP) && 0 + /* Single step trace mode */ + msr |=3D (target_ulong)1 << MSR_SE; + msr |=3D (target_ulong)1 << MSR_BE; +#endif +#if defined(CONFIG_USER_ONLY) + msr |=3D (target_ulong)1 << MSR_FP; /* Allow floating point usage */ + msr |=3D (target_ulong)1 << MSR_VR; /* Allow altivec usage */ + msr |=3D (target_ulong)1 << MSR_SPE; /* Allow SPE usage */ + msr |=3D (target_ulong)1 << MSR_PR; +#else + env->excp_prefix =3D env->hreset_excp_prefix; + env->nip =3D env->hreset_vector | env->excp_prefix; + if (env->mmu_model !=3D POWERPC_MMU_REAL) { + ppc_tlb_invalidate_all(env); + } +#endif + env->msr =3D msr & env->msr_mask; +#if defined(TARGET_PPC64) + if (env->mmu_model & POWERPC_MMU_64) { + env->msr |=3D (1ULL << MSR_SF); + } +#endif + hreg_compute_hflags(env); + env->reserve_addr =3D (target_ulong)-1ULL; + /* Be sure no exception or interrupt is pending */ + env->pending_interrupts =3D 0; + env->exception_index =3D POWERPC_EXCP_NONE; + env->error_code =3D 0; + /* Flush all TLBs */ + tlb_flush(env, 1); } =20 -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; } =20 -const ppc_def_t *ppc_find_by_pvr(uint32_t pvr) +const char *ppc_find_by_pvr(uint32_t pvr) { int i; =20 - for (i =3D 0; i < ARRAY_SIZE(ppc_defs); i++) { - if (!ppc_cpu_usable(&ppc_defs[i])) { + for (i =3D 0; i < ARRAY_SIZE(ppc_cpus); i++) { + if (!ppc_cpu_usable(&ppc_cpus[i])) { continue; } =20 /* If we have an exact match, we're done */ - if (pvr =3D=3D ppc_defs[i].pvr) { - return &ppc_defs[i]; + if (pvr =3D=3D ppc_cpus[i].pvr) { + return ppc_cpus[i].name; } } =20 @@ -10125,14 +10244,13 @@ const ppc_def_t *ppc_find_by_pvr(uint32_t pvr) =20 #include =20 -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; =20 - if (kvm_enabled() && (strcasecmp(name, "host") =3D=3D 0)) { - return kvmppc_host_cpu_def(); + if (!kvm_enabled() && (strcasecmp(name, "host") =3D=3D 0)) { + return NULL; } =20 /* Check if the given name is a PVR */ @@ -10147,36 +10265,104 @@ const ppc_def_t *cpu_ppc_find_by_name (const c= har *name) if (!qemu_isxdigit(*p++)) break; } - if (i =3D=3D 8) - return ppc_find_by_pvr(strtoul(name, NULL, 16)); - } - ret =3D NULL; - max =3D ARRAY_SIZE(ppc_defs); - for (i =3D 0; i < max; i++) { - if (!ppc_cpu_usable(&ppc_defs[i])) { - continue; + if (i =3D=3D 8) { + name =3D ppc_find_by_pvr(strtoul(name, NULL, 16)); + if (name =3D=3D NULL) { + return NULL; + } } + } =20 - if (strcasecmp(name, ppc_defs[i].name) =3D=3D 0) { - ret =3D &ppc_defs[i]; - break; - } + if (object_class_by_name(name) =3D=3D NULL) { + return NULL; } + return POWERPC_CPU(object_new(name)); +} =20 - 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 =3D POWERPC_CPU_CLASS(a); + PowerPCCPUClass *class_b =3D POWERPC_CPU_CLASS(b); + + if (class_a->pvr =3D=3D 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 =3D data; + PowerPCCPUClass *k =3D POWERPC_CPU_CLASS(klass); + PowerPCCPUListState *s =3D user_data; + const char *name; + + name =3D object_class_get_name(klass); + if (strcmp(name, "host") =3D=3D 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 =3D { + .file =3D f, + .cpu_fprintf =3D cpu_fprintf, + }; + GSList *list; + + list =3D object_class_get_list(TYPE_POWERPC_CPU, false); + list =3D 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 =3D { + .name =3D info->name, + .parent =3D TYPE_POWERPC_CPU, + .instance_size =3D sizeof(PowerPCCPU), + .instance_init =3D ppc_cpu_initfn, + .class_size =3D sizeof(PowerPCCPUClass), + .class_init =3D ppc_cpu_class_init, + .class_data =3D (void *)info, + }; + + type_register_static(&type); } =20 -void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf) +static TypeInfo ppc_cpu_type_info =3D { + .name =3D TYPE_POWERPC_CPU, + .parent =3D TYPE_CPU, + .instance_size =3D sizeof(PowerPCCPU), + .abstract =3D true, + .class_size =3D sizeof(PowerPCCPUClass), +}; + +static void ppc_cpu_register_types(void) { - int i, max; + int i; =20 - max =3D ARRAY_SIZE(ppc_defs); - for (i =3D 0; i < max; i++) { - if (!ppc_cpu_usable(&ppc_defs[i])) { + type_register_static(&ppc_cpu_type_info); + for (i =3D 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) --=20 1.7.7