summaryrefslogtreecommitdiffstats
path: root/target/ppc/translate_init.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/ppc/translate_init.c')
-rw-r--r--target/ppc/translate_init.c232
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;