diff options
author | Mrinmoy Ghosh <mrinmoy.ghosh@arm.com> | 2013-02-15 17:40:10 -0500 |
---|---|---|
committer | Mrinmoy Ghosh <mrinmoy.ghosh@arm.com> | 2013-02-15 17:40:10 -0500 |
commit | 8cef39fb6742d834e383f533539ba90f72bbc7d9 (patch) | |
tree | b390315c48692bcb3fce65bfda3fb747600b93bb /src/arch/arm/table_walker.cc | |
parent | 3af59ab386ba297b99d2a215f4c5efa10d0cfe56 (diff) | |
download | gem5-8cef39fb6742d834e383f533539ba90f72bbc7d9.tar.xz |
arm: fix a page table walker issue where a page could be translated multiple times
If multiple memory operations to the same page are miss the TLB they are
all inserted into the page table queue and before this change could result
in multiple uncessesary walks as well as duplicate enteries being inserted
into the TLB.
Diffstat (limited to 'src/arch/arm/table_walker.cc')
-rw-r--r-- | src/arch/arm/table_walker.cc | 33 |
1 files changed, 24 insertions, 9 deletions
diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc index 44f12833b..9755299ff 100644 --- a/src/arch/arm/table_walker.cc +++ b/src/arch/arm/table_walker.cc @@ -186,8 +186,15 @@ TableWalker::processWalkWrapper() assert(pendingQueue.size()); currState = pendingQueue.front(); - - if (!currState->transState->squashed()) { + // Check if a previous walk filled this request already + TlbEntry* te = tlb->lookup(currState->vaddr, currState->contextId, true); + + // Check if we still need to have a walk for this request. If the requesting + // instruction has been squashed, or a previous walk has filled the TLB with + // a match, we just want to get rid of the walk. The latter could happen + // when there are multiple outstanding misses to a single page and a + // previous request has been successfully translated. + if (!currState->transState->squashed() && !te) { // We've got a valid request, lets process it pending = true; pendingQueue.pop_front(); @@ -200,26 +207,34 @@ TableWalker::processWalkWrapper() // squashed we shouldn't bother. unsigned num_squashed = 0; ThreadContext *tc = currState->tc; - assert(currState->transState->squashed()); while ((num_squashed < numSquashable) && currState && - currState->transState->squashed()) { + (currState->transState->squashed() || te)) { pendingQueue.pop_front(); num_squashed++; DPRINTF(TLB, "Squashing table walk for address %#x\n", currState->vaddr); - // finish the translation which will delete the translation object - currState->transState->finish(new UnimpFault("Squashed Inst"), - currState->req, currState->tc, currState->mode); + if (currState->transState->squashed()) { + // finish the translation which will delete the translation object + currState->transState->finish(new UnimpFault("Squashed Inst"), + currState->req, currState->tc, currState->mode); + } else { + // translate the request now that we know it will work + currState->fault = tlb->translateTiming(currState->req, currState->tc, + currState->transState, currState->mode); + } // delete the current request delete currState; // peak at the next one - if (pendingQueue.size()) + if (pendingQueue.size()) { currState = pendingQueue.front(); - else + te = tlb->lookup(currState->vaddr, currState->contextId, true); + } else { + // Terminate the loop, nothing more to do currState = NULL; + } } // if we've still got pending translations schedule more work |