From: Giacomo Travaglini Date: Thu, 17 Sep 2020 16:31:55 +0000 (+0100) Subject: arch-arm: Fix implementation of TLBI ALLEx instructions X-Git-Tag: develop-gem5-snapshot~570 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=ad5fa9ebe440013aebe07818d1b86b81c1c9234e;p=gem5.git arch-arm: Fix implementation of TLBI ALLEx instructions The TLBIALL op in gem5 was designed after the AArch32 TLBIALL instruction. and was reused by the TLBI ALLEL1, ALLE2, ALLE3 logic. This is not correct for the following reasons: - TLBI ALLEx invalidates regardless of the VMID - TLBI ALLEx (AArch64) is "target regime" oriented, whereas TLBIALL (AArch32) is "current regime" oriented TLBIALL has a different behaviour depending on the current exception level: if issued at EL1 it will invalidate stage1 translations only; if at EL2, it will invalidate stage2 translations as well. TLBI ALLEx is more standard; every TLBI ALLE1 will invalidate stage1 and stage2 translations. This is because the instruction is not executable from the guest (EL1) So for TLBIALL the condition for stage2 forwarding will be: if (!isStage2 && isHyp) { Whereas for TLBI ALLEx will be: if (!isStage2 && target_el == EL1) { Change-Id: I282f2cfaecbfc883e173770e5d2578b41055bb7a Signed-off-by: Giacomo Travaglini Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/35241 Reviewed-by: Andreas Sandberg Maintainer: Andreas Sandberg Tested-by: kokoro --- diff --git a/src/arch/arm/isa.cc b/src/arch/arm/isa.cc index d3f9c9888..1c70a771e 100644 --- a/src/arch/arm/isa.cc +++ b/src/arch/arm/isa.cc @@ -1701,7 +1701,7 @@ ISA::setMiscReg(int misc_reg, RegVal val) { assert64(); - TLBIALL tlbiOp(EL3, true); + TLBIALLEL tlbiOp(EL3, true); tlbiOp(tc); return; } @@ -1710,7 +1710,7 @@ ISA::setMiscReg(int misc_reg, RegVal val) { assert64(); - TLBIALL tlbiOp(EL3, true); + TLBIALLEL tlbiOp(EL3, true); tlbiOp.broadcast(tc); return; } @@ -1720,7 +1720,7 @@ ISA::setMiscReg(int misc_reg, RegVal val) assert64(); scr = readMiscReg(MISCREG_SCR); - TLBIALL tlbiOp(EL2, haveSecurity && !scr.ns); + TLBIALLEL tlbiOp(EL2, haveSecurity && !scr.ns); tlbiOp(tc); return; } @@ -1730,12 +1730,30 @@ ISA::setMiscReg(int misc_reg, RegVal val) assert64(); scr = readMiscReg(MISCREG_SCR); - TLBIALL tlbiOp(EL2, haveSecurity && !scr.ns); + TLBIALLEL tlbiOp(EL2, haveSecurity && !scr.ns); tlbiOp.broadcast(tc); return; } // AArch64 TLB Invalidate All, EL1 case MISCREG_TLBI_ALLE1: + { + assert64(); + scr = readMiscReg(MISCREG_SCR); + + TLBIALLEL tlbiOp(EL1, haveSecurity && !scr.ns); + tlbiOp(tc); + return; + } + // AArch64 TLB Invalidate All, EL1, Inner Shareable + case MISCREG_TLBI_ALLE1IS: + { + assert64(); + scr = readMiscReg(MISCREG_SCR); + + TLBIALLEL tlbiOp(EL1, haveSecurity && !scr.ns); + tlbiOp.broadcast(tc); + return; + } case MISCREG_TLBI_VMALLS12E1: // @todo: handle VMID and stage 2 to enable Virtualization { @@ -1759,8 +1777,6 @@ ISA::setMiscReg(int misc_reg, RegVal val) tlbiOp(tc); return; } - // AArch64 TLB Invalidate All, EL1, Inner Shareable - case MISCREG_TLBI_ALLE1IS: case MISCREG_TLBI_VMALLS12E1IS: // @todo: handle VMID and stage 2 to enable Virtualization { diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc index a8e0cb30a..56bce2735 100644 --- a/src/arch/arm/tlb.cc +++ b/src/arch/arm/tlb.cc @@ -299,6 +299,36 @@ TLB::flush(const TLBIALL& tlbi_op) } } +void +TLB::flush(const TLBIALLEL &tlbi_op) +{ + DPRINTF(TLB, "Flushing all TLB entries (%s lookup)\n", + (tlbi_op.secureLookup ? "secure" : "non-secure")); + int x = 0; + TlbEntry *te; + while (x < size) { + te = &table[x]; + const bool el_match = te->checkELMatch( + tlbi_op.targetEL, tlbi_op.inHost); + if (te->valid && tlbi_op.secureLookup == !te->nstid && el_match) { + + DPRINTF(TLB, " - %s\n", te->print()); + te->valid = false; + stats.flushedEntries++; + } + ++x; + } + + stats.flushTlb++; + + // If there's a second stage TLB (and we're not it) + // and if we're targeting EL1 + // then flush it as well + if (!isStage2 && tlbi_op.targetEL == EL1) { + stage2Tlb->flush(tlbi_op.makeStage2()); + } +} + void TLB::flush(const TLBIALLN &tlbi_op) { diff --git a/src/arch/arm/tlb.hh b/src/arch/arm/tlb.hh index 5007b3ce3..b05c9ba30 100644 --- a/src/arch/arm/tlb.hh +++ b/src/arch/arm/tlb.hh @@ -62,6 +62,7 @@ class Stage2MMU; class TLB; class TLBIALL; +class TLBIALLEL; class TLBIALLN; class TLBIMVA; class TLBIASID; @@ -261,7 +262,12 @@ class TLB : public BaseTLB /** Reset the entire TLB */ - void flush(const TLBIALL& tlbi_op); + void flush(const TLBIALL &tlbi_op); + + /** Implementaton of AArch64 TLBI ALLE1(IS), ALLE2(IS), ALLE3(IS) + * instructions + */ + void flush(const TLBIALLEL &tlbi_op); /** Remove all entries in the non secure world, depending on whether they * were allocated in hyp mode or not diff --git a/src/arch/arm/tlbi_op.cc b/src/arch/arm/tlbi_op.cc index 76a309657..be7a78b2f 100644 --- a/src/arch/arm/tlbi_op.cc +++ b/src/arch/arm/tlbi_op.cc @@ -68,6 +68,20 @@ DTLBIALL::operator()(ThreadContext* tc) getMMUPtr(tc)->dflush(*this); } +void +TLBIALLEL::operator()(ThreadContext* tc) +{ + HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2); + inHost = (hcr.tge == 1 && hcr.e2h == 1); + getMMUPtr(tc)->flush(*this); + + // If CheckerCPU is connected, need to notify it of a flush + CheckerCPU *checker = tc->getCheckerCpuPtr(); + if (checker) { + getMMUPtr(checker)->flush(*this); + } +} + void TLBIASID::operator()(ThreadContext* tc) { diff --git a/src/arch/arm/tlbi_op.hh b/src/arch/arm/tlbi_op.hh index 5371da04d..8b405871d 100644 --- a/src/arch/arm/tlbi_op.hh +++ b/src/arch/arm/tlbi_op.hh @@ -121,6 +121,25 @@ class DTLBIALL : public TLBIALL void operator()(ThreadContext* tc) override; }; +/** Implementaton of AArch64 TLBI ALLE(1,2,3)(IS) instructions */ +class TLBIALLEL : public TLBIOp +{ + public: + TLBIALLEL(ExceptionLevel _targetEL, bool _secure) + : TLBIOp(_targetEL, _secure), inHost(false) + {} + + void operator()(ThreadContext* tc) override; + + TLBIALLEL + makeStage2() const + { + return TLBIALLEL(EL1, secureLookup); + } + + bool inHost; +}; + /** TLB Invalidate by ASID match */ class TLBIASID : public TLBIOp {