On Thu, 18 Jul 2019 13:42:14 +1000 Nicholas Piggin <npig...@gmail.com> wrote:
> This has been useful to modify and test the Linux pseries suspend > code but it requires modification to the guest to call it (due to > being gated by other unimplemented features). It is not otherwise > used by Linux yet, but work is slowly progressing there. > > Signed-off-by: Nicholas Piggin <npig...@gmail.com> > --- Reviewed-by: Greg Kurz <gr...@kaod.org> > Changes since v5: > - Fix prod bit semantics. > - Factor out the h_confer_self common code > > Changes since v4: > - Style > > hw/ppc/spapr.c | 1 + > hw/ppc/spapr_hcall.c | 74 ++++++++++++++++++++++++++++++++++++-------- > 2 files changed, 62 insertions(+), 13 deletions(-) > > diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c > index 68341c128d..00f7735a31 100644 > --- a/hw/ppc/spapr.c > +++ b/hw/ppc/spapr.c > @@ -1066,6 +1066,7 @@ static void spapr_dt_rtas(SpaprMachineState *spapr, > void *fdt) > add_str(hypertas, "hcall-tce"); > add_str(hypertas, "hcall-vio"); > add_str(hypertas, "hcall-splpar"); > + add_str(hypertas, "hcall-join"); > add_str(hypertas, "hcall-bulk"); > add_str(hypertas, "hcall-set-mode"); > add_str(hypertas, "hcall-sprg0"); > diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c > index 7c659dc75c..9b72ea8b68 100644 > --- a/hw/ppc/spapr_hcall.c > +++ b/hw/ppc/spapr_hcall.c > @@ -1069,6 +1069,62 @@ static target_ulong h_cede(PowerPCCPU *cpu, > SpaprMachineState *spapr, > return H_SUCCESS; > } > > +/* > + * Confer to self, aka join. Cede could use the same pattern as well, if > + * EXCP_HLT can be changed to ECXP_HALTED. > + */ > +static target_ulong h_confer_self(PowerPCCPU *cpu) > +{ > + CPUState *cs = CPU(cpu); > + SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); > + > + if (spapr_cpu->prod) { > + spapr_cpu->prod = false; > + return H_SUCCESS; > + } > + cs->halted = 1; > + cs->exception_index = EXCP_HALTED; > + cs->exit_request = 1; > + > + return H_SUCCESS; > +} > + > +static target_ulong h_join(PowerPCCPU *cpu, SpaprMachineState *spapr, > + target_ulong opcode, target_ulong *args) > +{ > + CPUPPCState *env = &cpu->env; > + CPUState *cs; > + bool last_unjoined = true; > + > + if (env->msr & (1ULL << MSR_EE)) { > + return H_BAD_MODE; > + } > + > + /* > + * Must not join the last CPU running. Interestingly, no such restriction > + * for H_CONFER-to-self, but that is probably not intended to be used > + * when H_JOIN is available. > + */ > + CPU_FOREACH(cs) { > + PowerPCCPU *c = POWERPC_CPU(cs); > + CPUPPCState *e = &c->env; > + if (c == cpu) { > + continue; > + } > + > + /* Don't have a way to indicate joined, so use halted && MSR[EE]=0 */ > + if (!cs->halted || (e->msr & (1ULL << MSR_EE))) { > + last_unjoined = false; > + break; > + } > + } > + if (last_unjoined) { > + return H_CONTINUE; > + } > + > + return h_confer_self(cpu); > +} > + > static target_ulong h_confer(PowerPCCPU *cpu, SpaprMachineState *spapr, > target_ulong opcode, target_ulong *args) > { > @@ -1089,26 +1145,15 @@ static target_ulong h_confer(PowerPCCPU *cpu, > SpaprMachineState *spapr, > return H_PARAMETER; > } > > - spapr_cpu = spapr_cpu_state(target_cpu); > - > /* > * target == self is a special case, we wait until prodded, without > * dispatch counter check. > */ > if (cpu == target_cpu) { > - if (spapr_cpu->prod) { > - spapr_cpu->prod = false; > - > - return H_SUCCESS; > - } > - > - cs->halted = 1; > - cs->exception_index = EXCP_HALTED; > - cs->exit_request = 1; > - > - return H_SUCCESS; > + return h_confer_self(cpu); > } > > + spapr_cpu = spapr_cpu_state(target_cpu); > if (!spapr_cpu->vpa_addr || ((dispatch & 1) == 0)) { > return H_SUCCESS; > } > @@ -1981,6 +2026,9 @@ static void hypercall_register_types(void) > spapr_register_hypercall(H_CONFER, h_confer); > spapr_register_hypercall(H_PROD, h_prod); > > + /* hcall-join */ > + spapr_register_hypercall(H_JOIN, h_join); > + > spapr_register_hypercall(H_SIGNAL_SYS_RESET, h_signal_sys_reset); > > /* processor register resource access h-calls */