uint32_t gservers_prop[smt_threads * 2];
int index = ppc_get_vcpu_dt_id(cpu);
+ if (cpu->cpu_version) {
+ ret = fdt_setprop(fdt, offset, "cpu-version",
+ &cpu->cpu_version, sizeof(cpu->cpu_version));
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
/* Build interrupt servers and gservers properties */
for (i = 0; i < smt_threads; i++) {
servers_prop[i] = cpu_to_be32(index + i);
kvmppc_set_papr(cpu);
}
+ if (cpu->max_compat) {
+ if (ppc_set_compat(cpu, cpu->max_compat) < 0) {
+ exit(1);
+ }
+ }
+
xics_cpu_setup(spapr->icp, cpu);
qemu_register_reset(spapr_cpu_reset, cpu);
* @env: #CPUPPCState
* @cpu_dt_id: CPU index used in the device tree. KVM uses this index too
* @max_compat: Maximal supported logical PVR from the command line
+ * @cpu_version: Current logical PVR, zero if in "raw" mode
*
* A PowerPC CPU.
*/
CPUPPCState env;
int cpu_dt_id;
uint32_t max_compat;
+ uint32_t cpu_version;
};
static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
void ppc_store_msr (CPUPPCState *env, target_ulong value);
void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf);
+int ppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version);
/* Time-base and decrementer management */
#ifndef NO_CPU_IO_DEFS
#define SPR_LPCR (0x13E)
#define SPR_BOOKE_DVC2 (0x13F)
#define SPR_BOOKE_TSR (0x150)
+#define SPR_PCR (0x152)
#define SPR_BOOKE_TCR (0x154)
#define SPR_BOOKE_TLB0PS (0x158)
#define SPR_BOOKE_TLB1PS (0x159)
PPC_INTERRUPT_PERFM, /* Performance monitor interrupt */
};
+/* Processor Compatibility mask (PCR) */
+enum {
+ PCR_COMPAT_2_05 = 1ull << (63-62),
+ PCR_COMPAT_2_06 = 1ull << (63-61),
+ PCR_VEC_DIS = 1ull << (63-0), /* Vec. disable (bit NA since POWER8) */
+ PCR_VSX_DIS = 1ull << (63-1), /* VSX disable (bit NA since POWER8) */
+ PCR_TM_DIS = 1ull << (63-2), /* Trans. memory disable (POWER8) */
+};
+
/*****************************************************************************/
static inline target_ulong cpu_read_xer(CPUPPCState *env)
/* Can't find information on what this should be on reset. This
* value is the one used by 74xx processors. */
vscr_init(env, 0x00010000);
+
+ /*
+ * Register PCR to report POWERPC_EXCP_PRIV_REG instead of
+ * POWERPC_EXCP_INVAL_SPR.
+ */
+ spr_register(env, SPR_PCR, "PCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
+ 0x00000000);
}
POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
}
}
+int ppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version)
+{
+ int ret = 0;
+ CPUPPCState *env = &cpu->env;
+
+ cpu->cpu_version = cpu_version;
+
+ switch (cpu_version) {
+ case CPU_POWERPC_LOGICAL_2_05:
+ env->spr[SPR_PCR] = PCR_COMPAT_2_05;
+ break;
+ case CPU_POWERPC_LOGICAL_2_06:
+ env->spr[SPR_PCR] = PCR_COMPAT_2_06;
+ break;
+ case CPU_POWERPC_LOGICAL_2_06_PLUS:
+ env->spr[SPR_PCR] = PCR_COMPAT_2_06;
+ break;
+ default:
+ env->spr[SPR_PCR] = 0;
+ break;
+ }
+
+ return ret;
+}
+
static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b)
{
ObjectClass *oc = (ObjectClass *)a;