diff options
author | Nicholas Piggin <npiggin@gmail.com> | 2020-03-19 16:44:39 +1000 |
---|---|---|
committer | David Gibson <david@gibson.dropbear.id.au> | 2020-03-24 11:56:14 +1100 |
commit | 0418bf78fe8e61e619782940e77ca2d18b8c2d35 (patch) | |
tree | e9e8d4439f380e8a70ee11bda948e70d1465ff41 /target/ppc/mmu-hash64.c | |
parent | f9e3e1a35e8fd63d61fae58bd98d24d7defa9316 (diff) |
target/ppc: Fix ISA v3.0 (POWER9) slbia implementation
The new ISA v3.0 slbia variants have not been implemented for TCG,
which can lead to crashing when a POWER9 machine boots Linux using
the hash MMU, for example ("disable_radix" kernel command line).
Add them.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Message-Id: <20200319064439.1020571-1-npiggin@gmail.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
[dwg: Fixed compile error for USER_ONLY builds]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Diffstat (limited to 'target/ppc/mmu-hash64.c')
-rw-r--r-- | target/ppc/mmu-hash64.c | 56 |
1 files changed, 49 insertions, 7 deletions
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c index 373d44de74..e5baabf0e1 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, |