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

Reply via email to