diff mbox

[v2] spapr: compute interrupt vector address from LPCR

Message ID 1459352314-12552-1-git-send-email-clg@fr.ibm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Cédric Le Goater March 30, 2016, 3:38 p.m. UTC
This address is changed by the linux kernel using the H_SET_MODE hcall
and needs to be restored when migrating a spapr VM running in
TCG. This can be done using the AIL bits from the LPCR register.

The patch introduces a helper routine cpu_ppc_get_excp_prefix() which
returns the effective address offset of the interrupt handler
depending on the LPCR_AIL bits. The same helper can be used in the
H_SET_MODE hcall, which lets us remove the H_SET_MODE_ADDR_TRANS_*
defines.

Signed-off-by: Cédric Le Goater <clg@fr.ibm.com>
---

 Changes since v1:

 - moved helper routine under target-ppc/
 - moved the restore of excp_prefix under cpu_post_load()

 hw/ppc/spapr_hcall.c        |   13 ++-----------
 include/hw/ppc/spapr.h      |    5 -----
 target-ppc/cpu.h            |    9 +++++++++
 target-ppc/machine.c        |   20 +++++++++++++++++++-
 target-ppc/translate_init.c |   14 ++++++++++++++
 5 files changed, 44 insertions(+), 17 deletions(-)

Comments

Greg Kurz March 30, 2016, 5:01 p.m. UTC | #1
On Wed, 30 Mar 2016 17:38:34 +0200
Cédric Le Goater <clg@fr.ibm.com> wrote:

> This address is changed by the linux kernel using the H_SET_MODE hcall
> and needs to be restored when migrating a spapr VM running in
> TCG. This can be done using the AIL bits from the LPCR register.
> 
> The patch introduces a helper routine cpu_ppc_get_excp_prefix() which
> returns the effective address offset of the interrupt handler
> depending on the LPCR_AIL bits. The same helper can be used in the
> H_SET_MODE hcall, which lets us remove the H_SET_MODE_ADDR_TRANS_*
> defines.
> 

<clarification>
... because these H_SET_MODE_ADDR_TRANS_* defines, which refer to the values
0, 1, 2 and 3 for the mflag argument to the H_SET_MODE hypercall as described
in section 14.5.4.3.8 of PAPR, are actually values for bits 39:40 (AIL) of the
LPCR register, as described in section 2.2 of PowerISA.
</clarification>

> Signed-off-by: Cédric Le Goater <clg@fr.ibm.com>
> ---
> 

Reviewed-by: Greg Kurz <gkurz@linux.vnet.ibm.com>

