summaryrefslogtreecommitdiff
path: root/src/mem/multi_level_page_table.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem/multi_level_page_table.hh')
-rw-r--r--src/mem/multi_level_page_table.hh206
1 files changed, 170 insertions, 36 deletions
diff --git a/src/mem/multi_level_page_table.hh b/src/mem/multi_level_page_table.hh
index 30f534706..bd40d37c1 100644
--- a/src/mem/multi_level_page_table.hh
+++ b/src/mem/multi_level_page_table.hh
@@ -39,7 +39,6 @@
#include <string>
#include "base/types.hh"
-#include "config/the_isa.hh"
#include "mem/page_table.hh"
class System;
@@ -99,13 +98,90 @@ class System;
*
* @see MultiLevelPageTable
*/
-template <class ISAOps>
+
+namespace {
+
+template <class First, class ...Rest>
+Addr
+prepTopTable(System *system, Addr pageSize)
+{
+ Addr addr = system->allocPhysPages(First::tableSize());
+ PortProxy &p = system->physProxy;
+ p.memsetBlob(addr, 0, First::tableSize() * pageSize);
+ return addr;
+}
+
+template <class ...Types>
+struct LastType;
+
+template <class First, class Second, class ...Rest>
+struct LastType<First, Second, Rest...>
+{
+ typedef typename LastType<Second, Rest...>::type type;
+};
+
+template <class Only>
+struct LastType<Only>
+{
+ typedef Only type;
+};
+
+
+template <class ...Types>
+struct WalkWrapper;
+
+template <class Final, class Only>
+struct WalkWrapper<Final, Only>
+{
+ static void
+ walk(System *system, Addr pageSize, Addr table, Addr vaddr,
+ bool allocate, Final *entry)
+ {
+ entry->read(system->physProxy, table, vaddr);
+ }
+};
+
+template <class Final, class First, class Second, class ...Rest>
+struct WalkWrapper<Final, First, Second, Rest...>
+{
+ static void
+ walk(System *system, Addr pageSize, Addr table, Addr vaddr,
+ bool allocate, Final *entry)
+ {
+ First first;
+ first.read(system->physProxy, table, vaddr);
+
+ Addr next;
+ if (!first.present()) {
+ fatal_if(!allocate,
+ "Page fault while walking the page table.");
+ next = prepTopTable<Second>(system, pageSize);
+ first.reset(next);
+ first.write(system->physProxy);
+ } else {
+ next = first.paddr();
+ }
+ WalkWrapper<Final, Second, Rest...>::walk(
+ system, pageSize, next, vaddr, allocate, entry);
+ }
+};
+
+template <class ...EntryTypes>
+void
+walk(System *system, Addr pageSize, Addr table, Addr vaddr,
+ bool allocate, typename LastType<EntryTypes...>::type *entry)
+{
+ WalkWrapper<typename LastType<EntryTypes...>::type, EntryTypes...>::walk(
+ system, pageSize, table, vaddr, allocate, entry);
+}
+
+}
+
+
+template <class ...EntryTypes>
class MultiLevelPageTable : public EmulationPageTable
{
- /**
- * ISA specific operations
- */
- ISAOps pTableISAOps;
+ typedef typename LastType<EntryTypes...>::type Final;
/**
* Pointer to System object
@@ -117,41 +193,99 @@ class MultiLevelPageTable : public EmulationPageTable
*/
Addr _basePtr;
- /**
- * Vector with sizes of all levels in base 2 logarithmic
- */
- const std::vector<uint8_t> logLevelSize;
-
- /**
- * Number of levels contained by the page table
- */
- const uint64_t numLevels;
-
- /**
- * Method for walking the page table
- *
- * @param vaddr Virtual address that is being looked-up
- * @param allocate Specifies whether memory should be allocated while
- * walking the page table
- * @return PTE_addr The address of the found PTE
- */
- void walk(Addr vaddr, bool allocate, Addr &PTE_addr);
-
public:
MultiLevelPageTable(const std::string &__name, uint64_t _pid,
- System *_sys, Addr pageSize,
- const std::vector<uint8_t> &layout);
- ~MultiLevelPageTable();
+ System *_sys, Addr pageSize) :
+ EmulationPageTable(__name, _pid, pageSize), system(_sys)
+ {}
+
+ ~MultiLevelPageTable() {}
- void initState(ThreadContext* tc) override;
+ void
+ initState(ThreadContext* tc) override
+ {
+ _basePtr = prepTopTable<EntryTypes...>(system, pageSize);
+ }
Addr basePtr() { return _basePtr; }
- void map(Addr vaddr, Addr paddr, int64_t size,
- uint64_t flags = 0) override;
- void remap(Addr vaddr, int64_t size, Addr new_vaddr) override;
- void unmap(Addr vaddr, int64_t size) override;
- void serialize(CheckpointOut &cp) const override;
- void unserialize(CheckpointIn &cp) override;
+ void
+ map(Addr vaddr, Addr paddr, int64_t size, uint64_t flags = 0) override
+ {
+ EmulationPageTable::map(vaddr, paddr, size, flags);
+
+ Final entry;
+
+ for (int64_t offset = 0; offset < size; offset += pageSize) {
+ walk<EntryTypes...>(system, pageSize, _basePtr,
+ vaddr + offset, true, &entry);
+
+ entry.reset(paddr + offset, true, flags & Uncacheable,
+ flags & ReadOnly);
+ entry.write(system->physProxy);
+
+ DPRINTF(MMU, "New mapping: %#x-%#x\n",
+ vaddr + offset, paddr + offset);
+ }
+ }
+
+ void
+ remap(Addr vaddr, int64_t size, Addr new_vaddr) override
+ {
+ EmulationPageTable::remap(vaddr, size, new_vaddr);
+
+ Final old_entry, new_entry;
+
+ for (int64_t offset = 0; offset < size; offset += pageSize) {
+ // Unmap the original mapping.
+ walk<EntryTypes...>(system, pageSize, _basePtr, vaddr + offset,
+ false, &old_entry);
+ old_entry.present(false);
+ old_entry.write(system->physProxy);
+
+ // Map the new one.
+ walk<EntryTypes...>(system, pageSize, _basePtr, new_vaddr + offset,
+ true, &new_entry);
+ new_entry.reset(old_entry.paddr(), true, old_entry.uncacheable(),
+ old_entry.readonly());
+ new_entry.write(system->physProxy);
+ }
+ }
+
+ void
+ unmap(Addr vaddr, int64_t size) override
+ {
+ EmulationPageTable::unmap(vaddr, size);
+
+ Final entry;
+
+ for (int64_t offset = 0; offset < size; offset += pageSize) {
+ walk<EntryTypes...>(system, pageSize, _basePtr,
+ vaddr + offset, false, &entry);
+ fatal_if(!entry.present(),
+ "PageTable::unmap: Address %#x not mapped.", vaddr);
+ entry.present(false);
+ entry.write(system->physProxy);
+ DPRINTF(MMU, "Unmapping: %#x\n", vaddr);
+ }
+ }
+
+ void
+ serialize(CheckpointOut &cp) const override
+ {
+ EmulationPageTable::serialize(cp);
+ /** Since, the page table is stored in system memory
+ * which is serialized separately, we will serialize
+ * just the base pointer
+ */
+ paramOut(cp, "ptable.pointer", _basePtr);
+ }
+
+ void
+ unserialize(CheckpointIn &cp) override
+ {
+ EmulationPageTable::unserialize(cp);
+ paramIn(cp, "ptable.pointer", _basePtr);
+ }
};
#endif // __MEM_MULTI_LEVEL_PAGE_TABLE_HH__