[gem5-dev] Change in gem5/gem5[develop]: arch-arm: Allow TLB to be used as a WalkCache
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
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) { +