diff mbox series

[3/6] target/ppc: Fix instruction loading endianness in alignment interrupt

Message ID 20230323022237.1807512-3-npiggin@gmail.com
State New
Headers show
Series [1/6] target/ppc: Fix width of some 32-bit SPRs | expand

Commit Message

Nicholas Piggin March 23, 2023, 2:22 a.m. UTC
powerpc ifetch endianness depends on MSR[LE] so it has to byteswap
after cpu_ldl_code(). This corrects DSISR bits in alignment
interrupts when running in little endian mode.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 target/ppc/excp_helper.c | 27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

Comments

Fabiano Rosas March 24, 2023, 1:30 p.m. UTC | #1
Hi Nick,

> powerpc ifetch endianness depends on MSR[LE] so it has to byteswap
> after cpu_ldl_code(). This corrects DSISR bits in alignment
> interrupts when running in little endian mode.
>

Just a thought, we have these tests that perhaps could have caught
this:  https://github.com/legoater/pnv-test

Despite the name they do have (some) support to pseries as well. Not
sure how the P8 support is these days though.

> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
> ---
>  target/ppc/excp_helper.c | 27 ++++++++++++++++++++++++++-
>  1 file changed, 26 insertions(+), 1 deletion(-)
>
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 287659c74d..5f0e363363 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -133,6 +133,31 @@ static void dump_hcall(CPUPPCState *env)
>                    env->nip);
>  }
>  
> +/* Return true iff byteswap is needed in a scalar memop */
> +static inline bool need_byteswap(CPUArchState *env)
> +{
> +#if TARGET_BIG_ENDIAN

TARGET_BIG_ENDIAN is always set for softmmu mode. See
configs/targets/ppc64-softmmu.mak

> +     return !!(env->msr & ((target_ulong)1 << MSR_LE));
> +#else
> +     return !(env->msr & ((target_ulong)1 << MSR_LE));
> +#endif
> +}
> +
> +static uint32_t ppc_ldl_code(CPUArchState *env, abi_ptr addr)
> +{
> +    uint32_t insn = cpu_ldl_code(env, addr);
> +#if TARGET_BIG_ENDIAN
> +    if (env->msr & ((target_ulong)1 << MSR_LE)) {
> +        insn = bswap32(insn);
> +    }
> +#else
> +    if (!(env->msr & ((target_ulong)1 << MSR_LE))) {
> +        insn = bswap32(insn);
> +    }
> +#endif
> +    return insn;
> +}
> +
>  static void ppc_excp_debug_sw_tlb(CPUPPCState *env, int excp)
>  {
>      const char *es;
> @@ -3097,7 +3122,7 @@ void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
>  
>      /* Restore state and reload the insn we executed, for filling in DSISR.  */
>      cpu_restore_state(cs, retaddr);
> -    insn = cpu_ldl_code(env, env->nip);
> +    insn = ppc_ldl_code(env, env->nip);
>  
>      switch (env->mmu_model) {
>      case POWERPC_MMU_SOFT_4xx:
Nicholas Piggin March 27, 2023, 4:25 a.m. UTC | #2
On Fri Mar 24, 2023 at 11:30 PM AEST, Fabiano Rosas wrote:
> Hi Nick,
>
> > powerpc ifetch endianness depends on MSR[LE] so it has to byteswap
> > after cpu_ldl_code(). This corrects DSISR bits in alignment
> > interrupts when running in little endian mode.
> >
>
> Just a thought, we have these tests that perhaps could have caught
> this:  https://github.com/legoater/pnv-test
>
> Despite the name they do have (some) support to pseries as well. Not
> sure how the P8 support is these days though.

Hey Fabiano,

Thanks for the review. Good thinking, and actually I did catch some
of these (the SPR size one) when running kvm-unit-tests with TCG. I
ported it to powernv too. I wonder if we should merge pnv-test into
kvm-unit-tests.

> > Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
> > ---
> >  target/ppc/excp_helper.c | 27 ++++++++++++++++++++++++++-
> >  1 file changed, 26 insertions(+), 1 deletion(-)
> >
> > diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> > index 287659c74d..5f0e363363 100644
> > --- a/target/ppc/excp_helper.c
> > +++ b/target/ppc/excp_helper.c
> > @@ -133,6 +133,31 @@ static void dump_hcall(CPUPPCState *env)
> >                    env->nip);
> >  }
> >  
> > +/* Return true iff byteswap is needed in a scalar memop */
> > +static inline bool need_byteswap(CPUArchState *env)
> > +{
> > +#if TARGET_BIG_ENDIAN
>
> TARGET_BIG_ENDIAN is always set for softmmu mode. See
> configs/targets/ppc64-softmmu.mak

I see, I just took it from translate.c and actually stupidly forgot
to actually call it here :) I'll fix it up.

Thanks,
Nick
diff mbox series

Patch

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 287659c74d..5f0e363363 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -133,6 +133,31 @@  static void dump_hcall(CPUPPCState *env)
                   env->nip);
 }
 
+/* Return true iff byteswap is needed in a scalar memop */
+static inline bool need_byteswap(CPUArchState *env)
+{
+#if TARGET_BIG_ENDIAN
+     return !!(env->msr & ((target_ulong)1 << MSR_LE));
+#else
+     return !(env->msr & ((target_ulong)1 << MSR_LE));
+#endif
+}
+
+static uint32_t ppc_ldl_code(CPUArchState *env, abi_ptr addr)
+{
+    uint32_t insn = cpu_ldl_code(env, addr);
+#if TARGET_BIG_ENDIAN
+    if (env->msr & ((target_ulong)1 << MSR_LE)) {
+        insn = bswap32(insn);
+    }
+#else
+    if (!(env->msr & ((target_ulong)1 << MSR_LE))) {
+        insn = bswap32(insn);
+    }
+#endif
+    return insn;
+}
+
 static void ppc_excp_debug_sw_tlb(CPUPPCState *env, int excp)
 {
     const char *es;
@@ -3097,7 +3122,7 @@  void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
 
     /* Restore state and reload the insn we executed, for filling in DSISR.  */
     cpu_restore_state(cs, retaddr);
-    insn = cpu_ldl_code(env, env->nip);
+    insn = ppc_ldl_code(env, env->nip);
 
     switch (env->mmu_model) {
     case POWERPC_MMU_SOFT_4xx: