aboutsummaryrefslogtreecommitdiff
path: root/hw/ppc/spapr_rtas.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/ppc/spapr_rtas.c')
-rw-r--r--hw/ppc/spapr_rtas.c30
1 files changed, 20 insertions, 10 deletions
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index cdf0b607a0..2b89e1d448 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -162,6 +162,8 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr,
if (cpu != NULL) {
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ Error *local_err = NULL;
if (!cs->halted) {
rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
@@ -173,7 +175,19 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr,
* new cpu enters */
kvm_cpu_synchronize_state(cs);
+ /* Set compatibility mode to match existing cpus */
+ ppc_set_compat(cpu, POWERPC_CPU(first_cpu)->compat_pvr, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
+ return;
+ }
+
env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME);
+
+ /* Enable Power-saving mode Exit Cause exceptions for the new CPU */
+ env->spr[SPR_LPCR] |= pcc->lpcr_pm;
+
env->nip = start;
env->gpr[3] = r3;
cs->halted = 0;
@@ -197,19 +211,15 @@ static void rtas_stop_self(PowerPCCPU *cpu, sPAPRMachineState *spapr,
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
cs->halted = 1;
qemu_cpu_kick(cs);
- /*
- * While stopping a CPU, the guest calls H_CPPR which
- * effectively disables interrupts on XICS level.
- * However decrementer interrupts in TCG can still
- * wake the CPU up so here we disable interrupts in MSR
- * as well.
- * As rtas_start_cpu() resets the whole MSR anyway, there is
- * no need to bother with specific bits, we just clear it.
- */
- env->msr = 0;
+
+ /* Disable Power-saving mode Exit Cause exceptions for the CPU.
+ * This could deliver an interrupt on a dying CPU and crash the
+ * guest */
+ env->spr[SPR_LPCR] &= ~pcc->lpcr_pm;
}
static inline int sysparm_st(target_ulong addr, target_ulong len,