Gabe Black has uploaded this change for review. (
https://gem5-review.googlesource.com/7350
Change subject: arch, mem: Abstract the data stored in the SE page tables.
......................................................................
arch, 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
---
M src/arch/alpha/faults.cc
M src/arch/sparc/faults.cc
M src/arch/x86/tlb.cc
M src/gpu-compute/gpu_tlb.cc
M src/mem/page_table.cc
M src/mem/page_table.hh
M src/sim/syscall_emul.hh
7 files changed, 110 insertions(+), 92 deletions(-)
diff --git a/src/arch/alpha/faults.cc b/src/arch/alpha/faults.cc
index 89b0ece..3433844 100644
--- a/src/arch/alpha/faults.cc
+++ b/src/arch/alpha/faults.cc
@@ -196,11 +196,14 @@
}
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<TLB *>(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<TLB *>(tc->getITBPtr())->insert(vaddr.page(), entry);
}
void
@@ -212,11 +215,14 @@
}
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<TLB *>(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<TLB *>(tc->getDTBPtr())->insert(vaddr.page(), entry);
}
} // namespace AlphaISA
diff --git a/src/arch/sparc/faults.cc b/src/arch/sparc/faults.cc
index 0b6a289..0f042b4 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 @@
}
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 @@
// 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<TLB *>(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 @@
}
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 @@
// 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<TLB *>(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 9336949..a3aec16 100644
--- a/src/arch/x86/tlb.cc
+++ b/src/arch/x86/tlb.cc
@@ -357,22 +357,26 @@
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<PageFault>(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 9cbf3e8..05d22da 100644
--- a/src/gpu-compute/gpu_tlb.cc
+++ b/src/gpu-compute/gpu_tlb.cc
@@ -808,18 +808,19 @@
"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<PageFault>(vaddr, true,
mode, true,
false);
@@ -827,11 +828,11 @@
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 @@
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 @@
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 @@
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 2d38877..266d368 100644
--- a/src/mem/page_table.cc
+++ b/src/mem/page_table.cc
@@ -40,19 +40,11 @@
#include <string>
#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,22 +58,17 @@
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);
} else {
- it = pTable.emplace(vaddr, nullptr).first;
+ it = pTable.emplace(vaddr, Entry()).first;
}
- it->second = new TheISA::TlbEntry(pid, vaddr, paddr,
- flags & Uncacheable,
- flags & ReadOnly);
+ it->second = Entry(paddr, flags);
eraseCacheEntry(vaddr);
- updateCache(vaddr, pTable[vaddr]);
+ updateCache(vaddr, &(it->second));
size -= pageSize;
vaddr += pageSize;
paddr += pageSize;
@@ -105,8 +92,7 @@
new_it->second = old_it->second;
pTable.erase(old_it);
eraseCacheEntry(vaddr);
- new_it->second->updateVaddr(new_vaddr);
- updateCache(new_vaddr, new_it->second);
+ updateCache(new_vaddr, &(new_it->second));
size -= pageSize;
vaddr += pageSize;
new_vaddr += pageSize;
@@ -117,7 +103,7 @@
EmulationPageTable::getMappings(std::vector<std::pair<Addr, Addr>>
*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
@@ -125,13 +111,12 @@
{
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());
eraseCacheEntry(vaddr);
- delete it->second;
pTable.erase(it);
size -= pageSize;
vaddr += pageSize;
@@ -151,7 +136,7 @@
return true;
}
-TheISA::TlbEntry *
+const EmulationPageTable::Entry *
EmulationPageTable::lookup(Addr vaddr)
{
Addr page_addr = pageAlign(vaddr);
@@ -168,19 +153,19 @@
if (iter == pTable.end())
return nullptr;
- updateCache(page_addr, iter->second);
- return iter->second;
+ updateCache(page_addr, &(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;
}
@@ -211,7 +196,8 @@
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());
}
@@ -225,13 +211,14 @@
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 4baac67..0891c1a 100644
--- a/src/mem/page_table.hh
+++ b/src/mem/page_table.hh
@@ -40,11 +40,8 @@
#include <string>
#include <unordered_map>
-#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,8 +49,18 @@
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<Addr, TheISA::TlbEntry *> PTable;
+ typedef std::unordered_map<Addr, Entry> PTable;
typedef PTable::iterator PTableItr;
PTable pTable;
@@ -62,7 +69,7 @@
CacheElement() { entry = nullptr; }
Addr vaddr;
- TheISA::TlbEntry *entry;
+ Entry *entry;
};
CacheElement pTableCache[3];
@@ -72,7 +79,7 @@
* @param pte page table entry to return
*/
void
- updateCache(Addr vaddr, TheISA::TlbEntry *entry)
+ updateCache(Addr vaddr, Entry *entry)
{
pTableCache[2].entry = pTableCache[1].entry;
pTableCache[2].vaddr = pTableCache[1].vaddr;
@@ -103,7 +110,7 @@
const Addr pageSize;
const Addr offsetMask;
- const uint64_t pid;
+ const uint64_t _pid;
const std::string _name;
public:
@@ -111,12 +118,14 @@
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
@@ -163,7 +172,7 @@
* @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 ef61299..eaa5e54 100644
--- a/src/sim/syscall_emul.hh
+++ b/src/sim/syscall_emul.hh
@@ -93,6 +93,7 @@
#include <memory>
#include <string>
+#include "arch/generic/tlb.hh"
#include "arch/utility.hh"
#include "base/intmath.hh"
#include "base/loader/object_file.hh"
--
To view, visit https://gem5-review.googlesource.com/7350
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings
Gerrit-Project: public/gem5
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I11e630f60682f0a0029b0683eb8ff0135fbd4317
Gerrit-Change-Number: 7350
Gerrit-PatchSet: 1
Gerrit-Owner: Gabe Black <gabebl...@google.com>
_______________________________________________
gem5-dev mailing list
gem5-dev@gem5.org
http://m5sim.org/mailman/listinfo/gem5-dev