diff options
author | Gabe Black <gblack@eecs.umich.edu> | 2007-11-12 18:06:57 -0800 |
---|---|---|
committer | Gabe Black <gblack@eecs.umich.edu> | 2007-11-12 18:06:57 -0800 |
commit | 1048b548fabfb7af2113f226f2151d3eb0e63289 (patch) | |
tree | d68b47ad4f335ade253f5ae87a158c6209d6ec20 /src/arch/x86/tlb.cc | |
parent | 6095dceb0c34cf79ecbd799ab4b2cbe7b7c8629a (diff) | |
download | gem5-1048b548fabfb7af2113f226f2151d3eb0e63289.tar.xz |
X86: Separate out the page table walker into it's own cc and hh.
--HG--
extra : convert_revision : cbc3af01ca3dc911a59224a574007c5c0bcf6042
Diffstat (limited to 'src/arch/x86/tlb.cc')
-rw-r--r-- | src/arch/x86/tlb.cc | 489 |
1 files changed, 16 insertions, 473 deletions
diff --git a/src/arch/x86/tlb.cc b/src/arch/x86/tlb.cc index dd516d2a0..68a22bc16 100644 --- a/src/arch/x86/tlb.cc +++ b/src/arch/x86/tlb.cc @@ -69,491 +69,26 @@ #include "cpu/base.hh" #include "mem/packet_access.hh" #include "mem/request.hh" -#include "sim/system.hh" - -namespace X86ISA { #if FULL_SYSTEM -TLB::TLB(const Params *p) : MemObject(p), walker(name(), this), size(p->size) -#else -TLB::TLB(const Params *p) : MemObject(p), size(p->size) +#include "arch/x86/pagetable_walker.hh" #endif + +namespace X86ISA { + +TLB::TLB(const Params *p) : SimObject(p), size(p->size) { tlb = new TlbEntry[size]; std::memset(tlb, 0, sizeof(TlbEntry) * size); for (int x = 0; x < size; x++) freeList.push_back(&tlb[x]); -} #if FULL_SYSTEM - -// 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) - -void -TLB::Walker::doNext(PacketPtr &read, PacketPtr &write) -{ - 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 && (!tlb->allowNX || !enableNX); - switch(state) { - case LongPML4: - 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) - panic("NX violation!\n"); - entry.noExec = pte.nx; - if (!pte.p) - panic("Page not present!\n"); - nextState = LongPDP; - break; - case LongPDP: - 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) - panic("NX violation!\n"); - if (!pte.p) - panic("Page not present!\n"); - nextState = LongPD; - break; - case LongPD: - doWrite = !pte.a; - pte.a = 1; - entry.writable = entry.writable && pte.w; - entry.user = entry.user && pte.u; - if (badNX) - panic("NX violation!\n"); - if (!pte.p) - panic("Page not present!\n"); - 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); - nextState = Ready; - delete read->req; - delete read; - read = NULL; - return; - } - case LongPTE: - doWrite = !pte.a; - pte.a = 1; - entry.writable = entry.writable && pte.w; - entry.user = entry.user && pte.u; - if (badNX) - panic("NX violation!\n"); - if (!pte.p) - panic("Page not present!\n"); - 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); - nextState = Ready; - delete read->req; - delete read; - read = NULL; - return; - case PAEPDP: - nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * size; - if (!pte.p) - panic("Page not present!\n"); - nextState = PAEPD; - break; - case PAEPD: - doWrite = !pte.a; - pte.a = 1; - entry.writable = pte.w; - entry.user = pte.u; - if (badNX) - panic("NX violation!\n"); - if (!pte.p) - panic("Page not present!\n"); - 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); - nextState = Ready; - delete read->req; - delete read; - read = NULL; - return; - } - case PAEPTE: - doWrite = !pte.a; - pte.a = 1; - entry.writable = entry.writable && pte.w; - entry.user = entry.user && pte.u; - if (badNX) - panic("NX violation!\n"); - if (!pte.p) - panic("Page not present!\n"); - 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); - nextState = Ready; - delete read->req; - delete read; - read = NULL; - return; - case PSEPD: - doWrite = !pte.a; - pte.a = 1; - entry.writable = pte.w; - entry.user = pte.u; - if (!pte.p) - panic("Page not present!\n"); - 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); - nextState = Ready; - delete read->req; - delete read; - read = NULL; - return; - } - case PD: - doWrite = !pte.a; - pte.a = 1; - entry.writable = pte.w; - entry.user = pte.u; - if (!pte.p) - panic("Page not present!\n"); - // 4 KB page - entry.size = 4 * (1 << 10); - nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size; - nextState = PTE; - break; - nextState = PTE; - break; - case PTE: - doWrite = !pte.a; - pte.a = 1; - entry.writable = pte.w; - entry.user = pte.u; - if (!pte.p) - panic("Page not present!\n"); - 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); - nextState = Ready; - delete read->req; - delete read; - read = NULL; - return; - default: - panic("Unknown page table walker state %d!\n"); - } - PacketPtr oldRead = read; - //If we didn't return, we're setting up another read. - uint32_t flags = oldRead->req->getFlags(); - if (uncacheable) - flags |= UNCACHEABLE; - else - flags &= ~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; - } -} - -void -TLB::Walker::start(ThreadContext * _tc, Addr vaddr) -{ - assert(state == Ready); - assert(!tc); - tc = _tc; - - 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; - top = (cr3.longPdtb << 12) + addr.longl4 * size; - } else { - // We're in some flavor of legacy mode. - CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4); - if (cr4.pae) { - // Do legacy PAE. - state = PAEPDP; - top = (cr3.paePdtb << 5) + addr.pael3 * size; - } else { - size = 4; - top = (cr3.pdtb << 12) + addr.norml2 * size; - if (cr4.pse) { - // Do legacy PSE. - state = PSEPD; - } else { - // Do legacy non PSE. - state = PD; - } - } - } - - nextState = Ready; - entry.vaddr = vaddr; - - enableNX = efer.nxe; - - RequestPtr request = - new Request(top, size, PHYSICAL | cr3.pcd ? UNCACHEABLE : 0); - read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast); - read->allocate(); - Enums::MemoryMode memMode = tlb->sys->getMemoryMode(); - if (memMode == Enums::timing) { - tc->suspend(); - port.sendTiming(read); - } else if (memMode == Enums::atomic) { - do { - port.sendAtomic(read); - PacketPtr write = NULL; - doNext(read, write); - state = nextState; - nextState = Ready; - if (write) - port.sendAtomic(write); - } while(read); - tc = NULL; - state = Ready; - nextState = Waiting; - } else { - panic("Unrecognized memory system mode.\n"); - } -} - -bool -TLB::Walker::WalkerPort::recvTiming(PacketPtr pkt) -{ - return walker->recvTiming(pkt); -} - -bool -TLB::Walker::recvTiming(PacketPtr pkt) -{ - inflight--; - if (pkt->isResponse() && !pkt->wasNacked()) { - if (pkt->isRead()) { - assert(inflight); - assert(state == Waiting); - assert(!read); - state = nextState; - nextState = Ready; - PacketPtr write = NULL; - doNext(pkt, write); - state = Waiting; - read = pkt; - if (write) { - writes.push_back(write); - } - sendPackets(); - } else { - sendPackets(); - } - if (inflight == 0 && read == NULL && writes.size() == 0) { - tc->activate(0); - tc = NULL; - state = Ready; - nextState = Waiting; - } - } else if (pkt->wasNacked()) { - pkt->reinitNacked(); - if (!port.sendTiming(pkt)) { - retrying = true; - if (pkt->isWrite()) { - writes.push_back(pkt); - } else { - assert(!read); - read = pkt; - } - } else { - inflight++; - } - } - return true; -} - -Tick -TLB::Walker::WalkerPort::recvAtomic(PacketPtr pkt) -{ - return 0; -} - -void -TLB::Walker::WalkerPort::recvFunctional(PacketPtr pkt) -{ - return; -} - -void -TLB::Walker::WalkerPort::recvStatusChange(Status status) -{ - if (status == RangeChange) { - if (!snoopRangeSent) { - snoopRangeSent = true; - sendStatusChange(Port::RangeChange); - } - return; - } - - panic("Unexpected recvStatusChange.\n"); -} - -void -TLB::Walker::WalkerPort::recvRetry() -{ - walker->recvRetry(); -} - -void -TLB::Walker::recvRetry() -{ - retrying = false; - sendPackets(); -} - -void -TLB::Walker::sendPackets() -{ - //If we're already waiting for the port to become available, just return. - if (retrying) - return; - - //Reads always have priority - if (read) { - if (!port.sendTiming(read)) { - retrying = true; - return; - } else { - inflight++; - delete read->req; - delete read; - read = NULL; - } - } - //Send off as many of the writes as we can. - while (writes.size()) { - PacketPtr write = writes.back(); - if (!port.sendTiming(write)) { - retrying = true; - return; - } else { - inflight++; - delete write->req; - delete write; - writes.pop_back(); - } - } -} - -Port * -TLB::getPort(const std::string &if_name, int idx) -{ - if (if_name == "walker_port") - return &walker.port; - else - panic("No tlb port named %s!\n", if_name); -} - -#else - -Port * -TLB::getPort(const std::string &if_name, int idx) -{ - panic("No tlb ports in se!\n", if_name); -} - + walker = p->walker; + walker->setTLB(this); #endif +} void TLB::insert(Addr vpn, TlbEntry &entry) @@ -593,6 +128,14 @@ TLB::lookup(Addr va, bool update_lru) return NULL; } +#if FULL_SYSTEM +void +TLB::walk(ThreadContext * _tc, Addr vaddr) +{ + walker->start(_tc, vaddr); +} +#endif + void TLB::invalidateAll() { |