diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 99b843ba2f..9dde61a667 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -4776,8 +4776,14 @@ DEFINE_SPAPR_MACHINE(10, 1); */ static void spapr_machine_10_0_class_options(MachineClass *mc) { + static GlobalProperty spapr_compat_10_0[] = { + { TYPE_POWERPC_CPU, "rtas-stopped-state", "false" }, + }; + spapr_machine_10_1_class_options(mc); compat_props_add(mc->compat_props, hw_compat_10_0, hw_compat_10_0_len); + compat_props_add(mc->compat_props, spapr_compat_10_0, + G_N_ELEMENTS(spapr_compat_10_0)); } DEFINE_SPAPR_MACHINE(10, 0); diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 787020f6f9..bbd661e96c 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1529,6 +1529,7 @@ struct ArchCPU { void *machine_data; int32_t node_id; /* NUMA node this CPU belongs to */ PPCHash64Options *hash64_opts; + bool rtas_stopped_state; /* Those resources are used only during code translation */ /* opcode handlers */ diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 86ead740ee..8dac1cd812 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -55,6 +55,11 @@ /* #define PPC_DEBUG_SPR */ /* #define USE_APPLE_GDB */ +static const Property powerpc_cpu_properties[] = { + DEFINE_PROP_BOOL("rtas-stopped-state", PowerPCCPU, + rtas_stopped_state, true), +}; + static inline void vscr_init(CPUPPCState *env, uint32_t val) { /* Altivec always uses round-to-nearest */ @@ -7529,6 +7534,8 @@ static void ppc_cpu_class_init(ObjectClass *oc, const void *data) &pcc->parent_unrealize); pcc->pvr_match = ppc_pvr_match_default; + device_class_set_props(dc, powerpc_cpu_properties); + resettable_class_set_parent_phases(rc, NULL, ppc_cpu_reset_hold, NULL, &pcc->parent_phases); diff --git a/target/ppc/machine.c b/target/ppc/machine.c index d72e5ecb94..49cfdc6d67 100644 --- a/target/ppc/machine.c +++ b/target/ppc/machine.c @@ -257,6 +257,45 @@ static int cpu_post_load(void *opaque, int version_id) ppc_store_sdr1(env, env->spr[SPR_SDR1]); } + if (!cpu->rtas_stopped_state) { + /* + * The source QEMU doesn't have fb802acdc8 and still uses halt + + * PM bits in LPCR to implement RTAS stopped state. The new (this) + * QEMU will have put the secondary vcpus in stopped state, + * waiting for the start-cpu RTAS call. That call will never come + * if the source cpus were already running. Try to infer the cpus + * state and set env->quiesced accordingly. + * + * env->quiesced = true ==> the cpu is waiting to start + * env->quiesced = false ==> the cpu is running (unless halted) + */ + + /* + * Halted _could_ mean quiesced, but it could also be cede, + * confer_self, power management, etc. + */ + if (CPU(cpu)->halted) { + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + /* + * Both the PSSCR_EC bit and LPCR PM bits set at cpu reset + * and rtas_stop and cleared at rtas_start, it's a good + * heuristic. + */ + if ((env->spr[SPR_PSSCR] & PSSCR_EC) && + (env->spr[SPR_LPCR] & pcc->lpcr_pm)) { + env->quiesced = true; + } else { + env->quiesced = false; + } + } else { + /* + * Old QEMU sets halted during rtas_stop_self. Not halted, + * therefore definitely not quiesced. + */ + env->quiesced = false; + } + } + post_load_update_msr(env); if (tcg_enabled()) { @@ -649,6 +688,28 @@ static const VMStateDescription vmstate_reservation = { } }; +static bool rtas_stopped_needed(void *opaque) +{ + PowerPCCPU *cpu = opaque; + + return cpu->rtas_stopped_state; +} + +static const VMStateDescription vmstate_rtas_stopped = { + .name = "cpu/rtas_stopped", + .version_id = 1, + .minimum_version_id = 1, + .needed = rtas_stopped_needed, + .fields = (const VMStateField[]) { + /* + * "RTAS stopped" state, independent of halted state. For QEMU + * < 10.0, this is taken from cpu->halted at cpu_post_load() + */ + VMSTATE_BOOL(env.quiesced, PowerPCCPU), + VMSTATE_END_OF_LIST() + } +}; + #ifdef TARGET_PPC64 static bool bhrb_needed(void *opaque) { @@ -715,6 +776,7 @@ const VMStateDescription vmstate_ppc_cpu = { &vmstate_tlbmas, &vmstate_compat, &vmstate_reservation, + &vmstate_rtas_stopped, NULL } };