From c4a8e5c36cbc30feee6ecd5c706e3275301b25ef Mon Sep 17 00:00:00 2001 From: Geoffrey Blake Date: Fri, 7 Mar 2014 15:56:23 -0500 Subject: 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. --- src/arch/arm/table_walker.cc | 26 ++++++++++++++++++++++---- 1 file 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,13 +160,22 @@ 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. DPRINTF(TLBVerbose, "creating new instance of WalkerState\n"); + 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) { @@ -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()) { -- cgit v1.2.3