[gem5-dev] Change in gem5/gem5[develop]: arch-arm: Allow TLB to be used as a WalkCache

2021-12-11 Thread Bobby Bruce (Gerrit) via gem5-dev
Bobby Bruce has submitted this change. (  
https://gem5-review.googlesource.com/c/public/gem5/+/52124 )


Change subject: arch-arm: Allow TLB to be used as a WalkCache
..

arch-arm: Allow TLB to be used as a WalkCache

This patch allows partial translation entries (intermediate PAs obtained
from a table walk) to be stored in an ArmTLB. This effectively means
reserving a fraction of the TLB entries to cache table walks

JIRA: https://gem5.atlassian.net/browse/GEM5-1108

Change-Id: Id0efb7d75dd017366c4c3b74de7b57355a53a01a
Signed-off-by: Giacomo Travaglini 
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/52124
Reviewed-by: Andreas Sandberg 
Maintainer: Andreas Sandberg 
Tested-by: kokoro 
---
M src/arch/arm/ArmTLB.py
M src/arch/arm/mmu.cc
M src/arch/arm/mmu.hh
M src/arch/arm/tlb.cc
M src/arch/arm/tlb.hh
5 files changed, 209 insertions(+), 48 deletions(-)

Approvals:
  Andreas Sandberg: Looks good to me, approved; Looks good to me, approved
  Giacomo Travaglini: Looks good to me, approved; Looks good to me, approved
  kokoro: Regressions pass




diff --git a/src/arch/arm/ArmTLB.py b/src/arch/arm/ArmTLB.py
index 4c86f72..10ed48b 100644
--- a/src/arch/arm/ArmTLB.py
+++ b/src/arch/arm/ArmTLB.py
@@ -51,6 +51,11 @@
 size = Param.Int(64, "TLB size")
 is_stage2 = Param.Bool(False, "Is this a stage 2 TLB?")

+partial_levels = VectorParam.ArmLookupLevel([],
+"List of intermediate lookup levels allowed to be cached in the  
TLB "

+"(=holding intermediate PAs obtained during a table walk")
+
+
 class ArmStage2TLB(ArmTLB):
 size = 32
 is_stage2 = True
diff --git a/src/arch/arm/mmu.cc b/src/arch/arm/mmu.cc
index cffbb20..f4a2114 100644
--- a/src/arch/arm/mmu.cc
+++ b/src/arch/arm/mmu.cc
@@ -67,6 +67,7 @@
 s1State(this, false), s2State(this, true),
 _attr(0),
 _release(nullptr),
+_hasWalkCache(false),
 stats(this)
 {
 // Cache system-level properties
@@ -102,6 +103,27 @@
 getDTBPtr()->setTableWalker(dtbWalker);

 BaseMMU::init();
+
+_hasWalkCache = checkWalkCache();
+}
+
+bool
+MMU::checkWalkCache() const
+{
+for (auto tlb : instruction) {
+if (static_cast(tlb)->walkCache())
+return true;
+}
+for (auto tlb : data) {
+if (static_cast(tlb)->walkCache())
+return true;
+}
+for (auto tlb : unified) {
+if (static_cast(tlb)->walkCache())
+return true;
+}
+
+return false;
 }

 void
@@ -858,11 +880,11 @@
 Fault fault = getResultTe(, req, tc, mode, translation, timing,
   functional, , state);
 // only proceed if we have a valid table entry
-if ((te == NULL) && (fault == NoFault)) delay = true;
+if (!isCompleteTranslation(te) && (fault == NoFault)) delay = true;

 // If we have the table entry transfer some of the attributes to the
 // request that triggered the translation
-if (te != NULL) {
+if (isCompleteTranslation(te)) {
 // Set memory attributes
 DPRINTF(TLBVerbose,
 "Setting memory attributes: shareable: %d,  
innerAttrs: %d, "

@@ -1429,7 +1451,7 @@
 *te = lookup(vaddr, state.asid, state.vmid, state.isHyp, is_secure,  
false,

  false, target_el, false, state.isStage2, mode);

-if (*te == NULL) {
+if (!isCompleteTranslation(*te)) {
 if (req->isPrefetch()) {
 // if the request is a prefetch don't attempt to fill the TLB  
or go
 // any further with the memory access (here we can safely use  
the

@@ -1474,12 +1496,12 @@
 if (state.isStage2) {
 // We are already in the stage 2 TLB. Grab the table entry for  
stage

 // 2 only. We are here because stage 1 translation is disabled.
-TlbEntry *s2_te = NULL;
+TlbEntry *s2_te = nullptr;
 // Get the stage 2 table entry
 fault = getTE(_te, req, tc, mode, translation, timing,  
functional,

   state.isSecure, state.curTranType, state);
 // Check permissions of stage 2
-if ((s2_te != NULL) && (fault == NoFault)) {
+if (isCompleteTranslation(s2_te) && (fault == NoFault)) {
 if (state.aarch64)
 fault = checkPermissions64(s2_te, req, mode, tc, state);
 else
@@ -1489,22 +1511,22 @@
 return fault;
 }

-TlbEntry *s1Te = NULL;
+TlbEntry *s1_te = nullptr;

 Addr vaddr_tainted = req->getVaddr();

 // Get the stage 1 table entry
-fault = getTE(, req, tc, mode, translation, timing, functional,
+fault = getTE(_te, req, tc, mode, translation, timing, functional,
   state.isSecure, state.curTranType, state);
 // only proceed if we have a valid table entry
-if ((s1Te != NULL) && (fault == NoFault)) {
+if (isCompleteTranslation(s1_te) && (fault == NoFault)) {
 // Check stage 1 permissions before checking 

[gem5-dev] Change in gem5/gem5[develop]: arch-arm: Allow TLB to be used as a WalkCache

2021-10-27 Thread Giacomo Travaglini (Gerrit) via gem5-dev
Giacomo Travaglini has uploaded this change for review. (  
https://gem5-review.googlesource.com/c/public/gem5/+/52124 )



Change subject: arch-arm: Allow TLB to be used as a WalkCache
..

arch-arm: Allow TLB to be used as a WalkCache

This patch allows partial translation entries (intermediate PAs obtained
from a table walk) to be stored in an ArmTLB. This effectively means
reserving a fraction of the TLB entries to cache table walks

JIRA: https://gem5.atlassian.net/browse/GEM5-1108

Change-Id: Id0efb7d75dd017366c4c3b74de7b57355a53a01a
Signed-off-by: Giacomo Travaglini 
---
M src/arch/arm/ArmTLB.py
M src/arch/arm/mmu.cc
M src/arch/arm/mmu.hh
M src/arch/arm/tlb.cc
M src/arch/arm/tlb.hh
5 files changed, 185 insertions(+), 37 deletions(-)



diff --git a/src/arch/arm/ArmTLB.py b/src/arch/arm/ArmTLB.py
index 4c86f72..10ed48b 100644
--- a/src/arch/arm/ArmTLB.py
+++ b/src/arch/arm/ArmTLB.py
@@ -51,6 +51,11 @@
 size = Param.Int(64, "TLB size")
 is_stage2 = Param.Bool(False, "Is this a stage 2 TLB?")

+partial_levels = VectorParam.ArmLookupLevel([],
+"List of intermediate lookup levels allowed to be cached in the  
TLB "

+"(=holding intermediate PAs obtained during a table walk")
+
+
 class ArmStage2TLB(ArmTLB):
 size = 32
 is_stage2 = True
diff --git a/src/arch/arm/mmu.cc b/src/arch/arm/mmu.cc
index ce052f1..6b6d10c 100644
--- a/src/arch/arm/mmu.cc
+++ b/src/arch/arm/mmu.cc
@@ -65,7 +65,7 @@
 test(nullptr),
 miscRegContext(0),
 s1State(this, false), s2State(this, true),
-_attr(0),
+_attr(0), _hasWalkCache(false),
 stats(this)
 {
 // Cache system-level properties
@@ -101,6 +101,27 @@
 getDTBPtr()->setTableWalker(dtbWalker);

 BaseMMU::init();
+
+_hasWalkCache = checkWalkCache();
+}
+
+bool
+MMU::checkWalkCache() const
+{
+for (auto tlb : instruction) {
+if (static_cast(tlb)->walkCache())
+return true;
+}
+for (auto tlb : data) {
+if (static_cast(tlb)->walkCache())
+return true;
+}
+for (auto tlb : unified) {
+if (static_cast(tlb)->walkCache())
+return true;
+}
+
+return false;
 }

 void
diff --git a/src/arch/arm/mmu.hh b/src/arch/arm/mmu.hh
index 2d0ef7b..7fa8210 100644
--- a/src/arch/arm/mmu.hh
+++ b/src/arch/arm/mmu.hh
@@ -342,6 +342,8 @@
 _attr = attr;
 }

+bool hasWalkCache() const { return _hasWalkCache; }
+
 /**
  * Determine the EL to use for the purpose of a translation given
  * a specific translation type. If the translation type doesn't
@@ -423,6 +425,13 @@
LookupLevel lookup_level, CachedState );

   protected:
+bool checkWalkCache() const;
+
+CachedState& updateMiscReg(
+ThreadContext *tc, ArmTranslationType tran_type,
+bool stage2);
+
+  protected:
 ContextID miscRegContext;

   public:
@@ -439,9 +448,7 @@

 AddrRange m5opRange;

-CachedState& updateMiscReg(
-ThreadContext *tc, ArmTranslationType tran_type,
-bool stage2);
+bool _hasWalkCache;

 struct Stats : public statistics::Group
 {
diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc
index e2897f8..a7c3f12 100644
--- a/src/arch/arm/tlb.cc
+++ b/src/arch/arm/tlb.cc
@@ -61,9 +61,33 @@
 TLB::TLB(const ArmTLBParams )
 : BaseTLB(p), table(new TlbEntry[p.size]), size(p.size),
   isStage2(p.is_stage2),
+  _walkCache(false),
   tableWalker(nullptr),
   stats(*this), rangeMRU(1), vmid(0)
 {
+for (int lvl = LookupLevel::L0;
+ lvl < LookupLevel::Num_ArmLookupLevel; lvl++) {
+
+auto it = std::find(
+p.partial_levels.begin(),
+p.partial_levels.end(),
+lvl);
+
+auto lookup_lvl = static_cast(lvl);
+
+if (it != p.partial_levels.end()) {
+// A partial entry from of the current LookupLevel can be
+// cached within the TLB
+partialLevels[lookup_lvl] = true;
+
+// Make sure this is not the last level (complete translation)
+if (lvl != LookupLevel::Num_ArmLookupLevel - 1) {
+_walkCache = true;
+}
+} else {
+partialLevels[lookup_lvl] = false;
+}
+}
 }

 TLB::~TLB()
@@ -79,32 +103,63 @@
 }

 TlbEntry*
-TLB::lookup(const Lookup _data)
+TLB::match(const Lookup _data)
 {
-TlbEntry *retval = NULL;
-const auto functional = lookup_data.functional;
-const auto mode = lookup_data.mode;
+// Vector of TLB entry candidates.
+// Only one of them will be assigned to retval and will
+// be returned to the MMU (in case of a hit)
+// The vector has one entry per lookup level as it stores
+// both complete and partial matches
+std::vector> hits{
+LookupLevel::Num_ArmLookupLevel, {0, nullptr}};

-// Maintaining LRU array
 int x = 0;
-while (retval == NULL && x < size) {
+