mem-cache: Create an address aware TempCacheBlk
[gem5.git] / src / mem / multi_level_page_table.hh
index 0e079b730ec8b39280bc1f4bba6250c404b36224..bd40d37c105f25f13627964de0c758dd64b1085d 100644 (file)
@@ -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>
-class MultiLevelPageTable : public PageTableBase
+
+namespace {
+
+template <class First, class ...Rest>
+Addr
+prepTopTable(System *system, Addr pageSize)
 {
-    /**
-     * ISA specific operations
-     */
-    ISAOps pTableISAOps;
+    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
+{
+    typedef typename LastType<EntryTypes...>::type Final;
 
     /**
      * Pointer to System object
@@ -115,43 +191,101 @@ class MultiLevelPageTable : public PageTableBase
     /**
      * Physical address to the last level of the page table
      */
-    Addr basePtr;
+    Addr _basePtr;
 
-    /**
-     * Vector with sizes of all levels in base 2 logarithmic
-     */
-    const std::vector<uint8_t> logLevelSize;
+public:
+    MultiLevelPageTable(const std::string &__name, uint64_t _pid,
+                        System *_sys, Addr pageSize) :
+            EmulationPageTable(__name, _pid, pageSize), system(_sys)
+    {}
 
-    /**
-     * Number of levels contained by the page table
-     */
-    const uint64_t numLevels;
+    ~MultiLevelPageTable() {}
 
-    /**
-     * 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
-     * @retval true if the page table walk has succeded, false otherwhise
-     */
-    bool walk(Addr vaddr, bool allocate, Addr &PTE_addr);
+    void
+    initState(ThreadContext* tc) override
+    {
+        _basePtr = prepTopTable<EntryTypes...>(system, pageSize);
+    }
 
-public:
-    MultiLevelPageTable(const std::string &__name, uint64_t _pid,
-                        System *_sys, Addr pageSize);
-    ~MultiLevelPageTable();
-
-    void initState(ThreadContext* tc) override;
-
-    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;
-    bool isUnmapped(Addr vaddr, int64_t size) override;
-    bool lookup(Addr vaddr, TheISA::TlbEntry &entry) override;
-    void serialize(CheckpointOut &cp) const override;
-    void unserialize(CheckpointIn &cp) override;
+    Addr basePtr() { return _basePtr; }
+
+    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__