diff options
Diffstat (limited to 'target/ppc/translate_init.c')
-rw-r--r-- | target/ppc/translate_init.c | 232 |
1 files changed, 126 insertions, 106 deletions
diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c index 43be9a8331..c827d1e388 100644 --- a/target/ppc/translate_init.c +++ b/target/ppc/translate_init.c @@ -34,6 +34,7 @@ #include "hw/ppc/ppc.h" #include "mmu-book3s-v3.h" #include "sysemu/qtest.h" +#include "qemu/cutils.h" //#define PPC_DUMP_CPU //#define PPC_DEBUG_SPR @@ -1842,7 +1843,7 @@ static inline uint32_t gen_tlbncfg(uint32_t assoc, uint32_t minsize, /* BookE 2.06 storage control registers */ static void gen_spr_BookE206(CPUPPCState *env, uint32_t mas_mask, - uint32_t *tlbncfg) + uint32_t *tlbncfg, uint32_t mmucfg) { #if !defined(CONFIG_USER_ONLY) const char *mas_names[8] = { @@ -1886,7 +1887,7 @@ static void gen_spr_BookE206(CPUPPCState *env, uint32_t mas_mask, spr_register(env, SPR_MMUCFG, "MMUCFG", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, - 0x00000000); /* TOFIX */ + mmucfg); switch (env->nb_ways) { case 4: spr_register(env, SPR_BOOKE_TLB3CFG, "TLB3CFG", @@ -4615,7 +4616,7 @@ static void init_proc_e200(CPUPPCState *env) &spr_read_spefscr, &spr_write_spefscr, 0x00000000); /* Memory management */ - gen_spr_BookE206(env, 0x0000005D, NULL); + gen_spr_BookE206(env, 0x0000005D, NULL, 0); /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, @@ -4888,6 +4889,7 @@ enum fsl_e500_version { fsl_e500v2, fsl_e500mc, fsl_e5500, + fsl_e6500, }; static void init_proc_e500(CPUPPCState *env, int version) @@ -4900,6 +4902,7 @@ static void init_proc_e500(CPUPPCState *env, int version) | 0x0020; /* 32 kb */ uint32_t l1cfg1 = 0x3800 /* 8 ways */ | 0x0020; /* 32 kb */ + uint32_t mmucfg = 0; #if !defined(CONFIG_USER_ONLY) int i; #endif @@ -4921,6 +4924,9 @@ static void init_proc_e500(CPUPPCState *env, int version) case fsl_e5500: ivor_mask = 0x000003FE0000FFFFULL; break; + case fsl_e6500: + ivor_mask = 0x000003FF0000FFFFULL; + break; } gen_spr_BookE(env, ivor_mask); gen_spr_usprg3(env); @@ -4953,6 +4959,12 @@ static void init_proc_e500(CPUPPCState *env, int version) tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512); tlbncfg[1] = gen_tlbncfg(64, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 64); break; + case fsl_e6500: + mmucfg = 0x6510B45; + env->nb_pids = 1; + tlbncfg[0] = 0x08052400; + tlbncfg[1] = 0x40028040; + break; default: cpu_abort(CPU(cpu), "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]); } @@ -4971,10 +4983,16 @@ static void init_proc_e500(CPUPPCState *env, int version) l1cfg0 |= 0x1000000; /* 64 byte cache block size */ l1cfg1 |= 0x1000000; /* 64 byte cache block size */ break; + case fsl_e6500: + env->dcache_line_size = 32; + env->icache_line_size = 32; + l1cfg0 |= 0x0F83820; + l1cfg1 |= 0x0B83820; + break; default: cpu_abort(CPU(cpu), "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]); } - gen_spr_BookE206(env, 0x000000DF, tlbncfg); + gen_spr_BookE206(env, 0x000000DF, tlbncfg, mmucfg); /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, @@ -5049,7 +5067,7 @@ static void init_proc_e500(CPUPPCState *env, int version) &spr_read_generic, SPR_NOACCESS, 0x00000000); /* XXX better abstract into Emb.xxx features */ - if (version == fsl_e5500) { + if ((version == fsl_e5500) || (version == fsl_e6500)) { spr_register(env, SPR_BOOKE_EPCR, "EPCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -5061,6 +5079,30 @@ static void init_proc_e500(CPUPPCState *env, int version) ivpr_mask = (target_ulong)~0xFFFFULL; } + if (version == fsl_e6500) { + spr_register(env, SPR_BOOKE_SPRG8, "SPRG8", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_SPRG9, "SPRG9", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Thread identification */ + spr_register(env, SPR_TIR, "TIR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_BOOKE_TLB0PS, "TLB0PS", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000004); + spr_register(env, SPR_BOOKE_TLB1PS, "TLB1PS", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x7FFFFFFC); + } + #if !defined(CONFIG_USER_ONLY) env->nb_tlb = 0; env->tlb_type = TLB_MAS; @@ -5253,6 +5295,55 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data) pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } + +static void init_proc_e6500(CPUPPCState *env) +{ + init_proc_e500(env, fsl_e6500); +} + +POWERPC_FAMILY(e6500)(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + dc->desc = "e6500 core"; + pcc->init_proc = init_proc_e6500; + pcc->check_pow = check_pow_none; + pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_MFTB | + PPC_WRTEE | PPC_RFDI | PPC_RFMCI | + PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | + PPC_FLOAT | PPC_FLOAT_FRES | + PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL | + PPC_FLOAT_STFIWX | PPC_WAIT | + PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC | + PPC_64B | PPC_POPCNTB | PPC_POPCNTWD | PPC_ALTIVEC; + pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_PERM_ISA206 | \ + PPC2_FP_CVT_S64 | PPC2_ATOMIC_ISA206; + pcc->msr_mask = (1ull << MSR_CM) | + (1ull << MSR_GS) | + (1ull << MSR_UCLE) | + (1ull << MSR_CE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IS) | + (1ull << MSR_DS) | + (1ull << MSR_PX) | + (1ull << MSR_RI) | + (1ull << MSR_VR); + pcc->mmu_model = POWERPC_MMU_BOOKE206; + pcc->excp_model = POWERPC_EXCP_BOOKE; + pcc->bus_model = PPC_FLAGS_INPUT_BookE; + pcc->bfd_mach = bfd_mach_ppc_e500; + pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DE | + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_VRE; +} + #endif /* Non-embedded PowerPC */ @@ -9813,42 +9904,15 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) PowerPCCPU *cpu = POWERPC_CPU(dev); PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); Error *local_err = NULL; -#if !defined(CONFIG_USER_ONLY) - int max_smt = kvmppc_smt_threads(); -#endif - -#if !defined(CONFIG_USER_ONLY) - if (smp_threads > max_smt) { - error_setg(errp, "Cannot support more than %d threads on PPC with %s", - max_smt, kvm_enabled() ? "KVM" : "TCG"); - return; - } - if (!is_power_of_2(smp_threads)) { - error_setg(errp, "Cannot support %d threads on PPC with %s, " - "threads count must be a power of 2.", - smp_threads, kvm_enabled() ? "KVM" : "TCG"); - return; - } -#endif cpu_exec_realizefn(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; } - -#if !defined(CONFIG_USER_ONLY) - cpu->cpu_dt_id = (cs->cpu_index / smp_threads) * max_smt - + (cs->cpu_index % smp_threads); - - if (kvm_enabled() && !kvm_vcpu_id_is_valid(cpu->cpu_dt_id)) { - error_setg(errp, "Can't create CPU with id %d in KVM", cpu->cpu_dt_id); - error_append_hint(errp, "Adjust the number of cpus to %d " - "or try to raise the number of threads per core\n", - cpu->cpu_dt_id * smp_threads / max_smt); - goto unrealize; + if (cpu->vcpu_id == UNASSIGNED_CPU_INDEX) { + cpu->vcpu_id = cs->cpu_index; } -#endif if (tcg_enabled()) { if (ppc_fixup_cpu(cpu) != 0) { @@ -10176,83 +10240,38 @@ PowerPCCPUClass *ppc_cpu_class_by_pvr_mask(uint32_t pvr) return pcc; } -static gint ppc_cpu_compare_class_name(gconstpointer a, gconstpointer b) -{ - ObjectClass *oc = (ObjectClass *)a; - const char *name = b; - PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); - - if (strncasecmp(name, object_class_get_name(oc), strlen(name)) == 0 && - ppc_cpu_is_valid(pcc) && - strcmp(object_class_get_name(oc) + strlen(name), - "-" TYPE_POWERPC_CPU) == 0) { - return 0; - } - return -1; -} - - -static ObjectClass *ppc_cpu_class_by_name(const char *name); - -static ObjectClass *ppc_cpu_class_by_alias(PowerPCCPUAlias *alias) -{ - ObjectClass *invalid_class = (void*)ppc_cpu_class_by_alias; - - /* Cache target class lookups in the alias table */ - if (!alias->oc) { - alias->oc = ppc_cpu_class_by_name(alias->model); - if (!alias->oc) { - /* Fast check for non-existing aliases */ - alias->oc = invalid_class; - } - } - - if (alias->oc == invalid_class) { - return NULL; - } else { - return alias->oc; - } -} - static ObjectClass *ppc_cpu_class_by_name(const char *name) { - GSList *list, *item; - ObjectClass *ret = NULL; + char *cpu_model, *typename; + ObjectClass *oc; const char *p; - int i, len; - - /* Check if the given name is a PVR */ - len = strlen(name); - if (len == 10 && name[0] == '0' && name[1] == 'x') { - p = name + 2; - goto check_pvr; - } else if (len == 8) { - p = name; - check_pvr: - for (i = 0; i < 8; i++) { - if (!qemu_isxdigit(*p++)) - break; - } - if (i == 8) { - return OBJECT_CLASS(ppc_cpu_class_by_pvr(strtoul(name, NULL, 16))); + unsigned long pvr; + + /* Lookup by PVR if cpu_model is valid 8 digit hex number + * (excl: 0x prefix if present) + */ + if (!qemu_strtoul(name, &p, 16, &pvr)) { + int len = p - name; + len = (len == 10) && (name[1] == 'x') ? len - 2 : len; + if ((len == 8) && (*p == '\0')) { + return OBJECT_CLASS(ppc_cpu_class_by_pvr(pvr)); } } - list = object_class_get_list(TYPE_POWERPC_CPU, false); - item = g_slist_find_custom(list, name, ppc_cpu_compare_class_name); - if (item != NULL) { - ret = OBJECT_CLASS(item->data); + cpu_model = g_ascii_strdown(name, -1); + p = ppc_cpu_lookup_alias(cpu_model); + if (p) { + g_free(cpu_model); + cpu_model = g_strdup(p); } - g_slist_free(list); - if (ret) { - return ret; - } + typename = g_strdup_printf("%s" POWERPC_CPU_TYPE_SUFFIX, cpu_model); + oc = object_class_by_name(typename); + g_free(typename); + g_free(cpu_model); - for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) { - if (strcmp(ppc_cpu_aliases[i].alias, name) == 0) { - return ppc_cpu_class_by_alias(&ppc_cpu_aliases[i]); - } + if (oc && ppc_cpu_is_valid(POWERPC_CPU_CLASS(oc))) { + return oc; } return NULL; @@ -10327,12 +10346,12 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data) } name = g_strndup(typename, - strlen(typename) - strlen("-" TYPE_POWERPC_CPU)); + strlen(typename) - strlen(POWERPC_CPU_TYPE_SUFFIX)); (*s->cpu_fprintf)(s->file, "PowerPC %-16s PVR %08x\n", name, pcc->pvr); for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) { PowerPCCPUAlias *alias = &ppc_cpu_aliases[i]; - ObjectClass *alias_oc = ppc_cpu_class_by_alias(alias); + ObjectClass *alias_oc = ppc_cpu_class_by_name(alias->model); if (alias_oc != oc) { continue; @@ -10388,7 +10407,7 @@ static void ppc_cpu_defs_entry(gpointer data, gpointer user_data) typename = object_class_get_name(oc); info = g_malloc0(sizeof(*info)); info->name = g_strndup(typename, - strlen(typename) - strlen("-" TYPE_POWERPC_CPU)); + strlen(typename) - strlen(POWERPC_CPU_TYPE_SUFFIX)); entry = g_malloc0(sizeof(*entry)); entry->value = info; @@ -10412,7 +10431,7 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp) CpuDefinitionInfoList *entry; CpuDefinitionInfo *info; - oc = ppc_cpu_class_by_alias(alias); + oc = ppc_cpu_class_by_name(alias->model); if (oc == NULL) { continue; } @@ -10544,6 +10563,7 @@ static void ppc_cpu_initfn(Object *obj) CPUPPCState *env = &cpu->env; cs->env_ptr = env; + cpu->vcpu_id = UNASSIGNED_CPU_INDEX; env->msr_mask = pcc->msr_mask; env->mmu_model = pcc->mmu_model; |