Revision 2985b86b target-ppc/translate_init.c
b/target-ppc/translate_init.c | ||
---|---|---|
9792 | 9792 |
} |
9793 | 9793 |
|
9794 | 9794 |
/*****************************************************************************/ |
9795 |
static int create_ppc_opcodes (CPUPPCState *env, const ppc_def_t *def)
|
|
9795 |
static void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp)
|
|
9796 | 9796 |
{ |
9797 |
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); |
|
9798 |
CPUPPCState *env = &cpu->env; |
|
9799 |
const ppc_def_t *def = pcc->info; |
|
9797 | 9800 |
opcode_t *opc; |
9798 | 9801 |
|
9799 | 9802 |
fill_new_table(env->opcodes, 0x40); |
... | ... | |
9801 | 9804 |
if (((opc->handler.type & def->insns_flags) != 0) || |
9802 | 9805 |
((opc->handler.type2 & def->insns_flags2) != 0)) { |
9803 | 9806 |
if (register_insn(env->opcodes, opc) < 0) { |
9804 |
printf("*** ERROR initializing PowerPC instruction "
|
|
9805 |
"0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2, |
|
9806 |
opc->opc3); |
|
9807 |
return -1;
|
|
9807 |
error_setg(errp, "ERROR initializing PowerPC instruction "
|
|
9808 |
"0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
|
|
9809 |
opc->opc3);
|
|
9810 |
return; |
|
9808 | 9811 |
} |
9809 | 9812 |
} |
9810 | 9813 |
} |
9811 | 9814 |
fix_opcode_tables(env->opcodes); |
9812 | 9815 |
fflush(stdout); |
9813 | 9816 |
fflush(stderr); |
9814 |
|
|
9815 |
return 0; |
|
9816 | 9817 |
} |
9817 | 9818 |
|
9818 | 9819 |
#if defined(PPC_DUMP_CPU) |
... | ... | |
10026 | 10027 |
return 0; |
10027 | 10028 |
} |
10028 | 10029 |
|
10029 |
int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
|
|
10030 |
static void ppc_cpu_realize(Object *obj, Error **errp)
|
|
10030 | 10031 |
{ |
10031 |
env->msr_mask = def->msr_mask; |
|
10032 |
env->mmu_model = def->mmu_model; |
|
10033 |
env->excp_model = def->excp_model; |
|
10034 |
env->bus_model = def->bus_model; |
|
10035 |
env->insns_flags = def->insns_flags; |
|
10036 |
env->insns_flags2 = def->insns_flags2; |
|
10037 |
env->flags = def->flags; |
|
10038 |
env->bfd_mach = def->bfd_mach; |
|
10039 |
env->check_pow = def->check_pow; |
|
10040 |
|
|
10041 |
#if defined(TARGET_PPC64) |
|
10042 |
if (def->sps) |
|
10043 |
env->sps = *def->sps; |
|
10044 |
else if (env->mmu_model & POWERPC_MMU_64) { |
|
10045 |
/* Use default sets of page sizes */ |
|
10046 |
static const struct ppc_segment_page_sizes defsps = { |
|
10047 |
.sps = { |
|
10048 |
{ .page_shift = 12, /* 4K */ |
|
10049 |
.slb_enc = 0, |
|
10050 |
.enc = { { .page_shift = 12, .pte_enc = 0 } } |
|
10051 |
}, |
|
10052 |
{ .page_shift = 24, /* 16M */ |
|
10053 |
.slb_enc = 0x100, |
|
10054 |
.enc = { { .page_shift = 24, .pte_enc = 0 } } |
|
10055 |
}, |
|
10056 |
}, |
|
10057 |
}; |
|
10058 |
env->sps = defsps; |
|
10059 |
} |
|
10060 |
#endif /* defined(TARGET_PPC64) */ |
|
10032 |
PowerPCCPU *cpu = POWERPC_CPU(obj); |
|
10033 |
CPUPPCState *env = &cpu->env; |
|
10034 |
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); |
|
10035 |
ppc_def_t *def = pcc->info; |
|
10036 |
Error *local_err = NULL; |
|
10061 | 10037 |
|
10062 | 10038 |
if (kvm_enabled()) { |
10063 | 10039 |
if (kvmppc_fixup_cpu(env) != 0) { |
10064 |
fprintf(stderr, "Unable to virtualize selected CPU with KVM\n");
|
|
10065 |
exit(1);
|
|
10040 |
error_setg(errp, "Unable to virtualize selected CPU with KVM");
|
|
10041 |
return;
|
|
10066 | 10042 |
} |
10067 | 10043 |
} else { |
10068 | 10044 |
if (ppc_fixup_cpu(env) != 0) { |
10069 |
fprintf(stderr, "Unable to emulate selected CPU with TCG\n");
|
|
10070 |
exit(1);
|
|
10045 |
error_setg(errp, "Unable to emulate selected CPU with TCG");
|
|
10046 |
return;
|
|
10071 | 10047 |
} |
10072 | 10048 |
} |
10073 | 10049 |
|
10074 |
if (create_ppc_opcodes(env, def) < 0) |
|
10075 |
return -1; |
|
10050 |
create_ppc_opcodes(cpu, &local_err); |
|
10051 |
if (local_err != NULL) { |
|
10052 |
error_propagate(errp, local_err); |
|
10053 |
return; |
|
10054 |
} |
|
10076 | 10055 |
init_ppc_proc(env, def); |
10077 | 10056 |
|
10078 | 10057 |
if (def->insns_flags & PPC_FLOAT) { |
... | ... | |
10088 | 10067 |
34, "power-spe.xml", 0); |
10089 | 10068 |
} |
10090 | 10069 |
|
10070 |
qemu_init_vcpu(env); |
|
10071 |
|
|
10091 | 10072 |
#if defined(PPC_DUMP_CPU) |
10092 | 10073 |
{ |
10093 | 10074 |
const char *mmu_model, *excp_model, *bus_model; |
... | ... | |
10249 | 10230 |
dump_ppc_sprs(env); |
10250 | 10231 |
fflush(stdout); |
10251 | 10232 |
#endif |
10252 |
|
|
10253 |
return 0; |
|
10254 | 10233 |
} |
10255 | 10234 |
|
10256 |
static bool ppc_cpu_usable(const ppc_def_t *def)
|
|
10235 |
static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b)
|
|
10257 | 10236 |
{ |
10258 |
#if defined(TARGET_PPCEMB) |
|
10259 |
/* When using the ppcemb target, we only support 440 style cores */ |
|
10260 |
if (def->mmu_model != POWERPC_MMU_BOOKE) { |
|
10261 |
return false; |
|
10237 |
ObjectClass *oc = (ObjectClass *)a; |
|
10238 |
uint32_t pvr = *(uint32_t *)b; |
|
10239 |
PowerPCCPUClass *pcc = (PowerPCCPUClass *)a; |
|
10240 |
|
|
10241 |
/* -cpu host does a PVR lookup during construction */ |
|
10242 |
if (unlikely(strcmp(object_class_get_name(oc), |
|
10243 |
TYPE_HOST_POWERPC_CPU) == 0)) { |
|
10244 |
return -1; |
|
10262 | 10245 |
} |
10263 |
#endif |
|
10264 | 10246 |
|
10265 |
return true;
|
|
10247 |
return pcc->info->pvr == pvr ? 0 : -1;
|
|
10266 | 10248 |
} |
10267 | 10249 |
|
10268 |
const ppc_def_t *ppc_find_by_pvr(uint32_t pvr)
|
|
10250 |
PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr)
|
|
10269 | 10251 |
{ |
10270 |
int i; |
|
10252 |
GSList *list, *item; |
|
10253 |
PowerPCCPUClass *pcc = NULL; |
|
10271 | 10254 |
|
10272 |
for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) { |
|
10273 |
if (!ppc_cpu_usable(&ppc_defs[i])) { |
|
10274 |
continue; |
|
10275 |
} |
|
10276 |
|
|
10277 |
/* If we have an exact match, we're done */ |
|
10278 |
if (pvr == ppc_defs[i].pvr) { |
|
10279 |
return &ppc_defs[i]; |
|
10280 |
} |
|
10255 |
list = object_class_get_list(TYPE_POWERPC_CPU, false); |
|
10256 |
item = g_slist_find_custom(list, &pvr, ppc_cpu_compare_class_pvr); |
|
10257 |
if (item != NULL) { |
|
10258 |
pcc = POWERPC_CPU_CLASS(item->data); |
|
10281 | 10259 |
} |
10260 |
g_slist_free(list); |
|
10261 |
|
|
10262 |
return pcc; |
|
10263 |
} |
|
10264 |
|
|
10265 |
static gint ppc_cpu_compare_class_name(gconstpointer a, gconstpointer b) |
|
10266 |
{ |
|
10267 |
ObjectClass *oc = (ObjectClass *)a; |
|
10268 |
const char *name = b; |
|
10282 | 10269 |
|
10283 |
return NULL; |
|
10270 |
if (strncasecmp(name, object_class_get_name(oc), strlen(name)) == 0 && |
|
10271 |
strcmp(object_class_get_name(oc) + strlen(name), |
|
10272 |
"-" TYPE_POWERPC_CPU) == 0) { |
|
10273 |
return 0; |
|
10274 |
} |
|
10275 |
return -1; |
|
10284 | 10276 |
} |
10285 | 10277 |
|
10286 | 10278 |
#include <ctype.h> |
10287 | 10279 |
|
10288 |
const ppc_def_t *cpu_ppc_find_by_name (const char *name)
|
|
10280 |
static ObjectClass *ppc_cpu_class_by_name(const char *name)
|
|
10289 | 10281 |
{ |
10290 |
const ppc_def_t *ret; |
|
10282 |
GSList *list, *item; |
|
10283 |
ObjectClass *ret = NULL; |
|
10291 | 10284 |
const char *p; |
10292 |
int i, max, len;
|
|
10285 |
int i, len; |
|
10293 | 10286 |
|
10294 |
if (kvm_enabled() && (strcasecmp(name, "host") == 0)) { |
|
10295 |
return kvmppc_host_cpu_def(); |
|
10287 |
if (strcasecmp(name, "host") == 0) { |
|
10288 |
if (kvm_enabled()) { |
|
10289 |
ret = object_class_by_name(TYPE_HOST_POWERPC_CPU); |
|
10290 |
} |
|
10291 |
return ret; |
|
10296 | 10292 |
} |
10297 | 10293 |
|
10298 | 10294 |
/* Check if the given name is a PVR */ |
... | ... | |
10307 | 10303 |
if (!qemu_isxdigit(*p++)) |
10308 | 10304 |
break; |
10309 | 10305 |
} |
10310 |
if (i == 8) |
|
10311 |
return ppc_find_by_pvr(strtoul(name, NULL, 16)); |
|
10312 |
} |
|
10313 |
ret = NULL; |
|
10314 |
max = ARRAY_SIZE(ppc_defs); |
|
10315 |
for (i = 0; i < max; i++) { |
|
10316 |
if (!ppc_cpu_usable(&ppc_defs[i])) { |
|
10317 |
continue; |
|
10306 |
if (i == 8) { |
|
10307 |
ret = OBJECT_CLASS(ppc_cpu_class_by_pvr(strtoul(name, NULL, 16))); |
|
10308 |
return ret; |
|
10318 | 10309 |
} |
10310 |
} |
|
10319 | 10311 |
|
10320 |
if (strcasecmp(name, ppc_defs[i].name) == 0) {
|
|
10321 |
ret = &ppc_defs[i];
|
|
10322 |
break;
|
|
10323 |
}
|
|
10312 |
list = object_class_get_list(TYPE_POWERPC_CPU, false);
|
|
10313 |
item = g_slist_find_custom(list, name, ppc_cpu_compare_class_name);
|
|
10314 |
if (item != NULL) {
|
|
10315 |
ret = OBJECT_CLASS(item->data);
|
|
10324 | 10316 |
} |
10317 |
g_slist_free(list); |
|
10325 | 10318 |
|
10326 | 10319 |
return ret; |
10327 | 10320 |
} |
10328 | 10321 |
|
10329 |
void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf)
|
|
10322 |
PowerPCCPU *cpu_ppc_init(const char *cpu_model)
|
|
10330 | 10323 |
{ |
10331 |
int i, max; |
|
10324 |
PowerPCCPU *cpu; |
|
10325 |
CPUPPCState *env; |
|
10326 |
ObjectClass *oc; |
|
10327 |
Error *err = NULL; |
|
10332 | 10328 |
|
10333 |
max = ARRAY_SIZE(ppc_defs); |
|
10334 |
for (i = 0; i < max; i++) { |
|
10335 |
if (!ppc_cpu_usable(&ppc_defs[i])) { |
|
10336 |
continue; |
|
10337 |
} |
|
10329 |
oc = ppc_cpu_class_by_name(cpu_model); |
|
10330 |
if (oc == NULL) { |
|
10331 |
return NULL; |
|
10332 |
} |
|
10338 | 10333 |
|
10339 |
(*cpu_fprintf)(f, "PowerPC %-16s PVR %08x\n", |
|
10340 |
ppc_defs[i].name, ppc_defs[i].pvr); |
|
10334 |
cpu = POWERPC_CPU(object_new(object_class_get_name(oc))); |
|
10335 |
env = &cpu->env; |
|
10336 |
|
|
10337 |
if (tcg_enabled()) { |
|
10338 |
ppc_translate_init(); |
|
10341 | 10339 |
} |
10340 |
|
|
10341 |
env->cpu_model_str = cpu_model; |
|
10342 |
|
|
10343 |
ppc_cpu_realize(OBJECT(cpu), &err); |
|
10344 |
if (err != NULL) { |
|
10345 |
fprintf(stderr, "%s\n", error_get_pretty(err)); |
|
10346 |
error_free(err); |
|
10347 |
object_delete(OBJECT(cpu)); |
|
10348 |
return NULL; |
|
10349 |
} |
|
10350 |
|
|
10351 |
return cpu; |
|
10352 |
} |
|
10353 |
|
|
10354 |
/* Sort by PVR, ordering special case "host" last. */ |
|
10355 |
static gint ppc_cpu_list_compare(gconstpointer a, gconstpointer b) |
|
10356 |
{ |
|
10357 |
ObjectClass *oc_a = (ObjectClass *)a; |
|
10358 |
ObjectClass *oc_b = (ObjectClass *)b; |
|
10359 |
PowerPCCPUClass *pcc_a = POWERPC_CPU_CLASS(oc_a); |
|
10360 |
PowerPCCPUClass *pcc_b = POWERPC_CPU_CLASS(oc_b); |
|
10361 |
const char *name_a = object_class_get_name(oc_a); |
|
10362 |
const char *name_b = object_class_get_name(oc_b); |
|
10363 |
|
|
10364 |
if (strcmp(name_a, TYPE_HOST_POWERPC_CPU) == 0) { |
|
10365 |
return 1; |
|
10366 |
} else if (strcmp(name_b, TYPE_HOST_POWERPC_CPU) == 0) { |
|
10367 |
return -1; |
|
10368 |
} else { |
|
10369 |
/* Avoid an integer overflow during subtraction */ |
|
10370 |
if (pcc_a->info->pvr < pcc_b->info->pvr) { |
|
10371 |
return -1; |
|
10372 |
} else if (pcc_a->info->pvr > pcc_b->info->pvr) { |
|
10373 |
return 1; |
|
10374 |
} else { |
|
10375 |
return 0; |
|
10376 |
} |
|
10377 |
} |
|
10378 |
} |
|
10379 |
|
|
10380 |
static void ppc_cpu_list_entry(gpointer data, gpointer user_data) |
|
10381 |
{ |
|
10382 |
ObjectClass *oc = data; |
|
10383 |
CPUListState *s = user_data; |
|
10384 |
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); |
|
10385 |
|
|
10386 |
(*s->cpu_fprintf)(s->file, "PowerPC %-16s PVR %08x\n", |
|
10387 |
pcc->info->name, pcc->info->pvr); |
|
10388 |
} |
|
10389 |
|
|
10390 |
void ppc_cpu_list(FILE *f, fprintf_function cpu_fprintf) |
|
10391 |
{ |
|
10392 |
CPUListState s = { |
|
10393 |
.file = f, |
|
10394 |
.cpu_fprintf = cpu_fprintf, |
|
10395 |
}; |
|
10396 |
GSList *list; |
|
10397 |
|
|
10398 |
list = object_class_get_list(TYPE_POWERPC_CPU, false); |
|
10399 |
list = g_slist_sort(list, ppc_cpu_list_compare); |
|
10400 |
g_slist_foreach(list, ppc_cpu_list_entry, &s); |
|
10401 |
g_slist_free(list); |
|
10402 |
} |
|
10403 |
|
|
10404 |
static void ppc_cpu_defs_entry(gpointer data, gpointer user_data) |
|
10405 |
{ |
|
10406 |
ObjectClass *oc = data; |
|
10407 |
CpuDefinitionInfoList **first = user_data; |
|
10408 |
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); |
|
10409 |
CpuDefinitionInfoList *entry; |
|
10410 |
CpuDefinitionInfo *info; |
|
10411 |
|
|
10412 |
info = g_malloc0(sizeof(*info)); |
|
10413 |
info->name = g_strdup(pcc->info->name); |
|
10414 |
|
|
10415 |
entry = g_malloc0(sizeof(*entry)); |
|
10416 |
entry->value = info; |
|
10417 |
entry->next = *first; |
|
10418 |
*first = entry; |
|
10342 | 10419 |
} |
10343 | 10420 |
|
10344 | 10421 |
CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp) |
10345 | 10422 |
{ |
10346 | 10423 |
CpuDefinitionInfoList *cpu_list = NULL; |
10347 |
int i;
|
|
10424 |
GSList *list;
|
|
10348 | 10425 |
|
10349 |
for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) {
|
|
10350 |
CpuDefinitionInfoList *entry;
|
|
10351 |
CpuDefinitionInfo *info;
|
|
10426 |
list = object_class_get_list(TYPE_POWERPC_CPU, false);
|
|
10427 |
g_slist_foreach(list, ppc_cpu_defs_entry, &cpu_list);
|
|
10428 |
g_slist_free(list);
|
|
10352 | 10429 |
|
10353 |
if (!ppc_cpu_usable(&ppc_defs[i])) { |
|
10354 |
continue; |
|
10355 |
} |
|
10430 |
return cpu_list; |
|
10431 |
} |
|
10356 | 10432 |
|
10357 |
info = g_malloc0(sizeof(*info)); |
|
10358 |
info->name = g_strdup(ppc_defs[i].name); |
|
10433 |
static void ppc_cpu_def_class_init(ObjectClass *oc, void *data) |
|
10434 |
{ |
|
10435 |
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); |
|
10436 |
ppc_def_t *info = data; |
|
10359 | 10437 |
|
10360 |
entry = g_malloc0(sizeof(*entry)); |
|
10361 |
entry->value = info; |
|
10362 |
entry->next = cpu_list; |
|
10363 |
cpu_list = entry; |
|
10364 |
} |
|
10438 |
pcc->info = info; |
|
10439 |
} |
|
10365 | 10440 |
|
10366 |
return cpu_list; |
|
10441 |
static void ppc_cpu_register_model(const ppc_def_t *def) |
|
10442 |
{ |
|
10443 |
TypeInfo type_info = { |
|
10444 |
.parent = TYPE_POWERPC_CPU, |
|
10445 |
.class_init = ppc_cpu_def_class_init, |
|
10446 |
.class_data = (void *)def, |
|
10447 |
}; |
|
10448 |
|
|
10449 |
type_info.name = g_strdup_printf("%s-" TYPE_POWERPC_CPU, def->name), |
|
10450 |
type_register(&type_info); |
|
10451 |
g_free((gpointer)type_info.name); |
|
10367 | 10452 |
} |
10368 | 10453 |
|
10369 | 10454 |
/* CPUClass::reset() */ |
... | ... | |
10434 | 10519 |
static void ppc_cpu_initfn(Object *obj) |
10435 | 10520 |
{ |
10436 | 10521 |
PowerPCCPU *cpu = POWERPC_CPU(obj); |
10522 |
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); |
|
10437 | 10523 |
CPUPPCState *env = &cpu->env; |
10524 |
ppc_def_t *def = pcc->info; |
|
10438 | 10525 |
|
10439 | 10526 |
cpu_exec_init(env); |
10527 |
|
|
10528 |
env->msr_mask = def->msr_mask; |
|
10529 |
env->mmu_model = def->mmu_model; |
|
10530 |
env->excp_model = def->excp_model; |
|
10531 |
env->bus_model = def->bus_model; |
|
10532 |
env->insns_flags = def->insns_flags; |
|
10533 |
env->insns_flags2 = def->insns_flags2; |
|
10534 |
env->flags = def->flags; |
|
10535 |
env->bfd_mach = def->bfd_mach; |
|
10536 |
env->check_pow = def->check_pow; |
|
10537 |
|
|
10538 |
#if defined(TARGET_PPC64) |
|
10539 |
if (def->sps) { |
|
10540 |
env->sps = *def->sps; |
|
10541 |
} else if (env->mmu_model & POWERPC_MMU_64) { |
|
10542 |
/* Use default sets of page sizes */ |
|
10543 |
static const struct ppc_segment_page_sizes defsps = { |
|
10544 |
.sps = { |
|
10545 |
{ .page_shift = 12, /* 4K */ |
|
10546 |
.slb_enc = 0, |
|
10547 |
.enc = { { .page_shift = 12, .pte_enc = 0 } } |
|
10548 |
}, |
|
10549 |
{ .page_shift = 24, /* 16M */ |
|
10550 |
.slb_enc = 0x100, |
|
10551 |
.enc = { { .page_shift = 24, .pte_enc = 0 } } |
|
10552 |
}, |
|
10553 |
}, |
|
10554 |
}; |
|
10555 |
env->sps = defsps; |
|
10556 |
} |
|
10557 |
#endif /* defined(TARGET_PPC64) */ |
|
10440 | 10558 |
} |
10441 | 10559 |
|
10442 | 10560 |
static void ppc_cpu_class_init(ObjectClass *oc, void *data) |
... | ... | |
10453 | 10571 |
.parent = TYPE_CPU, |
10454 | 10572 |
.instance_size = sizeof(PowerPCCPU), |
10455 | 10573 |
.instance_init = ppc_cpu_initfn, |
10456 |
.abstract = false,
|
|
10574 |
.abstract = true,
|
|
10457 | 10575 |
.class_size = sizeof(PowerPCCPUClass), |
10458 | 10576 |
.class_init = ppc_cpu_class_init, |
10459 | 10577 |
}; |
10460 | 10578 |
|
10461 | 10579 |
static void ppc_cpu_register_types(void) |
10462 | 10580 |
{ |
10581 |
int i; |
|
10582 |
|
|
10463 | 10583 |
type_register_static(&ppc_cpu_type_info); |
10584 |
|
|
10585 |
for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) { |
|
10586 |
const ppc_def_t *def = &ppc_defs[i]; |
|
10587 |
#if defined(TARGET_PPCEMB) |
|
10588 |
/* When using the ppcemb target, we only support 440 style cores */ |
|
10589 |
if (def->mmu_model != POWERPC_MMU_BOOKE) { |
|
10590 |
continue; |
|
10591 |
} |
|
10592 |
#endif |
|
10593 |
ppc_cpu_register_model(def); |
|
10594 |
} |
|
10464 | 10595 |
} |
10465 | 10596 |
|
10466 | 10597 |
type_init(ppc_cpu_register_types) |
Also available in: Unified diff