mem-cache: Add multiple eviction stats
[gem5.git] / src / arch / x86 / pagetable_walker.cc
index 853e062e775c8e574869628da8fff6d8b45c2c12..aab0a711892e0090b35f8609a3b2e863be840f26 100644 (file)
  * Authors: Gabe Black
  */
 
-#include "arch/x86/pagetable.hh"
 #include "arch/x86/pagetable_walker.hh"
+
+#include <memory>
+
+#include "arch/x86/faults.hh"
+#include "arch/x86/pagetable.hh"
 #include "arch/x86/tlb.hh"
 #include "arch/x86/vtophys.hh"
 #include "base/bitfield.hh"
 
 namespace X86ISA {
 
-// Unfortunately, the placement of the base field in a page table entry is
-// very erratic and would make a mess here. It might be moved here at some
-// point in the future.
-BitUnion64(PageTableEntry)
-    Bitfield<63> nx;
-    Bitfield<11, 9> avl;
-    Bitfield<8> g;
-    Bitfield<7> ps;
-    Bitfield<6> d;
-    Bitfield<5> a;
-    Bitfield<4> pcd;
-    Bitfield<3> pwt;
-    Bitfield<2> u;
-    Bitfield<1> w;
-    Bitfield<0> p;
-EndBitUnion(PageTableEntry)
-
 Fault
 Walker::start(ThreadContext * _tc, BaseTLB::Translation *_translation,
-              RequestPtr _req, BaseTLB::Mode _mode)
+              const RequestPtr &_req, BaseTLB::Mode _mode)
 {
     // TODO: in timing mode, instead of blocking when there are other
     // outstanding requests, see if this request can be coalesced with
@@ -139,23 +126,22 @@ Walker::recvTimingResp(PacketPtr pkt)
         delete senderWalk;
         // Since we block requests when another is outstanding, we
         // need to check if there is a waiting request to be serviced
-        if (currStates.size()) {
-            WalkerState * newState = currStates.front();
-            if (!newState->wasStarted())
-                newState->startWalk();
-        }
+        if (currStates.size() && !startWalkWrapperEvent.scheduled())
+            // delay sending any new requests until we are finished
+            // with the responses
+            schedule(startWalkWrapperEvent, clockEdge());
     }
     return true;
 }
 
 void
-Walker::WalkerPort::recvRetry()
+Walker::WalkerPort::recvReqRetry()
 {
-    walker->recvRetry();
+    walker->recvReqRetry();
 }
 
 void
-Walker::recvRetry()
+Walker::recvReqRetry()
 {
     std::list<WalkerState *>::iterator iter;
     for (iter = currStates.begin(); iter != currStates.end(); iter++) {
@@ -168,17 +154,27 @@ Walker::recvRetry()
 
 bool Walker::sendTiming(WalkerState* sendingState, PacketPtr pkt)
 {
-    pkt->pushSenderState(new WalkerSenderState(sendingState));
-    return port.sendTimingReq(pkt);
+    WalkerSenderState* walker_state = new WalkerSenderState(sendingState);
+    pkt->pushSenderState(walker_state);
+    if (port.sendTimingReq(pkt)) {
+        return true;
+    } else {
+        // undo the adding of the sender state and delete it, as we
+        // will do it again the next time we attempt to send it
+        pkt->popSenderState();
+        delete walker_state;
+        return false;
+    }
+
 }
 
-BaseMasterPort &
-Walker::getMasterPort(const std::string &if_name, PortID idx)
+Port &
+Walker::getPort(const std::string &if_name, PortID idx)
 {
     if (if_name == "port")
         return port;
     else
-        return MemObject::getMasterPort(if_name, idx);
+        return ClockedObject::getPort(if_name, idx);
 }
 
 void
@@ -192,11 +188,48 @@ Walker::WalkerState::initState(ThreadContext * _tc,
     timing = _isTiming;
 }
 
+void
+Walker::startWalkWrapper()
+{
+    unsigned num_squashed = 0;
+    WalkerState *currState = currStates.front();
+    while ((num_squashed < numSquashable) && currState &&
+        currState->translation->squashed()) {
+        currStates.pop_front();
+        num_squashed++;
+
+        DPRINTF(PageTableWalker, "Squashing table walk for address %#x\n",
+            currState->req->getVaddr());
+
+        // finish the translation which will delete the translation object
+        currState->translation->finish(
+            std::make_shared<UnimpFault>("Squashed Inst"),
+            currState->req, currState->tc, currState->mode);
+
+        // delete the current request if there are no inflight packets.
+        // if there is something in flight, delete when the packets are
+        // received and inflight is zero.
+        if (currState->numInflight() == 0) {
+            delete currState;
+        } else {
+            currState->squash();
+        }
+
+        // check the next translation request, if it exists
+        if (currStates.size())
+            currState = currStates.front();
+        else
+            currState = NULL;
+    }
+    if (currState && !currState->wasStarted())
+        currState->startWalk();
+}
+
 Fault
 Walker::WalkerState::startWalk()
 {
     Fault fault = NoFault;
-    assert(started == false);
+    assert(!started);
     started = true;
     setupWalk(req->getVaddr());
     if (timing) {
@@ -214,7 +247,7 @@ Walker::WalkerState::startWalk()
             nextState = Ready;
             if (write)
                 walker->port.sendAtomic(write);
-        } while(read);
+        } while (read);
         state = Ready;
         nextState = Waiting;
     }
@@ -225,7 +258,7 @@ Fault
 Walker::WalkerState::startFunctional(Addr &addr, unsigned &logBytes)
 {
     Fault fault = NoFault;
-    assert(started == false);
+    assert(!started);
     started = true;
     setupWalk(addr);
 
@@ -238,7 +271,7 @@ Walker::WalkerState::startFunctional(Addr &addr, unsigned &logBytes)
         assert(fault == NoFault || read == NULL);
         state = nextState;
         nextState = Ready;
-    } while(read);
+    } while (read);
     logBytes = entry.logBytes;
     addr = entry.paddr;
 
