x86: Timing support for pagetable walker
authorJoel Hestness <hestness@cs.utexas.edu>
Mon, 7 Feb 2011 06:14:18 +0000 (22:14 -0800)
committerJoel Hestness <hestness@cs.utexas.edu>
Mon, 7 Feb 2011 06:14:18 +0000 (22:14 -0800)
Move page table walker state to its own object type, and make the
walker instantiate state for each outstanding walk. By storing the
states in a queue, the walker is able to handle multiple outstanding
timing requests. Note that functional walks use separate state
elements.

src/arch/x86/pagetable_walker.cc
src/arch/x86/pagetable_walker.hh
src/arch/x86/tlb.cc
src/arch/x86/tlb.hh

index cf82727a974f5e5d8e4f8b182d3e6fd0c25b6e8a..7c386dd02f95e7ac4e671fb03f91e6c7cd240315 100644 (file)
@@ -40,6 +40,7 @@
 #include "arch/x86/pagetable.hh"
 #include "arch/x86/pagetable_walker.hh"
 #include "arch/x86/tlb.hh"
+#include "arch/x86/vtophys.hh"
 #include "base/bitfield.hh"
 #include "cpu/thread_context.hh"
 #include "cpu/base.hh"
@@ -67,12 +68,209 @@ BitUnion64(PageTableEntry)
 EndBitUnion(PageTableEntry)
 
 Fault
