arch-arm: Refactor PTW (#1060)

This PR is refactoring the Arm PageTableWalker in the following way:

1) Simplifying the currState handling logic (mainly the tear down)
2) Amending the TlbTestInterface APIs to use a RequestPtr reference
3) Use finalizePhysical even when MMU is off, which means allowing
memory mapped m5ops to work also in that circumstance
This commit is contained in:
Ivana Mitrovic
2024-04-24 21:00:42 -07:00
committed by GitHub
5 changed files with 250 additions and 317 deletions

View File

@@ -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<TlbTestInterface *>(_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(),

View File

@@ -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;

View File

@@ -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<Request>(
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<PrefetchAbort>(
if (currState->isFetch) {
return std::make_shared<PrefetchAbort>(
currState->vaddr_tainted,
ArmFault::TranslationLL + LookupLevel::L0, isStage2,
ArmFault::LpaeTran);
else
f = std::make_shared<DataAbort>(
} else {
return std::make_shared<DataAbort>(
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<PrefetchAbort>(
return std::make_shared<PrefetchAbort>(
currState->vaddr_tainted,
ArmFault::AddressSizeLL + start_lookup_level,
isStage2,
ArmFault::LpaeTran);
else
f = std::make_shared<DataAbort>(
return std::make_shared<DataAbort>(
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<Addr, Addr, TableWalker::LookupLevel>
@@ -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<Request>(
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

View File

@@ -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<uint8_t*>(&data);
}
uint64_t
getRawData() const override
{
@@ -291,6 +298,12 @@ class TableWalker : public ClockedObject
lookupLevel = LookupLevel::L2;
}
uint8_t*
getRawPtr() override
{
return reinterpret_cast<uint8_t*>(&data);
}
uint64_t
getRawData() const override
{
@@ -441,6 +454,12 @@ class TableWalker : public ClockedObject
uint8_t physAddrRange;
uint8_t*
getRawPtr() override
{
return reinterpret_cast<uint8_t*>(&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

View File

@@ -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;