arch-arm: Move testWalk check within the fetchDescriptor

We also unify the fault handling logic; rather than cleaning
up the WalkerState in several places scattered throughout the
walking code, we handle faults in the top level method

Change-Id: Ia22fb6f27044ff445fffbab228777a48efa473cb
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-by: Richard Cooper <richard.cooper@arm.com>
This commit is contained in:
Giacomo Travaglini
2024-02-02 13:59:49 +00:00
parent 6d0cb6eaa3
commit a299d2db0c
2 changed files with 121 additions and 132 deletions

View File

@@ -446,12 +446,13 @@ TableWalker::walk(const RequestPtr &_req, ThreadContext *_tc, uint16_t _asid,
}
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.
@@ -462,8 +463,17 @@ TableWalker::walk(const RequestPtr &_req, ThreadContext *_tc, uint16_t _asid,
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);
}
currState = NULL;
} else if (fault) {
currState->tc = NULL;
currState->req = NULL;
@@ -497,29 +507,36 @@ TableWalker::processWalkWrapper()
pending = true;
pendingQueue.pop_front();
bool long_desc_format = currState->aarch64 || currState->el == EL2 ||
isStage2 || longDescFormatInUse(currState->tc);
if (te && te->partial) {
currState->walkEntry = *te;
}
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) {
if (fault != NoFault) {
pending = false;
nextWalk(currState->tc);
currState->transState->finish(f, currState->req,
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);
}
currState = NULL;
return;
}
@@ -645,13 +662,6 @@ TableWalker::processWalk()
DPRINTF(TLB, " - Descriptor at address %#x (%s)\n", l1desc_addr,
currState->isSecure ? "s" : "ns");
Fault f = testWalk(l1desc_addr, sizeof(uint32_t),
TlbEntry::DomainType::NoAccess, LookupLevel::L1);
if (f) {
return f;
}
Request::Flags flag = Request::PT_WALK;
if (currState->sctlr.c == 0 || currState->isUncacheable) {
flag.set(Request::UNCACHEABLE);
@@ -661,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
@@ -811,13 +818,6 @@ TableWalker::processWalkLPAE()
desc_addr, currState->isSecure ? "s" : "ns");
}
Fault f = testWalk(desc_addr, sizeof(uint64_t),
TlbEntry::DomainType::NoAccess, start_lookup_level);
if (f) {
return f;
}
if (currState->sctlr.c == 0 || currState->isUncacheable) {
flag.set(Request::UNCACHEABLE);
}
@@ -826,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
@@ -1051,12 +1049,6 @@ TableWalker::processWalkAArch64()
ArmFault::LpaeTran);
}
Fault f = testWalk(desc_addr, sizeof(uint64_t),
TlbEntry::DomainType::NoAccess, start_lookup_level);
if (f) {
return f;
}
Request::Flags flag = Request::PT_WALK;
if (currState->sctlr.c == 0 || currState->isUncacheable) {
flag.set(Request::UNCACHEABLE);
@@ -1071,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>
@@ -1633,18 +1619,6 @@ TableWalker::doL1Descriptor()
DPRINTF(TLB, "L1 descriptor points to page table at: %#x (%s)\n",
l2desc_addr, currState->isSecure ? "s" : "ns");
currState->fault = testWalk(l2desc_addr, sizeof(uint32_t),
currState->l1Desc.domain(),
LookupLevel::L2);
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) {
@@ -1654,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;
}
@@ -1800,23 +1773,10 @@ TableWalker::doLongDescriptor()
return;
}
currState->fault = testWalk(
next_desc_addr, sizeof(uint64_t), TlbEntry::DomainType::Client,
toLookupLevel(currState->longDesc.lookupLevel +1));
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);
@@ -1840,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:
@@ -1967,7 +1926,7 @@ TableWalker::doL1DescriptorWrapper()
delete currState;
} else {
// need to do L2 descriptor
stateQueues[LookupLevel::L2].push_back(currState);
stashCurrState(LookupLevel::L2);
}
currState = NULL;
}
@@ -2093,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;
}
@@ -2108,12 +2067,13 @@ TableWalker::nextWalk(ThreadContext *tc)
completeDrain();
}
bool
TableWalker::fetchDescriptor(Addr desc_addr, uint8_t *data, int num_bytes,
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",
@@ -2125,50 +2085,47 @@ TableWalker::fetchDescriptor(Addr desc_addr, uint8_t *data, int num_bytes,
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, desc_addr, tran, num_bytes, flags);
fault = tran->fault;
if (fault != NoFault) {
currState->fault = fault;
}
} else {
fault = readDataUntimed(currState->tc,
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);
if (fault != NoFault) {
currState->fault = fault;
}
} else {
(this->*doDescriptor)();
}
} else {
RequestPtr req = std::make_shared<Request>(
desc_addr, num_bytes, flags, requestorId);
req->taskId(context_switch_task_id::DMA);
Fault fault = testWalk(desc_addr, num_bytes, 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);
}
} else if (!currState->functional) {
port->sendAtomicReq(req, data,
currState->tc->getCpuPtr()->clockPeriod());
@@ -2179,7 +2136,16 @@ TableWalker::fetchDescriptor(Addr desc_addr, uint8_t *data, int num_bytes,
(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

View File

@@ -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
{
@@ -1141,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);
@@ -1176,6 +1196,9 @@ 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);
public: /* Testing */