aboutsummaryrefslogtreecommitdiff
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.c345
1 files changed, 238 insertions, 107 deletions
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index e2eeb87650..2b03756ee1 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -9792,8 +9792,11 @@ static void fix_opcode_tables (opc_handler_t **ppc_opcodes)
}
/*****************************************************************************/
-static int create_ppc_opcodes (CPUPPCState *env, const ppc_def_t *def)
+static void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp)
{
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ CPUPPCState *env = &cpu->env;
+ const ppc_def_t *def = pcc->info;
opcode_t *opc;
fill_new_table(env->opcodes, 0x40);
@@ -9801,18 +9804,16 @@ static int create_ppc_opcodes (CPUPPCState *env, const ppc_def_t *def)
if (((opc->handler.type & def->insns_flags) != 0) ||
((opc->handler.type2 & def->insns_flags2) != 0)) {
if (register_insn(env->opcodes, opc) < 0) {
- printf("*** ERROR initializing PowerPC instruction "
- "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
- opc->opc3);
- return -1;
+ error_setg(errp, "ERROR initializing PowerPC instruction "
+ "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
+ opc->opc3);
+ return;
}
}
}
fix_opcode_tables(env->opcodes);
fflush(stdout);
fflush(stderr);
-
- return 0;
}
#if defined(PPC_DUMP_CPU)
@@ -10026,53 +10027,31 @@ static int ppc_fixup_cpu(CPUPPCState *env)
return 0;
}
-int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
+static void ppc_cpu_realize(Object *obj, Error **errp)
{
- env->msr_mask = def->msr_mask;
- env->mmu_model = def->mmu_model;
- env->excp_model = def->excp_model;
- env->bus_model = def->bus_model;
- env->insns_flags = def->insns_flags;
- env->insns_flags2 = def->insns_flags2;
- env->flags = def->flags;
- env->bfd_mach = def->bfd_mach;
- env->check_pow = def->check_pow;
-
-#if defined(TARGET_PPC64)
- if (def->sps)
- env->sps = *def->sps;
- else if (env->mmu_model & POWERPC_MMU_64) {
- /* Use default sets of page sizes */
- static const struct ppc_segment_page_sizes defsps = {
- .sps = {
- { .page_shift = 12, /* 4K */
- .slb_enc = 0,
- .enc = { { .page_shift = 12, .pte_enc = 0 } }
- },
- { .page_shift = 24, /* 16M */
- .slb_enc = 0x100,
- .enc = { { .page_shift = 24, .pte_enc = 0 } }
- },
- },
- };
- env->sps = defsps;
- }
-#endif /* defined(TARGET_PPC64) */
+ PowerPCCPU *cpu = POWERPC_CPU(obj);
+ CPUPPCState *env = &cpu->env;
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ ppc_def_t *def = pcc->info;
+ Error *local_err = NULL;
if (kvm_enabled()) {
if (kvmppc_fixup_cpu(env) != 0) {
- fprintf(stderr, "Unable to virtualize selected CPU with KVM\n");
- exit(1);
+ error_setg(errp, "Unable to virtualize selected CPU with KVM");
+ return;
}
} else {
if (ppc_fixup_cpu(env) != 0) {
- fprintf(stderr, "Unable to emulate selected CPU with TCG\n");
- exit(1);
+ error_setg(errp, "Unable to emulate selected CPU with TCG");
+ return;
}
}
- if (create_ppc_opcodes(env, def) < 0)
- return -1;
+ create_ppc_opcodes(cpu, &local_err);
+ if (local_err != NULL) {
+ error_propagate(errp, local_err);
+ return;
+ }
init_ppc_proc(env, def);
if (def->insns_flags & PPC_FLOAT) {
@@ -10088,6 +10067,8 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
34, "power-spe.xml", 0);
}
+ qemu_init_vcpu(env);
+
#if defined(PPC_DUMP_CPU)
{
const char *mmu_model, *excp_model, *bus_model;
@@ -10249,50 +10230,65 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
dump_ppc_sprs(env);
fflush(stdout);
#endif
-
- return 0;
}
-static bool ppc_cpu_usable(const ppc_def_t *def)
+static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b)
{
-#if defined(TARGET_PPCEMB)
- /* When using the ppcemb target, we only support 440 style cores */
- if (def->mmu_model != POWERPC_MMU_BOOKE) {
- return false;
+ ObjectClass *oc = (ObjectClass *)a;
+ uint32_t pvr = *(uint32_t *)b;
+ PowerPCCPUClass *pcc = (PowerPCCPUClass *)a;
+
+ /* -cpu host does a PVR lookup during construction */
+ if (unlikely(strcmp(object_class_get_name(oc),
+ TYPE_HOST_POWERPC_CPU) == 0)) {
+ return -1;
}
-#endif
- return true;
+ return pcc->info->pvr == pvr ? 0 : -1;
}
-const ppc_def_t *ppc_find_by_pvr(uint32_t pvr)
+PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr)
{
- int i;
+ GSList *list, *item;
+ PowerPCCPUClass *pcc = NULL;
- for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) {
- if (!ppc_cpu_usable(&ppc_defs[i])) {
- continue;
- }
-
- /* If we have an exact match, we're done */
- if (pvr == ppc_defs[i].pvr) {
- return &ppc_defs[i];
- }
+ list = object_class_get_list(TYPE_POWERPC_CPU, false);
+ item = g_slist_find_custom(list, &pvr, ppc_cpu_compare_class_pvr);
+ if (item != NULL) {
+ pcc = POWERPC_CPU_CLASS(item->data);
}
+ g_slist_free(list);
+
+ return pcc;
+}
+
+static gint ppc_cpu_compare_class_name(gconstpointer a, gconstpointer b)
+{
+ ObjectClass *oc = (ObjectClass *)a;
+ const char *name = b;
- return NULL;
+ if (strncasecmp(name, object_class_get_name(oc), strlen(name)) == 0 &&
+ strcmp(object_class_get_name(oc) + strlen(name),
+ "-" TYPE_POWERPC_CPU) == 0) {
+ return 0;
+ }
+ return -1;
}
#include <ctype.h>
-const ppc_def_t *cpu_ppc_find_by_name (const char *name)
+static ObjectClass *ppc_cpu_class_by_name(const char *name)
{
- const ppc_def_t *ret;
+ GSList *list, *item;
+ ObjectClass *ret = NULL;
const char *p;
- int i, max, len;
+ int i, len;
- if (kvm_enabled() && (strcasecmp(name, "host") == 0)) {
- return kvmppc_host_cpu_def();
+ if (strcasecmp(name, "host") == 0) {
+ if (kvm_enabled()) {
+ ret = object_class_by_name(TYPE_HOST_POWERPC_CPU);
+ }
+ return ret;
}
/* Check if the given name is a PVR */
@@ -10307,63 +10303,152 @@ 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) {
+ ret = OBJECT_CLASS(ppc_cpu_class_by_pvr(strtoul(name, NULL, 16)));
+ return ret;
}
+ }
- if (strcasecmp(name, ppc_defs[i].name) == 0) {
- ret = &ppc_defs[i];
- break;
- }
+ 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);
}
+ g_slist_free(list);
return ret;
}
-void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf)
+PowerPCCPU *cpu_ppc_init(const char *cpu_model)
{
- int i, max;
+ PowerPCCPU *cpu;
+ CPUPPCState *env;
+ ObjectClass *oc;
+ Error *err = NULL;
- max = ARRAY_SIZE(ppc_defs);
- for (i = 0; i < max; i++) {
- if (!ppc_cpu_usable(&ppc_defs[i])) {
- continue;
- }
+ oc = ppc_cpu_class_by_name(cpu_model);
+ if (oc == NULL) {
+ return NULL;
+ }
- (*cpu_fprintf)(f, "PowerPC %-16s PVR %08x\n",
- ppc_defs[i].name, ppc_defs[i].pvr);
+ cpu = POWERPC_CPU(object_new(object_class_get_name(oc)));
+ env = &cpu->env;
+
+ if (tcg_enabled()) {
+ ppc_translate_init();
}
+
+ env->cpu_model_str = cpu_model;
+
+ ppc_cpu_realize(OBJECT(cpu), &err);
+ if (err != NULL) {
+ fprintf(stderr, "%s\n", error_get_pretty(err));
+ error_free(err);
+ object_delete(OBJECT(cpu));
+ return NULL;
+ }
+
+ return cpu;
+}
+
+/* Sort by PVR, ordering special case "host" last. */
+static gint ppc_cpu_list_compare(gconstpointer a, gconstpointer b)
+{
+ ObjectClass *oc_a = (ObjectClass *)a;
+ ObjectClass *oc_b = (ObjectClass *)b;
+ PowerPCCPUClass *pcc_a = POWERPC_CPU_CLASS(oc_a);
+ PowerPCCPUClass *pcc_b = POWERPC_CPU_CLASS(oc_b);
+ const char *name_a = object_class_get_name(oc_a);
+ const char *name_b = object_class_get_name(oc_b);
+
+ if (strcmp(name_a, TYPE_HOST_POWERPC_CPU) == 0) {
+ return 1;
+ } else if (strcmp(name_b, TYPE_HOST_POWERPC_CPU) == 0) {
+ return -1;
+ } else {
+ /* Avoid an integer overflow during subtraction */
+ if (pcc_a->info->pvr < pcc_b->info->pvr) {
+ return -1;
+ } else if (pcc_a->info->pvr > pcc_b->info->pvr) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+}
+
+static void ppc_cpu_list_entry(gpointer data, gpointer user_data)
+{
+ ObjectClass *oc = data;
+ CPUListState *s = user_data;
+ PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
+
+ (*s->cpu_fprintf)(s->file, "PowerPC %-16s PVR %08x\n",
+ pcc->info->name, pcc->info->pvr);
+}
+
+void ppc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+ CPUListState 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_cpu_defs_entry(gpointer data, gpointer user_data)
+{
+ ObjectClass *oc = data;
+ CpuDefinitionInfoList **first = user_data;
+ PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
+ CpuDefinitionInfoList *entry;
+ CpuDefinitionInfo *info;
+
+ info = g_malloc0(sizeof(*info));
+ info->name = g_strdup(pcc->info->name);
+
+ entry = g_malloc0(sizeof(*entry));
+ entry->value = info;
+ entry->next = *first;
+ *first = entry;
}
CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
{
CpuDefinitionInfoList *cpu_list = NULL;
- int i;
+ GSList *list;
- for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) {
- CpuDefinitionInfoList *entry;
- CpuDefinitionInfo *info;
+ list = object_class_get_list(TYPE_POWERPC_CPU, false);
+ g_slist_foreach(list, ppc_cpu_defs_entry, &cpu_list);
+ g_slist_free(list);
- if (!ppc_cpu_usable(&ppc_defs[i])) {
- continue;
- }
+ return cpu_list;
+}
- info = g_malloc0(sizeof(*info));
- info->name = g_strdup(ppc_defs[i].name);
+static void ppc_cpu_def_class_init(ObjectClass *oc, void *data)
+{
+ PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
+ ppc_def_t *info = data;
- entry = g_malloc0(sizeof(*entry));
- entry->value = info;
- entry->next = cpu_list;
- cpu_list = entry;
- }
+ pcc->info = info;
+}
- return cpu_list;
+static void ppc_cpu_register_model(const ppc_def_t *def)
+{
+ TypeInfo type_info = {
+ .parent = TYPE_POWERPC_CPU,
+ .class_init = ppc_cpu_def_class_init,
+ .class_data = (void *)def,
+ };
+
+ type_info.name = g_strdup_printf("%s-" TYPE_POWERPC_CPU, def->name),
+ type_register(&type_info);
+ g_free((gpointer)type_info.name);
}
/* CPUClass::reset() */
@@ -10434,9 +10519,42 @@ static void ppc_cpu_reset(CPUState *s)
static void ppc_cpu_initfn(Object *obj)
{
PowerPCCPU *cpu = POWERPC_CPU(obj);
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
CPUPPCState *env = &cpu->env;
+ ppc_def_t *def = pcc->info;
cpu_exec_init(env);
+
+ env->msr_mask = def->msr_mask;
+ env->mmu_model = def->mmu_model;
+ env->excp_model = def->excp_model;
+ env->bus_model = def->bus_model;
+ env->insns_flags = def->insns_flags;
+ env->insns_flags2 = def->insns_flags2;
+ env->flags = def->flags;
+ env->bfd_mach = def->bfd_mach;
+ env->check_pow = def->check_pow;
+
+#if defined(TARGET_PPC64)
+ if (def->sps) {
+ env->sps = *def->sps;
+ } else if (env->mmu_model & POWERPC_MMU_64) {
+ /* Use default sets of page sizes */
+ static const struct ppc_segment_page_sizes defsps = {
+ .sps = {
+ { .page_shift = 12, /* 4K */
+ .slb_enc = 0,
+ .enc = { { .page_shift = 12, .pte_enc = 0 } }
+ },
+ { .page_shift = 24, /* 16M */
+ .slb_enc = 0x100,
+ .enc = { { .page_shift = 24, .pte_enc = 0 } }
+ },
+ },
+ };
+ env->sps = defsps;
+ }
+#endif /* defined(TARGET_PPC64) */
}
static void ppc_cpu_class_init(ObjectClass *oc, void *data)
@@ -10453,14 +10571,27 @@ static const TypeInfo ppc_cpu_type_info = {
.parent = TYPE_CPU,
.instance_size = sizeof(PowerPCCPU),
.instance_init = ppc_cpu_initfn,
- .abstract = false,
+ .abstract = true,
.class_size = sizeof(PowerPCCPUClass),
.class_init = ppc_cpu_class_init,
};
static void ppc_cpu_register_types(void)
{
+ int i;
+
type_register_static(&ppc_cpu_type_info);
+
+ for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) {
+ const ppc_def_t *def = &ppc_defs[i];
+#if defined(TARGET_PPCEMB)
+ /* When using the ppcemb target, we only support 440 style cores */
+ if (def->mmu_model != POWERPC_MMU_BOOKE) {
+ continue;
+ }
+#endif
+ ppc_cpu_register_model(def);
+ }
}
type_init(ppc_cpu_register_types)