diff --git a/src/arch/arm/mmu.cc b/src/arch/arm/mmu.cc index 07ecf5a7c8..b0ad4f1737 100644 --- a/src/arch/arm/mmu.cc +++ b/src/arch/arm/mmu.cc @@ -199,6 +199,26 @@ MMU::invalidateMiscReg() s2State.computeAddrTop.flush(); } +Fault +MMU::testAndFinalize(const RequestPtr &req, + ThreadContext *tc, Mode mode, + TlbEntry* te, CachedState &state) const +{ + // If we don't have a valid tlb entry it means virtual memory + // is not enabled + auto domain = te ? te-> domain : TlbEntry::DomainType::NoAccess; + + // Check for a tester generated address fault + Fault fault = testTranslation(req, mode, domain, state); + if (fault != NoFault) { + return fault; + } else { + // Now that we checked no fault has been generated in the + // translation process, we can finalize the physical address + return finalizePhysical(req, tc, mode); + } +} + Fault MMU::finalizePhysical(const RequestPtr &req, ThreadContext *tc, Mode mode) const @@ -848,7 +868,7 @@ MMU::translateMmuOff(ThreadContext *tc, const RequestPtr &req, Mode mode, state.isStage2); setAttr(temp_te.attributes); - return testTranslation(req, mode, TlbEntry::DomainType::NoAccess, state); + return testAndFinalize(req, tc, mode, nullptr, state); } Fault @@ -909,18 +929,11 @@ MMU::translateMmuOn(ThreadContext* tc, const RequestPtr &req, Mode mode, tranMethod); } - // Check for a trickbox generated address fault if (fault == NoFault) - fault = testTranslation(req, mode, te->domain, state); + fault = testAndFinalize(req, tc, mode, te, state); } - if (fault == NoFault) { - // Don't try to finalize a physical address unless the - // translation has completed (i.e., there is a table entry). - return te ? finalizePhysical(req, tc, mode) : NoFault; - } else { - return fault; - } + return fault; } Fault @@ -1551,12 +1564,16 @@ MMU::setTestInterface(SimObject *_ti) TlbTestInterface *ti(dynamic_cast(_ti)); fatal_if(!ti, "%s is not a valid ARM TLB tester\n", _ti->name()); test = ti; + itbWalker->setTestInterface(test); + dtbWalker->setTestInterface(test); + itbStage2Walker->setTestInterface(test); + dtbStage2Walker->setTestInterface(test); } } Fault MMU::testTranslation(const RequestPtr &req, Mode mode, - TlbEntry::DomainType domain, CachedState &state) + TlbEntry::DomainType domain, CachedState &state) const { if (!test || !req->hasSize() || req->getSize() == 0 || req->isCacheMaintenance()) { @@ -1566,28 +1583,6 @@ MMU::testTranslation(const RequestPtr &req, Mode mode, } } -Fault -MMU::testWalk(Addr pa, Addr size, Addr va, bool is_secure, Mode mode, - TlbEntry::DomainType domain, LookupLevel lookup_level, - bool stage2) -{ - return testWalk(pa, size, va, is_secure, mode, domain, lookup_level, - stage2 ? s2State : s1State); -} - -Fault -MMU::testWalk(Addr pa, Addr size, Addr va, bool is_secure, Mode mode, - TlbEntry::DomainType domain, LookupLevel lookup_level, - CachedState &state) -{ - if (!test) { - return NoFault; - } else { - return test->walkCheck(pa, size, va, is_secure, state.isPriv, mode, - domain, lookup_level); - } -} - MMU::Stats::Stats(statistics::Group *parent) : statistics::Group(parent), ADD_STAT(alignFaults, statistics::units::Count::get(), diff --git a/src/arch/arm/mmu.hh b/src/arch/arm/mmu.hh index 873686291c..36d34faade 100644 --- a/src/arch/arm/mmu.hh +++ b/src/arch/arm/mmu.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013, 2016, 2019-2023 Arm Limited + * Copyright (c) 2010-2013, 2016, 2019-2024 Arm Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -460,13 +460,7 @@ class MMU : public BaseMMU void setTestInterface(SimObject *ti); Fault testTranslation(const RequestPtr &req, Mode mode, - TlbEntry::DomainType domain, CachedState &state); - Fault testWalk(Addr pa, Addr size, Addr va, bool is_secure, Mode mode, - TlbEntry::DomainType domain, - LookupLevel lookup_level, bool stage2); - Fault testWalk(Addr pa, Addr size, Addr va, bool is_secure, Mode mode, - TlbEntry::DomainType domain, - LookupLevel lookup_level, CachedState &state); + TlbEntry::DomainType domain, CachedState &state) const; protected: bool checkWalkCache() const; @@ -477,6 +471,10 @@ class MMU : public BaseMMU ThreadContext *tc, ArmTranslationType tran_type, bool stage2); + Fault testAndFinalize(const RequestPtr &req, + ThreadContext *tc, Mode mode, + TlbEntry *te, CachedState &state) const; + protected: ContextID miscRegContext; diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc index 077abe653e..8750e7852c 100644 --- a/src/arch/arm/table_walker.cc +++ b/src/arch/arm/table_walker.cc @@ -62,7 +62,7 @@ using namespace ArmISA; TableWalker::TableWalker(const Params &p) : ClockedObject(p), requestorId(p.sys->getRequestorId(this)), - port(new Port(*this, requestorId)), + port(new Port(*this)), isStage2(p.is_stage2), tlb(NULL), currState(NULL), pending(false), numSquashable(p.num_squash_per_cycle), @@ -78,7 +78,8 @@ TableWalker::TableWalker(const Params &p) doL3LongDescEvent([this]{ doL3LongDescriptorWrapper(); }, name()), LongDescEventByLevel { &doL0LongDescEvent, &doL1LongDescEvent, &doL2LongDescEvent, &doL3LongDescEvent }, - doProcessEvent([this]{ processWalkWrapper(); }, name()) + doProcessEvent([this]{ processWalkWrapper(); }, name()), + test(nullptr) { sctlr = 0; @@ -139,25 +140,20 @@ TableWalker::WalkerState::WalkerState() : { } -TableWalker::Port::Port(TableWalker& _walker, RequestorID id) +TableWalker::Port::Port(TableWalker& _walker) : QueuedRequestPort(_walker.name() + ".port", reqQueue, snoopRespQueue), owner{_walker}, reqQueue(_walker, *this), - snoopRespQueue(_walker, *this), - requestorId(id) + snoopRespQueue(_walker, *this) { } PacketPtr TableWalker::Port::createPacket( - Addr desc_addr, int size, - uint8_t *data, Request::Flags flags, Tick delay, + const RequestPtr &req, + uint8_t *data, Tick delay, Event *event) { - RequestPtr req = std::make_shared( - desc_addr, size, flags, requestorId); - req->taskId(context_switch_task_id::DMA); - PacketPtr pkt = new Packet(req, MemCmd::ReadReq); pkt->dataStatic(data); @@ -171,10 +167,9 @@ TableWalker::Port::createPacket( void TableWalker::Port::sendFunctionalReq( - Addr desc_addr, int size, - uint8_t *data, Request::Flags flags) + const RequestPtr &req, uint8_t *data) { - auto pkt = createPacket(desc_addr, size, data, flags, 0, nullptr); + auto pkt = createPacket(req, data, 0, nullptr); sendFunctional(pkt); @@ -183,10 +178,10 @@ TableWalker::Port::sendFunctionalReq( void TableWalker::Port::sendAtomicReq( - Addr desc_addr, int size, - uint8_t *data, Request::Flags flags, Tick delay) + const RequestPtr &req, + uint8_t *data, Tick delay) { - auto pkt = createPacket(desc_addr, size, data, flags, delay, nullptr); + auto pkt = createPacket(req, data, delay, nullptr); Tick lat = sendAtomic(pkt); @@ -195,11 +190,11 @@ TableWalker::Port::sendAtomicReq( void TableWalker::Port::sendTimingReq( - Addr desc_addr, int size, - uint8_t *data, Request::Flags flags, Tick delay, + const RequestPtr &req, + uint8_t *data, Tick delay, Event *event) { - auto pkt = createPacket(desc_addr, size, data, flags, delay, event); + auto pkt = createPacket(req, data, delay, event); schedTimingReq(pkt, curTick()); } @@ -332,18 +327,15 @@ TableWalker::walk(const RequestPtr &_req, ThreadContext *_tc, uint16_t _asid, currState->startTime = curTick(); currState->tc = _tc; - // ARM DDI 0487A.f (ARMv8 ARM) pg J8-5672 - // aarch32/translation/translation/AArch32.TranslateAddress dictates - // even AArch32 EL0 will use AArch64 translation if EL1 is in AArch64. + currState->el = + MMU::tranTypeEL(_tc->readMiscReg(MISCREG_CPSR), + _tc->readMiscReg(MISCREG_SCR_EL3), + tranType); + if (isStage2) { - currState->el = EL1; currState->regime = TranslationRegime::EL10; currState->aarch64 = ELIs64(_tc, EL2); } else { - currState->el = - MMU::tranTypeEL(_tc->readMiscReg(MISCREG_CPSR), - _tc->readMiscReg(MISCREG_SCR_EL3), - tranType); currState->regime = translationRegime(_tc, currState->el); currState->aarch64 = @@ -442,40 +434,53 @@ TableWalker::walk(const RequestPtr &_req, ThreadContext *_tc, uint16_t _asid, ++stats.walksShortDescriptor; } - if (!currState->timing) { + if (currState->timing && (pending || pendingQueue.size())) { + pendingQueue.push_back(currState); + currState = NULL; + pendingChange(); + return NoFault; + } else { + if (currState->timing) { + pending = true; + pendingChange(); + } + Fault fault = NoFault; - if (currState->aarch64) + if (currState->aarch64) { fault = processWalkAArch64(); - else if (long_desc_format) + } else if (long_desc_format) { fault = processWalkLPAE(); - else + } else { fault = processWalk(); + } // If this was a functional non-timing access restore state to // how we found it. if (currState->functional) { delete currState; currState = savedCurrState; + } else if (currState->timing) { + if (fault) { + pending = false; + nextWalk(currState->tc); + delete currState; + currState = NULL; + } else { + // Either we are using the long descriptor, which means we + // need to extract the queue index from longDesc, or we are + // using the short. In the latter we always start at L1 + LookupLevel curr_lookup_level = long_desc_format ? + currState->longDesc.lookupLevel : LookupLevel::L1; + + stashCurrState(curr_lookup_level); + } + } else if (fault) { + currState->tc = NULL; + currState->req = NULL; } + return fault; } - - if (pending || pendingQueue.size()) { - pendingQueue.push_back(currState); - currState = NULL; - pendingChange(); - } else { - pending = true; - pendingChange(); - if (currState->aarch64) - return processWalkAArch64(); - else if (long_desc_format) - return processWalkLPAE(); - else - return processWalk(); - } - - return NoFault; } void @@ -501,27 +506,36 @@ TableWalker::processWalkWrapper() // We've got a valid request, lets process it pending = true; pendingQueue.pop_front(); - // Keep currState in case one of the processWalk... calls NULLs it + + bool long_desc_format = currState->aarch64 || currState->el == EL2 || + isStage2 || longDescFormatInUse(currState->tc); if (te && te->partial) { currState->walkEntry = *te; } - WalkerState *curr_state_copy = currState; - Fault f; - if (currState->aarch64) - f = processWalkAArch64(); - else if (bool hyp = currState->el == EL2; - longDescFormatInUse(currState->tc) || - hyp || isStage2) - f = processWalkLPAE(); - else - f = processWalk(); + Fault fault; + if (currState->aarch64) { + fault = processWalkAArch64(); + } else if (long_desc_format) { + fault = processWalkLPAE(); + } else { + fault = processWalk(); + } - if (f != NoFault) { - curr_state_copy->transState->finish(f, curr_state_copy->req, - curr_state_copy->tc, curr_state_copy->mode); + if (fault != NoFault) { + pending = false; + nextWalk(currState->tc); - delete curr_state_copy; + currState->transState->finish(fault, currState->req, + currState->tc, currState->mode); + + delete currState; + currState = NULL; + } else { + LookupLevel curr_lookup_level = long_desc_format ? + currState->longDesc.lookupLevel : LookupLevel::L1; + + stashCurrState(curr_lookup_level); } return; } @@ -648,23 +662,6 @@ TableWalker::processWalk() DPRINTF(TLB, " - Descriptor at address %#x (%s)\n", l1desc_addr, currState->isSecure ? "s" : "ns"); - // Trickbox address check - Fault f; - f = testWalk(l1desc_addr, sizeof(uint32_t), - TlbEntry::DomainType::NoAccess, LookupLevel::L1, isStage2); - if (f) { - DPRINTF(TLB, "Trickbox check caused fault on %#x\n", currState->vaddr_tainted); - if (currState->timing) { - pending = false; - nextWalk(currState->tc); - currState = NULL; - } else { - currState->tc = NULL; - currState->req = NULL; - } - return f; - } - Request::Flags flag = Request::PT_WALK; if (currState->sctlr.c == 0 || currState->isUncacheable) { flag.set(Request::UNCACHEABLE); @@ -674,16 +671,13 @@ TableWalker::processWalk() flag.set(Request::SECURE); } - bool delayed; - delayed = fetchDescriptor(l1desc_addr, (uint8_t*)&currState->l1Desc.data, - sizeof(uint32_t), flag, LookupLevel::L1, - &doL1DescEvent, - &TableWalker::doL1Descriptor); - if (!delayed) { - f = currState->fault; - } + fetchDescriptor( + l1desc_addr, currState->l1Desc, + sizeof(uint32_t), flag, LookupLevel::L1, + &doL1DescEvent, + &TableWalker::doL1Descriptor); - return f; + return currState->fault; } Fault @@ -824,23 +818,6 @@ TableWalker::processWalkLPAE() desc_addr, currState->isSecure ? "s" : "ns"); } - // Trickbox address check - Fault f = testWalk(desc_addr, sizeof(uint64_t), - TlbEntry::DomainType::NoAccess, start_lookup_level, - isStage2); - if (f) { - DPRINTF(TLB, "Trickbox check caused fault on %#x\n", currState->vaddr_tainted); - if (currState->timing) { - pending = false; - nextWalk(currState->tc); - currState = NULL; - } else { - currState->tc = NULL; - currState->req = NULL; - } - return f; - } - if (currState->sctlr.c == 0 || currState->isUncacheable) { flag.set(Request::UNCACHEABLE); } @@ -849,15 +826,13 @@ TableWalker::processWalkLPAE() currState->longDesc.aarch64 = false; currState->longDesc.grainSize = Grain4KB; - bool delayed = fetchDescriptor(desc_addr, (uint8_t*)&currState->longDesc.data, - sizeof(uint64_t), flag, start_lookup_level, - LongDescEventByLevel[start_lookup_level], - &TableWalker::doLongDescriptor); - if (!delayed) { - f = currState->fault; - } + fetchDescriptor( + desc_addr, currState->longDesc, + sizeof(uint64_t), flag, start_lookup_level, + LongDescEventByLevel[start_lookup_level], + &TableWalker::doLongDescriptor); - return f; + return currState->fault; } bool @@ -1022,30 +997,19 @@ TableWalker::processWalkAArch64() const bool is_atomic = currState->req->isAtomic(); if (fault) { - Fault f; - if (currState->isFetch) - f = std::make_shared( + if (currState->isFetch) { + return std::make_shared( currState->vaddr_tainted, ArmFault::TranslationLL + LookupLevel::L0, isStage2, ArmFault::LpaeTran); - else - f = std::make_shared( + } else { + return std::make_shared( currState->vaddr_tainted, TlbEntry::DomainType::NoAccess, is_atomic ? false : currState->isWrite, ArmFault::TranslationLL + LookupLevel::L0, isStage2, ArmFault::LpaeTran); - - if (currState->timing) { - pending = false; - nextWalk(currState->tc); - currState = NULL; - } else { - currState->tc = NULL; - currState->req = NULL; } - return f; - } if (tg == ReservedGrain) { @@ -1069,49 +1033,20 @@ TableWalker::processWalkAArch64() // necessary if (checkAddrSizeFaultAArch64(table_addr, currState->physAddrRange)) { DPRINTF(TLB, "Address size fault before any lookup\n"); - Fault f; if (currState->isFetch) - f = std::make_shared( + return std::make_shared( currState->vaddr_tainted, ArmFault::AddressSizeLL + start_lookup_level, isStage2, ArmFault::LpaeTran); else - f = std::make_shared( + return std::make_shared( currState->vaddr_tainted, TlbEntry::DomainType::NoAccess, is_atomic ? false : currState->isWrite, ArmFault::AddressSizeLL + start_lookup_level, isStage2, ArmFault::LpaeTran); - - - if (currState->timing) { - pending = false; - nextWalk(currState->tc); - currState = NULL; - } else { - currState->tc = NULL; - currState->req = NULL; - } - return f; - - } - - // Trickbox address check - Fault f = testWalk(desc_addr, sizeof(uint64_t), - TlbEntry::DomainType::NoAccess, start_lookup_level, isStage2); - if (f) { - DPRINTF(TLB, "Trickbox check caused fault on %#x\n", currState->vaddr_tainted); - if (currState->timing) { - pending = false; - nextWalk(currState->tc); - currState = NULL; - } else { - currState->tc = NULL; - currState->req = NULL; - } - return f; } Request::Flags flag = Request::PT_WALK; @@ -1128,18 +1063,12 @@ TableWalker::processWalkAArch64() currState->longDesc.grainSize = tg; currState->longDesc.physAddrRange = _physAddrRange; - if (currState->timing) { - fetchDescriptor(desc_addr, (uint8_t*) &currState->longDesc.data, - sizeof(uint64_t), flag, start_lookup_level, - LongDescEventByLevel[start_lookup_level], NULL); - } else { - fetchDescriptor(desc_addr, (uint8_t*)&currState->longDesc.data, - sizeof(uint64_t), flag, -1, NULL, - &TableWalker::doLongDescriptor); - f = currState->fault; - } + fetchDescriptor(desc_addr, currState->longDesc, + sizeof(uint64_t), flag, start_lookup_level, + LongDescEventByLevel[start_lookup_level], + &TableWalker::doLongDescriptor); - return f; + return currState->fault; } std::tuple @@ -1690,19 +1619,6 @@ TableWalker::doL1Descriptor() DPRINTF(TLB, "L1 descriptor points to page table at: %#x (%s)\n", l2desc_addr, currState->isSecure ? "s" : "ns"); - // Trickbox address check - currState->fault = testWalk(l2desc_addr, sizeof(uint32_t), - currState->l1Desc.domain(), - LookupLevel::L2, isStage2); - - if (currState->fault) { - if (!currState->timing) { - currState->tc = NULL; - currState->req = NULL; - } - return; - } - Request::Flags flag = Request::PT_WALK; if (currState->sctlr.c == 0 || currState->isUncacheable) { @@ -1712,14 +1628,13 @@ TableWalker::doL1Descriptor() if (currState->isSecure) flag.set(Request::SECURE); - bool delayed; - delayed = fetchDescriptor(l2desc_addr, - (uint8_t*)&currState->l2Desc.data, - sizeof(uint32_t), flag, -1, &doL2DescEvent, - &TableWalker::doL2Descriptor); - if (delayed) { - currState->delayed = true; - } + fetchDescriptor( + l2desc_addr, currState->l2Desc, + sizeof(uint32_t), flag, LookupLevel::L2, + &doL2DescEvent, + &TableWalker::doL2Descriptor); + + currState->delayed = currState->timing; return; } @@ -1858,24 +1773,10 @@ TableWalker::doLongDescriptor() return; } - // Trickbox address check - currState->fault = testWalk( - next_desc_addr, sizeof(uint64_t), TlbEntry::DomainType::Client, - toLookupLevel(currState->longDesc.lookupLevel +1), isStage2); - - if (currState->fault) { - if (!currState->timing) { - currState->tc = NULL; - currState->req = NULL; - } - return; - } - if (mmu->hasWalkCache()) { insertPartialTableEntry(currState->longDesc); } - Request::Flags flag = Request::PT_WALK; if (currState->secureLookup) flag.set(Request::SECURE); @@ -1899,13 +1800,12 @@ TableWalker::doLongDescriptor() break; } - bool delayed; - delayed = fetchDescriptor(next_desc_addr, (uint8_t*)&currState->longDesc.data, - sizeof(uint64_t), flag, -1, event, - &TableWalker::doLongDescriptor); - if (delayed) { - currState->delayed = true; - } + fetchDescriptor( + next_desc_addr, currState->longDesc, + sizeof(uint64_t), flag, L, event, + &TableWalker::doLongDescriptor); + + currState->delayed = currState->timing; } return; default: @@ -2026,7 +1926,7 @@ TableWalker::doL1DescriptorWrapper() delete currState; } else { // need to do L2 descriptor - stateQueues[LookupLevel::L2].push_back(currState); + stashCurrState(LookupLevel::L2); } currState = NULL; } @@ -2152,7 +2052,7 @@ TableWalker::doLongDescriptorWrapper(LookupLevel curr_lookup_level) if (curr_lookup_level >= LookupLevel::Num_ArmLookupLevel - 1) panic("Max. number of lookups already reached in table walk\n"); // Need to perform additional lookups - stateQueues[currState->longDesc.lookupLevel].push_back(currState); + stashCurrState(currState->longDesc.lookupLevel); } currState = NULL; } @@ -2167,75 +2067,85 @@ TableWalker::nextWalk(ThreadContext *tc) completeDrain(); } -bool -TableWalker::fetchDescriptor(Addr descAddr, uint8_t *data, int numBytes, - Request::Flags flags, int queueIndex, Event *event, +void +TableWalker::fetchDescriptor(Addr desc_addr, + DescriptorBase &descriptor, int num_bytes, + Request::Flags flags, LookupLevel lookup_level, Event *event, void (TableWalker::*doDescriptor)()) { - bool isTiming = currState->timing; + uint8_t *data = descriptor.getRawPtr(); DPRINTF(PageTableWalker, "Fetching descriptor at address: 0x%x stage2Req: %d\n", - descAddr, currState->stage2Req); + desc_addr, currState->stage2Req); - // If this translation has a stage 2 then we know descAddr is an IPA and + // If this translation has a stage 2 then we know desc_addr is an IPA and // needs to be translated before we can access the page table. Do that // check here. if (currState->stage2Req) { Fault fault; - if (isTiming) { + if (currState->timing) { auto *tran = new Stage2Walk(*this, data, event, currState->vaddr, currState->mode, currState->tranType); currState->stage2Tran = tran; - readDataTimed(currState->tc, descAddr, tran, numBytes, flags); + readDataTimed(currState->tc, desc_addr, tran, num_bytes, flags); fault = tran->fault; + + if (fault != NoFault) { + currState->fault = fault; + } } else { fault = readDataUntimed(currState->tc, - currState->vaddr, descAddr, data, numBytes, flags, + currState->vaddr, desc_addr, data, num_bytes, flags, currState->mode, currState->tranType, currState->functional); - } - if (fault != NoFault) { - currState->fault = fault; - } - if (isTiming) { - if (queueIndex >= 0) { - DPRINTF(PageTableWalker, "Adding to walker fifo: " - "queue size before adding: %d\n", - stateQueues[queueIndex].size()); - stateQueues[queueIndex].push_back(currState); - currState = NULL; + if (fault != NoFault) { + currState->fault = fault; } - } else { + (this->*doDescriptor)(); } } else { - if (isTiming) { - port->sendTimingReq(descAddr, numBytes, data, flags, + RequestPtr req = std::make_shared( + desc_addr, num_bytes, flags, requestorId); + req->taskId(context_switch_task_id::DMA); + + Fault fault = testWalk(req, descriptor.domain(), + lookup_level); + + if (fault != NoFault) { + currState->fault = fault; + return; + } + + if (currState->timing) { + port->sendTimingReq(req, data, currState->tc->getCpuPtr()->clockPeriod(), event); - if (queueIndex >= 0) { - DPRINTF(PageTableWalker, "Adding to walker fifo: " - "queue size before adding: %d\n", - stateQueues[queueIndex].size()); - stateQueues[queueIndex].push_back(currState); - currState = NULL; - } } else if (!currState->functional) { - port->sendAtomicReq(descAddr, numBytes, data, flags, + port->sendAtomicReq(req, data, currState->tc->getCpuPtr()->clockPeriod()); (this->*doDescriptor)(); } else { - port->sendFunctionalReq(descAddr, numBytes, data, flags); + port->sendFunctionalReq(req, data); (this->*doDescriptor)(); } } - return (isTiming); +} + +void +TableWalker::stashCurrState(int queue_idx) +{ + DPRINTF(PageTableWalker, "Adding to walker fifo: " + "queue size before adding: %d\n", + stateQueues[queue_idx].size()); + stateQueues[queue_idx].push_back(currState); + currState = NULL; } void @@ -2396,13 +2306,23 @@ TableWalker::pendingChange() } Fault -TableWalker::testWalk(Addr pa, Addr size, TlbEntry::DomainType domain, - LookupLevel lookup_level, bool stage2) +TableWalker::testWalk(const RequestPtr &walk_req, TlbEntry::DomainType domain, + LookupLevel lookup_level) { - return mmu->testWalk(pa, size, currState->vaddr, currState->isSecure, - currState->mode, domain, lookup_level, stage2); + if (!test) { + return NoFault; + } else { + return test->walkCheck(walk_req, currState->vaddr, currState->isSecure, + currState->el != EL0, + currState->mode, domain, lookup_level); + } } +void +TableWalker::setTestInterface(TlbTestInterface *ti) +{ + test = ti; +} uint8_t TableWalker::pageSizeNtoStatBin(uint8_t N) @@ -2503,8 +2423,7 @@ TableWalker::Stage2Walk::finish(const Fault &_fault, } if (_fault == NoFault && !req->getFlags().isSet(Request::NO_ACCESS)) { - parent.getTableWalkerPort().sendTimingReq( - req->getPaddr(), numBytes, data, req->getFlags(), + parent.getTableWalkerPort().sendTimingReq(req, data, tc->getCpuPtr()->clockPeriod(), event); } else { // We can't do the DMA access as there's been a problem, so tell the diff --git a/src/arch/arm/table_walker.hh b/src/arch/arm/table_walker.hh index c970d04268..ee56cb81f1 100644 --- a/src/arch/arm/table_walker.hh +++ b/src/arch/arm/table_walker.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016, 2019, 2021-2023 Arm Limited + * Copyright (c) 2010-2016, 2019, 2021-2024 Arm Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -86,6 +86,7 @@ class TableWalker : public ClockedObject virtual uint8_t offsetBits() const = 0; virtual bool secure(bool have_security, WalkerState *currState) const = 0; virtual std::string dbgHeader() const = 0; + virtual uint8_t* getRawPtr() = 0; virtual uint64_t getRawData() const = 0; virtual uint8_t texcb() const { @@ -122,6 +123,12 @@ class TableWalker : public ClockedObject lookupLevel = LookupLevel::L1; } + uint8_t* + getRawPtr() override + { + return reinterpret_cast(&data); + } + uint64_t getRawData() const override { @@ -291,6 +298,12 @@ class TableWalker : public ClockedObject lookupLevel = LookupLevel::L2; } + uint8_t* + getRawPtr() override + { + return reinterpret_cast(&data); + } + uint64_t getRawData() const override { @@ -441,6 +454,12 @@ class TableWalker : public ClockedObject uint8_t physAddrRange; + uint8_t* + getRawPtr() override + { + return reinterpret_cast(&data); + } + uint64_t getRawData() const override { @@ -943,14 +962,11 @@ class TableWalker : public ClockedObject class Port : public QueuedRequestPort { public: - Port(TableWalker& _walker, RequestorID id); + Port(TableWalker& _walker); - void sendFunctionalReq(Addr desc_addr, int size, - uint8_t *data, Request::Flags flag); - void sendAtomicReq(Addr desc_addr, int size, - uint8_t *data, Request::Flags flag, Tick delay); - void sendTimingReq(Addr desc_addr, int size, - uint8_t *data, Request::Flags flag, Tick delay, + void sendFunctionalReq(const RequestPtr &req, uint8_t *data); + void sendAtomicReq(const RequestPtr &req, uint8_t *data, Tick delay); + void sendTimingReq(const RequestPtr &req, uint8_t *data, Tick delay, Event *event); bool recvTimingResp(PacketPtr pkt) override; @@ -960,8 +976,7 @@ class TableWalker : public ClockedObject void handleResp(TableWalkerState *state, Addr addr, Addr size, Tick delay=0); - PacketPtr createPacket(Addr desc_addr, int size, - uint8_t *data, Request::Flags flag, + PacketPtr createPacket(const RequestPtr &req, uint8_t *data, Tick delay, Event *event); private: @@ -972,9 +987,6 @@ class TableWalker : public ClockedObject /** Packet queue used to store outgoing snoop responses. */ SnoopRespPacketQueue snoopRespQueue; - - /** Cached requestorId of the table walker */ - RequestorID requestorId; }; /** This translation class is used to trigger the data fetch once a timing @@ -1148,8 +1160,9 @@ class TableWalker : public ClockedObject void doLongDescriptorWrapper(LookupLevel curr_lookup_level); Event* LongDescEventByLevel[4]; - bool fetchDescriptor(Addr descAddr, uint8_t *data, int numBytes, - Request::Flags flags, int queueIndex, Event *event, + void fetchDescriptor(Addr desc_addr, + DescriptorBase &descriptor, int num_bytes, + Request::Flags flags, LookupLevel lookup_lvl, Event *event, void (TableWalker::*doDescriptor)()); Fault generateLongDescFault(ArmFault::FaultSource src); @@ -1183,10 +1196,18 @@ class TableWalker : public ClockedObject void pendingChange(); + /** Timing mode: saves the currState into the stateQueues */ + void stashCurrState(int queue_idx); + static uint8_t pageSizeNtoStatBin(uint8_t N); - Fault testWalk(Addr pa, Addr size, TlbEntry::DomainType domain, - LookupLevel lookup_level, bool stage2); + public: /* Testing */ + TlbTestInterface *test; + + void setTestInterface(TlbTestInterface *ti); + + Fault testWalk(const RequestPtr &walk_req, TlbEntry::DomainType domain, + LookupLevel lookup_level); }; } // namespace ArmISA diff --git a/src/arch/arm/tlb.hh b/src/arch/arm/tlb.hh index 3f8e649f94..01d945d5dc 100644 --- a/src/arch/arm/tlb.hh +++ b/src/arch/arm/tlb.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013, 2016, 2019-2022 Arm Limited + * Copyright (c) 2010-2013, 2016, 2019-2022, 2024 Arm Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -84,8 +84,7 @@ class TlbTestInterface /** * Check if a page table walker access should be forced to fail. * - * @param pa Physical address the walker is accessing - * @param size Walker access size + * @param req walk request bearing a valid phys address * @param va Virtual address that initiated the walk * @param is_secure Access from secure state * @param is_priv Access from a privileged mode (i.e., not EL0) @@ -93,7 +92,8 @@ class TlbTestInterface * @param domain Domain type * @param lookup_level Page table walker level */ - virtual Fault walkCheck(Addr pa, Addr size, Addr va, bool is_secure, + virtual Fault walkCheck(const RequestPtr &walk_req, + Addr va, bool is_secure, Addr is_priv, BaseMMU::Mode mode, TlbEntry::DomainType domain, enums::ArmLookupLevel lookup_level) = 0;