From a4e722725c90677d555675eca616c9d0990393f1 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Mon, 8 Jan 2018 23:37:57 -0800 Subject: [PATCH] tarch, mem: Abstract the data stored in the SE page tables. Rather than store the actual TLB entry that corresponds to a mapping, we can just store some abstracted information (address, a few flags) and then let the caller turn that into the appropriate entry. There could potentially be some small amount of overhead from creating entries vs. storing them and just installing them, but it's likely pretty minimal since that only happens on a TLB miss (ideally rare), and, if it is problematic, there could be some preallocated TLB entries which are just minimally filled in as necessary. This has the nice effect of finally making the page tables ISA agnostic. Change-Id: I11e630f60682f0a0029b0683eb8ff0135fbd4317 Reviewed-on: https://gem5-review.googlesource.com/7350 Reviewed-by: Gabe Black Maintainer: Gabe Black --- src/arch/alpha/faults.cc | 22 ++++++++++------ src/arch/sparc/faults.cc | 25 ++++++++++++------ src/arch/x86/tlb.cc | 16 +++++++----- src/gpu-compute/gpu_tlb.cc | 50 ++++++++++++++++++----------------- src/mem/page_table.cc | 53 ++++++++++++++------------------------ src/mem/page_table.hh | 25 ++++++++++++------ src/sim/syscall_emul.hh | 1 + 7 files changed, 105 insertions(+), 87 deletions(-) diff --git a/src/arch/alpha/faults.cc b/src/arch/alpha/faults.cc index 89b0ecea8..3433844c1 100644 --- a/src/arch/alpha/faults.cc +++ b/src/arch/alpha/faults.cc @@ -196,11 +196,14 @@ ItbPageFault::invoke(ThreadContext *tc, const StaticInstPtr &inst) } Process *p = tc->getProcessPtr(); - TlbEntry *entry = p->pTable->lookup(pc); - panic_if(!entry, "Tried to execute unmapped address %#x.\n", pc); + const EmulationPageTable::Entry *pte = p->pTable->lookup(pc); + panic_if(!pte, "Tried to execute unmapped address %#x.\n", pc); VAddr vaddr(pc); - dynamic_cast(tc->getITBPtr())->insert(vaddr.page(), *entry); + TlbEntry entry(p->pTable->pid(), vaddr.page(), pte->paddr, + pte->flags & EmulationPageTable::Uncacheable, + pte->flags & EmulationPageTable::ReadOnly); + dynamic_cast(tc->getITBPtr())->insert(vaddr.page(), entry); } void @@ -212,11 +215,14 @@ NDtbMissFault::invoke(ThreadContext *tc, const StaticInstPtr &inst) } Process *p = tc->getProcessPtr(); - TlbEntry *entry = p->pTable->lookup(vaddr); - if (!entry && p->fixupStackFault(vaddr)) - entry = p->pTable->lookup(vaddr); - panic_if(!entry, "Tried to access unmapped address %#x.\n", (Addr)vaddr); - dynamic_cast(tc->getDTBPtr())->insert(vaddr.page(), *entry); + const EmulationPageTable::Entry *pte = p->pTable->lookup(vaddr); + if (!pte && p->fixupStackFault(vaddr)) + pte = p->pTable->lookup(vaddr); + panic_if(!pte, "Tried to access unmapped address %#x.\n", (Addr)vaddr); + TlbEntry entry(p->pTable->pid(), vaddr.page(), pte->paddr, + pte->flags & EmulationPageTable::Uncacheable, + pte->flags & EmulationPageTable::ReadOnly); + dynamic_cast(tc->getDTBPtr())->insert(vaddr.page(), entry); } } // namespace AlphaISA diff --git a/src/arch/sparc/faults.cc b/src/arch/sparc/faults.cc index 0b6a28927..0f042b4ae 100644 --- a/src/arch/sparc/faults.cc +++ b/src/arch/sparc/faults.cc @@ -35,6 +35,7 @@ #include "arch/sparc/isa_traits.hh" #include "arch/sparc/process.hh" +#include "arch/sparc/tlb.hh" #include "arch/sparc/types.hh" #include "base/bitfield.hh" #include "base/trace.hh" @@ -629,8 +630,8 @@ FastInstructionAccessMMUMiss::invoke(ThreadContext *tc, } Process *p = tc->getProcessPtr(); - TlbEntry *entry = p->pTable->lookup(vaddr); - panic_if(!entry, "Tried to execute unmapped address %#x.\n", vaddr); + const EmulationPageTable::Entry *pte = p->pTable->lookup(vaddr); + panic_if(!pte, "Tried to execute unmapped address %#x.\n", vaddr); Addr alignedvaddr = p->pTable->pageAlign(vaddr); @@ -662,13 +663,17 @@ FastInstructionAccessMMUMiss::invoke(ThreadContext *tc, // the logic works out to the following for the context. int context_id = (is_real_address || trapped) ? 0 : primary_context; + TlbEntry entry(p->pTable->pid(), alignedvaddr, pte->paddr, + pte->flags & EmulationPageTable::Uncacheable, + pte->flags & EmulationPageTable::ReadOnly); + // Insert the TLB entry. // The entry specifying whether the address is "real" is set to // false for syscall emulation mode regardless of whether the // address is real in preceding code. Not sure sure that this is // correct, but also not sure if it matters at all. dynamic_cast(tc->getITBPtr())-> - insert(alignedvaddr, partition_id, context_id, false, entry->pte); + insert(alignedvaddr, partition_id, context_id, false, entry.pte); } void @@ -680,10 +685,10 @@ FastDataAccessMMUMiss::invoke(ThreadContext *tc, const StaticInstPtr &inst) } Process *p = tc->getProcessPtr(); - TlbEntry *entry = p->pTable->lookup(vaddr); - if (!entry && p->fixupStackFault(vaddr)) - entry = p->pTable->lookup(vaddr); - panic_if(!entry, "Tried to access unmapped address %#x.\n", vaddr); + const EmulationPageTable::Entry *pte = p->pTable->lookup(vaddr); + if (!pte && p->fixupStackFault(vaddr)) + pte = p->pTable->lookup(vaddr); + panic_if(!pte, "Tried to access unmapped address %#x.\n", vaddr); Addr alignedvaddr = p->pTable->pageAlign(vaddr); @@ -745,13 +750,17 @@ FastDataAccessMMUMiss::invoke(ThreadContext *tc, const StaticInstPtr &inst) // The partition id distinguishes between virtualized environments. int const partition_id = 0; + TlbEntry entry(p->pTable->pid(), alignedvaddr, pte->paddr, + pte->flags & EmulationPageTable::Uncacheable, + pte->flags & EmulationPageTable::ReadOnly); + // Insert the TLB entry. // The entry specifying whether the address is "real" is set to // false for syscall emulation mode regardless of whether the // address is real in preceding code. Not sure sure that this is // correct, but also not sure if it matters at all. dynamic_cast(tc->getDTBPtr())-> - insert(alignedvaddr, partition_id, context_id, false, entry->pte); + insert(alignedvaddr, partition_id, context_id, false, entry.pte); } void diff --git a/src/arch/x86/tlb.cc b/src/arch/x86/tlb.cc index 93369494d..a3aec1676 100644 --- a/src/arch/x86/tlb.cc +++ b/src/arch/x86/tlb.cc @@ -357,22 +357,26 @@ TLB::translate(RequestPtr req, ThreadContext *tc, Translation *translation, assert(entry); } else { Process *p = tc->getProcessPtr(); - TlbEntry *newEntry = p->pTable->lookup(vaddr); - if (!newEntry && mode != Execute) { + const EmulationPageTable::Entry *pte = + p->pTable->lookup(vaddr); + if (!pte && mode != Execute) { // Check if we just need to grow the stack. if (p->fixupStackFault(vaddr)) { // If we did, lookup the entry for the new page. - newEntry = p->pTable->lookup(vaddr); + pte = p->pTable->lookup(vaddr); } } - if (!newEntry) { + if (!pte) { return std::make_shared(vaddr, true, mode, true, false); } else { Addr alignedVaddr = p->pTable->pageAlign(vaddr); DPRINTF(TLB, "Mapping %#x to %#x\n", alignedVaddr, - newEntry->pageStart()); - entry = insert(alignedVaddr, *newEntry); + pte->paddr); + entry = insert(alignedVaddr, TlbEntry( + p->pTable->pid(), alignedVaddr, pte->paddr, + pte->flags & EmulationPageTable::Uncacheable, + pte->flags & EmulationPageTable::ReadOnly)); } DPRINTF(TLB, "Miss was serviced.\n"); } diff --git a/src/gpu-compute/gpu_tlb.cc b/src/gpu-compute/gpu_tlb.cc index 9cbf3e8fa..05d22dad6 100644 --- a/src/gpu-compute/gpu_tlb.cc +++ b/src/gpu-compute/gpu_tlb.cc @@ -808,18 +808,19 @@ namespace X86ISA "at pc %#x.\n", vaddr, tc->instAddr()); Process *p = tc->getProcessPtr(); - TlbEntry *newEntry = p->pTable->lookup(vaddr); + const EmulationPageTable::Entry *pte = + p->pTable->lookup(vaddr); - if (!newEntry && mode != BaseTLB::Execute) { + if (!pte && mode != BaseTLB::Execute) { // penalize a "page fault" more if (timing) latency += missLatency2; if (p->fixupStackFault(vaddr)) - newEntry = p->pTable->lookup(vaddr); + pte = p->pTable->lookup(vaddr); } - if (!newEntry) { + if (!pte) { return std::make_shared(vaddr, true, mode, true, false); @@ -827,11 +828,11 @@ namespace X86ISA Addr alignedVaddr = p->pTable->pageAlign(vaddr); DPRINTF(GPUTLB, "Mapping %#x to %#x\n", - alignedVaddr, newEntry->pageStart()); + alignedVaddr, pte->paddr); - GpuTlbEntry gpuEntry; - *(TlbEntry *)&gpuEntry = *newEntry; - gpuEntry.valid = true; + GpuTlbEntry gpuEntry( + p->pTable->pid(), alignedVaddr, + pte->paddr, true); entry = insert(alignedVaddr, gpuEntry); } @@ -1335,18 +1336,18 @@ namespace X86ISA Addr alignedVaddr = p->pTable->pageAlign(vaddr); assert(alignedVaddr == virtPageAddr); #endif - TlbEntry *newEntry = p->pTable->lookup(vaddr); - if (!newEntry && sender_state->tlbMode != BaseTLB::Execute && + const EmulationPageTable::Entry *pte = p->pTable->lookup(vaddr); + if (!pte && sender_state->tlbMode != BaseTLB::Execute && p->fixupStackFault(vaddr)) { - newEntry = p->pTable->lookup(vaddr); + pte = p->pTable->lookup(vaddr); } - if (newEntry) { + if (pte) { DPRINTF(GPUTLB, "Mapping %#x to %#x\n", alignedVaddr, - newEntry->pageStart()); + pte->paddr); sender_state->tlbEntry = - new GpuTlbEntry(0, newEntry->vaddr, newEntry->paddr, true); + new GpuTlbEntry(0, virtPageAddr, pte->paddr, true); } else { sender_state->tlbEntry = new GpuTlbEntry(0, 0, 0, false); @@ -1533,10 +1534,11 @@ namespace X86ISA assert(alignedVaddr == virt_page_addr); #endif - TlbEntry *newEntry = p->pTable->lookup(vaddr); - if (!newEntry && sender_state->tlbMode != BaseTLB::Execute && + const EmulationPageTable::Entry *pte = + p->pTable->lookup(vaddr); + if (!pte && sender_state->tlbMode != BaseTLB::Execute && p->fixupStackFault(vaddr)) { - newEntry = p->pTable->lookup(vaddr); + pte = p->pTable->lookup(vaddr); } if (!sender_state->prefetch) { @@ -1545,23 +1547,23 @@ namespace X86ISA assert(success); DPRINTF(GPUTLB, "Mapping %#x to %#x\n", alignedVaddr, - newEntry->pageStart()); + pte->paddr); sender_state->tlbEntry = - new GpuTlbEntry(0, newEntry->vaddr, - newEntry->paddr, success); + new GpuTlbEntry(0, virt_page_addr, + pte->paddr, success); } else { // If this was a prefetch, then do the normal thing if it // was a successful translation. Otherwise, send an empty // TLB entry back so that it can be figured out as empty and // handled accordingly. - if (newEntry) { + if (pte) { DPRINTF(GPUTLB, "Mapping %#x to %#x\n", alignedVaddr, - newEntry->pageStart()); + pte->paddr); sender_state->tlbEntry = - new GpuTlbEntry(0, newEntry->vaddr, - newEntry->paddr, success); + new GpuTlbEntry(0, virt_page_addr, + pte->paddr, success); } else { DPRINTF(GPUPrefetch, "Prefetch failed %#x\n", alignedVaddr); diff --git a/src/mem/page_table.cc b/src/mem/page_table.cc index ee504196a..8a11ada76 100644 --- a/src/mem/page_table.cc +++ b/src/mem/page_table.cc @@ -40,19 +40,11 @@ #include #include "base/trace.hh" -#include "config/the_isa.hh" #include "debug/MMU.hh" #include "sim/faults.hh" #include "sim/serialize.hh" using namespace std; -using namespace TheISA; - -EmulationPageTable::~EmulationPageTable() -{ - for (auto &iter : pTable) - delete iter.second; -} void EmulationPageTable::map(Addr vaddr, Addr paddr, int64_t size, uint64_t flags) @@ -66,20 +58,15 @@ EmulationPageTable::map(Addr vaddr, Addr paddr, int64_t size, uint64_t flags) while (size > 0) { auto it = pTable.find(vaddr); if (it != pTable.end()) { - if (clobber) { - delete it->second; - } else { - // already mapped - panic("EmulationPageTable::allocate: addr %#x already mapped", - vaddr); - } + // already mapped + panic_if(!clobber, + "EmulationPageTable::allocate: addr %#x already mapped", + vaddr); + it->second = Entry(paddr, flags); } else { - it = pTable.emplace(vaddr, nullptr).first; + pTable.emplace(vaddr, Entry(paddr, flags)); } - it->second = new TheISA::TlbEntry(pid, vaddr, paddr, - flags & Uncacheable, - flags & ReadOnly); size -= pageSize; vaddr += pageSize; paddr += pageSize; @@ -102,7 +89,6 @@ EmulationPageTable::remap(Addr vaddr, int64_t size, Addr new_vaddr) new_it->second = old_it->second; pTable.erase(old_it); - new_it->second->updateVaddr(new_vaddr); size -= pageSize; vaddr += pageSize; new_vaddr += pageSize; @@ -113,7 +99,7 @@ void EmulationPageTable::getMappings(std::vector> *addr_maps) { for (auto &iter : pTable) - addr_maps->push_back(make_pair(iter.first, iter.second->pageStart())); + addr_maps->push_back(make_pair(iter.first, iter.second.paddr)); } void @@ -121,12 +107,11 @@ EmulationPageTable::unmap(Addr vaddr, int64_t size) { assert(pageOffset(vaddr) == 0); - DPRINTF(MMU, "Unmapping page: %#x-%#x\n", vaddr, vaddr+ size); + DPRINTF(MMU, "Unmapping page: %#x-%#x\n", vaddr, vaddr + size); while (size > 0) { auto it = pTable.find(vaddr); assert(it != pTable.end()); - delete it->second; pTable.erase(it); size -= pageSize; vaddr += pageSize; @@ -146,25 +131,25 @@ EmulationPageTable::isUnmapped(Addr vaddr, int64_t size) return true; } -TheISA::TlbEntry * +const EmulationPageTable::Entry * EmulationPageTable::lookup(Addr vaddr) { Addr page_addr = pageAlign(vaddr); PTableItr iter = pTable.find(page_addr); if (iter == pTable.end()) return nullptr; - return iter->second; + return &(iter->second); } bool EmulationPageTable::translate(Addr vaddr, Addr &paddr) { - TheISA::TlbEntry *entry = lookup(vaddr); + const Entry *entry = lookup(vaddr); if (!entry) { DPRINTF(MMU, "Couldn't Translate: %#x\n", vaddr); return false; } - paddr = pageOffset(vaddr) + entry->pageStart(); + paddr = pageOffset(vaddr) + entry->paddr; DPRINTF(MMU, "Translating: %#x->%#x\n", vaddr, paddr); return true; } @@ -195,7 +180,8 @@ EmulationPageTable::serialize(CheckpointOut &cp) const ScopedCheckpointSection sec(cp, csprintf("Entry%d", count++)); paramOut(cp, "vaddr", pte.first); - pte.second->serialize(cp); + paramOut(cp, "paddr", pte.second.paddr); + paramOut(cp, "flags", pte.second.flags); } assert(count == pTable.size()); } @@ -209,13 +195,14 @@ EmulationPageTable::unserialize(CheckpointIn &cp) for (int i = 0; i < count; ++i) { ScopedCheckpointSection sec(cp, csprintf("Entry%d", i)); - TheISA::TlbEntry *entry = new TheISA::TlbEntry(); - entry->unserialize(cp); - Addr vaddr; - paramIn(cp, "vaddr", vaddr); + UNSERIALIZE_SCALAR(vaddr); + Addr paddr; + uint64_t flags; + UNSERIALIZE_SCALAR(paddr); + UNSERIALIZE_SCALAR(flags); - pTable[vaddr] = entry; + pTable.emplace(vaddr, Entry(paddr, flags)); } } diff --git a/src/mem/page_table.hh b/src/mem/page_table.hh index 733cdd2e3..fc0c0923e 100644 --- a/src/mem/page_table.hh +++ b/src/mem/page_table.hh @@ -40,11 +40,8 @@ #include #include -#include "arch/isa_traits.hh" -#include "arch/tlb.hh" #include "base/intmath.hh" #include "base/types.hh" -#include "config/the_isa.hh" #include "mem/request.hh" #include "sim/serialize.hh" @@ -52,15 +49,25 @@ class ThreadContext; class EmulationPageTable : public Serializable { + public: + struct Entry + { + Addr paddr; + uint64_t flags; + + Entry(Addr paddr, uint64_t flags) : paddr(paddr), flags(flags) {} + Entry() {} + }; + protected: - typedef std::unordered_map PTable; + typedef std::unordered_map PTable; typedef PTable::iterator PTableItr; PTable pTable; const Addr pageSize; const Addr offsetMask; - const uint64_t pid; + const uint64_t _pid; const std::string _name; public: @@ -68,12 +75,14 @@ class EmulationPageTable : public Serializable EmulationPageTable( const std::string &__name, uint64_t _pid, Addr _pageSize) : pageSize(_pageSize), offsetMask(mask(floorLog2(_pageSize))), - pid(_pid), _name(__name) + _pid(_pid), _name(__name) { assert(isPowerOf2(pageSize)); } - virtual ~EmulationPageTable(); + uint64_t pid() const { return _pid; }; + + virtual ~EmulationPageTable() {}; /* generic page table mapping flags * unset | set @@ -120,7 +129,7 @@ class EmulationPageTable : public Serializable * @param vaddr The virtual address. * @return The page table entry corresponding to vaddr. */ - virtual TheISA::TlbEntry *lookup(Addr vaddr); + const Entry *lookup(Addr vaddr); /** * Translate function diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh index ef61299a0..eaa5e542c 100644 --- a/src/sim/syscall_emul.hh +++ b/src/sim/syscall_emul.hh @@ -93,6 +93,7 @@ #include #include +#include "arch/generic/tlb.hh" #include "arch/utility.hh" #include "base/intmath.hh" #include "base/loader/object_file.hh" -- 2.30.2