-Walker::doNext(PacketPtr &write)
+Walker::start(ThreadContext * _tc, BaseTLB::Translation *_translation,
+              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
+    // another one (i.e. either coalesce or start walk)
+    WalkerState * newState = new WalkerState(this, _translation, _req);
+    newState->initState(_tc, _mode, sys->getMemoryMode() == Enums::timing);
+    if (currStates.size()) {
+        assert(newState->isTiming());
+        DPRINTF(PageTableWalker, "Walks in progress: %d\n", currStates.size());
+        currStates.push_back(newState);
+        return NoFault;
+    } else {
+        currStates.push_back(newState);
+        Fault fault = newState->startWalk();
+        if (!newState->isTiming()) {
+            currStates.pop_front();
+            delete newState;
+        }
+        return fault;
+    }
+}
+
+Fault
+Walker::startFunctional(ThreadContext * _tc, Addr &addr, Addr &pageSize,
+              BaseTLB::Mode _mode)
+{
+    funcState.initState(_tc, _mode);
+    return funcState.startFunctional(addr, pageSize);
+}
+
+bool
+Walker::WalkerPort::recvTiming(PacketPtr pkt)
+{
+    return walker->recvTiming(pkt);
+}
+
+bool
+Walker::recvTiming(PacketPtr pkt)
+{
+    if (pkt->isResponse() || pkt->wasNacked()) {
+        WalkerSenderState * senderState =
+                dynamic_cast<WalkerSenderState *>(pkt->senderState);
+        pkt->senderState = senderState->saved;
+        WalkerState * senderWalk = senderState->senderWalk;
+        bool walkComplete = senderWalk->recvPacket(pkt);
+        delete senderState;
+        if (walkComplete) {
+            std::list<WalkerState *>::iterator iter;
+            for (iter = currStates.begin(); iter != currStates.end(); iter++) {
+                WalkerState * walkerState = *(iter);
+                if (walkerState == senderWalk) {
+                    iter = currStates.erase(iter);
+                    break;
+                }
+            }
+            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();
+            }
+        }
+    } else {
+        DPRINTF(PageTableWalker, "Received strange packet\n");
+    }
+    return true;
+}
+
+Tick
+Walker::WalkerPort::recvAtomic(PacketPtr pkt)
+{
+    return 0;
+}
+
+void
+Walker::WalkerPort::recvFunctional(PacketPtr pkt)
+{
+    return;
+}
+
+void
+Walker::WalkerPort::recvStatusChange(Status status)
+{
+    if (status == RangeChange) {
+        if (!snoopRangeSent) {
+            snoopRangeSent = true;
+            sendStatusChange(Port::RangeChange);
+        }
+        return;
+    }
+
+    panic("Unexpected recvStatusChange.\n");
+}
+
+void
+Walker::WalkerPort::recvRetry()
+{
+    walker->recvRetry();
+}
+
+void
+Walker::recvRetry()
+{
+    std::list<WalkerState *>::iterator iter;
+    for (iter = currStates.begin(); iter != currStates.end(); iter++) {
+        WalkerState * walkerState = *(iter);
+        if (walkerState->isRetrying()) {
+            walkerState->retry();
+        }
+    }
+}
+
+bool Walker::sendTiming(WalkerState* sendingState, PacketPtr pkt)
+{
+    pkt->senderState = new WalkerSenderState(sendingState, pkt->senderState);
+    return port.sendTiming(pkt);
+}
+
+Port *
+Walker::getPort(const std::string &if_name, int idx)
+{
+    if (if_name == "port")
+        return &port;
+    else
+        panic("No page table walker port named %s!\n", if_name);
+}
+
+void
+Walker::WalkerState::initState(ThreadContext * _tc,
+        BaseTLB::Mode _mode, bool _isTiming)
+{
+    assert(state == Ready);
+    started = false;
+    tc = _tc;
+    mode = _mode;
+    timing = _isTiming;
+}
+
+Fault
+Walker::WalkerState::startWalk()
+{
+    Fault fault = NoFault;
+    assert(started == false);
+    started = true;
+    setupWalk(req->getVaddr());
+    if (timing) {
+        nextState = state;
+        state = Waiting;
+        timingFault = NoFault;
+        sendPackets();
+    } else {
+        do {
+            walker->port.sendAtomic(read);
+            PacketPtr write = NULL;
+            fault = stepWalk(write);
+            assert(fault == NoFault || read == NULL);
+            state = nextState;
+            nextState = Ready;
+            if (write)
+                walker->port.sendAtomic(write);
+        } while(read);
+        state = Ready;
+        nextState = Waiting;
+    }
+    return fault;
+}
+
+Fault
+Walker::WalkerState::startFunctional(Addr &addr, Addr &pageSize)
+{
+    Fault fault = NoFault;
+    assert(started == false);
+    started = true;
+    setupWalk(addr);
+
+    do {
+        walker->port.sendFunctional(read);
+        // On a functional access (page table lookup), writes should
+        // not happen so this pointer is ignored after stepWalk
+        PacketPtr write = NULL;
+        fault = stepWalk(write);
+        assert(fault == NoFault || read == NULL);
+        state = nextState;
+        nextState = Ready;
+    } while(read);
+    pageSize = entry.size;
+    addr = entry.paddr;
+
+    return fault;
+}
+
+Fault
+Walker::WalkerState::stepWalk(PacketPtr &write)
 {
     assert(state != Ready && state != Waiting);
+    Fault fault = NoFault;
     write = NULL;
     PageTableEntry pte;
-    if (size == 8)
+    if (dataSize == 8)
         pte = read->get<uint64_t>();
     else
         pte = read->get<uint32_t>();
@@ -80,19 +278,22 @@ Walker::doNext(PacketPtr &write)
     bool uncacheable = pte.pcd;
     Addr nextRead = 0;
     bool doWrite = false;
+    bool doTLBInsert = false;
+    bool doEndWalk = false;
     bool badNX = pte.nx && mode == BaseTLB::Execute && enableNX;
     switch(state) {
       case LongPML4:
         DPRINTF(PageTableWalker,
                 "Got long mode PML4 entry %#016x.\n", (uint64_t)pte);
-        nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl3 * size;
+        nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl3 * dataSize;
         doWrite = !pte.a;
         pte.a = 1;
         entry.writable = pte.w;
         entry.user = pte.u;
         if (badNX || !pte.p) {
-            stop();
-            return pageFault(pte.p);
+            doEndWalk = true;
+            fault = pageFault(pte.p);
+            break;
         }
         entry.noExec = pte.nx;
         nextState = LongPDP;
@@ -100,14 +301,15 @@ Walker::doNext(PacketPtr &write)
       case LongPDP:
         DPRINTF(PageTableWalker,
                 "Got long mode PDP entry %#016x.\n", (uint64_t)pte);
-        nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl2 * size;
+        nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl2 * dataSize;
         doWrite = !pte.a;
         pte.a = 1;
         entry.writable = entry.writable && pte.w;
         entry.user = entry.user && pte.u;
         if (badNX || !pte.p) {
-            stop();
-            return pageFault(pte.p);
+            doEndWalk = true;
+            fault = pageFault(pte.p);
+            break;
         }
         nextState = LongPD;
         break;
@@ -119,14 +321,15 @@ Walker::doNext(PacketPtr &write)
         entry.writable = entry.writable && pte.w;
         entry.user = entry.user && pte.u;
         if (badNX || !pte.p) {
-            stop();
-            return pageFault(pte.p);
+            doEndWalk = true;
+            fault = pageFault(pte.p);
+            break;
         }
         if (!pte.ps) {
             // 4 KB page
             entry.size = 4 * (1 << 10);
             nextRead =
-                ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl1 * size;
+                ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl1 * dataSize;
             nextState = LongPTE;
             break;
         } else {
@@ -137,9 +340,9 @@ Walker::doNext(PacketPtr &write)
             entry.global = pte.g;
             entry.patBit = bits(pte, 12);
             entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1);
-            tlb->insert(entry.vaddr, entry);
-            stop();
-            return NoFault;
+            doTLBInsert = true;
+            doEndWalk = true;
+            break;
         }
       case LongPTE:
         DPRINTF(PageTableWalker,
@@ -149,24 +352,26 @@ Walker::doNext(PacketPtr &write)
         entry.writable = entry.writable && pte.w;
         entry.user = entry.user && pte.u;
         if (badNX || !pte.p) {
-            stop();
-            return pageFault(pte.p);
+            doEndWalk = true;
+            fault = pageFault(pte.p);
+            break;
         }
         entry.paddr = (uint64_t)pte & (mask(40) << 12);
         entry.uncacheable = uncacheable;
         entry.global = pte.g;
         entry.patBit = bits(pte, 12);
         entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
-        tlb->insert(entry.vaddr, entry);
-        stop();
-        return NoFault;
+        doTLBInsert = true;
+        doEndWalk = true;
+        break;
       case PAEPDP:
         DPRINTF(PageTableWalker,
                 "Got legacy mode PAE PDP entry %#08x.\n", (uint32_t)pte);
-        nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * size;
+        nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * dataSize;
         if (!pte.p) {
-            stop();
-            return pageFault(pte.p);
+            doEndWalk = true;
+            fault = pageFault(pte.p);
+            break;
         }
         nextState = PAEPD;
         break;
@@ -178,13 +383,14 @@ Walker::doNext(PacketPtr &write)
         entry.writable = pte.w;
         entry.user = pte.u;
         if (badNX || !pte.p) {
-            stop();
-            return pageFault(pte.p);
+            doEndWalk = true;
+            fault = pageFault(pte.p);
+            break;
         }
         if (!pte.ps) {
             // 4 KB page
             entry.size = 4 * (1 << 10);
-            nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael1 * size;
+            nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael1 * dataSize;
             nextState = PAEPTE;
             break;
         } else {
@@ -195,9 +401,9 @@ Walker::doNext(PacketPtr &write)
             entry.global = pte.g;
             entry.patBit = bits(pte, 12);
             entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1);
-            tlb->insert(entry.vaddr, entry);
-            stop();
-            return NoFault;
+            doTLBInsert = true;
+            doEndWalk = true;
+            break;
         }
       case PAEPTE:
         DPRINTF(PageTableWalker,
@@ -207,17 +413,18 @@ Walker::doNext(PacketPtr &write)
         entry.writable = entry.writable && pte.w;
         entry.user = entry.user && pte.u;
         if (badNX || !pte.p) {
-            stop();
-            return pageFault(pte.p);
+            doEndWalk = true;
+            fault = pageFault(pte.p);
+            break;
         }
         entry.paddr = (uint64_t)pte & (mask(40) << 12);
         entry.uncacheable = uncacheable;
         entry.global = pte.g;
         entry.patBit = bits(pte, 7);
         entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
-        tlb->insert(entry.vaddr, entry);
-        stop();
-        return NoFault;
+        doTLBInsert = true;
+        doEndWalk = true;
+        break;
       case PSEPD:
         DPRINTF(PageTableWalker,
                 "Got legacy mode PSE PD entry %#08x.\n", (uint32_t)pte);
@@ -226,14 +433,15 @@ Walker::doNext(PacketPtr &write)
         entry.writable = pte.w;
         entry.user = pte.u;
         if (!pte.p) {
-            stop();
-            return pageFault(pte.p);
+            doEndWalk = true;
+            fault = pageFault(pte.p);
+            break;
         }
         if (!pte.ps) {
             // 4 KB page
             entry.size = 4 * (1 << 10);
             nextRead =
-                ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size;
+                ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * dataSize;
             nextState = PTE;
             break;
         } else {
@@ -244,9 +452,9 @@ Walker::doNext(PacketPtr &write)
             entry.global = pte.g;
             entry.patBit = bits(pte, 12);
             entry.vaddr = entry.vaddr & ~((4 * (1 << 20)) - 1);
-            tlb->insert(entry.vaddr, entry);
-            stop();
-            return NoFault;
+            doTLBInsert = true;
+            doEndWalk = true;
+            break;
         }
       case PD:
         DPRINTF(PageTableWalker,
@@ -256,12 +464,13 @@ Walker::doNext(PacketPtr &write)
         entry.writable = pte.w;
         entry.user = pte.u;
         if (!pte.p) {
-            stop();
-            return pageFault(pte.p);
+            doEndWalk = true;
+            fault = pageFault(pte.p);
+            break;
         }
         // 4 KB page
         entry.size = 4 * (1 << 10);
-        nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size;
+        nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * dataSize;
         nextState = PTE;
         break;
       case PTE:
@@ -272,66 +481,73 @@ Walker::doNext(PacketPtr &write)
         entry.writable = pte.w;
         entry.user = pte.u;
         if (!pte.p) {
-            stop();
-            return pageFault(pte.p);
+            doEndWalk = true;
+            fault = pageFault(pte.p);
+            break;
         }
         entry.paddr = (uint64_t)pte & (mask(20) << 12);
         entry.uncacheable = uncacheable;
         entry.global = pte.g;
         entry.patBit = bits(pte, 7);
         entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
-        tlb->insert(entry.vaddr, entry);
-        stop();
-        return NoFault;
+        doTLBInsert = true;
+        doEndWalk = true;
+        break;
       default:
         panic("Unknown page table walker state %d!\n");
     }
-    PacketPtr oldRead = read;
-    //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);
-    read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
-    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->cmd = MemCmd::WriteReq;
-        write->setDest(Packet::Broadcast);
+    if (doEndWalk) {
+        if (doTLBInsert)
+            if (!functional)
+                walker->tlb->insert(entry.vaddr, entry);
+        endWalk();
     } else {
-        write = NULL;
-        delete oldRead->req;
-        delete oldRead;
+        PacketPtr oldRead = read;
+        //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);
+        read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
+        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->cmd = MemCmd::WriteReq;
+            write->setDest(Packet::Broadcast);
+        } else {
+            write = NULL;
+            delete oldRead->req;
+            delete oldRead;
+        }
     }
-    return NoFault;
+    return fault;
 }
 
