summaryrefslogtreecommitdiff
path: root/src/arch/arm/table_walker.cc
diff options
context:
space:
mode:
authorGeoffrey Blake <Geoffrey.Blake@arm.com>2014-03-07 15:56:23 -0500
committerGeoffrey Blake <Geoffrey.Blake@arm.com>2014-03-07 15:56:23 -0500
commitc4a8e5c36cbc30feee6ecd5c706e3275301b25ef (patch)
tree6df832ed4d134b38286073dd488122e136e34613 /src/arch/arm/table_walker.cc
parente88cffb30a808bcfe30858167ae704ca890c72df (diff)
downloadgem5-c4a8e5c36cbc30feee6ecd5c706e3275301b25ef.tar.xz
arm: Handle functional TLB walks properly
The table walker code currently accounts for two types of walks, Atomic and Timing, and treats them differently. Atomic walks keep a single instance of WalkerState around for all walks to use in currState. Timing mode keeps a queue of in-flight WalkerStates and maintains currState as NULL between walks. If a functional walk is done during Timing mode, it is treated as an atomic walk and either creates a persistent WalkerState if in between Timing walks, or stomps an existing currState for an in-progress Timing walk. This patch distinguishes functional walks as being able to exist at any time and sets up a temporary WalkerState for its exclusive use and then cleans up when finished, leaving any in progress Atomic or Timing walks undisturbed.
Diffstat (limited to 'src/arch/arm/table_walker.cc')
-rw-r--r--src/arch/arm/table_walker.cc26
1 files changed, 22 insertions, 4 deletions
diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc
index 7eda13b3e..ea2865aeb 100644
--- a/src/arch/arm/table_walker.cc
+++ b/src/arch/arm/table_walker.cc
@@ -160,8 +160,9 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint16_t _asid,
bool secure, TLB::ArmTranslationType tranType)
{
assert(!(_functional && _timing));
+ WalkerState *savedCurrState = NULL;
- if (!currState) {
+ if (!currState && !_functional) {
// For atomic mode, a new WalkerState instance should be only created
// once per TLB. For timing mode, a new instance is generated for every
// TLB miss.
@@ -169,6 +170,14 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint16_t _asid,
currState = new WalkerState();
currState->tableWalker = this;
+ } else if (_functional) {
+ // If we are mixing functional mode with timing (or even
+ // atomic), we need to to be careful and clean up after
+ // ourselves to not risk getting into an inconsistent state.
+ DPRINTF(TLBVerbose, "creating functional instance of WalkerState\n");
+ savedCurrState = currState;
+ currState = new WalkerState();
+ currState->tableWalker = this;
} else if (_timing) {
// This is a translation that was completed and then faulted again
// because some underlying parameters that affect the translation
@@ -264,12 +273,21 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint16_t _asid,
}
if (!currState->timing) {
+ Fault fault = NoFault;
if (currState->aarch64)
- return processWalkAArch64();
+ fault = processWalkAArch64();
else if (long_desc_format)
- return processWalkLPAE();
+ fault = processWalkLPAE();
else
- return processWalk();
+ fault = processWalk();
+
+ // If this was a functional non-timing access restore state to
+ // how we found it.
+ if (currState->functional) {
+ delete currState;
+ currState = savedCurrState;
+ }
+ return fault;
}
if (pending || pendingQueue.size()) {