cpu: Check for instruction-count events before fetch

Instruction fetch should not commence if there already is an
instruction-count event in the queue.

The most conspicuous scenario where this leads to obvious breakage,
is guest debugging.  Imagine the first bytes in the program pointed to
by _start are invalid instruction encoding, and we pass the --wait-gdb
flag.  Then in GDB we set $pc to point to valid instructions, and we
"continue".  gem5 will abort with "invalid instruction".

This is not how real targets behave: neither software- (e.g. ptrace)
based debuggers, nor low-level (e.g. OpenOCD or XMD connected over
JTAG to debug early initialization code eg when the MMU has not been
switched on yet, etc.)  Fetching should start from where $pc was set
to.  This patch tries to model this behavior.

Change-Id: Ibce6fdbbb082edf1073ae96745bc7867878f99ca
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/27587
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Boris Shingarov
2020-04-07 16:26:24 -04:00
parent c046e61216
commit eeedf63c86
4 changed files with 11 additions and 3 deletions

View File

@@ -646,6 +646,8 @@ AtomicSimpleCPU::tick()
return;
}
serviceInstCountEvents();
Fault fault = NoFault;
TheISA::PCState pcState = thread->pcState();

View File

@@ -302,6 +302,12 @@ BaseSimpleCPU::setupFetchRequest(const RequestPtr &req)
instRequestorId(), instAddr);
}
void
BaseSimpleCPU::serviceInstCountEvents()
{
SimpleExecContext &t_info = *threadInfo[curThread];
t_info.thread->comInstEventQueue.serviceEvents(t_info.numInst);
}
void
BaseSimpleCPU::preExecute()
@@ -316,9 +322,6 @@ BaseSimpleCPU::preExecute()
t_info.setPredicate(true);
t_info.setMemAccPredicate(true);
// check for instruction-count-based events
thread->comInstEventQueue.serviceEvents(t_info.numInst);
// decode the instruction
TheISA::PCState pcState = thread->pcState();

View File

@@ -130,6 +130,7 @@ class BaseSimpleCPU : public BaseCPU
public:
void checkForInterrupts();
void setupFetchRequest(const RequestPtr &req);
void serviceInstCountEvents();
void preExecute();
void postExecute();
void advancePC(const Fault &fault);

View File

@@ -805,6 +805,8 @@ TimingSimpleCPU::advanceInst(const Fault &fault)
if (tryCompleteDrain())
return;
serviceInstCountEvents();
if (_status == BaseSimpleCPU::Running) {
// kick off fetch of next instruction... callback from icache
// response will cause that instruction to be executed,