@@ -253,9 +286,9 @@ Walker::WalkerState::stepWalk(PacketPtr &write)
     write = NULL;
     PageTableEntry pte;
     if (dataSize == 8)
-        pte = read->get<uint64_t>();
+        pte = read->getLE<uint64_t>();
     else
-        pte = read->get<uint32_t>();
+        pte = read->getLE<uint32_t>();
     VAddr vaddr = entry.vaddr;
     bool uncacheable = pte.pcd;
     Addr nextRead = 0;
@@ -488,20 +521,18 @@ Walker::WalkerState::stepWalk(PacketPtr &write)
         //If we didn't return, we're setting up another read.
         Request::Flags flags = oldRead->req->getFlags();
         flags.set(Request::UNCACHEABLE, uncacheable);
-        RequestPtr request =
-            new Request(nextRead, oldRead->getSize(), flags, walker->masterId);
+        RequestPtr request = std::make_shared<Request>(
+            nextRead, oldRead->getSize(), flags, walker->masterId);
         read = new Packet(request, MemCmd::ReadReq);
         read->allocate();
         // If we need to write, adjust the read packet to write the modified
         // value back to memory.
         if (doWrite) {
             write = oldRead;
-            write->set<uint64_t>(pte);
+            write->setLE<uint64_t>(pte);
             write->cmd = MemCmd::WriteReq;
-            write->clearDest();
         } else {
             write = NULL;
-            delete oldRead->req;
             delete oldRead;
         }
     }
@@ -512,7 +543,6 @@ void
 Walker::WalkerState::endWalk()
 {
     nextState = Ready;
-    delete read->req;
     delete read;
     read = NULL;
 }
@@ -559,8 +589,10 @@ Walker::WalkerState::setupWalk(Addr vaddr)
     Request::Flags flags = Request::PHYSICAL;
     if (cr3.pcd)
         flags.set(Request::UNCACHEABLE);
-    RequestPtr request = new Request(topAddr, dataSize, flags,
-                                     walker->masterId);
+
+    RequestPtr request = std::make_shared<Request>(
+        topAddr, dataSize, flags, walker->masterId);
+
     read = new Packet(request, MemCmd::ReadReq);
     read->allocate();
 }
@@ -571,11 +603,18 @@ Walker::WalkerState::recvPacket(PacketPtr pkt)
     assert(pkt->isResponse());
     assert(inflight);
     assert(state == Waiting);
-    assert(!read);
     inflight--;
+    if (squashed) {
+        // if were were squashed, return true once inflight is zero and
+        // this WalkerState will be freed there.
+        return (inflight == 0);
+    }
     if (pkt->isRead()) {
+        // should not have a pending read it we also had one outstanding
+        assert(!read);
+
         // @todo someone should pay for this
-        pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
+        pkt->headerDelay = pkt->payloadDelay = 0;
 
         state = nextState;
         nextState = Ready;
@@ -596,7 +635,7 @@ Walker::WalkerState::recvPacket(PacketPtr pkt)
         nextState = Waiting;
         if (timingFault == NoFault) {
             /*
-             * Finish the translation. Now that we now the right entry is
+             * Finish the translation. Now that we know the right entry is
              * in the TLB, this should work with no memory accesses.
              * There could be new faults unrelated to the table walk like
              * permissions violations, so we'll need the return value as
@@ -651,6 +690,12 @@ Walker::WalkerState::sendPackets()
     }
 }
 
+unsigned
+Walker::WalkerState::numInflight() const
+{
+    return inflight;
+}
+
 bool
 Walker::WalkerState::isRetrying()
 {
@@ -669,6 +714,12 @@ Walker::WalkerState::wasStarted()
     return started;
 }
 
+void
+Walker::WalkerState::squash()
+{
+    squashed = true;
+}
+
 void
 Walker::WalkerState::retry()
 {
@@ -683,7 +734,8 @@ Walker::WalkerState::pageFault(bool present)
     HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
     if (mode == BaseTLB::Execute && !enableNX)
         mode = BaseTLB::Read;
-    return new PageFault(entry.vaddr, present, mode, m5reg.cpl == 3, false);
+    return std::make_shared<PageFault>(entry.vaddr, present, mode,
+                                       m5reg.cpl == 3, false);
 }
 
 /* end namespace X86ISA */ }