To be able to boot on newer hardware that the software support, PowerISA defines a logical PVR, one per every PowerISA specification version from 2.04.
This adds the "compat" option which takes values 205 or 206 and forces QEMU to boot the guest with a logical PVR (CPU_POWERPC_LOGICAL_2_05 or CPU_POWERPC_LOGICAL_2_06). The guest reads the logical PVR value from "cpu-version" property of a CPU device node. Cc: Nikunj A Dadhania <nik...@linux.vnet.ibm.com> Cc: Andreas Färber <afaer...@suse.de> Signed-off-by: Alexey Kardashevskiy <a...@ozlabs.ru> --- hw/ppc/spapr.c | 13 ++++++++- target-ppc/cpu-models.h | 16 +++++++++++ target-ppc/cpu.h | 4 +++ target-ppc/translate_init.c | 67 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 1 deletion(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 7e53a5f..9fcbd96 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -206,6 +206,7 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr) CPU_FOREACH(cpu) { DeviceClass *dc = DEVICE_GET_CLASS(cpu); + CPUPPCState *env = &POWERPC_CPU(cpu)->env; uint32_t associativity[] = {cpu_to_be32(0x5), cpu_to_be32(0x0), cpu_to_be32(0x0), @@ -238,6 +239,14 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr) if (ret < 0) { return ret; } + + if (env->compat) { + ret = fdt_setprop(fdt, offset, "cpu-version", + &env->compat, sizeof(env->compat)); + if (ret < 0) { + return ret; + } + } } return ret; } @@ -1101,7 +1110,7 @@ static SaveVMHandlers savevm_htab_handlers = { static void ppc_spapr_init(QEMUMachineInitArgs *args) { ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; + const char *cpu_model; const char *kernel_filename = args->kernel_filename; const char *kernel_cmdline = args->kernel_cmdline; const char *initrd_filename = args->initrd_filename; @@ -1121,6 +1130,8 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) msi_supported = true; + cpu_model = qemu_opt_get(qemu_get_cpu_opts(), "type"); + spapr = g_malloc0(sizeof(*spapr)); QLIST_INIT(&spapr->phbs); diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h index 49ba4a4..38f38d1 100644 --- a/target-ppc/cpu-models.h +++ b/target-ppc/cpu-models.h @@ -583,6 +583,16 @@ enum { CPU_POWERPC_RS64II = 0x00340000, CPU_POWERPC_RS64III = 0x00360000, CPU_POWERPC_RS64IV = 0x00370000, + + /* Logical CPUs */ + CPU_POWERPC_LOGICAL_MASK = 0xFFFFFFFF, + 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, + #endif /* defined(TARGET_PPC64) */ /* Original POWER */ /* XXX: should be POWER (RIOS), RSC3308, RSC4608, @@ -745,4 +755,10 @@ enum { POWERPC_SVR_8641D = 0x80900121, }; +/* Processor Compatibility Register (PCR) */ +enum { + POWERPC_ISA_COMPAT_2_05 = 1ULL << 62, + POWERPC_ISA_COMPAT_2_06 = 1ULL << 61, +}; + #endif diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index bb84767..8e30518 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1006,6 +1006,9 @@ struct CPUPPCState { /* Device control registers */ ppc_dcr_t *dcr_env; + /* Architecture compatibility mode PVR */ + uint32_t compat; + int dcache_line_size; int icache_line_size; @@ -1330,6 +1333,7 @@ static inline int cpu_mmu_index (CPUPPCState *env) #define SPR_BOOKE_DVC1 (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) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index c030a20..b297fb3 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -28,6 +28,7 @@ #include "mmu-hash32.h" #include "mmu-hash64.h" #include "qemu/error-report.h" +#include "qapi/visitor.h" //#define PPC_DUMP_CPU //#define PPC_DEBUG_SPR @@ -7201,6 +7202,10 @@ static void init_proc_POWER7 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic, 0x00000000); + spr_register(env, SPR_PCR, "PCR", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + 0x00000000); #if !defined(CONFIG_USER_ONLY) env->slb_nr = 32; #endif @@ -7330,6 +7335,57 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) } #endif /* defined (TARGET_PPC64) */ +static void powerpc_get_compat(Object *obj, Visitor *v, + void *opaque, const char *name, Error **errp) +{ + PowerPCCPU *cpu = POWERPC_CPU(obj); + int64_t value = 0; + + switch (cpu->env.compat) { + case CPU_POWERPC_LOGICAL_2_05: + value = 205; + break; + case CPU_POWERPC_LOGICAL_2_06: + value = 206; + break; + case 0: + break; + default: + perror("Unsupported mode, only are 205, 206 supported\n"); + break; + } + + visit_type_int(v, &value, name, errp); +} + +static void powerpc_set_compat(Object *obj, Visitor *v, + void *opaque, const char *name, Error **errp) +{ + PowerPCCPU *cpu = POWERPC_CPU(obj); + Error *error = NULL; + int64_t value; + + visit_type_int(v, &value, name, &error); + if (error) { + error_propagate(errp, error); + return; + } + + switch (value) { + case 0: + cpu->env.compat = 0; + break; + case 205: + cpu->env.compat = CPU_POWERPC_LOGICAL_2_05; + break; + case 206: + cpu->env.compat = CPU_POWERPC_LOGICAL_2_06; + break; + default: + perror("Unsupported mode, only are 205, 206 supported\n"); + return; + } +} /*****************************************************************************/ /* Generic CPU instantiation routine */ @@ -7497,6 +7553,12 @@ static void init_ppc_proc(PowerPCCPU *cpu) "registered.\n" " Attempt QEMU to crash very soon !\n"); } + + if (env->spr_cb[SPR_PCR].oea_read) { + object_property_add(OBJECT(cpu), "compat", "int", + powerpc_get_compat, powerpc_set_compat, + NULL, NULL, NULL); + } } #if defined(PPC_DUMP_CPU) @@ -8376,6 +8438,10 @@ PowerPCCPU *cpu_ppc_init(const char *cpu_model) return NULL; } + if (cpu_parse_options(CPU(cpu))) { + return NULL; + } + return cpu; } @@ -8674,6 +8740,7 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) #endif dc->fw_name = "PowerPC,UNKNOWN"; + cc->parse_options = cpu_default_parse_options_func; } static const TypeInfo ppc_cpu_type_info = { -- 1.8.4.rc4