diff options
-rw-r--r-- | target-ppc/cpu-models.c | 1 | ||||
-rw-r--r-- | target-ppc/cpu-models.h | 5 | ||||
-rw-r--r-- | target-ppc/cpu-qom.h | 2 | ||||
-rw-r--r-- | target-ppc/kvm.c | 4 | ||||
-rw-r--r-- | target-ppc/translate_init.c | 44 |
5 files changed, 56 insertions, 0 deletions
diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c index 8dea560383..04d88c574b 100644 --- a/target-ppc/cpu-models.c +++ b/target-ppc/cpu-models.c @@ -44,6 +44,7 @@ PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); \ \ pcc->pvr = _pvr; \ + pcc->pvr_mask = CPU_POWERPC_DEFAULT_MASK; \ pcc->svr = _svr; \ dc->desc = _desc; \ } \ diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h index d9145d147f..731ec4a6c2 100644 --- a/target-ppc/cpu-models.h +++ b/target-ppc/cpu-models.h @@ -39,6 +39,7 @@ extern PowerPCCPUAlias ppc_cpu_aliases[]; /*****************************************************************************/ /* PVR definitions for most known PowerPC */ enum { + CPU_POWERPC_DEFAULT_MASK = 0xFFFFFFFF, /* PowerPC 401 family */ /* Generic PowerPC 401 */ #define CPU_POWERPC_401 CPU_POWERPC_401G2 @@ -552,10 +553,14 @@ enum { CPU_POWERPC_POWER6 = 0x003E0000, CPU_POWERPC_POWER6_5 = 0x0F000001, /* POWER6 in POWER5 mode */ CPU_POWERPC_POWER6A = 0x0F000002, + CPU_POWERPC_POWER7_BASE = 0x003F0000, + CPU_POWERPC_POWER7_MASK = 0xFFFF0000, CPU_POWERPC_POWER7_v20 = 0x003F0200, CPU_POWERPC_POWER7_v21 = 0x003F0201, CPU_POWERPC_POWER7_v23 = 0x003F0203, CPU_POWERPC_POWER7P_v21 = 0x004A0201, + CPU_POWERPC_POWER8_BASE = 0x004B0000, + CPU_POWERPC_POWER8_MASK = 0xFFFF0000, CPU_POWERPC_POWER8_v10 = 0x004B0100, CPU_POWERPC_970 = 0x00390202, CPU_POWERPC_970FX_v10 = 0x00391100, diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h index 827e5dd0e1..72b22329b0 100644 --- a/target-ppc/cpu-qom.h +++ b/target-ppc/cpu-qom.h @@ -54,6 +54,7 @@ typedef struct PowerPCCPUClass { void (*parent_reset)(CPUState *cpu); uint32_t pvr; + uint32_t pvr_mask; uint32_t svr; uint64_t insns_flags; uint64_t insns_flags2; @@ -99,6 +100,7 @@ static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env) #define ENV_OFFSET offsetof(PowerPCCPU, env) PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr); +PowerPCCPUClass *ppc_cpu_class_by_pvr_mask(uint32_t pvr); void ppc_cpu_do_interrupt(CPUState *cpu); void ppc_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 29a8dedf4c..781b72f1ea 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -1745,6 +1745,7 @@ static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data) uint32_t icache_size = kvmppc_read_int_cpu_dt("i-cache-size"); /* Now fix up the class with information we can query from the host */ + pcc->pvr = mfpvr(); if (vmx != -1) { /* Only override when we know what the host supports */ @@ -1795,6 +1796,9 @@ static int kvm_ppc_register_host_cpu_type(void) pvr_pcc = ppc_cpu_class_by_pvr(host_pvr); if (pvr_pcc == NULL) { + pvr_pcc = ppc_cpu_class_by_pvr_mask(host_pvr); + } + if (pvr_pcc == NULL) { return -1; } type_info.parent = object_class_get_name(OBJECT_CLASS(pvr_pcc)); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 47825ac543..3d3952c329 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7221,6 +7221,8 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) dc->fw_name = "PowerPC,POWER7"; dc->desc = "POWER7"; + pcc->pvr = CPU_POWERPC_POWER7_BASE; + pcc->pvr_mask = CPU_POWERPC_POWER7_MASK; pcc->init_proc = init_proc_POWER7; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | @@ -7256,6 +7258,8 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) dc->fw_name = "PowerPC,POWER8"; dc->desc = "POWER8"; + pcc->pvr = CPU_POWERPC_POWER8_BASE; + pcc->pvr_mask = CPU_POWERPC_POWER8_MASK; pcc->init_proc = init_proc_POWER7; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -8188,6 +8192,44 @@ PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr) return pcc; } +static gint ppc_cpu_compare_class_pvr_mask(gconstpointer a, gconstpointer b) +{ + ObjectClass *oc = (ObjectClass *)a; + uint32_t pvr = *(uint32_t *)b; + PowerPCCPUClass *pcc = (PowerPCCPUClass *)a; + gint ret; + + /* -cpu host does a PVR lookup during construction */ + if (unlikely(strcmp(object_class_get_name(oc), + TYPE_HOST_POWERPC_CPU) == 0)) { + return -1; + } + +#if defined(TARGET_PPCEMB) + if (pcc->mmu_model != POWERPC_MMU_BOOKE) { + return -1; + } +#endif + ret = (((pcc->pvr & pcc->pvr_mask) == (pvr & pcc->pvr_mask)) ? 0 : -1); + + return ret; +} + +PowerPCCPUClass *ppc_cpu_class_by_pvr_mask(uint32_t pvr) +{ + GSList *list, *item; + PowerPCCPUClass *pcc = NULL; + + list = object_class_get_list(TYPE_POWERPC_CPU, true); + item = g_slist_find_custom(list, &pvr, ppc_cpu_compare_class_pvr_mask); + 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; @@ -8559,6 +8601,8 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); pcc->parent_realize = dc->realize; + pcc->pvr = CPU_POWERPC_DEFAULT_MASK; + pcc->pvr_mask = CPU_POWERPC_DEFAULT_MASK; dc->realize = ppc_cpu_realizefn; dc->unrealize = ppc_cpu_unrealizefn; |