diff options
author | Alexey Kardashevskiy <aik@ozlabs.ru> | 2014-05-23 12:26:50 +1000 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2014-06-16 13:24:37 +0200 |
commit | 8dfa3a5e85eca94a93b1495136f49c5776fd5ada (patch) | |
tree | 7726147b23a12b6653e98e5b4d86ec52205f679b | |
parent | af354f19a9b6a655eac1c49b66d3be021e7ed3d9 (diff) | |
download | qemu-8dfa3a5e85eca94a93b1495136f49c5776fd5ada.zip qemu-8dfa3a5e85eca94a93b1495136f49c5776fd5ada.tar.gz qemu-8dfa3a5e85eca94a93b1495136f49c5776fd5ada.tar.bz2 |
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>
-rw-r--r-- | target-ppc/cpu-models.h | 10 | ||||
-rw-r--r-- | target-ppc/cpu-qom.h | 2 | ||||
-rw-r--r-- | target-ppc/translate_init.c | 75 |
3 files changed, 87 insertions, 0 deletions
diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h index 9a003b4..db75896 100644 --- a/target-ppc/cpu-models.h +++ b/target-ppc/cpu-models.h @@ -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, diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h index 046ea0e..533de8f 100644 --- a/target-ppc/cpu-qom.h +++ b/target-ppc/cpu-qom.h @@ -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) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 16ecada..2e273dcf 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -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; |