diff --git a/src/arch/arm/mmu.hh b/src/arch/arm/mmu.hh index 23fd5a253d..6d35b3f3c8 100644 --- a/src/arch/arm/mmu.hh +++ b/src/arch/arm/mmu.hh @@ -105,8 +105,29 @@ class MMU : public BaseMMU void flush(const OP &tlbi_op) { - getITBPtr()->flush(tlbi_op); - getDTBPtr()->flush(tlbi_op); + if (tlbi_op.stage1Flush()) { + flushStage1(tlbi_op); + } + + if (tlbi_op.stage2Flush()) { + flushStage2(tlbi_op.makeStage2()); + } + } + + template + void + flushStage1(const OP &tlbi_op) + { + iflush(tlbi_op); + dflush(tlbi_op); + } + + template + void + flushStage2(const OP &tlbi_op) + { + itbStage2->flush(tlbi_op); + dtbStage2->flush(tlbi_op); } template diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc index 0f8a8d6bf5..d759819bc7 100644 --- a/src/arch/arm/tlb.cc +++ b/src/arch/arm/tlb.cc @@ -283,11 +283,6 @@ TLB::flushAll() } stats.flushTlb++; - - // If there's a second stage TLB (and we're not it) then flush it as well - if (!isStage2) { - stage2Tlb->flushAll(); - } } void @@ -312,12 +307,6 @@ TLB::flush(const TLBIALL& tlbi_op) } stats.flushTlb++; - - // If there's a second stage TLB (and we're not it) then flush it as well - // if we're currently in hyp mode - if (!isStage2 && isHyp) { - stage2Tlb->flush(tlbi_op.makeStage2()); - } } void @@ -341,13 +330,6 @@ TLB::flush(const TLBIALLEL &tlbi_op) } 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 @@ -372,12 +354,6 @@ TLB::flush(const TLBIVMALL &tlbi_op) } stats.flushTlb++; - - // If there's a second stage TLB (and we're not it) then flush it as well - // if we're currently in hyp mode - if (!isStage2 && tlbi_op.stage2) { - stage2Tlb->flush(tlbi_op.makeStage2()); - } } void @@ -403,11 +379,6 @@ TLB::flush(const TLBIALLN &tlbi_op) } stats.flushTlb++; - - // If there's a second stage TLB (and we're not it) then flush it as well - if (!isStage2 && !hyp) { - stage2Tlb->flush(tlbi_op.makeStage2()); - } } void diff --git a/src/arch/arm/tlbi_op.cc b/src/arch/arm/tlbi_op.cc index bd784ce100..5bcc009d82 100644 --- a/src/arch/arm/tlbi_op.cc +++ b/src/arch/arm/tlbi_op.cc @@ -48,6 +48,7 @@ TLBIALL::operator()(ThreadContext* tc) HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2); inHost = (hcr.tge == 1 && hcr.e2h == 1); el2Enabled = EL2Enabled(tc); + currentEL = currEL(tc); getMMUPtr(tc)->flush(*this); @@ -108,10 +109,10 @@ TLBIASID::operator()(ThreadContext* tc) inHost = (hcr.tge == 1 && hcr.e2h == 1); el2Enabled = EL2Enabled(tc); - getMMUPtr(tc)->flush(*this); + getMMUPtr(tc)->flushStage1(*this); CheckerCPU *checker = tc->getCheckerCpuPtr(); if (checker) { - getMMUPtr(checker)->flush(*this); + getMMUPtr(checker)->flushStage1(*this); } } @@ -145,11 +146,11 @@ TLBIMVAA::operator()(ThreadContext* tc) { HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2); inHost = (hcr.tge == 1 && hcr.e2h == 1); - getMMUPtr(tc)->flush(*this); + getMMUPtr(tc)->flushStage1(*this); CheckerCPU *checker = tc->getCheckerCpuPtr(); if (checker) { - getMMUPtr(checker)->flush(*this); + getMMUPtr(checker)->flushStage1(*this); } } @@ -158,11 +159,11 @@ TLBIMVA::operator()(ThreadContext* tc) { HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2); inHost = (hcr.tge == 1 && hcr.e2h == 1); - getMMUPtr(tc)->flush(*this); + getMMUPtr(tc)->flushStage1(*this); CheckerCPU *checker = tc->getCheckerCpuPtr(); if (checker) { - getMMUPtr(checker)->flush(*this); + getMMUPtr(checker)->flushStage1(*this); } } diff --git a/src/arch/arm/tlbi_op.hh b/src/arch/arm/tlbi_op.hh index ce72dfbca3..924aabde38 100644 --- a/src/arch/arm/tlbi_op.hh +++ b/src/arch/arm/tlbi_op.hh @@ -72,6 +72,28 @@ class TLBIOp (*this)(oc); } + /** + * Return true if the TLBI op needs to flush stage1 + * entries, Defaulting to true in the TLBIOp abstract + * class + */ + virtual bool + stage1Flush() const + { + return true; + } + + /** + * Return true if the TLBI op needs to flush stage2 + * entries, Defaulting to false in the TLBIOp abstract + * class + */ + virtual bool + stage2Flush() const + { + return false; + } + bool secureLookup; ExceptionLevel targetEL; }; @@ -81,11 +103,20 @@ class TLBIALL : public TLBIOp { public: TLBIALL(ExceptionLevel _targetEL, bool _secure) - : TLBIOp(_targetEL, _secure), inHost(false), el2Enabled(false) + : TLBIOp(_targetEL, _secure), inHost(false), el2Enabled(false), + currentEL(EL0) {} void operator()(ThreadContext* tc) override; + bool + stage2Flush() const override + { + // TLBIALL (AArch32) flushing stage2 entries if we're currently + // in hyp mode + return currentEL == EL2; + } + TLBIALL makeStage2() const { @@ -94,6 +125,7 @@ class TLBIALL : public TLBIOp bool inHost; bool el2Enabled; + ExceptionLevel currentEL; }; /** Instruction TLB Invalidate All */ @@ -132,6 +164,13 @@ class TLBIALLEL : public TLBIOp void operator()(ThreadContext* tc) override; + bool + stage2Flush() const override + { + // If we're targeting EL1 then flush stage2 as well + return targetEL == EL1; + } + TLBIALLEL makeStage2() const { @@ -152,6 +191,12 @@ class TLBIVMALL : public TLBIOp void operator()(ThreadContext* tc) override; + bool + stage2Flush() const override + { + return stage2; + } + TLBIVMALL makeStage2() const { @@ -215,6 +260,12 @@ class TLBIALLN : public TLBIOp void operator()(ThreadContext* tc) override; + bool + stage2Flush() const override + { + return targetEL != EL2; + } + TLBIALLN makeStage2() const {