ARM: Fix table walk going on while ASID changes error
authorAli Saidi <Ali.Saidi@ARM.com>
Mon, 4 Apr 2011 16:42:27 +0000 (11:42 -0500)
committerAli Saidi <Ali.Saidi@ARM.com>
Mon, 4 Apr 2011 16:42:27 +0000 (11:42 -0500)
src/arch/arm/faults.cc
src/arch/arm/faults.hh
src/arch/arm/table_walker.cc
src/arch/arm/tlb.cc

index 9ce2e2da41b80c1e29714ca31bc84c4b48086dfe..9fdd58da0e8eecbf5fb14e7f1e68f1546689dc16 100644 (file)
@@ -74,6 +74,9 @@ template<> ArmFault::FaultVals ArmFaultVals<FastInterrupt>::vals =
 template<> ArmFault::FaultVals ArmFaultVals<FlushPipe>::vals =
     {"Pipe Flush", 0x00, MODE_SVC, 0, 0, true, true}; // some dummy values
 
+template<> ArmFault::FaultVals ArmFaultVals<ReExec>::vals =
+    {"ReExec Flush", 0x00, MODE_SVC, 0, 0, true, true}; // some dummy values
+
 Addr 
 ArmFault::getVector(ThreadContext *tc)
 {
@@ -225,6 +228,17 @@ FlushPipe::invoke(ThreadContext *tc, StaticInstPtr inst) {
     tc->pcState(pc);
 }
 
+void
+ReExec::invoke(ThreadContext *tc, StaticInstPtr inst) {
+    DPRINTF(Faults, "Invoking ReExec Fault\n");
+
+    // Set the PC to then the faulting instruction.
+    // Net effect is simply squashing all instructions including this
+    // instruction and refetching/rexecuting current instruction
+    PCState pc = tc->pcState();
+    tc->pcState(pc);
+}
+
 template void AbortFault<PrefetchAbort>::invoke(ThreadContext *tc,
                                                 StaticInstPtr inst);
 template void AbortFault<DataAbort>::invoke(ThreadContext *tc,
index 633e74eae83044de5d59d597958b79d6eb121992..8df8d0abfa01f9e5186baf9a6e42fd74153df090 100644 (file)
@@ -242,6 +242,16 @@ class FlushPipe : public ArmFaultVals<FlushPipe>
             StaticInstPtr inst = StaticInst::nullStaticInstPtr);
 };
 
+// A fault that flushes the pipe, including the faulting instructions
+class ReExec : public ArmFaultVals<ReExec>
+{
+  public:
+    ReExec() {}
+    void invoke(ThreadContext *tc,
+            StaticInstPtr inst = StaticInst::nullStaticInstPtr);
+};
+
+
 static inline Fault genMachineCheckFault()
 {
     return new Reset();
index e2207e26ba9180b05e1519b2a9348b67cec05245..2d0e323f669df2dfb1b2c1e971f6b48896fc39e2 100644 (file)
@@ -114,8 +114,16 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _
 
         currState = new WalkerState();
         currState->tableWalker = this;
-    }
-    else if (_timing) {
+    } else if (_timing) {
+        // This is a translation that was completed and then faulted again
+        // because some underlying parameters that affect the translation
+        // changed out from under us (e.g. asid). It will either be a
+        // misprediction, in which case nothing will happen or we'll use
+        // this fault to re-execute the faulting instruction which should clean
+        // up everything.
+        if (currState->vaddr == _req->getVaddr()) {
+            return new ReExec;
+        }
         panic("currState should always be empty in timing mode!\n");
     }
 
index f1c8ae41a56622d476702820c268b73a5991744b..ccbca3d9c476e635a3ddf7bd3a2d113ff8f3a3d2 100644 (file)
@@ -446,8 +446,10 @@ Fault
 TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
         Translation *translation, bool &delay, bool timing)
 {
-    if (!miscRegValid)
+    if (!miscRegValid) {
         updateMiscReg(tc);
+        DPRINTF(TLBVerbose, "TLB variables changed!\n");
+    }
 
     Addr vaddr = req->getVaddr();
     uint32_t flags = req->getFlags();
@@ -456,7 +458,7 @@ TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
     bool is_write = (mode == Write);
     bool is_priv = isPriv && !(flags & UserMode);
 
-    DPRINTF(TLBVerbose, "CPSR is user:%d UserMode:%d\n",
+    DPRINTF(TLBVerbose, "CPSR is priv:%d UserMode:%d\n",
             isPriv, flags & UserMode);
     // If this is a clrex instruction, provide a PA of 0 with no fault
     // This will force the monitor to set the tracked address to 0