arch-arm: Fix implementation of TLBI ALLEx instructions
authorGiacomo Travaglini <giacomo.travaglini@arm.com>
Thu, 17 Sep 2020 16:31:55 +0000 (17:31 +0100)
committerGiacomo Travaglini <giacomo.travaglini@arm.com>
Fri, 23 Oct 2020 16:23:27 +0000 (16:23 +0000)
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 <giacomo.travaglini@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/35241
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
src/arch/arm/isa.cc
src/arch/arm/tlb.cc
src/arch/arm/tlb.hh
src/arch/arm/tlbi_op.cc
src/arch/arm/tlbi_op.hh

index d3f9c9888402f686a95bb8e1c6e4fcabae3ebd1f..1c70a771e902871cecd7346685a46a64d8116624 100644 (file)
@@ -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
             {
index a8e0cb30a70057d34e8b53c2663e3663b8a71cfd..56bce27353f643fe73b89215f4c91423972e2953 100644 (file)
@@ -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)
 {
index 5007b3ce39cfb81a978d22240e43c8e206d9fe9d..b05c9ba30d8890c4a494ea7c8d5d8bdeb5f01e32 100644 (file)
@@ -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
index 76a30965747c1c5c3719eb944f8959cb3aec6f45..be7a78b2fc30b6867dd0559b2a582e1820b20014 100644 (file)
@@ -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)
 {
index 5371da04d010051d0cad2aa83add891e13fd56df..8b405871d1fc6691dbb6d6bcb05170a93d22c25d 100644 (file)
@@ -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
 {