On 30/10/16 22:11, David Gibson wrote: > The pseries machine type is a bit unusual in that it runs a paravirtualized > guest. The guest expects to interact with a hypervisor, and qemu > emulates the functions of that hypervisor directly, rather than executing > hypervisor code within the emulated system. > > To implement this in TCG, we need to intercept hypercall instructions and > direct them to the machine's hypercall handlers, rather than attempting to > perform a privilege change within TCG. This is controlled by a global > hook - cpu_ppc_hypercall. > > This cleanup makes the handling a little cleaner and more extensible that > a single global variable. Instead, each CPU to have hypercalls intercepted > has a pointer set to a QOM object implementing a new virtual hypervisor > interface. A method in that interface is called by TCG when it sees a > hypercall instruction. It's possible we may want to add other methods in > future.
Reviewed-by: Alexey Kardashevskiy <a...@ozlabs.ru> I did not realize it is a global hook :) > > Signed-off-by: David Gibson <da...@gibson.dropbear.id.au> > --- > hw/ppc/spapr.c | 8 +++++--- > hw/ppc/spapr_cpu_core.c | 1 + > target-ppc/cpu.h | 26 ++++++++++++++++++++++++-- > target-ppc/excp_helper.c | 11 ++++------- > target-ppc/translate_init.c | 12 ++++++++++++ > 5 files changed, 46 insertions(+), 12 deletions(-) > > diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c > index 3551439..b7762ee 100644 > --- a/hw/ppc/spapr.c > +++ b/hw/ppc/spapr.c > @@ -1006,7 +1006,8 @@ static uint64_t translate_kernel_address(void *opaque, > uint64_t addr) > return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR; > } > > -static void emulate_spapr_hypercall(PowerPCCPU *cpu) > +static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp, > + PowerPCCPU *cpu) > { > CPUPPCState *env = &cpu->env; > > @@ -1778,8 +1779,6 @@ static void ppc_spapr_init(MachineState *machine) > > QLIST_INIT(&spapr->phbs); > > - cpu_ppc_hypercall = emulate_spapr_hypercall; > - > /* Allocate RMA if necessary */ > rma_alloc_size = kvmppc_alloc_rma(&rma); > > @@ -2610,6 +2609,7 @@ static void spapr_machine_class_init(ObjectClass *oc, > void *data) > FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc); > NMIClass *nc = NMI_CLASS(oc); > HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); > + PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc); > > mc->desc = "pSeries Logical Partition (PAPR compliant)"; > > @@ -2641,6 +2641,7 @@ static void spapr_machine_class_init(ObjectClass *oc, > void *data) > fwc->get_dev_path = spapr_get_fw_dev_path; > nc->nmi_monitor_handler = spapr_nmi; > smc->phb_placement = spapr_phb_placement; > + vhc->hypercall = emulate_spapr_hypercall; > } > > static const TypeInfo spapr_machine_info = { > @@ -2656,6 +2657,7 @@ static const TypeInfo spapr_machine_info = { > { TYPE_FW_PATH_PROVIDER }, > { TYPE_NMI }, > { TYPE_HOTPLUG_HANDLER }, > + { TYPE_PPC_VIRTUAL_HYPERVISOR }, > { } > }, > }; > diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c > index 1357293..ee5cd14 100644 > --- a/hw/ppc/spapr_cpu_core.c > +++ b/hw/ppc/spapr_cpu_core.c > @@ -57,6 +57,7 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, > PowerPCCPU *cpu, > cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ); > > /* Enable PAPR mode in TCG or KVM */ > + cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr)); > cpu_ppc_set_papr(cpu); > > if (cpu->max_compat) { > diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h > index 1c90adb..a655105 100644 > --- a/target-ppc/cpu.h > +++ b/target-ppc/cpu.h > @@ -1148,6 +1148,9 @@ do { \ > env->wdt_period[3] = (d_); \ > } while (0) > > +typedef struct PPCVirtualHypervisor PPCVirtualHypervisor; > +typedef struct PPCVirtualHypervisorClass PPCVirtualHypervisorClass; > + > /** > * PowerPCCPU: > * @env: #CPUPPCState > @@ -1166,6 +1169,7 @@ struct PowerPCCPU { > int cpu_dt_id; > uint32_t max_compat; > uint32_t cpu_version; > + PPCVirtualHypervisor *vhyp; > }; > > static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env) > @@ -1180,6 +1184,25 @@ static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState > *env) > PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr); > PowerPCCPUClass *ppc_cpu_class_by_pvr_mask(uint32_t pvr); > > +struct PPCVirtualHypervisor { > + Object parent; > +}; > + > +struct PPCVirtualHypervisorClass { > + InterfaceClass parent; > + void (*hypercall)(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu); > +}; > + > +#define TYPE_PPC_VIRTUAL_HYPERVISOR "ppc-virtual-hypervisor" > +#define PPC_VIRTUAL_HYPERVISOR(obj) \ > + OBJECT_CHECK(PPCVirtualHypervisor, (obj), TYPE_PPC_VIRTUAL_HYPERVISOR) > +#define PPC_VIRTUAL_HYPERVISOR_CLASS(klass) \ > + OBJECT_CLASS_CHECK(PPCVirtualHypervisorClass, (klass), \ > + TYPE_PPC_VIRTUAL_HYPERVISOR) > +#define PPC_VIRTUAL_HYPERVISOR_GET_CLASS(obj) \ > + OBJECT_GET_CLASS(PPCVirtualHypervisorClass, (obj), \ > + TYPE_PPC_VIRTUAL_HYPERVISOR) > + > void ppc_cpu_do_interrupt(CPUState *cpu); > bool ppc_cpu_exec_interrupt(CPUState *cpu, int int_req); > void ppc_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, > @@ -1252,6 +1275,7 @@ void store_booke_tcr (CPUPPCState *env, target_ulong > val); > void store_booke_tsr (CPUPPCState *env, target_ulong val); > void ppc_tlb_invalidate_all (CPUPPCState *env); > void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr); > +void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp); > void cpu_ppc_set_papr(PowerPCCPU *cpu); > #endif > #endif > @@ -2421,8 +2445,6 @@ static inline bool lsw_reg_in_range(int start, int > nregs, int rx) > (start + nregs > 32 && (rx >= start || rx < start + nregs - 32)); > } > > -extern void (*cpu_ppc_hypercall)(PowerPCCPU *); > - > void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env); > > /** > diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c > index 808760b..a077939 100644 > --- a/target-ppc/excp_helper.c > +++ b/target-ppc/excp_helper.c > @@ -35,11 +35,6 @@ > #endif > > > /*****************************************************************************/ > -/* PowerPC Hypercall emulation */ > - > -void (*cpu_ppc_hypercall)(PowerPCCPU *); > - > -/*****************************************************************************/ > /* Exception processing */ > #if defined(CONFIG_USER_ONLY) > void ppc_cpu_do_interrupt(CPUState *cs) > @@ -318,8 +313,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int > excp_model, int excp) > env->nip += 4; > > /* "PAPR mode" built-in hypercall emulation */ > - if ((lev == 1) && cpu_ppc_hypercall) { > - cpu_ppc_hypercall(cpu); > + if ((lev == 1) && cpu->vhyp) { > + PPCVirtualHypervisorClass *vhc = > + PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); > + vhc->hypercall(cpu->vhyp, cpu); > return; > } > if (lev == 1) { > diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c > index 208fa1e..21899a4 100644 > --- a/target-ppc/translate_init.c > +++ b/target-ppc/translate_init.c > @@ -8857,6 +8857,11 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) > > #if !defined(CONFIG_USER_ONLY) > > +void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp) > +{ > + cpu->vhyp = vhyp; > +} > + > void cpu_ppc_set_papr(PowerPCCPU *cpu) > { > CPUPPCState *env = &cpu->env; > @@ -10587,9 +10592,16 @@ static const TypeInfo ppc_cpu_type_info = { > .class_init = ppc_cpu_class_init, > }; > > +static const TypeInfo ppc_vhyp_type_info = { > + .name = TYPE_PPC_VIRTUAL_HYPERVISOR, > + .parent = TYPE_INTERFACE, > + .class_size = sizeof(PPCVirtualHypervisorClass), > +}; > + > static void ppc_cpu_register_types(void) > { > type_register_static(&ppc_cpu_type_info); > + type_register_static(&ppc_vhyp_type_info); > } > > type_init(ppc_cpu_register_types) > -- Alexey