changeset a9f05ab40763 in /z/repo/m5 details: http://repo.m5sim.org/m5?cmd=changeset;node=a9f05ab40763 description: x86: Timing support for pagetable walker
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. diffstat: src/arch/x86/pagetable_walker.cc | 922 ++++++++++++++++++++++---------------- src/arch/x86/pagetable_walker.hh | 181 ++++--- src/arch/x86/tlb.cc | 6 + src/arch/x86/tlb.hh | 2 + 4 files changed, 647 insertions(+), 464 deletions(-) diffs (truncated from 1247 to 300 lines): diff -r 267e1e16e51b -r a9f05ab40763 src/arch/x86/pagetable_walker.cc --- a/src/arch/x86/pagetable_walker.cc Sun Feb 06 22:14:18 2011 -0800 +++ b/src/arch/x86/pagetable_walker.cc Sun Feb 06 22:14:18 2011 -0800 @@ -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,328 +68,36 @@ EndBitUnion(PageTableEntry) Fault -Walker::doNext(PacketPtr &write) +Walker::start(ThreadContext * _tc, BaseTLB::Translation *_translation, + RequestPtr _req, BaseTLB::Mode _mode) { - assert(state != Ready && state != Waiting); - write = NULL; - PageTableEntry pte; - if (size == 8) - pte = read->get<uint64_t>(); - else - pte = read->get<uint32_t>(); - VAddr vaddr = entry.vaddr; - bool uncacheable = pte.pcd; - Addr nextRead = 0; - bool doWrite = 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; - doWrite = !pte.a; - pte.a = 1; - entry.writable = pte.w; - entry.user = pte.u; - if (badNX || !pte.p) { - stop(); - return pageFault(pte.p); + // 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; } - entry.noExec = pte.nx; - nextState = LongPDP; - break; - case LongPDP: - DPRINTF(PageTableWalker, - "Got long mode PDP entry %#016x.\n", (uint64_t)pte); - nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl2 * size; - 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); - } - nextState = LongPD; - break; - case LongPD: - DPRINTF(PageTableWalker, - "Got long mode PD entry %#016x.\n", (uint64_t)pte); - 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); - } - if (!pte.ps) { - // 4 KB page - entry.size = 4 * (1 << 10); - nextRead = - ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl1 * size; - nextState = LongPTE; - break; - } else { - // 2 MB page - entry.size = 2 * (1 << 20); - entry.paddr = (uint64_t)pte & (mask(31) << 21); - entry.uncacheable = uncacheable; - 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; - } - case LongPTE: - DPRINTF(PageTableWalker, - "Got long mode PTE entry %#016x.\n", (uint64_t)pte); - 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); - } - 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; - 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; - if (!pte.p) { - stop(); - return pageFault(pte.p); - } - nextState = PAEPD; - break; - case PAEPD: - DPRINTF(PageTableWalker, - "Got legacy mode PAE PD entry %#08x.\n", (uint32_t)pte); - doWrite = !pte.a; - pte.a = 1; - entry.writable = pte.w; - entry.user = pte.u; - if (badNX || !pte.p) { - stop(); - return pageFault(pte.p); - } - if (!pte.ps) { - // 4 KB page - entry.size = 4 * (1 << 10); - nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael1 * size; - nextState = PAEPTE; - break; - } else { - // 2 MB page - entry.size = 2 * (1 << 20); - entry.paddr = (uint64_t)pte & (mask(31) << 21); - entry.uncacheable = uncacheable; - 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; - } - case PAEPTE: - DPRINTF(PageTableWalker, - "Got legacy mode PAE PTE entry %#08x.\n", (uint32_t)pte); - 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); - } - 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; - case PSEPD: - DPRINTF(PageTableWalker, - "Got legacy mode PSE PD entry %#08x.\n", (uint32_t)pte); - doWrite = !pte.a; - pte.a = 1; - entry.writable = pte.w; - entry.user = pte.u; - if (!pte.p) { - stop(); - return pageFault(pte.p); - } - if (!pte.ps) { - // 4 KB page - entry.size = 4 * (1 << 10); - nextRead = - ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size; - nextState = PTE; - break; - } else { - // 4 MB page - entry.size = 4 * (1 << 20); - entry.paddr = bits(pte, 20, 13) << 32 | bits(pte, 31, 22) << 22; - entry.uncacheable = uncacheable; - 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; - } - case PD: - DPRINTF(PageTableWalker, - "Got legacy mode PD entry %#08x.\n", (uint32_t)pte); - doWrite = !pte.a; - pte.a = 1; - entry.writable = pte.w; - entry.user = pte.u; - if (!pte.p) { - stop(); - return pageFault(pte.p); - } - // 4 KB page - entry.size = 4 * (1 << 10); - nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size; - nextState = PTE; - break; - case PTE: - DPRINTF(PageTableWalker, - "Got legacy mode PTE entry %#08x.\n", (uint32_t)pte); - doWrite = !pte.a; - pte.a = 1; - entry.writable = pte.w; - entry.user = pte.u; - if (!pte.p) { - stop(); - return pageFault(pte.p); - } - 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; - default: - panic("Unknown page table walker state %d!\n"); + return fault; } - 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; } Fault -Walker::start(ThreadContext * _tc, BaseTLB::Translation *_translation, - RequestPtr _req, BaseTLB::Mode _mode) +Walker::startFunctional(ThreadContext * _tc, Addr &addr, Addr &pageSize, + BaseTLB::Mode _mode) { - assert(state == Ready); - tc = _tc; - req = _req; - Addr vaddr = req->getVaddr(); - mode = _mode; - translation = _translation; - - 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; - if (efer.lma) { - // Do long mode. - state = LongPML4; _______________________________________________ m5-dev mailing list m5-dev@m5sim.org http://m5sim.org/mailman/listinfo/m5-dev