arm: refactor page table walking

Introduce and use a lookup table.

Using fetchDescriptor() rather than DMA cleanly handles nested paging.

Change-Id: I69ec762f176bd752ba1040890e731826b58d15a6
This commit is contained in:
Curtis Dunham 2016-08-02 10:38:03 +01:00
parent 09218ed397
commit 8b3434a4f2
2 changed files with 15 additions and 40 deletions

View file

@ -65,8 +65,10 @@ TableWalker::TableWalker(const Params *p)
pendingReqs(0), pendingReqs(0),
pendingChangeTick(curTick()), pendingChangeTick(curTick()),
doL1DescEvent(this), doL2DescEvent(this), doL1DescEvent(this), doL2DescEvent(this),
doL0LongDescEvent(this), doL1LongDescEvent(this), doL2LongDescEvent(this), doL0LongDescEvent(this), doL1LongDescEvent(this),
doL3LongDescEvent(this), doL2LongDescEvent(this), doL3LongDescEvent(this),
LongDescEventByLevel { &doL0LongDescEvent, &doL1LongDescEvent,
&doL2LongDescEvent, &doL3LongDescEvent },
doProcessEvent(this) doProcessEvent(this)
{ {
sctlr = 0; sctlr = 0;
@ -138,7 +140,8 @@ void
TableWalker::completeDrain() TableWalker::completeDrain()
{ {
if (drainState() == DrainState::Draining && if (drainState() == DrainState::Draining &&
stateQueues[L1].empty() && stateQueues[L2].empty() && stateQueues[L0].empty() && stateQueues[L1].empty() &&
stateQueues[L2].empty() && stateQueues[L3].empty() &&
pendingQueue.empty()) { pendingQueue.empty()) {
DPRINTF(Drain, "TableWalker done draining, processing drain event\n"); DPRINTF(Drain, "TableWalker done draining, processing drain event\n");
@ -697,12 +700,10 @@ TableWalker::processWalkLPAE()
currState->longDesc.aarch64 = false; currState->longDesc.aarch64 = false;
currState->longDesc.grainSize = Grain4KB; currState->longDesc.grainSize = Grain4KB;
Event *event = start_lookup_level == L1 ? (Event *) &doL1LongDescEvent
: (Event *) &doL2LongDescEvent;
bool delayed = fetchDescriptor(desc_addr, (uint8_t*)&currState->longDesc.data, bool delayed = fetchDescriptor(desc_addr, (uint8_t*)&currState->longDesc.data,
sizeof(uint64_t), flag, start_lookup_level, sizeof(uint64_t), flag, start_lookup_level,
event, &TableWalker::doLongDescriptor); LongDescEventByLevel[start_lookup_level],
&TableWalker::doLongDescriptor);
if (!delayed) { if (!delayed) {
f = currState->fault; f = currState->fault;
} }
@ -967,32 +968,9 @@ TableWalker::processWalkAArch64()
currState->longDesc.grainSize = tg; currState->longDesc.grainSize = tg;
if (currState->timing) { if (currState->timing) {
Event *event; fetchDescriptor(desc_addr, (uint8_t*) &currState->longDesc.data,
switch (start_lookup_level) { sizeof(uint64_t), flag, start_lookup_level,
case L0: LongDescEventByLevel[start_lookup_level], NULL);
event = (Event *) &doL0LongDescEvent;
break;
case L1:
event = (Event *) &doL1LongDescEvent;
break;
case L2:
event = (Event *) &doL2LongDescEvent;
break;
case L3:
event = (Event *) &doL3LongDescEvent;
break;
default:
panic("Invalid table lookup level");
break;
}
port->dmaAction(MemCmd::ReadReq, desc_addr, sizeof(uint64_t),
event, (uint8_t*) &currState->longDesc.data,
currState->tc->getCpuPtr()->clockPeriod(), flag);
DPRINTF(TLBVerbose,
"Adding to walker fifo: queue size before adding: %d\n",
stateQueues[start_lookup_level].size());
stateQueues[start_lookup_level].push_back(currState);
currState = NULL;
} else { } else {
fetchDescriptor(desc_addr, (uint8_t*)&currState->longDesc.data, fetchDescriptor(desc_addr, (uint8_t*)&currState->longDesc.data,
sizeof(uint64_t), flag, -1, NULL, sizeof(uint64_t), flag, -1, NULL,
@ -1672,19 +1650,15 @@ TableWalker::doLongDescriptor()
if (currState->secureLookup) if (currState->secureLookup)
flag.set(Request::SECURE); flag.set(Request::SECURE);
currState->longDesc.lookupLevel = LookupLevel L = currState->longDesc.lookupLevel =
(LookupLevel) (currState->longDesc.lookupLevel + 1); (LookupLevel) (currState->longDesc.lookupLevel + 1);
Event *event = NULL; Event *event = NULL;
switch (currState->longDesc.lookupLevel) { switch (L) {
case L1: case L1:
assert(currState->aarch64); assert(currState->aarch64);
event = &doL1LongDescEvent;
break;
case L2: case L2:
event = &doL2LongDescEvent;
break;
case L3: case L3:
event = &doL3LongDescEvent; event = LongDescEventByLevel[L];
break; break;
default: default:
panic("Wrong lookup level in table walk\n"); panic("Wrong lookup level in table walk\n");

View file

@ -944,6 +944,7 @@ class TableWalker : public MemObject
&TableWalker::doL3LongDescriptorWrapper> doL3LongDescEvent; &TableWalker::doL3LongDescriptorWrapper> doL3LongDescEvent;
void doLongDescriptorWrapper(LookupLevel curr_lookup_level); void doLongDescriptorWrapper(LookupLevel curr_lookup_level);
Event* LongDescEventByLevel[4];
bool fetchDescriptor(Addr descAddr, uint8_t *data, int numBytes, bool fetchDescriptor(Addr descAddr, uint8_t *data, int numBytes,
Request::Flags flags, int queueIndex, Event *event, Request::Flags flags, int queueIndex, Event *event,