diff mbox series

[2/2] target/ppc: Fix ISA v3.0 (POWER9) slbia implementation

Message ID 20200318044135.851716-2-npiggin@gmail.com
State New
Headers show
Series [1/2] target/ppc: Fix slbia TLB invalidation gap | expand

Commit Message

Nicholas Piggin March 18, 2020, 4:41 a.m. UTC
Linux using the hash MMU ("disable_radix" command line) on a POWER9
machine quickly hits translation bugs due to using v3.0 slbia
features that are not implemented in TCG. Add them.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 target/ppc/helper.h     |  2 +-
 target/ppc/mmu-hash64.c | 57 ++++++++++++++++++++++++++++++++++++-----
 target/ppc/translate.c  |  5 +++-
 3 files changed, 55 insertions(+), 9 deletions(-)

Comments

Cédric Le Goater March 18, 2020, 5:08 p.m. UTC | #1
On 3/18/20 5:41 AM, Nicholas Piggin wrote:
> Linux using the hash MMU ("disable_radix" command line) on a POWER9
> machine quickly hits translation bugs due to using v3.0 slbia
> features that are not implemented in TCG. Add them.

I checked the ISA books and this looks OK but you are also modifying
slbie.

Thanks,

C. 


> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
> ---
>  target/ppc/helper.h     |  2 +-
>  target/ppc/mmu-hash64.c | 57 ++++++++++++++++++++++++++++++++++++-----
>  target/ppc/translate.c  |  5 +++-
>  3 files changed, 55 insertions(+), 9 deletions(-)
> 
> diff --git a/target/ppc/helper.h b/target/ppc/helper.h
> index ee1498050d..2dfa1c6942 100644
> --- a/target/ppc/helper.h
> +++ b/target/ppc/helper.h
> @@ -615,7 +615,7 @@ DEF_HELPER_FLAGS_3(store_slb, TCG_CALL_NO_RWG, void, env, tl, tl)
>  DEF_HELPER_2(load_slb_esid, tl, env, tl)
>  DEF_HELPER_2(load_slb_vsid, tl, env, tl)
>  DEF_HELPER_2(find_slb_vsid, tl, env, tl)
> -DEF_HELPER_FLAGS_1(slbia, TCG_CALL_NO_RWG, void, env)
> +DEF_HELPER_FLAGS_2(slbia, TCG_CALL_NO_RWG, void, env, i32)
>  DEF_HELPER_FLAGS_2(slbie, TCG_CALL_NO_RWG, void, env, tl)
>  DEF_HELPER_FLAGS_2(slbieg, TCG_CALL_NO_RWG, void, env, tl)
>  #endif
> diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
> index 373d44de74..deb1c13a66 100644
> --- a/target/ppc/mmu-hash64.c
> +++ b/target/ppc/mmu-hash64.c
> @@ -95,9 +95,10 @@ void dump_slb(PowerPCCPU *cpu)
>      }
>  }
> 
> -void helper_slbia(CPUPPCState *env)
> +void helper_slbia(CPUPPCState *env, uint32_t ih)
>  {
>      PowerPCCPU *cpu = env_archcpu(env);
> +    int starting_entry;
>      int n;
> 
>      /*
> @@ -111,18 +112,59 @@ void helper_slbia(CPUPPCState *env)
>       * expected that slbmte is more common than slbia, and slbia is usually
>       * going to evict valid SLB entries, so that tradeoff is unlikely to be a
>       * good one.
> +     *
> +     * ISA v2.05 introduced IH field with values 0,1,2,6. These all invalidate
> +     * the same SLB entries (everything but entry 0), but differ in what
> +     * "lookaside information" is invalidated. TCG can ignore this and flush
> +     * everything.
> +     *
> +     * ISA v3.0 introduced additional values 3,4,7, which change what SLBs are
> +     * invalidated.
>       */
> 
> -    /* XXX: Warning: slbia never invalidates the first segment */
> -    for (n = 1; n < cpu->hash64_opts->slb_size; n++) {
> -        ppc_slb_t *slb = &env->slb[n];
> +    env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
> +
> +    starting_entry = 1; /* default for IH=0,1,2,6 */
> +
> +    if (env->mmu_model == POWERPC_MMU_3_00) {
> +        switch (ih) {
> +        case 0x7:
> +            /* invalidate no SLBs, but all lookaside information */
> +            return;
> 
> -        if (slb->esid & SLB_ESID_V) {
> -            slb->esid &= ~SLB_ESID_V;
> +        case 0x3:
> +        case 0x4:
> +            /* also considers SLB entry 0 */
> +            starting_entry = 0;
> +            break;
> +
> +        case 0x5:
> +            /* treat undefined values as ih==0, and warn */
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "slbia undefined IH field %u.\n", ih);
> +            break;
> +
> +        default:
> +            /* 0,1,2,6 */
> +            break;
>          }
>      }
> 
> -    env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
> +    for (n = starting_entry; n < cpu->hash64_opts->slb_size; n++) {
> +        ppc_slb_t *slb = &env->slb[n];
> +
> +        if (!(slb->esid & SLB_ESID_V)) {
> +            continue;
> +        }
> +        if (env->mmu_model == POWERPC_MMU_3_00) {
> +            if (ih == 0x3 && (slb->vsid & SLB_VSID_C) == 0) {
> +                /* preserves entries with a class value of 0 */
> +                continue;
> +            }
> +        }
> +
> +        slb->esid &= ~SLB_ESID_V;
> +    }
>  }
> 
>  static void __helper_slbie(CPUPPCState *env, target_ulong addr,
> @@ -136,6 +178,7 @@ static void __helper_slbie(CPUPPCState *env, target_ulong addr,
>          return;
>      }
> 
> +    env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
>      if (slb->esid & SLB_ESID_V) {
>          slb->esid &= ~SLB_ESID_V;
> 
> diff --git a/target/ppc/translate.c b/target/ppc/translate.c
> index eb0ddba850..e514732a09 100644
> --- a/target/ppc/translate.c
> +++ b/target/ppc/translate.c
> @@ -5027,12 +5027,15 @@ static void gen_tlbsync(DisasContext *ctx)
>  /* slbia */
>  static void gen_slbia(DisasContext *ctx)
>  {
> +    uint32_t ih = (ctx->opcode >> 21) & 0x7;
> +    TCGv_i32 t0 = tcg_const_i32(ih);
> +
>  #if defined(CONFIG_USER_ONLY)
>      GEN_PRIV;
>  #else
>      CHK_SV;
> 
> -    gen_helper_slbia(cpu_env);
> +    gen_helper_slbia(cpu_env, t0);
>  #endif /* defined(CONFIG_USER_ONLY) */
>  }
>
Benjamin Herrenschmidt March 18, 2020, 8:46 p.m. UTC | #2
On Wed, 2020-03-18 at 18:08 +0100, Cédric Le Goater wrote:
> On 3/18/20 5:41 AM, Nicholas Piggin wrote:
> > Linux using the hash MMU ("disable_radix" command line) on a POWER9
> > machine quickly hits translation bugs due to using v3.0 slbia
> > features that are not implemented in TCG. Add them.
> 
> I checked the ISA books and this looks OK but you are also modifying
> slbie.

For the same reason, I believe slbie needs to invalidate caches even if
the entry isn't present.

The kernel will under some circumstances overwrite SLB entries without
invalidating (because the translation itself isn't invalid, it's just
that the SLB is full, so anything cached in the ERAT is still
technically ok).

However, when those things get really invalidated, they need to be
taken out, even if they no longer have a corresponding SLB entry.

Cheers,
Ben.

> Thanks,
> 
> C. 
> 
> 
> > Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
> > ---
> >  target/ppc/helper.h     |  2 +-
> >  target/ppc/mmu-hash64.c | 57 ++++++++++++++++++++++++++++++++++++-
> > ----
> >  target/ppc/translate.c  |  5 +++-
> >  3 files changed, 55 insertions(+), 9 deletions(-)
> > 
> > diff --git a/target/ppc/helper.h b/target/ppc/helper.h
> > index ee1498050d..2dfa1c6942 100644
> > --- a/target/ppc/helper.h
> > +++ b/target/ppc/helper.h
> > @@ -615,7 +615,7 @@ DEF_HELPER_FLAGS_3(store_slb, TCG_CALL_NO_RWG,
> > void, env, tl, tl)
> >  DEF_HELPER_2(load_slb_esid, tl, env, tl)
> >  DEF_HELPER_2(load_slb_vsid, tl, env, tl)
> >  DEF_HELPER_2(find_slb_vsid, tl, env, tl)
> > -DEF_HELPER_FLAGS_1(slbia, TCG_CALL_NO_RWG, void, env)
> > +DEF_HELPER_FLAGS_2(slbia, TCG_CALL_NO_RWG, void, env, i32)
> >  DEF_HELPER_FLAGS_2(slbie, TCG_CALL_NO_RWG, void, env, tl)
> >  DEF_HELPER_FLAGS_2(slbieg, TCG_CALL_NO_RWG, void, env, tl)
> >  #endif
> > diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
> > index 373d44de74..deb1c13a66 100644
> > --- a/target/ppc/mmu-hash64.c
> > +++ b/target/ppc/mmu-hash64.c
> > @@ -95,9 +95,10 @@ void dump_slb(PowerPCCPU *cpu)
> >      }
> >  }
> > 
> > -void helper_slbia(CPUPPCState *env)
> > +void helper_slbia(CPUPPCState *env, uint32_t ih)
> >  {
> >      PowerPCCPU *cpu = env_archcpu(env);
> > +    int starting_entry;
> >      int n;
> > 
> >      /*
> > @@ -111,18 +112,59 @@ void helper_slbia(CPUPPCState *env)
> >       * expected that slbmte is more common than slbia, and slbia
> > is usually
> >       * going to evict valid SLB entries, so that tradeoff is
> > unlikely to be a
> >       * good one.
> > +     *
> > +     * ISA v2.05 introduced IH field with values 0,1,2,6. These
> > all invalidate
> > +     * the same SLB entries (everything but entry 0), but differ
> > in what
> > +     * "lookaside information" is invalidated. TCG can ignore this
> > and flush
> > +     * everything.
> > +     *
> > +     * ISA v3.0 introduced additional values 3,4,7, which change
> > what SLBs are
> > +     * invalidated.
> >       */
> > 
> > -    /* XXX: Warning: slbia never invalidates the first segment */
> > -    for (n = 1; n < cpu->hash64_opts->slb_size; n++) {
> > -        ppc_slb_t *slb = &env->slb[n];
> > +    env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
> > +
> > +    starting_entry = 1; /* default for IH=0,1,2,6 */
> > +
> > +    if (env->mmu_model == POWERPC_MMU_3_00) {
> > +        switch (ih) {
> > +        case 0x7:
> > +            /* invalidate no SLBs, but all lookaside information
> > */
> > +            return;
> > 
> > -        if (slb->esid & SLB_ESID_V) {
> > -            slb->esid &= ~SLB_ESID_V;
> > +        case 0x3:
> > +        case 0x4:
> > +            /* also considers SLB entry 0 */
> > +            starting_entry = 0;
> > +            break;
> > +
> > +        case 0x5:
> > +            /* treat undefined values as ih==0, and warn */
> > +            qemu_log_mask(LOG_GUEST_ERROR,
> > +                          "slbia undefined IH field %u.\n", ih);
> > +            break;
> > +
> > +        default:
> > +            /* 0,1,2,6 */
> > +            break;
> >          }
> >      }
> > 
> > -    env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
> > +    for (n = starting_entry; n < cpu->hash64_opts->slb_size; n++)
> > {
> > +        ppc_slb_t *slb = &env->slb[n];
> > +
> > +        if (!(slb->esid & SLB_ESID_V)) {
> > +            continue;
> > +        }
> > +        if (env->mmu_model == POWERPC_MMU_3_00) {
> > +            if (ih == 0x3 && (slb->vsid & SLB_VSID_C) == 0) {
> > +                /* preserves entries with a class value of 0 */
> > +                continue;
> > +            }
> > +        }
> > +
> > +        slb->esid &= ~SLB_ESID_V;
> > +    }
> >  }
> > 
> >  static void __helper_slbie(CPUPPCState *env, target_ulong addr,
> > @@ -136,6 +178,7 @@ static void __helper_slbie(CPUPPCState *env,
> > target_ulong addr,
> >          return;
> >      }
> > 
> > +    env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
> >      if (slb->esid & SLB_ESID_V) {
> >          slb->esid &= ~SLB_ESID_V;
> > 
> > diff --git a/target/ppc/translate.c b/target/ppc/translate.c
> > index eb0ddba850..e514732a09 100644
> > --- a/target/ppc/translate.c
> > +++ b/target/ppc/translate.c
> > @@ -5027,12 +5027,15 @@ static void gen_tlbsync(DisasContext *ctx)
> >  /* slbia */
> >  static void gen_slbia(DisasContext *ctx)
> >  {
> > +    uint32_t ih = (ctx->opcode >> 21) & 0x7;
> > +    TCGv_i32 t0 = tcg_const_i32(ih);
> > +
> >  #if defined(CONFIG_USER_ONLY)
> >      GEN_PRIV;
> >  #else
> >      CHK_SV;
> > 
> > -    gen_helper_slbia(cpu_env);
> > +    gen_helper_slbia(cpu_env, t0);
> >  #endif /* defined(CONFIG_USER_ONLY) */
> >  }
> >
Nicholas Piggin March 19, 2020, 2:42 a.m. UTC | #3
Benjamin Herrenschmidt's on March 19, 2020 6:46 am:
> On Wed, 2020-03-18 at 18:08 +0100, Cédric Le Goater wrote:
>> On 3/18/20 5:41 AM, Nicholas Piggin wrote:
>> > Linux using the hash MMU ("disable_radix" command line) on a POWER9
>> > machine quickly hits translation bugs due to using v3.0 slbia
>> > features that are not implemented in TCG. Add them.
>> 
>> I checked the ISA books and this looks OK but you are also modifying
>> slbie.

That was a mistake that leaked in from debugging the crashes.

> For the same reason, I believe slbie needs to invalidate caches even if
> the entry isn't present.

I don't think it does per the ISA. If we overwrite it then we can only
invalidate with slbia. That's why there is that slb insertion cache for
pre-POWER9 that lets us use slbies to context switch so long as none 
have been overwritten.

> The kernel will under some circumstances overwrite SLB entries without
> invalidating (because the translation itself isn't invalid, it's just
> that the SLB is full, so anything cached in the ERAT is still
> technically ok).
> 
> However, when those things get really invalidated, they need to be
> taken out, even if they no longer have a corresponding SLB entry.

Yeah we track that and do slbia in that case.

Thanks,
Nick
David Gibson March 19, 2020, 5:22 a.m. UTC | #4
On Thu, Mar 19, 2020 at 07:46:54AM +1100, Benjamin Herrenschmidt wrote:
> On Wed, 2020-03-18 at 18:08 +0100, Cédric Le Goater wrote:
> > On 3/18/20 5:41 AM, Nicholas Piggin wrote:
> > > Linux using the hash MMU ("disable_radix" command line) on a POWER9
> > > machine quickly hits translation bugs due to using v3.0 slbia
> > > features that are not implemented in TCG. Add them.
> > 
> > I checked the ISA books and this looks OK but you are also modifying
> > slbie.
> 
> For the same reason, I believe slbie needs to invalidate caches even if
> the entry isn't present.
> 
> The kernel will under some circumstances overwrite SLB entries without
> invalidating (because the translation itself isn't invalid, it's just
> that the SLB is full, so anything cached in the ERAT is still
> technically ok).
> 
> However, when those things get really invalidated, they need to be
> taken out, even if they no longer have a corresponding SLB entry.

Right, the slbie change is certainly correct, but it doesn't match
what the commit message says this is doing.  Nick, can you split that
out please.
diff mbox series

Patch

diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index ee1498050d..2dfa1c6942 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -615,7 +615,7 @@  DEF_HELPER_FLAGS_3(store_slb, TCG_CALL_NO_RWG, void, env, tl, tl)
 DEF_HELPER_2(load_slb_esid, tl, env, tl)
 DEF_HELPER_2(load_slb_vsid, tl, env, tl)
 DEF_HELPER_2(find_slb_vsid, tl, env, tl)
-DEF_HELPER_FLAGS_1(slbia, TCG_CALL_NO_RWG, void, env)
+DEF_HELPER_FLAGS_2(slbia, TCG_CALL_NO_RWG, void, env, i32)
 DEF_HELPER_FLAGS_2(slbie, TCG_CALL_NO_RWG, void, env, tl)
 DEF_HELPER_FLAGS_2(slbieg, TCG_CALL_NO_RWG, void, env, tl)
 #endif
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index 373d44de74..deb1c13a66 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -95,9 +95,10 @@  void dump_slb(PowerPCCPU *cpu)
     }
 }
 
-void helper_slbia(CPUPPCState *env)
+void helper_slbia(CPUPPCState *env, uint32_t ih)
 {
     PowerPCCPU *cpu = env_archcpu(env);
+    int starting_entry;
     int n;
 
     /*
@@ -111,18 +112,59 @@  void helper_slbia(CPUPPCState *env)
      * expected that slbmte is more common than slbia, and slbia is usually
      * going to evict valid SLB entries, so that tradeoff is unlikely to be a
      * good one.
+     *
+     * ISA v2.05 introduced IH field with values 0,1,2,6. These all invalidate
+     * the same SLB entries (everything but entry 0), but differ in what
+     * "lookaside information" is invalidated. TCG can ignore this and flush
+     * everything.
+     *
+     * ISA v3.0 introduced additional values 3,4,7, which change what SLBs are
+     * invalidated.
      */
 
-    /* XXX: Warning: slbia never invalidates the first segment */
-    for (n = 1; n < cpu->hash64_opts->slb_size; n++) {
-        ppc_slb_t *slb = &env->slb[n];
+    env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
+
+    starting_entry = 1; /* default for IH=0,1,2,6 */
+
+    if (env->mmu_model == POWERPC_MMU_3_00) {
+        switch (ih) {
+        case 0x7:
+            /* invalidate no SLBs, but all lookaside information */
+            return;
 
-        if (slb->esid & SLB_ESID_V) {
-            slb->esid &= ~SLB_ESID_V;
+        case 0x3:
+        case 0x4:
+            /* also considers SLB entry 0 */
+            starting_entry = 0;
+            break;
+
+        case 0x5:
+            /* treat undefined values as ih==0, and warn */
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "slbia undefined IH field %u.\n", ih);
+            break;
+
+        default:
+            /* 0,1,2,6 */
+            break;
         }
     }
 
-    env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
+    for (n = starting_entry; n < cpu->hash64_opts->slb_size; n++) {
+        ppc_slb_t *slb = &env->slb[n];
+
+        if (!(slb->esid & SLB_ESID_V)) {
+            continue;
+        }
+        if (env->mmu_model == POWERPC_MMU_3_00) {
+            if (ih == 0x3 && (slb->vsid & SLB_VSID_C) == 0) {
+                /* preserves entries with a class value of 0 */
+                continue;
+            }
+        }
+
+        slb->esid &= ~SLB_ESID_V;
+    }
 }
 
 static void __helper_slbie(CPUPPCState *env, target_ulong addr,
@@ -136,6 +178,7 @@  static void __helper_slbie(CPUPPCState *env, target_ulong addr,
         return;
     }
 
+    env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
     if (slb->esid & SLB_ESID_V) {
         slb->esid &= ~SLB_ESID_V;
 
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index eb0ddba850..e514732a09 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -5027,12 +5027,15 @@  static void gen_tlbsync(DisasContext *ctx)
 /* slbia */
 static void gen_slbia(DisasContext *ctx)
 {
+    uint32_t ih = (ctx->opcode >> 21) & 0x7;
+    TCGv_i32 t0 = tcg_const_i32(ih);
+
 #if defined(CONFIG_USER_ONLY)
     GEN_PRIV;
 #else
     CHK_SV;
 
-    gen_helper_slbia(cpu_env);
+    gen_helper_slbia(cpu_env, t0);
 #endif /* defined(CONFIG_USER_ONLY) */
 }