misc: Replaced master/slave terminology
[gem5.git] / src / mem / multi_level_page_table.hh
index f71dc0dbc42fa05dc5f9e38e2be2bbd3a1c1a073..68a32b16015aa1917bb419c93dfa41fea0eb2f66 100644 (file)
@@ -24,8 +24,6 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Alexandru Dutu
  */
 
 /**
 #include <string>
 
 #include "base/types.hh"
-#include "config/the_isa.hh"
 #include "mem/page_table.hh"
-
-class System;
+#include "sim/system.hh"
 
 /**
  * This class implements an in-memory multi-level page table that can be
@@ -99,13 +95,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
@@ -115,41 +188,104 @@ class MultiLevelPageTable : public EmulationPageTable
     /**
      * 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
-     */
-    void walk(Addr vaddr, bool allocate, Addr &PTE_addr);
+    void
+    initState() override
+    {
+        if (shared)
+            return;
 
-public:
-    MultiLevelPageTable(const std::string &__name, uint64_t _pid,
-                        System *_sys, Addr pageSize,
-                        const std::vector<uint8_t> &layout);
-    ~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;
-    void serialize(CheckpointOut &cp) const override;
-    void unserialize(CheckpointIn &cp) override;
+        _basePtr = prepTopTable<EntryTypes...>(system, pageSize);
+    }
+
+    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__