target-ppc: Add "compat" CPU option

PowerISA defines a compatibility mode for server POWERPC CPUs which
is supported by the PCR special register which is hypervisor privileged.
To support this mode for guests, SPAPR defines a set of virtual PVRs,
one per PowerISA spec version. When a hypervisor needs a guest to work in
a compatibility mode, it puts a virtual PVR value into @cpu-version
property of a CPU node.

This introduces a "compat" CPU option which defines maximal compatibility
mode enabled. The supported modes are power6/power7/power8.

This does not change the existing behaviour, new property will be used
by next patches.

Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
Alexey Kardashevskiy 2014-05-23 12:26:50 +10:00 committed by Alexander Graf
parent af354f19a9
commit 8dfa3a5e85
3 changed files with 87 additions and 0 deletions

View file

@ -595,6 +595,16 @@ enum {
CPU_POWERPC_PA6T = 0x00900000,
};
/* Logical PVR definitions for sPAPR */
enum {
CPU_POWERPC_LOGICAL_2_04 = 0x0F000001,
CPU_POWERPC_LOGICAL_2_05 = 0x0F000002,
CPU_POWERPC_LOGICAL_2_06 = 0x0F000003,
CPU_POWERPC_LOGICAL_2_06_PLUS = 0x0F100003,
CPU_POWERPC_LOGICAL_2_07 = 0x0F000004,
CPU_POWERPC_LOGICAL_2_08 = 0x0F000005,
};
/* System version register (used on MPC 8xxx) */
enum {
POWERPC_SVR_NONE = 0x00000000,

View file

@ -83,6 +83,7 @@ typedef struct PowerPCCPUClass {
* PowerPCCPU:
* @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
*
* A PowerPC CPU.
*/
@ -93,6 +94,7 @@ struct PowerPCCPU {
CPUPPCState env;
int cpu_dt_id;
uint32_t max_compat;
};
static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)

View file

@ -28,6 +28,8 @@
#include "mmu-hash32.h"
#include "mmu-hash64.h"
#include "qemu/error-report.h"
#include "qapi/visitor.h"
#include "hw/qdev-properties.h"
//#define PPC_DUMP_CPU
//#define PPC_DEBUG_SPR
@ -7680,6 +7682,76 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
pcc->l1_icache_size = 0x10000;
}
static void powerpc_get_compat(Object *obj, Visitor *v,
void *opaque, const char *name, Error **errp)
{
char *value = (char *)"";
Property *prop = opaque;
uint32_t *max_compat = qdev_get_prop_ptr(DEVICE(obj), prop);
switch (*max_compat) {
case CPU_POWERPC_LOGICAL_2_05:
value = (char *)"power6";
break;
case CPU_POWERPC_LOGICAL_2_06:
value = (char *)"power7";
break;
case CPU_POWERPC_LOGICAL_2_07:
value = (char *)"power8";
break;
case 0:
break;
default:
error_setg(errp, "Internal error: compat is set to %x",
max_compat ? *max_compat : -1);
break;
}
visit_type_str(v, &value, name, errp);
}
static void powerpc_set_compat(Object *obj, Visitor *v,
void *opaque, const char *name, Error **errp)
{
Error *error = NULL;
char *value = NULL;
Property *prop = opaque;
uint32_t *max_compat = qdev_get_prop_ptr(DEVICE(obj), prop);
visit_type_str(v, &value, name, &error);
if (error) {
error_propagate(errp, error);
return;
}
if (strcmp(value, "power6") == 0) {
*max_compat = CPU_POWERPC_LOGICAL_2_05;
} else if (strcmp(value, "power7") == 0) {
*max_compat = CPU_POWERPC_LOGICAL_2_06;
} else if (strcmp(value, "power8") == 0) {
*max_compat = CPU_POWERPC_LOGICAL_2_07;
} else {
error_setg(errp, "Invalid compatibility mode \"%s\"", value);
}
g_free(value);
}
static PropertyInfo powerpc_compat_propinfo = {
.name = "str",
.legacy_name = "powerpc-server-compat",
.get = powerpc_get_compat,
.set = powerpc_set_compat,
};
#define DEFINE_PROP_POWERPC_COMPAT(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, powerpc_compat_propinfo, uint32_t)
static Property powerpc_servercpu_properties[] = {
DEFINE_PROP_POWERPC_COMPAT("compat", PowerPCCPU, max_compat),
DEFINE_PROP_END_OF_LIST(),
};
static void init_proc_POWER7 (CPUPPCState *env)
{
gen_spr_ne_601(env);
@ -7766,6 +7838,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
dc->fw_name = "PowerPC,POWER7";
dc->desc = "POWER7";
dc->props = powerpc_servercpu_properties;
pcc->pvr = CPU_POWERPC_POWER7_BASE;
pcc->pvr_mask = CPU_POWERPC_POWER7_MASK;
pcc->init_proc = init_proc_POWER7;
@ -7825,6 +7898,7 @@ POWERPC_FAMILY(POWER7P)(ObjectClass *oc, void *data)
dc->fw_name = "PowerPC,POWER7+";
dc->desc = "POWER7+";
dc->props = powerpc_servercpu_properties;
pcc->pvr = CPU_POWERPC_POWER7P_BASE;
pcc->pvr_mask = CPU_POWERPC_POWER7P_MASK;
pcc->init_proc = init_proc_POWER7;
@ -7896,6 +7970,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
dc->fw_name = "PowerPC,POWER8";
dc->desc = "POWER8";
dc->props = powerpc_servercpu_properties;
pcc->pvr = CPU_POWERPC_POWER8_BASE;
pcc->pvr_mask = CPU_POWERPC_POWER8_MASK;
pcc->init_proc = init_proc_POWER8;