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.
This commit is contained in:
parent
e88cffb30a
commit
c4a8e5c36c
1 changed files with 22 additions and 4 deletions
|
@ -160,13 +160,22 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint16_t _asid,
|
||||||
bool secure, TLB::ArmTranslationType tranType)
|
bool secure, TLB::ArmTranslationType tranType)
|
||||||
{
|
{
|
||||||
assert(!(_functional && _timing));
|
assert(!(_functional && _timing));
|
||||||
|
WalkerState *savedCurrState = NULL;
|
||||||
|
|
||||||
if (!currState) {
|
if (!currState && !_functional) {
|
||||||
// For atomic mode, a new WalkerState instance should be only created
|
// For atomic mode, a new WalkerState instance should be only created
|
||||||
// once per TLB. For timing mode, a new instance is generated for every
|
// once per TLB. For timing mode, a new instance is generated for every
|
||||||
// TLB miss.
|
// TLB miss.
|
||||||
DPRINTF(TLBVerbose, "creating new instance of WalkerState\n");
|
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 = new WalkerState();
|
||||||
currState->tableWalker = this;
|
currState->tableWalker = this;
|
||||||
} else if (_timing) {
|
} else if (_timing) {
|
||||||
|
@ -264,12 +273,21 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint16_t _asid,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!currState->timing) {
|
if (!currState->timing) {
|
||||||
|
Fault fault = NoFault;
|
||||||
if (currState->aarch64)
|
if (currState->aarch64)
|
||||||
return processWalkAArch64();
|
fault = processWalkAArch64();
|
||||||
else if (long_desc_format)
|
else if (long_desc_format)
|
||||||
return processWalkLPAE();
|
fault = processWalkLPAE();
|
||||||
else
|
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()) {
|
if (pending || pendingQueue.size()) {
|
||||||
|
|
Loading…
Reference in a new issue