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
[email protected]
http://m5sim.org/mailman/listinfo/m5-dev