From f3e3c60805a78147e5ab4e5f3f19aed008aa227d Mon Sep 17 00:00:00 2001 From: Giacomo Travaglini Date: Thu, 18 Jan 2024 17:02:32 +0000 Subject: [PATCH] arch-arm: Proper support for NonSecure IPA space in Secure state Change-Id: Ie2e2278ecdc5213db74999e3561b2918937c2c2e Signed-off-by: Giacomo Travaglini --- src/arch/arm/insts/misc64.cc | 15 ++----------- src/arch/arm/mmu.cc | 17 +++++++++----- src/arch/arm/mmu.hh | 6 +++-- src/arch/arm/pagetable.hh | 4 ++++ src/arch/arm/regs/misc_types.hh | 4 ++++ src/arch/arm/stage2_lookup.cc | 4 ++-- src/arch/arm/stage2_lookup.hh | 4 +++- src/arch/arm/table_walker.cc | 24 +++++++++++++++----- src/arch/arm/table_walker.hh | 15 +++++++++++-- src/arch/arm/tlbi_op.cc | 10 +++++---- src/arch/arm/tlbi_op.hh | 39 +++++++++++++++++++++++++++++---- src/arch/arm/types.hh | 7 ++++++ 12 files changed, 110 insertions(+), 39 deletions(-) diff --git a/src/arch/arm/insts/misc64.cc b/src/arch/arm/insts/misc64.cc index cc149dd676..4ad44bfc63 100644 --- a/src/arch/arm/insts/misc64.cc +++ b/src/arch/arm/insts/misc64.cc @@ -339,14 +339,7 @@ TlbiOp64::tlbiIpaS2(ThreadContext *tc, RegVal value, bool last_level, TlbiAttr attrs) { if (EL2Enabled(tc)) { - if (ss == SecurityState::Secure && bits(value, 63)) { - ss = SecurityState::NonSecure; - } - - const int top_bit = ArmSystem::physAddrRange(tc) == 52 ? - 39 : 35; - TLBIIPA tlbi_op(TranslationRegime::EL10, ss, - static_cast(bits(value, top_bit, 0)) << 12, + TLBIIPA tlbi_op(tc, TranslationRegime::EL10, ss, value, last_level, attrs); if (shareable) { @@ -398,11 +391,7 @@ TlbiOp64::tlbiRipaS2(ThreadContext *tc, RegVal value, bool last_level, TlbiAttr attrs) { if (EL2Enabled(tc)) { - if (ss == SecurityState::Secure && bits(value, 63)) { - ss = SecurityState::NonSecure; - } - - TLBIRIPA tlbi_op(TranslationRegime::EL10, ss, value, + TLBIRIPA tlbi_op(tc, TranslationRegime::EL10, ss, value, last_level, attrs); if (shareable) { diff --git a/src/arch/arm/mmu.cc b/src/arch/arm/mmu.cc index 3df8b9356c..d349455c3b 100644 --- a/src/arch/arm/mmu.cc +++ b/src/arch/arm/mmu.cc @@ -1385,11 +1385,11 @@ MMU::tranTypeEL(CPSR cpsr, SCR scr, ArmTranslationType type) Fault MMU::getTE(TlbEntry **te, const RequestPtr &req, ThreadContext *tc, Mode mode, Translation *translation, bool timing, bool functional, - SecurityState ss, ArmTranslationType tran_type, + SecurityState ss, PASpace ipaspace, ArmTranslationType tran_type, bool stage2) { return getTE(te, req, tc, mode, translation, timing, functional, - ss, tran_type, stage2 ? s2State : s1State); + ss, ipaspace, tran_type, stage2 ? s2State : s1State); } TlbEntry* @@ -1416,7 +1416,7 @@ MMU::lookup(Addr va, uint16_t asid, vmid_t vmid, SecurityState ss, Fault MMU::getTE(TlbEntry **te, const RequestPtr &req, ThreadContext *tc, Mode mode, Translation *translation, bool timing, bool functional, - SecurityState ss, ArmTranslationType tran_type, + SecurityState ss, PASpace ipaspace, ArmTranslationType tran_type, CachedState& state) { // In a 2-stage system, the IPA->PA translation can be started via this @@ -1459,7 +1459,7 @@ MMU::getTE(TlbEntry **te, const RequestPtr &req, ThreadContext *tc, Mode mode, fault = getTableWalker(mode, state.isStage2)->walk( req, tc, state.asid, state.vmid, mode, translation, timing, functional, ss, - tran_type, state.stage2DescReq, *te); + ipaspace, tran_type, state.stage2DescReq, *te); // for timing mode, return and wait for table walk, if (timing || fault != NoFault) { @@ -1482,12 +1482,16 @@ MMU::getResultTe(TlbEntry **te, const RequestPtr &req, Fault fault; if (state.isStage2) { + PASpace ipaspace = state.securityState == SecurityState::Secure ? + PASpace::Secure : PASpace::NonSecure; + // 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 = nullptr; // Get the stage 2 table entry fault = getTE(&s2_te, req, tc, mode, translation, timing, functional, - state.securityState, state.curTranType, state); + state.securityState, ipaspace, + state.curTranType, state); // Check permissions of stage 2 if (isCompleteTranslation(s2_te) && (fault == NoFault)) { if (state.aarch64) @@ -1505,7 +1509,8 @@ MMU::getResultTe(TlbEntry **te, const RequestPtr &req, // Get the stage 1 table entry fault = getTE(&s1_te, req, tc, mode, translation, timing, functional, - state.securityState, state.curTranType, state); + state.securityState, PASpace::NonSecure, + state.curTranType, state); // only proceed if we have a valid table entry if (isCompleteTranslation(s1_te) && (fault == NoFault)) { // Check stage 1 permissions before checking stage 2 diff --git a/src/arch/arm/mmu.hh b/src/arch/arm/mmu.hh index c9e0ff1a2e..46d904278a 100644 --- a/src/arch/arm/mmu.hh +++ b/src/arch/arm/mmu.hh @@ -412,12 +412,14 @@ class MMU : public BaseMMU Fault getTE(TlbEntry **te, const RequestPtr &req, ThreadContext *tc, Mode mode, Translation *translation, bool timing, bool functional, - SecurityState ss, ArmTranslationType tran_type, + SecurityState ss, PASpace ipaspace, + ArmTranslationType tran_type, bool stage2); Fault getTE(TlbEntry **te, const RequestPtr &req, ThreadContext *tc, Mode mode, Translation *translation, bool timing, bool functional, - SecurityState ss, ArmTranslationType tran_type, + SecurityState ss, PASpace ipaspace, + ArmTranslationType tran_type, CachedState &state); Fault getResultTe(TlbEntry **te, const RequestPtr &req, diff --git a/src/arch/arm/pagetable.hh b/src/arch/arm/pagetable.hh index ab17b3df0d..8a3f7943d5 100644 --- a/src/arch/arm/pagetable.hh +++ b/src/arch/arm/pagetable.hh @@ -241,6 +241,8 @@ struct TlbEntry : public Serializable bool ns; // Security state of the translation regime SecurityState ss; + // IPA Space (stage2 entries only) + PASpace ipaSpace; // Translation regime on insert, AARCH64 EL0&1, AARCH32 -> el=1 TranslationRegime regime; // This is used to distinguish between instruction and data entries @@ -272,6 +274,7 @@ struct TlbEntry : public Serializable domain(DomainType::Client), mtype(MemoryType::StronglyOrdered), longDescFormat(false), global(false), valid(true), ns(true), ss(SecurityState::NonSecure), + ipaSpace(PASpace::NonSecure), regime(TranslationRegime::EL10), type(TypeTLB::unified), partial(false), nonCacheable(uncacheable), @@ -292,6 +295,7 @@ struct TlbEntry : public Serializable domain(DomainType::Client), mtype(MemoryType::StronglyOrdered), longDescFormat(false), global(false), valid(false), ns(true), ss(SecurityState::NonSecure), + ipaSpace(PASpace::NonSecure), regime(TranslationRegime::EL10), type(TypeTLB::unified), partial(false), nonCacheable(false), shareable(false), outerShareable(false), xn(0), pxn(0), diff --git a/src/arch/arm/regs/misc_types.hh b/src/arch/arm/regs/misc_types.hh index 5bb3b59847..171d80e511 100644 --- a/src/arch/arm/regs/misc_types.hh +++ b/src/arch/arm/regs/misc_types.hh @@ -655,6 +655,10 @@ namespace ArmISA Bitfield<19> vs; // Only defined for VTCR_EL2 Bitfield<21> ha; // Only defined for VTCR_EL2 Bitfield<22> hd; // Only defined for VTCR_EL2 + Bitfield<29> nsw; // Only defined for VTCR_EL2 + Bitfield<29> sw; // Only defined for VSTCR_EL2 + Bitfield<30> nsa; // Only defined for VTCR_EL2 + Bitfield<30> sa; // Only defined for VSTCR_EL2 EndBitUnion(VTCR_t) BitUnion32(PRRR) diff --git a/src/arch/arm/stage2_lookup.cc b/src/arch/arm/stage2_lookup.cc index febfd60fee..7c3bf8421c 100644 --- a/src/arch/arm/stage2_lookup.cc +++ b/src/arch/arm/stage2_lookup.cc @@ -57,7 +57,7 @@ Fault Stage2LookUp::getTe(ThreadContext *tc, TlbEntry *destTe) { fault = mmu->getTE(&stage2Te, req, tc, mode, this, timing, - functional, ss, tranType, true); + functional, ss, ipaSpace, tranType, true); // Call finish if we're done already if ((fault != NoFault) || (stage2Te != NULL)) { @@ -193,7 +193,7 @@ Stage2LookUp::finish(const Fault &_fault, const RequestPtr &req, if ((fault == NoFault) && (stage2Te == NULL)) { // OLD_LOOK: stage2Tlb fault = mmu->getTE(&stage2Te, req, tc, mode, this, - timing, functional, ss, tranType, true); + timing, functional, ss, ipaSpace, tranType, true); } // Now we have the stage 2 table entry we need to merge it with the stage diff --git a/src/arch/arm/stage2_lookup.hh b/src/arch/arm/stage2_lookup.hh index 2192e244be..c6701ab013 100644 --- a/src/arch/arm/stage2_lookup.hh +++ b/src/arch/arm/stage2_lookup.hh @@ -73,6 +73,7 @@ class Stage2LookUp : public BaseMMU::Translation bool complete; bool selfDelete; SecurityState ss; + PASpace ipaSpace; public: Stage2LookUp(MMU *_mmu, TlbEntry s1_te, const RequestPtr &_req, @@ -82,7 +83,8 @@ class Stage2LookUp : public BaseMMU::Translation : mmu(_mmu), stage1Te(s1_te), s1Req(_req), transState(_transState), mode(_mode), timing(_timing), functional(_functional), tranType(_tranType), stage2Te(nullptr), - fault(NoFault), complete(false), selfDelete(false), ss(_ss) + fault(NoFault), complete(false), selfDelete(false), ss(_ss), + ipaSpace(s1_te.ns ? PASpace::NonSecure : PASpace::Secure) { req = std::make_shared(); req->setVirt(s1_te.pAddr(s1Req->getVaddr()), s1Req->getSize(), diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc index 6f4116dbe0..81111cddd6 100644 --- a/src/arch/arm/table_walker.cc +++ b/src/arch/arm/table_walker.cc @@ -295,7 +295,8 @@ Fault TableWalker::walk(const RequestPtr &_req, ThreadContext *_tc, uint16_t _asid, vmid_t _vmid, MMU::Mode _mode, MMU::Translation *_trans, bool _timing, bool _functional, - SecurityState ss, MMU::ArmTranslationType tranType, + SecurityState ss, PASpace ipaspace, + MMU::ArmTranslationType tranType, bool _stage2Req, const TlbEntry *walk_entry) { assert(!(_functional && _timing)); @@ -344,6 +345,7 @@ TableWalker::walk(const RequestPtr &_req, ThreadContext *_tc, uint16_t _asid, if (isStage2) { currState->regime = TranslationRegime::EL10; currState->aarch64 = ELIs64(_tc, EL2); + currState->ipaSpace = ipaspace; } else { currState->regime = translationRegime(_tc, currState->el); @@ -382,7 +384,8 @@ TableWalker::walk(const RequestPtr &_req, ThreadContext *_tc, uint16_t _asid, currState->hcr = currState->tc->readMiscReg(MISCREG_HCR_EL2); if (isStage2) { currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR_EL1); - if (currState->secureLookup) { + if (currState->ss == SecurityState::Secure && + currState->ipaSpace == PASpace::Secure) { currState->vtcr = currState->tc->readMiscReg(MISCREG_VSTCR_EL2); } else { @@ -905,12 +908,19 @@ TableWalker::processWalkAArch64() switch (currState->regime) { case TranslationRegime::EL10: if (isStage2) { - if (currState->secureLookup) { + if (currState->ss == SecurityState::Secure && + currState->ipaSpace == PASpace::Secure) { + // Secure EL1&0 Secure IPA DPRINTF(TLB, " - Selecting VSTTBR_EL2 (AArch64 stage 2)\n"); ttbr = currState->tc->readMiscReg(MISCREG_VSTTBR_EL2); + currState->secureLookup = !currState->vtcr.sw; } else { + // Secure EL1&0 NonSecure IPA or NonSecure EL1&0 DPRINTF(TLB, " - Selecting VTTBR_EL2 (AArch64 stage 2)\n"); ttbr = currState->tc->readMiscReg(MISCREG_VTTBR_EL2); + currState->secureLookup = currState->ss == SecurityState::Secure ? + !currState->vtcr.nsw : // Secure EL1&0 NonSecure IPA + false; // NonSecure EL1&0 } tsz = 64 - currState->vtcr.t0sz64; tg = GrainMap_tg0[currState->vtcr.tg0]; @@ -1809,8 +1819,10 @@ TableWalker::doLongDescriptor() case LongDescriptor::Table: { // Set hierarchical permission flags - currState->secureLookup = currState->secureLookup && - currState->longDesc.secureTable(); + if (!isStage2) { + currState->secureLookup = currState->secureLookup && + currState->longDesc.secureTable(); + } currState->longDescData->rwTable = currState->longDescData->rwTable && (currState->longDesc.rwTable() || currState->hpd); @@ -2246,6 +2258,7 @@ TableWalker::insertPartialTableEntry(LongDescriptor &descriptor) te.lookupLevel = descriptor.lookupLevel; te.ns = !descriptor.secure(have_security, currState); te.ss = currState->ss; + te.ipaSpace = currState->ipaSpace; // Used by stage2 entries only te.type = TypeTLB::unified; te.regime = currState->regime; @@ -2292,6 +2305,7 @@ TableWalker::insertTableEntry(DescriptorBase &descriptor, bool long_descriptor) te.lookupLevel = descriptor.lookupLevel; te.ns = !descriptor.secure(have_security, currState); te.ss = currState->ss; + te.ipaSpace = currState->ipaSpace; // Used by stage2 entries only te.xn = descriptor.xn(); te.type = currState->mode == BaseMMU::Execute ? TypeTLB::instruction : TypeTLB::data; diff --git a/src/arch/arm/table_walker.hh b/src/arch/arm/table_walker.hh index 66d5ea3674..f391a4f1fd 100644 --- a/src/arch/arm/table_walker.hh +++ b/src/arch/arm/table_walker.hh @@ -493,8 +493,13 @@ class TableWalker : public ClockedObject secure(bool have_security, WalkerState *currState) const override { if (type() == Block || type() == Page) { - return have_security && - (currState->secureLookup && !bits(data, 5)); + if (isStage2) { + return have_security && currState->secureLookup && + !currState->vtcr.nsa; + } else { + return have_security && + (currState->secureLookup && !bits(data, 5)); + } } else { return have_security && currState->secureLookup; } @@ -906,6 +911,11 @@ class TableWalker : public ClockedObject * long descriptor table attributes. */ bool secureLookup = false; + /** IPA space (Secure vs NonSecure); stage2 only. + * This depends on whether the stage1 translation targeted + * a secure or non-secure IPA space */ + PASpace ipaSpace; + /** True if table walks are uncacheable (for table descriptors) */ bool isUncacheable; @@ -1143,6 +1153,7 @@ class TableWalker : public ClockedObject uint16_t asid, vmid_t _vmid, BaseMMU::Mode mode, BaseMMU::Translation *_trans, bool timing, bool functional, SecurityState ss, + PASpace ipaspace, MMU::ArmTranslationType tran_type, bool stage2, const TlbEntry *walk_entry); diff --git a/src/arch/arm/tlbi_op.cc b/src/arch/arm/tlbi_op.cc index 11d9d0a541..40a4e8d8c2 100644 --- a/src/arch/arm/tlbi_op.cc +++ b/src/arch/arm/tlbi_op.cc @@ -328,7 +328,8 @@ TLBIIPA::matchEntry(TlbEntry* te, vmid_t vmid) const { TlbEntry::Lookup lookup_data = lookupGen(vmid); - return te->match(lookup_data) && (!lastLevel || !te->partial); + return te->match(lookup_data) && (!lastLevel || !te->partial) && + ipaSpace == te->ipaSpace; } bool @@ -371,9 +372,10 @@ TLBIRIPA::matchEntry(TlbEntry* te, vmid_t vmid) const auto addr_match = te->match(lookup_data) && (!lastLevel || !te->partial); if (addr_match) { - return tgMap[rangeData.tg] == te->tg && - (resTLBIttl(rangeData.tg, rangeData.ttl) || - rangeData.ttl == te->lookupLevel); + return ipaSpace == te->ipaSpace && + tgMap[rangeData.tg] == te->tg && + (resTLBIttl(rangeData.tg, rangeData.ttl) || + rangeData.ttl == te->lookupLevel); } else { return false; } diff --git a/src/arch/arm/tlbi_op.hh b/src/arch/arm/tlbi_op.hh index cb130e8b5e..20d31a7e25 100644 --- a/src/arch/arm/tlbi_op.hh +++ b/src/arch/arm/tlbi_op.hh @@ -409,9 +409,37 @@ class TLBIIPA : public TLBIOp public: TLBIIPA(TranslationRegime _target_regime, SecurityState _ss, Addr _addr, bool last_level, Attr _attr=Attr::None) - : TLBIOp(_target_regime, _ss, _attr), addr(_addr), lastLevel(last_level) + : TLBIOp(_target_regime, _ss, _attr), + addr(_addr), + lastLevel(last_level), + ipaSpace(PASpace::NonSecure) {} + TLBIIPA(ThreadContext *tc, TranslationRegime _target_regime, + SecurityState _ss, RegVal val, + bool last_level, Attr _attr=Attr::None) + : TLBIOp(_target_regime, _ss, _attr), + addr(0), + lastLevel(last_level), + ipaSpace(PASpace::NonSecure) + { + const int top_bit = ArmSystem::physAddrRange(tc) == 52 ? + 39 : 35; + addr = static_cast(bits(val, top_bit, 0)) << 12; + + switch (ss) { + case SecurityState::NonSecure: + ipaSpace = PASpace::NonSecure; + break; + case SecurityState::Secure: + ipaSpace = bits(val, 63) ? + PASpace::NonSecure : PASpace::Secure; + break; + default: + panic("Invalid SecurityState\n"); + } + } + void operator()(ThreadContext* tc) override; bool matchEntry(TlbEntry *entry, vmid_t curr_vmid) const override; @@ -424,6 +452,7 @@ class TLBIIPA : public TLBIOp Addr addr; bool lastLevel; + PASpace ipaSpace; }; /** TLB Range Invalidate by VA */ @@ -456,11 +485,13 @@ class TLBIRMVAA : public TLBIRange, public TLBIMVAA class TLBIRIPA : public TLBIRange, public TLBIIPA { public: - TLBIRIPA(TranslationRegime _target_regime, SecurityState _ss, + TLBIRIPA(ThreadContext *tc, TranslationRegime _target_regime, SecurityState _ss, RegVal val, bool last_level, Attr _attr) : TLBIRange(val), - TLBIIPA(_target_regime, _ss, startAddress(), last_level, _attr) - {} + TLBIIPA(tc, _target_regime, _ss, val, last_level, _attr) + { + addr = startAddress(); + } bool matchEntry(TlbEntry *entry, vmid_t curr_vmid) const override; }; diff --git a/src/arch/arm/types.hh b/src/arch/arm/types.hh index 86c632c498..d0a578a524 100644 --- a/src/arch/arm/types.hh +++ b/src/arch/arm/types.hh @@ -275,6 +275,13 @@ namespace ArmISA Secure }; + /** Physical Address Space */ + enum class PASpace + { + NonSecure, + Secure + }; + enum ExceptionLevel { EL0 = 0,