Once a compatiblity mode is negotiated with the guest, h_client_architecture_support() uses run_on_cpu() to update each CPU to the new mode. We're going to want this logic somewhere else shortly, so make a helper function to do this global update.
We put it in target-ppc/compat.c - it makes as much sense at the CPU level as it does at the machine level. We also move the cpu_synchronize_state() into ppc_set_compat(), since it doesn't really make any sense to call that without synchronizing state. Signed-off-by: David Gibson <da...@gibson.dropbear.id.au> --- hw/ppc/spapr_hcall.c | 31 +++++-------------------------- target-ppc/compat.c | 36 ++++++++++++++++++++++++++++++++++++ target-ppc/cpu.h | 3 +++ 3 files changed, 44 insertions(+), 26 deletions(-) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 3bd6d06..4eaf9a6 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -881,20 +881,6 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPRMachineState *spapr, return ret; } -typedef struct { - uint32_t compat_pvr; - Error *err; -} SetCompatState; - -static void do_set_compat(CPUState *cs, void *arg) -{ - PowerPCCPU *cpu = POWERPC_CPU(cs); - SetCompatState *s = arg; - - cpu_synchronize_state(cs); - ppc_set_compat(cpu, s->compat_pvr, &s->err); -} - static target_ulong h_client_architecture_support(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, @@ -902,7 +888,6 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, { target_ulong list = ppc64_phys_to_real(args[0]); target_ulong ov_table; - CPUState *cs; bool explicit_match = false; /* Matched the CPU's real PVR */ uint32_t max_compat = cpu->max_compat; uint32_t best_compat = 0; @@ -949,18 +934,12 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, /* Update CPUs */ if (cpu->compat_pvr != best_compat) { - CPU_FOREACH(cs) { - SetCompatState s = { - .compat_pvr = best_compat, - .err = NULL, - }; + Error *local_err = NULL; - run_on_cpu(cs, do_set_compat, &s); - - if (s.err) { - error_report_err(s.err); - return H_HARDWARE; - } + ppc_set_compat_all(best_compat, &local_err); + if (local_err) { + error_report_err(local_err); + return H_HARDWARE; } } diff --git a/target-ppc/compat.c b/target-ppc/compat.c index 1059555..0b12b58 100644 --- a/target-ppc/compat.c +++ b/target-ppc/compat.c @@ -124,6 +124,8 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp) pcr = compat->pcr; } + cpu_synchronize_state(CPU(cpu)); + cpu->compat_pvr = compat_pvr; env->spr[SPR_PCR] = pcr & pcc->pcr_mask; @@ -136,6 +138,40 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp) } } +#if !defined(CONFIG_USER_ONLY) +typedef struct { + uint32_t compat_pvr; + Error *err; +} SetCompatState; + +static void do_set_compat(CPUState *cs, void *arg) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + SetCompatState *s = arg; + + ppc_set_compat(cpu, s->compat_pvr, &s->err); +} + +void ppc_set_compat_all(uint32_t compat_pvr, Error **errp) +{ + CPUState *cs; + + CPU_FOREACH(cs) { + SetCompatState s = { + .compat_pvr = compat_pvr, + .err = NULL, + }; + + run_on_cpu(cs, do_set_compat, &s); + + if (s.err) { + error_propagate(errp, s.err); + return; + } + } +} +#endif + int ppc_compat_max_threads(PowerPCCPU *cpu) { const CompatInfo *compat = compat_by_pvr(cpu->compat_pvr); diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 91e8be8..201a655 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1317,6 +1317,9 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch) bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr, uint32_t min_compat_pvr, uint32_t max_compat_pvr); void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp); +#if !defined(CONFIG_USER_ONLY) +void ppc_set_compat_all(uint32_t compat_pvr, Error **errp); +#endif int ppc_compat_max_threads(PowerPCCPU *cpu); #endif /* defined(TARGET_PPC64) */ -- 2.7.4