>  Changes since v1:
> 
>  - moved helper routine under target-ppc/
>  - moved the restore of excp_prefix under cpu_post_load()
> 
>  hw/ppc/spapr_hcall.c        |   13 ++-----------
>  include/hw/ppc/spapr.h      |    5 -----
>  target-ppc/cpu.h            |    9 +++++++++
>  target-ppc/machine.c        |   20 +++++++++++++++++++-
>  target-ppc/translate_init.c |   14 ++++++++++++++
>  5 files changed, 44 insertions(+), 17 deletions(-)
> 
> Index: qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
> ===================================================================
> --- qemu-dgibson-for-2.6.git.orig/hw/ppc/spapr_hcall.c
> +++ qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
> @@ -835,17 +835,8 @@ static target_ulong h_set_mode_resource_
>          return H_P4;
>      }
> 
> -    switch (mflags) {
> -    case H_SET_MODE_ADDR_TRANS_NONE:
> -        prefix = 0;
> -        break;
> -    case H_SET_MODE_ADDR_TRANS_0001_8000:
> -        prefix = 0x18000;
> -        break;
> -    case H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000:
> -        prefix = 0xC000000000004000ULL;
> -        break;
> -    default:
> +    prefix = cpu_ppc_get_excp_prefix(mflags);
> +    if (prefix == (target_ulong) -1ULL) {
>          return H_UNSUPPORTED_FLAG;
>      }
> 
> Index: qemu-dgibson-for-2.6.git/target-ppc/machine.c
> ===================================================================
> --- qemu-dgibson-for-2.6.git.orig/target-ppc/machine.c
> +++ qemu-dgibson-for-2.6.git/target-ppc/machine.c
> @@ -156,12 +156,26 @@ static void cpu_pre_save(void *opaque)
>      }
>  }
> 
> +
> +static int cpu_post_load_excp_prefix(CPUPPCState *env)
> +{
> +    int ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
> +    target_ulong prefix = cpu_ppc_get_excp_prefix(ail);
> +
> +    if (prefix == (target_ulong) -1ULL) {
> +        return -EINVAL;
> +    }
> +    env->excp_prefix = prefix;
> +    return 0;
> +}
> +
>  static int cpu_post_load(void *opaque, int version_id)
>  {
>      PowerPCCPU *cpu = opaque;
>      CPUPPCState *env = &cpu->env;
>      int i;
>      target_ulong msr;
> +    int ret = 0;
> 
>      /*
>       * We always ignore the source PVR. The user or management
> @@ -201,7 +215,11 @@ static int cpu_post_load(void *opaque, i
> 
>      hreg_compute_mem_idx(env);
> 
> -    return 0;
> +    if (env->spr[SPR_LPCR] & LPCR_AIL) {
> +        ret = cpu_post_load_excp_prefix(env);
> +    }
> +
> +    return ret;
>  }
> 
>  static bool fpu_needed(void *opaque)
> Index: qemu-dgibson-for-2.6.git/target-ppc/translate_init.c
> ===================================================================
> --- qemu-dgibson-for-2.6.git.orig/target-ppc/translate_init.c
> +++ qemu-dgibson-for-2.6.git/target-ppc/translate_init.c
> @@ -8522,6 +8522,20 @@ void cpu_ppc_set_papr(PowerPCCPU *cpu)
>      }
>  }
> 
> +target_ulong cpu_ppc_get_excp_prefix(target_ulong ail)
> +{
> +    switch (ail) {
> +    case AIL_NONE:
> +        return 0;
> +    case AIL_0001_8000:
> +        return 0x18000;
> +    case AIL_C000_0000_0000_4000:
> +        return 0xC000000000004000ULL;
> +    default:
> +        return (target_ulong) -1ULL;
> +    }
> +}
> +
>  #endif /* !defined(CONFIG_USER_ONLY) */
> 
>  #endif /* defined (TARGET_PPC64) */
> Index: qemu-dgibson-for-2.6.git/target-ppc/cpu.h
> ===================================================================
> --- qemu-dgibson-for-2.6.git.orig/target-ppc/cpu.h
> +++ qemu-dgibson-for-2.6.git/target-ppc/cpu.h
> @@ -1269,6 +1269,7 @@ void store_booke_tsr (CPUPPCState *env,
>  void ppc_tlb_invalidate_all (CPUPPCState *env);
>  void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
>  void cpu_ppc_set_papr(PowerPCCPU *cpu);
> +target_ulong cpu_ppc_get_excp_prefix(target_ulong ail);
>  #endif
>  #endif
> 
> @@ -2277,6 +2278,14 @@ enum {
>      HMER_XSCOM_STATUS_LSH       = (63 - 23),
>  };
> 
> +/* Alternate Interrupt Location (AIL) */
> +enum {
> +    AIL_NONE                = 0,
> +    AIL_RESERVED            = 1,
> +    AIL_0001_8000           = 2,
> +    AIL_C000_0000_0000_4000 = 3,
> +};
> +
>  /*****************************************************************************/
> 
>  static inline target_ulong cpu_read_xer(CPUPPCState *env)
> Index: qemu-dgibson-for-2.6.git/include/hw/ppc/spapr.h
> ===================================================================
> --- qemu-dgibson-for-2.6.git.orig/include/hw/ppc/spapr.h
> +++ qemu-dgibson-for-2.6.git/include/hw/ppc/spapr.h
> @@ -204,11 +204,6 @@ struct sPAPRMachineState {
>  #define H_SET_MODE_ENDIAN_BIG    0
>  #define H_SET_MODE_ENDIAN_LITTLE 1
> 
> -/* Flags for H_SET_MODE_RESOURCE_ADDR_TRANS_MODE */
> -#define H_SET_MODE_ADDR_TRANS_NONE                  0
> -#define H_SET_MODE_ADDR_TRANS_0001_8000             2
> -#define H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000   3
> -
>  /* VASI States */
>  #define H_VASI_INVALID    0
>  #define H_VASI_ENABLED    1
> 
>
Greg Kurz March 30, 2016, 5:12 p.m. UTC | #2
On Wed, 30 Mar 2016 17:38:34 +0200
Cédric Le Goater <clg@fr.ibm.com> wrote:

> This address is changed by the linux kernel using the H_SET_MODE hcall
> and needs to be restored when migrating a spapr VM running in
> TCG. This can be done using the AIL bits from the LPCR register.
> 
> The patch introduces a helper routine cpu_ppc_get_excp_prefix() which
> returns the effective address offset of the interrupt handler
> depending on the LPCR_AIL bits. The same helper can be used in the
> H_SET_MODE hcall, which lets us remove the H_SET_MODE_ADDR_TRANS_*
> defines.
> 
> Signed-off-by: Cédric Le Goater <clg@fr.ibm.com>
> ---
> 

Sorry I hit the send button too quickly... Just a nit but my Reviewed-by stands.

>  Changes since v1:
> 
>  - moved helper routine under target-ppc/
>  - moved the restore of excp_prefix under cpu_post_load()
> 
>  hw/ppc/spapr_hcall.c        |   13 ++-----------
>  include/hw/ppc/spapr.h      |    5 -----
>  target-ppc/cpu.h            |    9 +++++++++
>  target-ppc/machine.c        |   20 +++++++++++++++++++-
>  target-ppc/translate_init.c |   14 ++++++++++++++
>  5 files changed, 44 insertions(+), 17 deletions(-)
> 
> Index: qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
> ===================================================================
> --- qemu-dgibson-for-2.6.git.orig/hw/ppc/spapr_hcall.c
> +++ qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
> @@ -835,17 +835,8 @@ static target_ulong h_set_mode_resource_
>          return H_P4;
>      }
> 
> -    switch (mflags) {
> -    case H_SET_MODE_ADDR_TRANS_NONE:
> -        prefix = 0;
> -        break;
> -    case H_SET_MODE_ADDR_TRANS_0001_8000:
> -        prefix = 0x18000;
> -        break;
> -    case H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000:
> -        prefix = 0xC000000000004000ULL;
> -        break;
> -    default:
> +    prefix = cpu_ppc_get_excp_prefix(mflags);
> +    if (prefix == (target_ulong) -1ULL) {

+    if (prefix == (target_ulong) (-1ULL)) {

to make ./scripts/checkpatch.pl happy :)

>          return H_UNSUPPORTED_FLAG;
>      }
> 
> Index: qemu-dgibson-for-2.6.git/target-ppc/machine.c
> ===================================================================
> --- qemu-dgibson-for-2.6.git.orig/target-ppc/machine.c
> +++ qemu-dgibson-for-2.6.git/target-ppc/machine.c
> @@ -156,12 +156,26 @@ static void cpu_pre_save(void *opaque)
>      }
>  }
> 
> +
> +static int cpu_post_load_excp_prefix(CPUPPCState *env)
> +{
> +    int ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
> +    target_ulong prefix = cpu_ppc_get_excp_prefix(ail);
> +
> +    if (prefix == (target_ulong) -1ULL) {
> +        return -EINVAL;
> +    }
> +    env->excp_prefix = prefix;
> +    return 0;
> +}
> +
>  static int cpu_post_load(void *opaque, int version_id)
>  {
>      PowerPCCPU *cpu = opaque;
>      CPUPPCState *env = &cpu->env;
>      int i;
>      target_ulong msr;
> +    int ret = 0;
> 
>      /*
>       * We always ignore the source PVR. The user or management
> @@ -201,7 +215,11 @@ static int cpu_post_load(void *opaque, i
> 
>      hreg_compute_mem_idx(env);
> 
> -    return 0;
> +    if (env->spr[SPR_LPCR] & LPCR_AIL) {
> +        ret = cpu_post_load_excp_prefix(env);
> +    }
> +
> +    return ret;
>  }
> 
>  static bool fpu_needed(void *opaque)
> Index: qemu-dgibson-for-2.6.git/target-ppc/translate_init.c
> ===================================================================
> --- qemu-dgibson-for-2.6.git.orig/target-ppc/translate_init.c
> +++ qemu-dgibson-for-2.6.git/target-ppc/translate_init.c
> @@ -8522,6 +8522,20 @@ void cpu_ppc_set_papr(PowerPCCPU *cpu)
>      }
>  }
> 
> +target_ulong cpu_ppc_get_excp_prefix(target_ulong ail)
> +{
> +    switch (ail) {
> +    case AIL_NONE:
> +        return 0;
> +    case AIL_0001_8000:
> +        return 0x18000;
> +    case AIL_C000_0000_0000_4000:
> +        return 0xC000000000004000ULL;
> +    default:
> +        return (target_ulong) -1ULL;
> +    }
> +}
> +
>  #endif /* !defined(CONFIG_USER_ONLY) */
> 
>  #endif /* defined (TARGET_PPC64) */
> Index: qemu-dgibson-for-2.6.git/target-ppc/cpu.h
> ===================================================================
> --- qemu-dgibson-for-2.6.git.orig/target-ppc/cpu.h
> +++ qemu-dgibson-for-2.6.git/target-ppc/cpu.h
> @@ -1269,6 +1269,7 @@ void store_booke_tsr (CPUPPCState *env,
>  void ppc_tlb_invalidate_all (CPUPPCState *env);
>  void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
>  void cpu_ppc_set_papr(PowerPCCPU *cpu);
> +target_ulong cpu_ppc_get_excp_prefix(target_ulong ail);
>  #endif
>  #endif
> 
> @@ -2277,6 +2278,14 @@ enum {
>      HMER_XSCOM_STATUS_LSH       = (63 - 23),
>  };
> 
> +/* Alternate Interrupt Location (AIL) */
> +enum {
> +    AIL_NONE                = 0,
> +    AIL_RESERVED            = 1,
> +    AIL_0001_8000           = 2,
> +    AIL_C000_0000_0000_4000 = 3,
> +};
> +
>  /*****************************************************************************/
> 
>  static inline target_ulong cpu_read_xer(CPUPPCState *env)
> Index: qemu-dgibson-for-2.6.git/include/hw/ppc/spapr.h
> ===================================================================
> --- qemu-dgibson-for-2.6.git.orig/include/hw/ppc/spapr.h
> +++ qemu-dgibson-for-2.6.git/include/hw/ppc/spapr.h
> @@ -204,11 +204,6 @@ struct sPAPRMachineState {
>  #define H_SET_MODE_ENDIAN_BIG    0
>  #define H_SET_MODE_ENDIAN_LITTLE 1
> 
> -/* Flags for H_SET_MODE_RESOURCE_ADDR_TRANS_MODE */
> -#define H_SET_MODE_ADDR_TRANS_NONE                  0
> -#define H_SET_MODE_ADDR_TRANS_0001_8000             2
> -#define H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000   3
> -
>  /* VASI States */
>  #define H_VASI_INVALID    0
>  #define H_VASI_ENABLED    1
Greg Kurz March 30, 2016, 5:15 p.m. UTC | #3
On Wed, 30 Mar 2016 19:01:31 +0200
Greg Kurz <gkurz@linux.vnet.ibm.com> wrote:

> On Wed, 30 Mar 2016 17:38:34 +0200
> Cédric Le Goater <clg@fr.ibm.com> wrote:
> 
> > This address is changed by the linux kernel using the H_SET_MODE hcall
> > and needs to be restored when migrating a spapr VM running in
> > TCG. This can be done using the AIL bits from the LPCR register.
> > 
> > The patch introduces a helper routine cpu_ppc_get_excp_prefix() which
> > returns the effective address offset of the interrupt handler
> > depending on the LPCR_AIL bits. The same helper can be used in the
> > H_SET_MODE hcall, which lets us remove the H_SET_MODE_ADDR_TRANS_*
> > defines.
> >   
> 
> <clarification>
> ... because these H_SET_MODE_ADDR_TRANS_* defines, which refer to the values
> 0, 1, 2 and 3 for the mflag argument to the H_SET_MODE hypercall as described
> in section 14.5.4.3.8 of PAPR, are actually values for bits 39:40 (AIL) of the
> LPCR register, as described in section 2.2 of PowerISA.

read "section section 2.2 of chapter 2 of book-III S in PowerISA" :)

> </clarification>
> 
> > Signed-off-by: Cédric Le Goater <clg@fr.ibm.com>
> > ---
> >   
> 
> Reviewed-by: Greg Kurz <gkurz@linux.vnet.ibm.com>
> 
> >  Changes since v1:
> > 
> >  - moved helper routine under target-ppc/
> >  - moved the restore of excp_prefix under cpu_post_load()
> > 
> >  hw/ppc/spapr_hcall.c        |   13 ++-----------
> >  include/hw/ppc/spapr.h      |    5 -----
> >  target-ppc/cpu.h            |    9 +++++++++
> >  target-ppc/machine.c        |   20 +++++++++++++++++++-
> >  target-ppc/translate_init.c |   14 ++++++++++++++
> >  5 files changed, 44 insertions(+), 17 deletions(-)
> > 
> > Index: qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
> > ===================================================================
> > --- qemu-dgibson-for-2.6.git.orig/hw/ppc/spapr_hcall.c
> > +++ qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
> > @@ -835,17 +835,8 @@ static target_ulong h_set_mode_resource_
> >          return H_P4;
> >      }
> > 
> > -    switch (mflags) {
> > -    case H_SET_MODE_ADDR_TRANS_NONE:
> > -        prefix = 0;
> > -        break;
> > -    case H_SET_MODE_ADDR_TRANS_0001_8000:
> > -        prefix = 0x18000;
> > -        break;
> > -    case H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000:
> > -        prefix = 0xC000000000004000ULL;
> > -        break;
> > -    default:
> > +    prefix = cpu_ppc_get_excp_prefix(mflags);
> > +    if (prefix == (target_ulong) -1ULL) {
> >          return H_UNSUPPORTED_FLAG;
> >      }
> > 
> > Index: qemu-dgibson-for-2.6.git/target-ppc/machine.c
> > ===================================================================
> > --- qemu-dgibson-for-2.6.git.orig/target-ppc/machine.c
> > +++ qemu-dgibson-for-2.6.git/target-ppc/machine.c
> > @@ -156,12 +156,26 @@ static void cpu_pre_save(void *opaque)
> >      }
> >  }
> > 
> > +
> > +static int cpu_post_load_excp_prefix(CPUPPCState *env)
> > +{
> > +    int ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
> > +    target_ulong prefix = cpu_ppc_get_excp_prefix(ail);
> > +
> > +    if (prefix == (target_ulong) -1ULL) {
> > +        return -EINVAL;
> > +    }
> > +    env->excp_prefix = prefix;
> > +    return 0;
> > +}
> > +
> >  static int cpu_post_load(void *opaque, int version_id)
> >  {
> >      PowerPCCPU *cpu = opaque;
> >      CPUPPCState *env = &cpu->env;
> >      int i;
> >      target_ulong msr;
> > +    int ret = 0;
> > 
> >      /*
> >       * We always ignore the source PVR. The user or management
> > @@ -201,7 +215,11 @@ static int cpu_post_load(void *opaque, i
> > 
> >      hreg_compute_mem_idx(env);
> > 
> > -    return 0;
> > +    if (env->spr[SPR_LPCR] & LPCR_AIL) {
> > +        ret = cpu_post_load_excp_prefix(env);
> > +    }
> > +
> > +    return ret;
> >  }
> > 
> >  static bool fpu_needed(void *opaque)
> > Index: qemu-dgibson-for-2.6.git/target-ppc/translate_init.c
> > ===================================================================
> > --- qemu-dgibson-for-2.6.git.orig/target-ppc/translate_init.c
> > +++ qemu-dgibson-for-2.6.git/target-ppc/translate_init.c
> > @@ -8522,6 +8522,20 @@ void cpu_ppc_set_papr(PowerPCCPU *cpu)
> >      }
> >  }
> > 
> > +target_ulong cpu_ppc_get_excp_prefix(target_ulong ail)
> > +{
> > +    switch (ail) {
> > +    case AIL_NONE:
> > +        return 0;
> > +    case AIL_0001_8000:
> > +        return 0x18000;
> > +    case AIL_C000_0000_0000_4000:
> > +        return 0xC000000000004000ULL;
> > +    default:
> > +        return (target_ulong) -1ULL;
> > +    }
> > +}
> > +
> >  #endif /* !defined(CONFIG_USER_ONLY) */
> > 
> >  #endif /* defined (TARGET_PPC64) */
> > Index: qemu-dgibson-for-2.6.git/target-ppc/cpu.h
> > ===================================================================
> > --- qemu-dgibson-for-2.6.git.orig/target-ppc/cpu.h
> > +++ qemu-dgibson-for-2.6.git/target-ppc/cpu.h
> > @@ -1269,6 +1269,7 @@ void store_booke_tsr (CPUPPCState *env,
> >  void ppc_tlb_invalidate_all (CPUPPCState *env);
> >  void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
> >  void cpu_ppc_set_papr(PowerPCCPU *cpu);
> > +target_ulong cpu_ppc_get_excp_prefix(target_ulong ail);
> >  #endif
> >  #endif
> > 
> > @@ -2277,6 +2278,14 @@ enum {
> >      HMER_XSCOM_STATUS_LSH       = (63 - 23),
> >  };
> > 
> > +/* Alternate Interrupt Location (AIL) */
> > +enum {
> > +    AIL_NONE                = 0,
> > +    AIL_RESERVED            = 1,
> > +    AIL_0001_8000           = 2,
> > +    AIL_C000_0000_0000_4000 = 3,
> > +};
> > +
> >  /*****************************************************************************/
> > 
> >  static inline target_ulong cpu_read_xer(CPUPPCState *env)
> > Index: qemu-dgibson-for-2.6.git/include/hw/ppc/spapr.h
> > ===================================================================
> > --- qemu-dgibson-for-2.6.git.orig/include/hw/ppc/spapr.h
> > +++ qemu-dgibson-for-2.6.git/include/hw/ppc/spapr.h
> > @@ -204,11 +204,6 @@ struct sPAPRMachineState {
> >  #define H_SET_MODE_ENDIAN_BIG    0
> >  #define H_SET_MODE_ENDIAN_LITTLE 1
> > 
> > -/* Flags for H_SET_MODE_RESOURCE_ADDR_TRANS_MODE */
> > -#define H_SET_MODE_ADDR_TRANS_NONE                  0
> > -#define H_SET_MODE_ADDR_TRANS_0001_8000             2
> > -#define H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000   3
> > -
> >  /* VASI States */
> >  #define H_VASI_INVALID    0
> >  #define H_VASI_ENABLED    1
> > 
> >   
> 
>
David Gibson March 31, 2016, 4:55 a.m. UTC | #4
On Wed, Mar 30, 2016 at 05:38:34PM +0200, Cédric Le Goater wrote:
> This address is changed by the linux kernel using the H_SET_MODE hcall
> and needs to be restored when migrating a spapr VM running in
> TCG. This can be done using the AIL bits from the LPCR register.
> 
> The patch introduces a helper routine cpu_ppc_get_excp_prefix() which
> returns the effective address offset of the interrupt handler
> depending on the LPCR_AIL bits. The same helper can be used in the
> H_SET_MODE hcall, which lets us remove the H_SET_MODE_ADDR_TRANS_*
> defines.
> 
> Signed-off-by: Cédric Le Goater <clg@fr.ibm.com>

I've applied this (with Greg's minor amendments) to ppc-for-2.6),
since it certainly improves behaviour, although I have a couple of
queries:

> ---
> 
>  Changes since v1:
> 
>  - moved helper routine under target-ppc/
>  - moved the restore of excp_prefix under cpu_post_load()
> 
>  hw/ppc/spapr_hcall.c        |   13 ++-----------
>  include/hw/ppc/spapr.h      |    5 -----
>  target-ppc/cpu.h            |    9 +++++++++
>  target-ppc/machine.c        |   20 +++++++++++++++++++-
>  target-ppc/translate_init.c |   14 ++++++++++++++
>  5 files changed, 44 insertions(+), 17 deletions(-)
> 
> Index: qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
> ===================================================================
> --- qemu-dgibson-for-2.6.git.orig/hw/ppc/spapr_hcall.c
> +++ qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
> @@ -835,17 +835,8 @@ static target_ulong h_set_mode_resource_
>          return H_P4;
>      }
>  
> -    switch (mflags) {
> -    case H_SET_MODE_ADDR_TRANS_NONE:
> -        prefix = 0;
> -        break;
> -    case H_SET_MODE_ADDR_TRANS_0001_8000:
> -        prefix = 0x18000;
> -        break;
> -    case H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000:
> -        prefix = 0xC000000000004000ULL;
> -        break;
> -    default:
> +    prefix = cpu_ppc_get_excp_prefix(mflags);
> +    if (prefix == (target_ulong) -1ULL) {
>          return H_UNSUPPORTED_FLAG;
>      }
>  
> Index: qemu-dgibson-for-2.6.git/target-ppc/machine.c
> ===================================================================
> --- qemu-dgibson-for-2.6.git.orig/target-ppc/machine.c
> +++ qemu-dgibson-for-2.6.git/target-ppc/machine.c
> @@ -156,12 +156,26 @@ static void cpu_pre_save(void *opaque)
>      }
>  }
>  
> +
> +static int cpu_post_load_excp_prefix(CPUPPCState *env)
> +{
> +    int ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
> +    target_ulong prefix = cpu_ppc_get_excp_prefix(ail);
> +
> +    if (prefix == (target_ulong) -1ULL) {
> +        return -EINVAL;
> +    }
> +    env->excp_prefix = prefix;
> +    return 0;
> +}
> +
>  static int cpu_post_load(void *opaque, int version_id)
>  {
>      PowerPCCPU *cpu = opaque;
>      CPUPPCState *env = &cpu->env;
>      int i;
>      target_ulong msr;
> +    int ret = 0;
>  
>      /*
>       * We always ignore the source PVR. The user or management
> @@ -201,7 +215,11 @@ static int cpu_post_load(void *opaque, i
>  
>      hreg_compute_mem_idx(env);
>  
> -    return 0;
> +    if (env->spr[SPR_LPCR] & LPCR_AIL) {
> +        ret = cpu_post_load_excp_prefix(env);
> +    }

Why not call this unconditionally?  If AIL == 0 it will still do the
right thing.

Aren't there also circumstances where the exception prefix can depend
on the MSR?  Do those need to be handled somewhere?

> +
> +    return ret;
>  }
>  
>  static bool fpu_needed(void *opaque)
> Index: qemu-dgibson-for-2.6.git/target-ppc/translate_init.c
> ===================================================================
> --- qemu-dgibson-for-2.6.git.orig/target-ppc/translate_init.c
> +++ qemu-dgibson-for-2.6.git/target-ppc/translate_init.c
> @@ -8522,6 +8522,20 @@ void cpu_ppc_set_papr(PowerPCCPU *cpu)
>      }
>  }
>  
> +target_ulong cpu_ppc_get_excp_prefix(target_ulong ail)
> +{
> +    switch (ail) {
> +    case AIL_NONE:
> +        return 0;
> +    case AIL_0001_8000:
> +        return 0x18000;
> +    case AIL_C000_0000_0000_4000:
> +        return 0xC000000000004000ULL;
> +    default:
> +        return (target_ulong) -1ULL;
> +    }
> +}
> +
>  #endif /* !defined(CONFIG_USER_ONLY) */
>  
>  #endif /* defined (TARGET_PPC64) */
> Index: qemu-dgibson-for-2.6.git/target-ppc/cpu.h
> ===================================================================
> --- qemu-dgibson-for-2.6.git.orig/target-ppc/cpu.h
> +++ qemu-dgibson-for-2.6.git/target-ppc/cpu.h
> @@ -1269,6 +1269,7 @@ void store_booke_tsr (CPUPPCState *env,
>  void ppc_tlb_invalidate_all (CPUPPCState *env);
>  void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
>  void cpu_ppc_set_papr(PowerPCCPU *cpu);
> +target_ulong cpu_ppc_get_excp_prefix(target_ulong ail);
>  #endif
>  #endif
>  
> @@ -2277,6 +2278,14 @@ enum {
>      HMER_XSCOM_STATUS_LSH       = (63 - 23),
>  };
>  
> +/* Alternate Interrupt Location (AIL) */
> +enum {
> +    AIL_NONE                = 0,
> +    AIL_RESERVED            = 1,
> +    AIL_0001_8000           = 2,
> +    AIL_C000_0000_0000_4000 = 3,
> +};
> +
>  /*****************************************************************************/
>  
>  static inline target_ulong cpu_read_xer(CPUPPCState *env)
> Index: qemu-dgibson-for-2.6.git/include/hw/ppc/spapr.h
> ===================================================================
> --- qemu-dgibson-for-2.6.git.orig/include/hw/ppc/spapr.h
> +++ qemu-dgibson-for-2.6.git/include/hw/ppc/spapr.h
> @@ -204,11 +204,6 @@ struct sPAPRMachineState {
>  #define H_SET_MODE_ENDIAN_BIG    0
>  #define H_SET_MODE_ENDIAN_LITTLE 1
>  
> -/* Flags for H_SET_MODE_RESOURCE_ADDR_TRANS_MODE */
> -#define H_SET_MODE_ADDR_TRANS_NONE                  0
> -#define H_SET_MODE_ADDR_TRANS_0001_8000             2
> -#define H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000   3
> -
>  /* VASI States */
>  #define H_VASI_INVALID    0
>  #define H_VASI_ENABLED    1
>
Mark Cave-Ayland March 31, 2016, 7:13 a.m. UTC | #5
On 31/03/16 05:55, David Gibson wrote:

> On Wed, Mar 30, 2016 at 05:38:34PM +0200, Cédric Le Goater wrote:
>> This address is changed by the linux kernel using the H_SET_MODE hcall
>> and needs to be restored when migrating a spapr VM running in
>> TCG. This can be done using the AIL bits from the LPCR register.
>>
>> The patch introduces a helper routine cpu_ppc_get_excp_prefix() which
>> returns the effective address offset of the interrupt handler
>> depending on the LPCR_AIL bits. The same helper can be used in the
>> H_SET_MODE hcall, which lets us remove the H_SET_MODE_ADDR_TRANS_*
>> defines.
>>
>> Signed-off-by: Cédric Le Goater <clg@fr.ibm.com>
> 
> I've applied this (with Greg's minor amendments) to ppc-for-2.6),
> since it certainly improves behaviour, although I have a couple of
> queries:
> 
>> ---
>>
>>  Changes since v1:
>>
>>  - moved helper routine under target-ppc/
>>  - moved the restore of excp_prefix under cpu_post_load()
>>
>>  hw/ppc/spapr_hcall.c        |   13 ++-----------
>>  include/hw/ppc/spapr.h      |    5 -----
>>  target-ppc/cpu.h            |    9 +++++++++
>>  target-ppc/machine.c        |   20 +++++++++++++++++++-
>>  target-ppc/translate_init.c |   14 ++++++++++++++
>>  5 files changed, 44 insertions(+), 17 deletions(-)
>>
>> Index: qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
>> ===================================================================
>> --- qemu-dgibson-for-2.6.git.orig/hw/ppc/spapr_hcall.c
>> +++ qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
>> @@ -835,17 +835,8 @@ static target_ulong h_set_mode_resource_
>>          return H_P4;
>>      }
>>  
>> -    switch (mflags) {
>> -    case H_SET_MODE_ADDR_TRANS_NONE:
>> -        prefix = 0;
>> -        break;
>> -    case H_SET_MODE_ADDR_TRANS_0001_8000:
>> -        prefix = 0x18000;
>> -        break;
>> -    case H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000:
>> -        prefix = 0xC000000000004000ULL;
>> -        break;
>> -    default:
>> +    prefix = cpu_ppc_get_excp_prefix(mflags);
>> +    if (prefix == (target_ulong) -1ULL) {
>>          return H_UNSUPPORTED_FLAG;
>>      }
>>  
>> Index: qemu-dgibson-for-2.6.git/target-ppc/machine.c
>> ===================================================================
>> --- qemu-dgibson-for-2.6.git.orig/target-ppc/machine.c
>> +++ qemu-dgibson-for-2.6.git/target-ppc/machine.c
>> @@ -156,12 +156,26 @@ static void cpu_pre_save(void *opaque)
>>      }
>>  }
>>  
>> +
>> +static int cpu_post_load_excp_prefix(CPUPPCState *env)
>> +{
>> +    int ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
>> +    target_ulong prefix = cpu_ppc_get_excp_prefix(ail);
>> +
>> +    if (prefix == (target_ulong) -1ULL) {
>> +        return -EINVAL;
>> +    }
>> +    env->excp_prefix = prefix;
>> +    return 0;
>> +}
>> +
>>  static int cpu_post_load(void *opaque, int version_id)
>>  {
>>      PowerPCCPU *cpu = opaque;
>>      CPUPPCState *env = &cpu->env;
>>      int i;
>>      target_ulong msr;
>> +    int ret = 0;
>>  
>>      /*
>>       * We always ignore the source PVR. The user or management
>> @@ -201,7 +215,11 @@ static int cpu_post_load(void *opaque, i
>>  
>>      hreg_compute_mem_idx(env);
>>  
>> -    return 0;
>> +    if (env->spr[SPR_LPCR] & LPCR_AIL) {
>> +        ret = cpu_post_load_excp_prefix(env);
>> +    }
> 
> Why not call this unconditionally?  If AIL == 0 it will still do the
> right thing.
> 
> Aren't there also circumstances where the exception prefix can depend
> on the MSR?  Do those need to be handled somewhere?

Yes indeed - this was part of my patchset last year to fix up various
migration issues for the Mac PPC machines (see commit
2360b6e84f78d41fa0f76555a947148b73645259).

I agree that having the env->excp_prefix logic split like this isn't a
particularly great idea. Let's just have a single helper function as in
the patch above and use that in both places (and in fact with recent
changes I have a feeling env->excp_prefix is one of the few remaining
reasons that the above change is still required, but please check this).


ATB,

Mark.
Cédric Le Goater March 31, 2016, 8:16 a.m. UTC | #6
On 03/31/2016 06:55 AM, David Gibson wrote:
> On Wed, Mar 30, 2016 at 05:38:34PM +0200, Cédric Le Goater wrote:
>> This address is changed by the linux kernel using the H_SET_MODE hcall
>> and needs to be restored when migrating a spapr VM running in
>> TCG. This can be done using the AIL bits from the LPCR register.
>>
>> The patch introduces a helper routine cpu_ppc_get_excp_prefix() which
>> returns the effective address offset of the interrupt handler
>> depending on the LPCR_AIL bits. The same helper can be used in the
>> H_SET_MODE hcall, which lets us remove the H_SET_MODE_ADDR_TRANS_*
>> defines.
>>
>> Signed-off-by: Cédric Le Goater <clg@fr.ibm.com>
> 
> I've applied this (with Greg's minor amendments) to ppc-for-2.6),
> since it certainly improves behaviour, although I have a couple of
> queries:
> 
>> ---
>>
>>  Changes since v1:
>>
>>  - moved helper routine under target-ppc/
>>  - moved the restore of excp_prefix under cpu_post_load()
>>
>>  hw/ppc/spapr_hcall.c        |   13 ++-----------
>>  include/hw/ppc/spapr.h      |    5 -----
>>  target-ppc/cpu.h            |    9 +++++++++
>>  target-ppc/machine.c        |   20 +++++++++++++++++++-
>>  target-ppc/translate_init.c |   14 ++++++++++++++
>>  5 files changed, 44 insertions(+), 17 deletions(-)
>>
>> Index: qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
>> ===================================================================
>> --- qemu-dgibson-for-2.6.git.orig/hw/ppc/spapr_hcall.c
>> +++ qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
>> @@ -835,17 +835,8 @@ static target_ulong h_set_mode_resource_
>>          return H_P4;
>>      }
>>  
>> -    switch (mflags) {
>> -    case H_SET_MODE_ADDR_TRANS_NONE:
>> -        prefix = 0;
>> -        break;
>> -    case H_SET_MODE_ADDR_TRANS_0001_8000:
>> -        prefix = 0x18000;
>> -        break;
>> -    case H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000:
>> -        prefix = 0xC000000000004000ULL;
>> -        break;
>> -    default:
>> +    prefix = cpu_ppc_get_excp_prefix(mflags);
>> +    if (prefix == (target_ulong) -1ULL) {
>>          return H_UNSUPPORTED_FLAG;
>>      }
>>  
>> Index: qemu-dgibson-for-2.6.git/target-ppc/machine.c
>> ===================================================================
>> --- qemu-dgibson-for-2.6.git.orig/target-ppc/machine.c
>> +++ qemu-dgibson-for-2.6.git/target-ppc/machine.c
>> @@ -156,12 +156,26 @@ static void cpu_pre_save(void *opaque)
>>      }
>>  }
>>  
>> +
>> +static int cpu_post_load_excp_prefix(CPUPPCState *env)
>> +{
>> +    int ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
>> +    target_ulong prefix = cpu_ppc_get_excp_prefix(ail);
>> +
>> +    if (prefix == (target_ulong) -1ULL) {
>> +        return -EINVAL;
>> +    }
>> +    env->excp_prefix = prefix;
>> +    return 0;
>> +}
>> +
>>  static int cpu_post_load(void *opaque, int version_id)
>>  {
>>      PowerPCCPU *cpu = opaque;
>>      CPUPPCState *env = &cpu->env;
>>      int i;
>>      target_ulong msr;
>> +    int ret = 0;
>>  
>>      /*
>>       * We always ignore the source PVR. The user or management
>> @@ -201,7 +215,11 @@ static int cpu_post_load(void *opaque, i
>>  
>>      hreg_compute_mem_idx(env);
>>  
>> -    return 0;
>> +    if (env->spr[SPR_LPCR] & LPCR_AIL) {
>> +        ret = cpu_post_load_excp_prefix(env);
>> +    }
> 
> Why not call this unconditionally?  If AIL == 0 it will still do the
> right thing.

yes, indeed. the test is not required.

> Aren't there also circumstances where the exception prefix can depend
> on the MSR?  Do those need to be handled somewhere?

Well, if translation is not enabled, LPCR_AIL should be 0, and so should 
be excp_prefix. Is that something we should check/enforce at restart ? 


Looking closer, we could probably get rid of excp_prefix (for spapr) and 
compute the value directly from LPCR in powerpc_excp() where we really need 
it.

C.

>> +
>> +    return ret;
>>  }
>>  
>>  static bool fpu_needed(void *opaque)
>> Index: qemu-dgibson-for-2.6.git/target-ppc/translate_init.c
>> ===================================================================
>> --- qemu-dgibson-for-2.6.git.orig/target-ppc/translate_init.c
>> +++ qemu-dgibson-for-2.6.git/target-ppc/translate_init.c
>> @@ -8522,6 +8522,20 @@ void cpu_ppc_set_papr(PowerPCCPU *cpu)
>>      }
>>  }
>>  
>> +target_ulong cpu_ppc_get_excp_prefix(target_ulong ail)
>> +{
>> +    switch (ail) {
>> +    case AIL_NONE:
>> +        return 0;
>> +    case AIL_0001_8000:
>> +        return 0x18000;
>> +    case AIL_C000_0000_0000_4000:
>> +        return 0xC000000000004000ULL;
>> +    default:
>> +        return (target_ulong) -1ULL;
>> +    }
>> +}
>> +
>>  #endif /* !defined(CONFIG_USER_ONLY) */
>>  
>>  #endif /* defined (TARGET_PPC64) */
>> Index: qemu-dgibson-for-2.6.git/target-ppc/cpu.h
>> ===================================================================
>> --- qemu-dgibson-for-2.6.git.orig/target-ppc/cpu.h
>> +++ qemu-dgibson-for-2.6.git/target-ppc/cpu.h
>> @@ -1269,6 +1269,7 @@ void store_booke_tsr (CPUPPCState *env,
>>  void ppc_tlb_invalidate_all (CPUPPCState *env);
>>  void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
>>  void cpu_ppc_set_papr(PowerPCCPU *cpu);
>> +target_ulong cpu_ppc_get_excp_prefix(target_ulong ail);
>>  #endif
>>  #endif
>>  
>> @@ -2277,6 +2278,14 @@ enum {
>>      HMER_XSCOM_STATUS_LSH       = (63 - 23),
>>  };
>>  
>> +/* Alternate Interrupt Location (AIL) */
>> +enum {
>> +    AIL_NONE                = 0,
>> +    AIL_RESERVED            = 1,
>> +    AIL_0001_8000           = 2,
>> +    AIL_C000_0000_0000_4000 = 3,
>> +};
>> +
>>  /*****************************************************************************/
>>  
>>  static inline target_ulong cpu_read_xer(CPUPPCState *env)
>> Index: qemu-dgibson-for-2.6.git/include/hw/ppc/spapr.h
>> ===================================================================
>> --- qemu-dgibson-for-2.6.git.orig/include/hw/ppc/spapr.h
>> +++ qemu-dgibson-for-2.6.git/include/hw/ppc/spapr.h
>> @@ -204,11 +204,6 @@ struct sPAPRMachineState {
>>  #define H_SET_MODE_ENDIAN_BIG    0
>>  #define H_SET_MODE_ENDIAN_LITTLE 1
>>  
>> -/* Flags for H_SET_MODE_RESOURCE_ADDR_TRANS_MODE */
>> -#define H_SET_MODE_ADDR_TRANS_NONE                  0
>> -#define H_SET_MODE_ADDR_TRANS_0001_8000             2
>> -#define H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000   3
>> -
>>  /* VASI States */
>>  #define H_VASI_INVALID    0
>>  #define H_VASI_ENABLED    1
>>
>
Cédric Le Goater March 31, 2016, 8:20 a.m. UTC | #7
On 03/30/2016 07:12 PM, Greg Kurz wrote:
> On Wed, 30 Mar 2016 17:38:34 +0200
> Cédric Le Goater <clg@fr.ibm.com> wrote:
> 
>> This address is changed by the linux kernel using the H_SET_MODE hcall
>> and needs to be restored when migrating a spapr VM running in
>> TCG. This can be done using the AIL bits from the LPCR register.
>>
>> The patch introduces a helper routine cpu_ppc_get_excp_prefix() which
>> returns the effective address offset of the interrupt handler
>> depending on the LPCR_AIL bits. The same helper can be used in the
>> H_SET_MODE hcall, which lets us remove the H_SET_MODE_ADDR_TRANS_*
>> defines.
>>
>> Signed-off-by: Cédric Le Goater <clg@fr.ibm.com>
>> ---
>>
> 
> Sorry I hit the send button too quickly... Just a nit but my Reviewed-by stands.
> 
>>  Changes since v1:
>>
>>  - moved helper routine under target-ppc/
>>  - moved the restore of excp_prefix under cpu_post_load()
>>
>>  hw/ppc/spapr_hcall.c        |   13 ++-----------
>>  include/hw/ppc/spapr.h      |    5 -----
>>  target-ppc/cpu.h            |    9 +++++++++
>>  target-ppc/machine.c        |   20 +++++++++++++++++++-
>>  target-ppc/translate_init.c |   14 ++++++++++++++
>>  5 files changed, 44 insertions(+), 17 deletions(-)
>>
>> Index: qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
>> ===================================================================
>> --- qemu-dgibson-for-2.6.git.orig/hw/ppc/spapr_hcall.c
>> +++ qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
>> @@ -835,17 +835,8 @@ static target_ulong h_set_mode_resource_
>>          return H_P4;
>>      }
>>
>> -    switch (mflags) {
>> -    case H_SET_MODE_ADDR_TRANS_NONE:
>> -        prefix = 0;
>> -        break;
>> -    case H_SET_MODE_ADDR_TRANS_0001_8000:
>> -        prefix = 0x18000;
>> -        break;
>> -    case H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000:
>> -        prefix = 0xC000000000004000ULL;
>> -        break;
>> -    default:
>> +    prefix = cpu_ppc_get_excp_prefix(mflags);
>> +    if (prefix == (target_ulong) -1ULL) {
> 
> +    if (prefix == (target_ulong) (-1ULL)) {
> 
> to make ./scripts/checkpatch.pl happy :)

yes. 

The funny thing is that checkpatch.pl does not complain for the exact
same line below. Looks like a checkpatch.pl bug to me.

C.

> 
>>          return H_UNSUPPORTED_FLAG;
>>      }
>>
>> Index: qemu-dgibson-for-2.6.git/target-ppc/machine.c
>> ===================================================================
>> --- qemu-dgibson-for-2.6.git.orig/target-ppc/machine.c
>> +++ qemu-dgibson-for-2.6.git/target-ppc/machine.c
>> @@ -156,12 +156,26 @@ static void cpu_pre_save(void *opaque)
>>      }
>>  }
>>
>> +
>> +static int cpu_post_load_excp_prefix(CPUPPCState *env)
>> +{
>> +    int ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
>> +    target_ulong prefix = cpu_ppc_get_excp_prefix(ail);
>> +
>> +    if (prefix == (target_ulong) -1ULL) {
>> +        return -EINVAL;
>> +    }
>> +    env->excp_prefix = prefix;
>> +    return 0;
>> +}
>> +
>>  static int cpu_post_load(void *opaque, int version_id)
>>  {
>>      PowerPCCPU *cpu = opaque;
>>      CPUPPCState *env = &cpu->env;
>>      int i;
>>      target_ulong msr;
>> +    int ret = 0;
>>
>>      /*
>>       * We always ignore the source PVR. The user or management
>> @@ -201,7 +215,11 @@ static int cpu_post_load(void *opaque, i
>>
>>      hreg_compute_mem_idx(env);
>>
>> -    return 0;
>> +    if (env->spr[SPR_LPCR] & LPCR_AIL) {
>> +        ret = cpu_post_load_excp_prefix(env);
>> +    }
>> +
>> +    return ret;
>>  }
>>
>>  static bool fpu_needed(void *opaque)
>> Index: qemu-dgibson-for-2.6.git/target-ppc/translate_init.c
>> ===================================================================
>> --- qemu-dgibson-for-2.6.git.orig/target-ppc/translate_init.c
>> +++ qemu-dgibson-for-2.6.git/target-ppc/translate_init.c
>> @@ -8522,6 +8522,20 @@ void cpu_ppc_set_papr(PowerPCCPU *cpu)
>>      }
>>  }
>>
>> +target_ulong cpu_ppc_get_excp_prefix(target_ulong ail)
>> +{
>> +    switch (ail) {
>> +    case AIL_NONE:
>> +        return 0;
>> +    case AIL_0001_8000:
>> +        return 0x18000;
>> +    case AIL_C000_0000_0000_4000:
>> +        return 0xC000000000004000ULL;
>> +    default:
>> +        return (target_ulong) -1ULL;
>> +    }
>> +}
>> +
>>  #endif /* !defined(CONFIG_USER_ONLY) */
>>
>>  #endif /* defined (TARGET_PPC64) */
>> Index: qemu-dgibson-for-2.6.git/target-ppc/cpu.h
>> ===================================================================
>> --- qemu-dgibson-for-2.6.git.orig/target-ppc/cpu.h
>> +++ qemu-dgibson-for-2.6.git/target-ppc/cpu.h
>> @@ -1269,6 +1269,7 @@ void store_booke_tsr (CPUPPCState *env,
>>  void ppc_tlb_invalidate_all (CPUPPCState *env);
>>  void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
>>  void cpu_ppc_set_papr(PowerPCCPU *cpu);
>> +target_ulong cpu_ppc_get_excp_prefix(target_ulong ail);
>>  #endif
>>  #endif
>>
>> @@ -2277,6 +2278,14 @@ enum {
>>      HMER_XSCOM_STATUS_LSH       = (63 - 23),
>>  };
>>
>> +/* Alternate Interrupt Location (AIL) */
>> +enum {
>> +    AIL_NONE                = 0,
>> +    AIL_RESERVED            = 1,
>> +    AIL_0001_8000           = 2,
>> +    AIL_C000_0000_0000_4000 = 3,
>> +};
>> +
>>  /*****************************************************************************/
>>
>>  static inline target_ulong cpu_read_xer(CPUPPCState *env)
>> Index: qemu-dgibson-for-2.6.git/include/hw/ppc/spapr.h
>> ===================================================================
>> --- qemu-dgibson-for-2.6.git.orig/include/hw/ppc/spapr.h
>> +++ qemu-dgibson-for-2.6.git/include/hw/ppc/spapr.h
>> @@ -204,11 +204,6 @@ struct sPAPRMachineState {
>>  #define H_SET_MODE_ENDIAN_BIG    0
>>  #define H_SET_MODE_ENDIAN_LITTLE 1
>>
>> -/* Flags for H_SET_MODE_RESOURCE_ADDR_TRANS_MODE */
>> -#define H_SET_MODE_ADDR_TRANS_NONE                  0
>> -#define H_SET_MODE_ADDR_TRANS_0001_8000             2
>> -#define H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000   3
>> -
>>  /* VASI States */
>>  #define H_VASI_INVALID    0
>>  #define H_VASI_ENABLED    1
>
Cédric Le Goater March 31, 2016, 9:33 a.m. UTC | #8
>>> Index: qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
>>> ===================================================================
>>> --- qemu-dgibson-for-2.6.git.orig/hw/ppc/spapr_hcall.c
>>> +++ qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
>>> @@ -835,17 +835,8 @@ static target_ulong h_set_mode_resource_
>>>          return H_P4;
>>>      }
>>>
>>> -    switch (mflags) {
>>> -    case H_SET_MODE_ADDR_TRANS_NONE:
>>> -        prefix = 0;
>>> -        break;
>>> -    case H_SET_MODE_ADDR_TRANS_0001_8000:
>>> -        prefix = 0x18000;
>>> -        break;
>>> -    case H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000:
>>> -        prefix = 0xC000000000004000ULL;
>>> -        break;
>>> -    default:
>>> +    prefix = cpu_ppc_get_excp_prefix(mflags);
>>> +    if (prefix == (target_ulong) -1ULL) {
>>
>> +    if (prefix == (target_ulong) (-1ULL)) {
>>
>> to make ./scripts/checkpatch.pl happy :)
> 
> yes. 
> 
> The funny thing is that checkpatch.pl does not complain for the exact
> same line below. Looks like a checkpatch.pl bug to me.

Well, the reason is that a new possible type 'target_ulong' is caught a 
little late in the checkpatch process and this is why the script complains 
at the first occurrence.

Pointer casts are caught early but not casts, probably because this is too
complex to catch with a regex.
 
So the easy fix would be to add 'target_ulong' in the @typeList array. 
This seems reasonable enough as 'target_ulong' is a common qemu type.

C.
David Gibson April 1, 2016, 2:43 a.m. UTC | #9
On Thu, Mar 31, 2016 at 08:13:09AM +0100, Mark Cave-Ayland wrote:
> On 31/03/16 05:55, David Gibson wrote:
> 
> > On Wed, Mar 30, 2016 at 05:38:34PM +0200, Cédric Le Goater wrote:
> >> This address is changed by the linux kernel using the H_SET_MODE hcall
> >> and needs to be restored when migrating a spapr VM running in
> >> TCG. This can be done using the AIL bits from the LPCR register.
> >>
> >> The patch introduces a helper routine cpu_ppc_get_excp_prefix() which
> >> returns the effective address offset of the interrupt handler
> >> depending on the LPCR_AIL bits. The same helper can be used in the
> >> H_SET_MODE hcall, which lets us remove the H_SET_MODE_ADDR_TRANS_*
> >> defines.
> >>
> >> Signed-off-by: Cédric Le Goater <clg@fr.ibm.com>
> > 
> > I've applied this (with Greg's minor amendments) to ppc-for-2.6),
> > since it certainly improves behaviour, although I have a couple of
> > queries:
> > 
> >> ---
> >>
> >>  Changes since v1:
> >>
> >>  - moved helper routine under target-ppc/
> >>  - moved the restore of excp_prefix under cpu_post_load()
> >>
> >>  hw/ppc/spapr_hcall.c        |   13 ++-----------
> >>  include/hw/ppc/spapr.h      |    5 -----
> >>  target-ppc/cpu.h            |    9 +++++++++
> >>  target-ppc/machine.c        |   20 +++++++++++++++++++-
> >>  target-ppc/translate_init.c |   14 ++++++++++++++
> >>  5 files changed, 44 insertions(+), 17 deletions(-)
> >>
> >> Index: qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
> >> ===================================================================
> >> --- qemu-dgibson-for-2.6.git.orig/hw/ppc/spapr_hcall.c
> >> +++ qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
> >> @@ -835,17 +835,8 @@ static target_ulong h_set_mode_resource_
> >>          return H_P4;
> >>      }
> >>  
> >> -    switch (mflags) {
> >> -    case H_SET_MODE_ADDR_TRANS_NONE:
> >> -        prefix = 0;
> >> -        break;
> >> -    case H_SET_MODE_ADDR_TRANS_0001_8000:
> >> -        prefix = 0x18000;
> >> -        break;
> >> -    case H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000:
> >> -        prefix = 0xC000000000004000ULL;
> >> -        break;
> >> -    default:
> >> +    prefix = cpu_ppc_get_excp_prefix(mflags);
> >> +    if (prefix == (target_ulong) -1ULL) {
> >>          return H_UNSUPPORTED_FLAG;
> >>      }
> >>  
> >> Index: qemu-dgibson-for-2.6.git/target-ppc/machine.c
> >> ===================================================================
> >> --- qemu-dgibson-for-2.6.git.orig/target-ppc/machine.c
> >> +++ qemu-dgibson-for-2.6.git/target-ppc/machine.c
> >> @@ -156,12 +156,26 @@ static void cpu_pre_save(void *opaque)
> >>      }
> >>  }
> >>  
> >> +
> >> +static int cpu_post_load_excp_prefix(CPUPPCState *env)
> >> +{
> >> +    int ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
> >> +    target_ulong prefix = cpu_ppc_get_excp_prefix(ail);
> >> +
> >> +    if (prefix == (target_ulong) -1ULL) {
> >> +        return -EINVAL;
> >> +    }
> >> +    env->excp_prefix = prefix;
> >> +    return 0;
> >> +}
> >> +
> >>  static int cpu_post_load(void *opaque, int version_id)
> >>  {
> >>      PowerPCCPU *cpu = opaque;
> >>      CPUPPCState *env = &cpu->env;
> >>      int i;
> >>      target_ulong msr;
> >> +    int ret = 0;
> >>  
> >>      /*
> >>       * We always ignore the source PVR. The user or management
> >> @@ -201,7 +215,11 @@ static int cpu_post_load(void *opaque, i
> >>  
> >>      hreg_compute_mem_idx(env);
> >>  
> >> -    return 0;
> >> +    if (env->spr[SPR_LPCR] & LPCR_AIL) {
> >> +        ret = cpu_post_load_excp_prefix(env);
> >> +    }
> > 
> > Why not call this unconditionally?  If AIL == 0 it will still do the
> > right thing.
> > 
> > Aren't there also circumstances where the exception prefix can depend
> > on the MSR?  Do those need to be handled somewhere?
> 
> Yes indeed - this was part of my patchset last year to fix up various
> migration issues for the Mac PPC machines (see commit
> 2360b6e84f78d41fa0f76555a947148b73645259).
> 
> I agree that having the env->excp_prefix logic split like this isn't a
> particularly great idea. Let's just have a single helper function as in
> the patch above and use that in both places (and in fact with recent
> changes I have a feeling env->excp_prefix is one of the few remaining
> reasons that the above change is still required, but please check this).

Right.

So, what I'd really prefer to see here is a single
update_excp_prefix() helper which will set env->excp_prefix based on
whatever registers are relevant (LPCR, MSR and probably the cpu
model).  That would be called on incoming migration, and after
updating any of the relevant registers (so from the mtmsr and mtlpcr
emulations).  H_SET_MODE should be handled by first updating the LPCR
value, then calling the update helper.

Cédric, I'm ok if you provide a version of that which only handles
POWER7 and POWER8 (i.e. spapr compatible models for now).  Mark - if
you can supply corrections to that outline for Macintosh era models,
that would be great.

I do want to get the basic migration problem fixed before 2.6 is
release.
David Gibson April 1, 2016, 3:34 a.m. UTC | #10
On Thu, Mar 31, 2016 at 03:55:42PM +1100, David Gibson wrote:
> On Wed, Mar 30, 2016 at 05:38:34PM +0200, Cédric Le Goater wrote:
> > This address is changed by the linux kernel using the H_SET_MODE hcall
> > and needs to be restored when migrating a spapr VM running in
> > TCG. This can be done using the AIL bits from the LPCR register.
> > 
> > The patch introduces a helper routine cpu_ppc_get_excp_prefix() which
> > returns the effective address offset of the interrupt handler
> > depending on the LPCR_AIL bits. The same helper can be used in the
> > H_SET_MODE hcall, which lets us remove the H_SET_MODE_ADDR_TRANS_*
> > defines.
> > 
> > Signed-off-by: Cédric Le Goater <clg@fr.ibm.com>
> 
> I've applied this (with Greg's minor amendments) to ppc-for-2.6),
> since it certainly improves behaviour, although I have a couple of
> queries:

And.. I've take it out again now.  In addition to the fact that I'd
like some rework suggested elsewhere, it breaks compile for 32-bit ppc
targets.
diff mbox

Patch

Index: qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
===================================================================
--- qemu-dgibson-for-2.6.git.orig/hw/ppc/spapr_hcall.c
+++ qemu-dgibson-for-2.6.git/hw/ppc/spapr_hcall.c
@@ -835,17 +835,8 @@  static target_ulong h_set_mode_resource_
         return H_P4;
     }
 
-    switch (mflags) {
-    case H_SET_MODE_ADDR_TRANS_NONE:
-        prefix = 0;
-        break;
-    case H_SET_MODE_ADDR_TRANS_0001_8000:
-        prefix = 0x18000;
-        break;
-    case H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000:
-        prefix = 0xC000000000004000ULL;
-        break;
-    default:
+    prefix = cpu_ppc_get_excp_prefix(mflags);
+    if (prefix == (target_ulong) -1ULL) {
         return H_UNSUPPORTED_FLAG;
     }
 
Index: qemu-dgibson-for-2.6.git/target-ppc/machine.c
===================================================================
--- qemu-dgibson-for-2.6.git.orig/target-ppc/machine.c
+++ qemu-dgibson-for-2.6.git/target-ppc/machine.c
@@ -156,12 +156,26 @@  static void cpu_pre_save(void *opaque)
     }
 }
 
+
+static int cpu_post_load_excp_prefix(CPUPPCState *env)
+{
+    int ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
+    target_ulong prefix = cpu_ppc_get_excp_prefix(ail);
+
+    if (prefix == (target_ulong) -1ULL) {
+        return -EINVAL;
+    }
+    env->excp_prefix = prefix;
+    return 0;
+}
+
 static int cpu_post_load(void *opaque, int version_id)
 {
     PowerPCCPU *cpu = opaque;
     CPUPPCState *env = &cpu->env;
     int i;
     target_ulong msr;
+    int ret = 0;
 
     /*
      * We always ignore the source PVR. The user or management
@@ -201,7 +215,11 @@  static int cpu_post_load(void *opaque, i
 
     hreg_compute_mem_idx(env);
 
-    return 0;
+    if (env->spr[SPR_LPCR] & LPCR_AIL) {
+        ret = cpu_post_load_excp_prefix(env);
+    }
+
+    return ret;
 }
 
 static bool fpu_needed(void *opaque)
Index: qemu-dgibson-for-2.6.git/target-ppc/translate_init.c
===================================================================
--- qemu-dgibson-for-2.6.git.orig/target-ppc/translate_init.c
+++ qemu-dgibson-for-2.6.git/target-ppc/translate_init.c
@@ -8522,6 +8522,20 @@  void cpu_ppc_set_papr(PowerPCCPU *cpu)
     }
 }
 
+target_ulong cpu_ppc_get_excp_prefix(target_ulong ail)
+{
+    switch (ail) {
+    case AIL_NONE:
+        return 0;
+    case AIL_0001_8000:
+        return 0x18000;
+    case AIL_C000_0000_0000_4000:
+        return 0xC000000000004000ULL;
+    default:
+        return (target_ulong) -1ULL;
+    }
+}
+
 #endif /* !defined(CONFIG_USER_ONLY) */
 
 #endif /* defined (TARGET_PPC64) */
Index: qemu-dgibson-for-2.6.git/target-ppc/cpu.h
===================================================================
--- qemu-dgibson-for-2.6.git.orig/target-ppc/cpu.h
+++ qemu-dgibson-for-2.6.git/target-ppc/cpu.h
@@ -1269,6 +1269,7 @@  void store_booke_tsr (CPUPPCState *env,
 void ppc_tlb_invalidate_all (CPUPPCState *env);
 void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
 void cpu_ppc_set_papr(PowerPCCPU *cpu);
+target_ulong cpu_ppc_get_excp_prefix(target_ulong ail);
 #endif
 #endif
 
@@ -2277,6 +2278,14 @@  enum {
     HMER_XSCOM_STATUS_LSH       = (63 - 23),
 };
 
+/* Alternate Interrupt Location (AIL) */
+enum {
+    AIL_NONE                = 0,
+    AIL_RESERVED            = 1,
+    AIL_0001_8000           = 2,
+    AIL_C000_0000_0000_4000 = 3,
+};
+
 /*****************************************************************************/
 
 static inline target_ulong cpu_read_xer(CPUPPCState *env)
Index: qemu-dgibson-for-2.6.git/include/hw/ppc/spapr.h
===================================================================
--- qemu-dgibson-for-2.6.git.orig/include/hw/ppc/spapr.h
+++ qemu-dgibson-for-2.6.git/include/hw/ppc/spapr.h
@@ -204,11 +204,6 @@  struct sPAPRMachineState {
 #define H_SET_MODE_ENDIAN_BIG    0
 #define H_SET_MODE_ENDIAN_LITTLE 1
 
-/* Flags for H_SET_MODE_RESOURCE_ADDR_TRANS_MODE */
-#define H_SET_MODE_ADDR_TRANS_NONE                  0
-#define H_SET_MODE_ADDR_TRANS_0001_8000             2
-#define H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000   3
-
 /* VASI States */
 #define H_VASI_INVALID    0
 #define H_VASI_ENABLED    1