-Fault
-Walker::start(ThreadContext * _tc, BaseTLB::Translation *_translation,
-              RequestPtr _req, BaseTLB::Mode _mode)
+void
+Walker::WalkerState::endWalk()
 {
-    assert(state == Ready);
-    tc = _tc;
-    req = _req;
-    Addr vaddr = req->getVaddr();
-    mode = _mode;
-    translation = _translation;
+    nextState = Ready;
+    delete read->req;
+    delete read;
+    read = NULL;
+}
 
+void
+Walker::WalkerState::setupWalk(Addr vaddr)
+{
     VAddr addr = vaddr;
-
-    //Figure out what we're doing.
     CR3 cr3 = tc->readMiscRegNoEffect(MISCREG_CR3);
-    Addr top = 0;
     // Check if we're in long mode or not
     Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER);
-    size = 8;
+    dataSize = 8;
+    Addr topAddr;
     if (efer.lma) {
         // Do long mode.
         state = LongPML4;
-        top = (cr3.longPdtb << 12) + addr.longl4 * size;
+        topAddr = (cr3.longPdtb << 12) + addr.longl4 * dataSize;
         enableNX = efer.nxe;
     } else {
         // We're in some flavor of legacy mode.
@@ -339,11 +555,11 @@ Walker::start(ThreadContext * _tc, BaseTLB::Translation *_translation,
         if (cr4.pae) {
             // Do legacy PAE.
             state = PAEPDP;
-            top = (cr3.paePdtb << 5) + addr.pael3 * size;
+            topAddr = (cr3.paePdtb << 5) + addr.pael3 * dataSize;
             enableNX = efer.nxe;
         } else {
-            size = 4;
-            top = (cr3.pdtb << 12) + addr.norml2 * size;
+            dataSize = 4;
+            topAddr = (cr3.pdtb << 12) + addr.norml2 * dataSize;
             if (cr4.pse) {
                 // Do legacy PSE.
                 state = PSEPD;
@@ -361,44 +577,13 @@ Walker::start(ThreadContext * _tc, BaseTLB::Translation *_translation,
     Request::Flags flags = Request::PHYSICAL;
     if (cr3.pcd)
         flags.set(Request::UNCACHEABLE);
-    RequestPtr request = new Request(top, size, flags);
+    RequestPtr request = new Request(topAddr, dataSize, flags);
     read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
     read->allocate();
-    Enums::MemoryMode memMode = sys->getMemoryMode();
-    if (memMode == Enums::timing) {
-        nextState = state;
-        state = Waiting;
-        timingFault = NoFault;
-        sendPackets();
-    } else if (memMode == Enums::atomic) {
-        Fault fault;
-        do {
-            port.sendAtomic(read);
-            PacketPtr write = NULL;
-            fault = doNext(write);
-            assert(fault == NoFault || read == NULL);
-            state = nextState;
-            nextState = Ready;
-            if (write)
-                port.sendAtomic(write);
-        } while(read);
-        state = Ready;
-        nextState = Waiting;
-        return fault;
-    } else {
-        panic("Unrecognized memory system mode.\n");
-    }
-    return NoFault;
-}
-
-bool
-Walker::WalkerPort::recvTiming(PacketPtr pkt)
-{
-    return walker->recvTiming(pkt);
 }
 
 bool
-Walker::recvTiming(PacketPtr pkt)
+Walker::WalkerState::recvPacket(PacketPtr pkt)
 {
     if (pkt->isResponse() && !pkt->wasNacked()) {
         assert(inflight);
@@ -410,7 +595,7 @@ Walker::recvTiming(PacketPtr pkt)
             nextState = Ready;
             PacketPtr write = NULL;
             read = pkt;
-            timingFault = doNext(write);
+            timingFault = stepWalk(write);
             state = Waiting;
             assert(timingFault == NoFault || read == NULL);
             if (write) {
@@ -432,7 +617,7 @@ Walker::recvTiming(PacketPtr pkt)
                  * well.
                  */
                 bool delayedResponse;
-                Fault fault = tlb->translate(req, tc, NULL, mode,
+                Fault fault = walker->tlb->translate(req, tc, NULL, mode,
                         delayedResponse, true);
                 assert(!delayedResponse);
                 // Let the CPU continue.
@@ -441,10 +626,12 @@ Walker::recvTiming(PacketPtr pkt)
                 // There was a fault during the walk. Let the CPU know.
                 translation->finish(timingFault, req, tc, mode);
             }
+            return true;
         }
     } else if (pkt->wasNacked()) {
+        DPRINTF(PageTableWalker, "Request was nacked. Entering retry state\n");
         pkt->reinitNacked();
-        if (!port.sendTiming(pkt)) {
+        if (!walker->sendTiming(this, pkt)) {
             inflight--;
             retrying = true;
             if (pkt->isWrite()) {
@@ -455,50 +642,11 @@ Walker::recvTiming(PacketPtr pkt)
             }
         }
     }
-    return true;
-}
-
-Tick
-Walker::WalkerPort::recvAtomic(PacketPtr pkt)
-{
-    return 0;
-}
-
-void
-Walker::WalkerPort::recvFunctional(PacketPtr pkt)
-{
-    return;
-}
-
-void
-Walker::WalkerPort::recvStatusChange(Status status)
-{
-    if (status == RangeChange) {
-        if (!snoopRangeSent) {
-            snoopRangeSent = true;
-            sendStatusChange(Port::RangeChange);
-        }
-        return;
-    }
-
-    panic("Unexpected recvStatusChange.\n");
-}
-
-void
-Walker::WalkerPort::recvRetry()
-{
-    walker->recvRetry();
+    return false;
 }
 
 void
-Walker::recvRetry()
-{
-    retrying = false;
-    sendPackets();
-}
-
-void
-Walker::sendPackets()
+Walker::WalkerState::sendPackets()
 {
     //If we're already waiting for the port to become available, just return.
     if (retrying)
@@ -509,7 +657,7 @@ Walker::sendPackets()
         PacketPtr pkt = read;
         read = NULL;
         inflight++;
-        if (!port.sendTiming(pkt)) {
+        if (!walker->sendTiming(this, pkt)) {
             retrying = true;
             read = pkt;
             inflight--;
@@ -521,7 +669,7 @@ Walker::sendPackets()
         PacketPtr write = writes.back();
         writes.pop_back();
         inflight++;
-        if (!port.sendTiming(write)) {
+        if (!walker->sendTiming(this, write)) {
             retrying = true;
             writes.push_back(write);
             inflight--;
@@ -530,17 +678,33 @@ Walker::sendPackets()
     }
 }
 
-Port *
-Walker::getPort(const std::string &if_name, int idx)
+bool
+Walker::WalkerState::isRetrying()
 {
-    if (if_name == "port")
-        return &port;
-    else
-        panic("No page table walker port named %s!\n", if_name);
+    return retrying;
+}
+
+bool
+Walker::WalkerState::isTiming()
+{
+    return timing;
+}
+
+bool
+Walker::WalkerState::wasStarted()
+{
+    return started;
+}
+
+void
+Walker::WalkerState::retry()
+{
+    retrying = false;
+    sendPackets();
 }
 
 Fault
-Walker::pageFault(bool present)
+Walker::WalkerState::pageFault(bool present)
 {
     DPRINTF(PageTableWalker, "Raising page fault.\n");
     HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
@@ -549,7 +713,7 @@ Walker::pageFault(bool present)
     return new PageFault(entry.vaddr, present, mode, m5reg.cpl == 3, false);
 }
 
-}
+/* end namespace X86ISA */ }
 
 X86ISA::Walker *
 X86PagetableWalkerParams::create()
index 68f85be9356ec77c8567d2e708ca5c36504f3cd3..007c577ae9f2d522edabf0172054f66264ea2015 100644 (file)
@@ -45,6 +45,7 @@
 #include "arch/x86/pagetable.hh"
 #include "arch/x86/tlb.hh"
 #include "base/types.hh"
+#include "base/fast_alloc.hh"
 #include "mem/mem_object.hh"
 #include "mem/packet.hh"
 #include "params/X86PagetableWalker.hh"
@@ -56,70 +57,8 @@ namespace X86ISA
 {
     class Walker : public MemObject
     {
-      public:
-        enum State {
-            Ready,
-            Waiting,
-            // Long mode
-            LongPML4, LongPDP, LongPD, LongPTE,
-            // PAE legacy mode
-            PAEPDP, PAEPD, PAEPTE,
-            // Non PAE legacy mode with and without PSE
-            PSEPD, PD, PTE
-        };
-
-        // Act on the current state and determine what to do next. The global
-        // read should be the packet that just came back from a read and write
-        // should be NULL. When the function returns, read is either NULL
-        // if the machine is finished, or points to a packet to initiate
-        // the next read. If any write is required to update an "accessed"
-        // bit, write will point to a packet to do the write. Otherwise it
-        // will be NULL. The return value is whatever fault was incurred
-        // during this stage of the lookup.
-        Fault doNext(PacketPtr &write);
-
-        // Kick off the state machine.
-        Fault start(ThreadContext * _tc, BaseTLB::Translation *translation,
-                RequestPtr req, BaseTLB::Mode mode);
-        // Clean up after the state machine.
-        void
-        stop()
-        {
-            nextState = Ready;
-            delete read->req;
-            delete read;
-            read = NULL;
-        }
-
       protected:
-
-        /*
-         * State having to do with sending packets.
-         */
-        PacketPtr read;
-        std::vector<PacketPtr> writes;
-
-        // How many memory operations are in flight.
-        unsigned inflight;
-
-        bool retrying;
-
-        /*
-         * The fault, if any, that's waiting to be delivered in timing mode.
-         */
-        Fault timingFault;
-
-        /*
-         * Functions for dealing with packets.
-         */
-        bool recvTiming(PacketPtr pkt);
-        void recvRetry();
-
-        void sendPackets();
-
-        /*
-         * Port for accessing memory
-         */
+        // Port for accessing memory
         class WalkerPort : public Port
         {
           public:
@@ -146,31 +85,106 @@ namespace X86ISA
             }
         };
 
+        friend class WalkerPort;
+        WalkerPort port;
         Port *getPort(const std::string &if_name, int idx = -1);
 
-        friend class WalkerPort;
+        // State to track each walk of the page table
+        class WalkerState : public FastAlloc
+        {
+          private:
+            enum State {
+                Ready,
+                Waiting,
+                // Long mode
+                LongPML4, LongPDP, LongPD, LongPTE,
+                // PAE legacy mode
+                PAEPDP, PAEPD, PAEPTE,
+                // Non PAE legacy mode with and without PSE
+                PSEPD, PD, PTE
+            };
 
-        WalkerPort port;
+          protected:
+            Walker * walker;
+            ThreadContext *tc;
+            RequestPtr req;
+            State state;
+            State nextState;
+            int dataSize;
+            bool enableNX;
+            unsigned inflight;
+            TlbEntry entry;
+            PacketPtr read;
+            std::vector<PacketPtr> writes;
+            Fault timingFault;
+            TLB::Translation * translation;
+            BaseTLB::Mode mode;
+            bool functional;
+            bool timing;
+            bool retrying;
+            bool started;
+
+          public:
+            WalkerState(Walker * _walker, BaseTLB::Translation *_translation,
+                    RequestPtr _req, bool _isFunctional = false) :
+                        walker(_walker), req(_req), state(Ready),
+                        nextState(Ready), inflight(0),
+                        translation(_translation),
+                        functional(_isFunctional), timing(false),
+                        retrying(false), started(false)
+            {
+            }
+            void initState(ThreadContext * _tc, BaseTLB::Mode _mode,
+                           bool _isTiming = false);
+            Fault startWalk();
+            Fault startFunctional(Addr &addr, Addr &pageSize);
+            bool recvPacket(PacketPtr pkt);
+            bool isRetrying();
+            bool wasStarted();
+            bool isTiming();
+            void retry();
+            std::string name() const {return walker->name();}
+
+          private:
+            void setupWalk(Addr vaddr);
+            Fault stepWalk(PacketPtr &write);
+            void sendPackets();
+            void endWalk();
+            Fault pageFault(bool present);
+        };
+
+        friend class WalkerState;
+        // State for timing and atomic accesses (need multiple per walker in
+        // the case of multiple outstanding requests in timing mode)
+        std::list<WalkerState *> currStates;
+        // State for functional accesses (only need one of these per walker)
+        WalkerState funcState;
+
+        struct WalkerSenderState : public Packet::SenderState
+        {
+            WalkerState * senderWalk;
+            Packet::SenderState * saved;
+            WalkerSenderState(WalkerState * _senderWalk,
+                    Packet::SenderState * _saved) :
+                senderWalk(_senderWalk), saved(_saved) {}
+        };
 
+      public:
+        // Kick off the state machine.
+        Fault start(ThreadContext * _tc, BaseTLB::Translation *translation,
+                RequestPtr req, BaseTLB::Mode mode);
+        Fault startFunctional(ThreadContext * _tc, Addr &addr,
+                Addr &pageSize, BaseTLB::Mode mode);
+
+      protected:
         // The TLB we're supposed to load.
         TLB * tlb;
         System * sys;
-        BaseTLB::Translation * translation;
-
-        /*
-         * State machine state.
-         */
-        ThreadContext * tc;
-        RequestPtr req;
-        State state;
-        State nextState;
-        int size;
-        bool enableNX;
-        BaseTLB::Mode mode;
-        bool user;
-        TlbEntry entry;
-        
-        Fault pageFault(bool present);
+
+        // Functions for dealing with packets.
+        bool recvTiming(PacketPtr pkt);
+        void recvRetry();
+        bool sendTiming(WalkerState * sendingState, PacketPtr pkt);
 
       public:
 
@@ -182,11 +196,8 @@ namespace X86ISA
         typedef X86PagetableWalkerParams Params;
 
         Walker(const Params *params) :
-            MemObject(params),
-            read(NULL), inflight(0), retrying(false),
-            port(name() + ".port", this),
-            tlb(NULL), sys(params->system),
-            tc(NULL), state(Ready), nextState(Ready)
+            MemObject(params), port(name() + ".port", this),
+            funcState(this, NULL, NULL, true), tlb(NULL), sys(params->system)
         {
         }
     };
index 7fa2e172cc6d31116ee85e1798e8bc7753d712f4..a02c5e6a3004b2202c7db3b3875f8be9cec5122f 100644 (file)
@@ -725,6 +725,12 @@ TLB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
     return tc->getCpuPtr()->ticks(1);
 }
 
+Walker *
+TLB::getWalker()
+{
+    return walker;
+}
+
 #endif
 
 void
index 0e96b26b826e847d357677d92e3db7570e280361..965d331ba8528687a4a05d5c29369ec6855f9449 100644 (file)
@@ -89,6 +89,8 @@ namespace X86ISA
       protected:
 
         Walker * walker;
+      public:
+        Walker *getWalker();
 #endif
 
       public: