mem: Page Table map api modification
authorAlexandru Dutu <alexandru.dutu@amd.com>
Mon, 24 Nov 2014 02:01:09 +0000 (18:01 -0800)
committerAlexandru Dutu <alexandru.dutu@amd.com>
Mon, 24 Nov 2014 02:01:09 +0000 (18:01 -0800)
This patch adds uncacheable/cacheable and read-only/read-write attributes to
the map method of PageTableBase. It also modifies the constructor of TlbEntry
structs for all architectures to consider the new attributes.

14 files changed:
src/arch/alpha/pagetable.hh
src/arch/arm/pagetable.hh
src/arch/mips/pagetable.hh
src/arch/power/tlb.hh
src/arch/sparc/pagetable.hh
src/arch/x86/pagetable.cc
src/arch/x86/pagetable.hh
src/mem/multi_level_page_table.hh
src/mem/multi_level_page_table_impl.hh
src/mem/page_table.cc
src/mem/page_table.hh
src/sim/Process.py
src/sim/process.cc
src/sim/process.hh

index b9091d5b6dcf928414f41751c7b70d6731e91d96..ca44de7fad44a5e2080ff5951627c6926cc21cac 100644 (file)
@@ -104,7 +104,8 @@ struct TlbEntry
 
 
     //Construct an entry that maps to physical address addr.
-    TlbEntry(Addr _asn, Addr _vaddr, Addr _paddr)
+    TlbEntry(Addr _asn, Addr _vaddr, Addr _paddr,
+             bool uncacheable, bool read_only)
     {
         VAddr vaddr(_vaddr);
         VAddr paddr(_paddr);
@@ -117,6 +118,9 @@ struct TlbEntry
         fonr = false;
         fonw = false;
         valid = true;
+        if (uncacheable || read_only)
+            warn("Alpha TlbEntry does not support uncacheable"
+                 " or read-only mappings\n");
     }
 
     TlbEntry()
index 591ec98075bb17b4a6892136f47baae53e8d29c4..c1956cf095e017f7965f0eb046ceaf09a0ac16ba 100644 (file)
@@ -147,18 +147,21 @@ struct TlbEntry
     bool pxn;               // Privileged Execute Never (LPAE only)
 
     //Construct an entry that maps to physical address addr for SE mode
-    TlbEntry(Addr _asn, Addr _vaddr, Addr _paddr) :
+    TlbEntry(Addr _asn, Addr _vaddr, Addr _paddr,
+             bool uncacheable, bool read_only) :
          pfn(_paddr >> PageShift), size(PageBytes - 1), vpn(_vaddr >> PageShift),
          attributes(0), lookupLevel(L1), asid(_asn), vmid(0), N(0),
-         innerAttrs(0), outerAttrs(0), ap(0), hap(0x3),
+         innerAttrs(0), outerAttrs(0), ap(read_only ? 0x3 : 0), hap(0x3),
          domain(DomainType::Client),  mtype(MemoryType::StronglyOrdered),
          longDescFormat(false), isHyp(false), global(false), valid(true),
-         ns(true), nstid(true), el(0), nonCacheable(false), shareable(false),
-         outerShareable(false), xn(0), pxn(0)
+         ns(true), nstid(true), el(0), nonCacheable(uncacheable),
+         shareable(false), outerShareable(false), xn(0), pxn(0)
     {
         // no restrictions by default, hap = 0x3
 
         // @todo Check the memory type
+        if (read_only)
+            warn("ARM TlbEntry does not support read-only mappings\n");
     }
 
     TlbEntry() :
index 8678eb7e4762aedf4ad9861d2b312922aef95284..992d6649ba54927dcd6631784cd55a272258db07 100755 (executable)
@@ -83,7 +83,14 @@ struct TlbEntry
 {
     Addr _pageStart;
     TlbEntry() {}
-    TlbEntry(Addr asn, Addr vaddr, Addr paddr) : _pageStart(paddr) {}
+    TlbEntry(Addr asn, Addr vaddr, Addr paddr,
+             bool uncacheable, bool read_only)
+        : _pageStart(paddr)
+    {
+        if (uncacheable || read_only)
+            warn("MIPS TlbEntry does not support uncacheable"
+                 " or read-only mappings\n");
+    }
 
     Addr pageStart()
     {
index 9ea1fca8bb5b7f3e65dcb9b16b15647bddbce276..0abafc7776202c73c3abf9c257190c61a54ddb78 100644 (file)
@@ -62,9 +62,13 @@ struct TlbEntry
     {
     }
 
-    TlbEntry(Addr asn, Addr vaddr, Addr paddr)
+    TlbEntry(Addr asn, Addr vaddr, Addr paddr,
+             bool uncacheable, bool read_only)
         : _pageStart(paddr)
     {
+        if (uncacheable || read_only)
+            warn("Power TlbEntry does not support uncacheable"
+                 " or read-only mappings\n");
     }
 
     void
index aba17e505000d9b3a0fd1fa8a0fae78f8915872e..727727f951765a53f741177c21b7d65c805e235c 100644 (file)
@@ -230,14 +230,18 @@ struct TlbEntry
     TlbEntry()
     {}
 
-    TlbEntry(Addr asn, Addr vaddr, Addr paddr)
+    TlbEntry(Addr asn, Addr vaddr, Addr paddr,
+             bool uncacheable, bool read_only)
     {
         uint64_t entry = 0;
-        entry |= 1ULL << 1; // Writable
+        if (!read_only)
+            entry |= 1ULL << 1; // Writable
         entry |= 0ULL << 2; // Available in nonpriveleged mode
         entry |= 0ULL << 3; // No side effects
-        entry |= 1ULL << 4; // Virtually cachable
-        entry |= 1ULL << 5; // Physically cachable
+        if (!uncacheable) {
+            entry |= 1ULL << 4; // Virtually cachable
+            entry |= 1ULL << 5; // Physically cachable
+        }
         entry |= 0ULL << 6; // Not locked
         entry |= mbits(paddr, 39, 13); // Physical address
         entry |= 0ULL << 48; // size = 8k
index a9ef1812979b4c3e65a2f1fdb3732ab8c0979ee1..cd4df42e7934356dba2503cd3066ff58f16be354 100644 (file)
 namespace X86ISA
 {
 
-TlbEntry::TlbEntry(Addr asn, Addr _vaddr, Addr _paddr) :
-    paddr(_paddr), vaddr(_vaddr), logBytes(PageShift), writable(true),
-    user(true), uncacheable(false), global(false), patBit(0), noExec(false)
+TlbEntry::TlbEntry(Addr asn, Addr _vaddr, Addr _paddr,
+                   bool uncacheable, bool read_only) :
+    paddr(_paddr), vaddr(_vaddr), logBytes(PageShift), writable(!read_only),
+    user(true), uncacheable(uncacheable), global(false), patBit(0),
+    noExec(false)
 {}
 
 void
index 86e488bdc0ad7a92d6a658ab590db5a8c33e1178..639815893e06fff94f254c1e14e311c89f38aa0a 100644 (file)
@@ -128,7 +128,8 @@ namespace X86ISA
 
         TlbEntryTrie::Handle trieHandle;
 
-        TlbEntry(Addr asn, Addr _vaddr, Addr _paddr);
+        TlbEntry(Addr asn, Addr _vaddr, Addr _paddr,
+                 bool uncacheable, bool read_only);
         TlbEntry() {}
 
         void
@@ -157,13 +158,12 @@ namespace X86ISA
      */
     const std::vector<uint8_t> PageTableLayout = {9, 9, 9, 9};
 
+    /* x86 specific PTE flags */
     enum PTEField{
-        PTE_NotPresent = 0,
-        PTE_Present,
-        PTE_ReadOnly = 0,
-        PTE_ReadWrite,
-        PTE_Supervisor = 0,
-        PTE_UserSupervisor,
+        PTE_NotPresent  = 1,
+        PTE_Supervisor  = 2,
+        PTE_ReadOnly    = 4,
+        PTE_Uncacheable = 8,
     };
 
     /** Page table operations specific to x86 ISA.
@@ -172,14 +172,12 @@ namespace X86ISA
     class PageTableOps
     {
       public:
-        void setPTEFields(PageTableEntry& PTE,
-                          uint64_t present = PTE_Present,
-                          uint64_t read_write = PTE_ReadWrite,
-                          uint64_t user_supervisor = PTE_UserSupervisor)
+        void setPTEFields(PageTableEntry& PTE, uint64_t flags = 0)
         {
-            PTE.p = present;
-            PTE.w = read_write;
-            PTE.u = user_supervisor;// both user and supervisor access allowed
+            PTE.p   = flags & PTE_NotPresent  ? 0 : 1;
+            PTE.pcd = flags & PTE_Uncacheable ? 1 : 0;
+            PTE.w   = flags & PTE_ReadOnly    ? 0 : 1;
+            PTE.u   = flags & PTE_Supervisor  ? 0 : 1;
         }
 
         /** returns the physical memory address of the page table */
@@ -196,6 +194,16 @@ namespace X86ISA
             return PTE.base;
         }
 
+        bool isUncacheable(const PageTableEntry PTE)
+        {
+            return PTE.pcd;
+        }
+
+        bool isReadOnly(PageTableEntry PTE)
+        {
+            return !PTE.w;
+        }
+
         /** sets the page number in a page table entry */
         void setPnum(PageTableEntry& PTE, Addr paddr)
         {
index 8d9febac8993f1e0a3629b8fc191bbfb7d346cb3..232121c21141f835ea0951e6ccac8ce59e75bc82 100644 (file)
@@ -147,7 +147,8 @@ public:
 
     void initState(ThreadContext* tc);
 
-    void map(Addr vaddr, Addr paddr, int64_t size, bool clobber = false);
+    void map(Addr vaddr, Addr paddr, int64_t size,
+             uint64_t flags = 0);
     void remap(Addr vaddr, int64_t size, Addr new_vaddr);
     void unmap(Addr vaddr, int64_t size);
     bool isUnmapped(Addr vaddr, int64_t size);
index 3d8cbe75dd9907b32fdd4ef65523f5ec772c842b..6714a170e4c404183f8ba3bd09a67558f264eac2 100644 (file)
@@ -137,8 +137,9 @@ MultiLevelPageTable<ISAOps>::walk(Addr vaddr, bool allocate, Addr &PTE_addr)
 template <class ISAOps>
 void
 MultiLevelPageTable<ISAOps>::map(Addr vaddr, Addr paddr,
-                                 int64_t size, bool clobber)
+                                 int64_t size, uint64_t flags)
 {
+    bool clobber = flags & Clobber;
     // starting address must be page aligned
     assert(pageOffset(vaddr) == 0);
 
@@ -155,12 +156,21 @@ MultiLevelPageTable<ISAOps>::map(Addr vaddr, Addr paddr,
                 fatal("addr 0x%x already mapped to %x", vaddr, entry_paddr);
             }
             pTableISAOps.setPnum(PTE, paddr >> PageShift);
-            pTableISAOps.setPTEFields(PTE);
+            uint64_t PTE_flags = 0;
+            if (flags & NotPresent)
+                PTE_flags |= TheISA::PTE_NotPresent;
+            if (flags & Uncacheable)
+                PTE_flags |= TheISA::PTE_Uncacheable;
+            if (flags & ReadOnly)
+                PTE_flags |= TheISA::PTE_ReadOnly;
+            pTableISAOps.setPTEFields(PTE, PTE_flags);
             p.write<PageTableEntry>(PTE_addr, PTE);
             DPRINTF(MMU, "New mapping: %#x-%#x\n", vaddr, paddr);
 
             eraseCacheEntry(vaddr);
-            updateCache(vaddr, TlbEntry(pid, vaddr, paddr));
+            updateCache(vaddr, TlbEntry(pid, vaddr, paddr,
+                                        flags & Uncacheable,
+                                        flags & ReadOnly));
         }
 
     }
@@ -205,7 +215,9 @@ MultiLevelPageTable<ISAOps>::remap(Addr vaddr, int64_t size, Addr new_vaddr)
             }
 
             eraseCacheEntry(vaddr);
-            updateCache(new_vaddr, TlbEntry(pid, new_vaddr, paddr));
+            updateCache(new_vaddr, TlbEntry(pid, new_vaddr, paddr,
+                                            pTableISAOps.isUncacheable(PTE),
+                                            pTableISAOps.isReadOnly(PTE)));
         } else {
             fatal("Page fault while remapping");
         }
@@ -290,7 +302,9 @@ MultiLevelPageTable<ISAOps>::lookup(Addr vaddr, TlbEntry &entry)
         if (pnum == 0)
             return false;
 
-        entry = TlbEntry(pid, vaddr, pnum << PageShift);
+        entry = TlbEntry(pid, vaddr, pnum << PageShift,
+                         pTableISAOps.isUncacheable(PTE),
+                         pTableISAOps.isReadOnly(PTE));
         updateCache(page_addr, entry);
     } else {
         return false;
index fdea1fbad75b07fcbbdb0f3c5c3de8b80e5d3123..d3af09e1e5ede68010f53889b0bd6614c7fc07e5 100644 (file)
@@ -62,8 +62,9 @@ FuncPageTable::~FuncPageTable()
 }
 
 void
-FuncPageTable::map(Addr vaddr, Addr paddr, int64_t size, bool clobber)
+FuncPageTable::map(Addr vaddr, Addr paddr, int64_t size, uint64_t flags)
 {
+    bool clobber = flags & Clobber;
     // starting address must be page aligned
     assert(pageOffset(vaddr) == 0);
 
@@ -75,7 +76,9 @@ FuncPageTable::map(Addr vaddr, Addr paddr, int64_t size, bool clobber)
             fatal("FuncPageTable::allocate: addr 0x%x already mapped", vaddr);
         }
 
-        pTable[vaddr] = TheISA::TlbEntry(pid, vaddr, paddr);
+        pTable[vaddr] = TheISA::TlbEntry(pid, vaddr, paddr,
+                                         flags & Uncacheable,
+                                         flags & ReadOnly);
         eraseCacheEntry(vaddr);
         updateCache(vaddr, pTable[vaddr]);
     }
index be0983996ed8f9bedead7b544b6beb00b5b2fdcf..22b5c61eb3dd079385985d2a8ae4bf65060e766e 100644 (file)
@@ -85,6 +85,20 @@ class PageTableBase
 
     virtual ~PageTableBase() {};
 
+    /* generic page table mapping flags
+     *              unset | set
+     * bit 0 - no-clobber | clobber
+     * bit 1 - present    | not-present
+     * bit 2 - cacheable  | uncacheable
+     * bit 3 - read-write | read-only
+     */
+    enum MappingFlags : uint32_t {
+        Clobber     = 1,
+        NotPresent  = 2,
+        Uncacheable = 4,
+        ReadOnly    = 8,
+    };
+
     virtual void initState(ThreadContext* tc) = 0;
 
     // for DPRINTF compatibility
@@ -93,8 +107,16 @@ class PageTableBase
     Addr pageAlign(Addr a)  { return (a & ~offsetMask); }
     Addr pageOffset(Addr a) { return (a &  offsetMask); }
 
+    /**
+     * Maps a virtual memory region to a physical memory region.
+     * @param vaddr The starting virtual address of the region.
+     * @param paddr The starting physical address where the region is mapped.
+     * @param size The length of the region.
+     * @param flags Generic mapping flags that can be set by or-ing values
+     *              from MappingFlags enum.
+     */
     virtual void map(Addr vaddr, Addr paddr, int64_t size,
-                     bool clobber = false) = 0;
+                     uint64_t flags = 0) = 0;
     virtual void remap(Addr vaddr, int64_t size, Addr new_vaddr) = 0;
     virtual void unmap(Addr vaddr, int64_t size) = 0;
 
@@ -197,7 +219,8 @@ class FuncPageTable : public PageTableBase
     {
     }
 
-    void map(Addr vaddr, Addr paddr, int64_t size, bool clobber = false);
+    void map(Addr vaddr, Addr paddr, int64_t size,
+             uint64_t flags = 0);
     void remap(Addr vaddr, int64_t size, Addr new_vaddr);
     void unmap(Addr vaddr, int64_t size);
 
index f64ab0883a9123ca361ab3195d14401ef5f7673b..ca9aaf5b11da11e7c2d9b97ce334ccab1b719149 100644 (file)
@@ -45,7 +45,7 @@ class Process(SimObject):
 
     @classmethod
     def export_methods(cls, code):
-        code('bool map(Addr vaddr, Addr paddr, int size);')
+        code('bool map(Addr vaddr, Addr paddr, int size, bool cacheable=true);')
 
 class EmulatedDriver(SimObject):
     type = 'EmulatedDriver'
index f53c6b8507f5f8f9f558c3faaf8f4e5e1bd82eb2..0412c27e018e104c65fe2be1026fc6d1f5c456d5 100644 (file)
@@ -338,7 +338,7 @@ Process::allocateMem(Addr vaddr, int64_t size, bool clobber)
 {
     int npages = divCeil(size, (int64_t)PageBytes);
     Addr paddr = system->allocPhysPages(npages);
-    pTable->map(vaddr, paddr, size, clobber);
+    pTable->map(vaddr, paddr, size, clobber ? PageTableBase::Clobber : 0);
 }
 
 bool
@@ -553,9 +553,10 @@ Process::unserialize(Checkpoint *cp, const std::string &section)
 
 
 bool
-Process::map(Addr vaddr, Addr paddr, int size)
+Process::map(Addr vaddr, Addr paddr, int size, bool cacheable)
 {
-    pTable->map(vaddr, paddr, size);
+    pTable->map(vaddr, paddr, size,
+                cacheable ? 0 : PageTableBase::Uncacheable);
     return true;
 }
 
index d0865f9907b46dd95dd469309f26effac4a9cfdd..85ac8a1d5c29c89a9f8a05368d2f201e1da6ef97 100644 (file)
@@ -219,19 +219,19 @@ class Process : public SimObject
     bool fixupStackFault(Addr vaddr);
 
     /**
-     * Map a contiguous range of virtual addresses in this process's
+     * Maps a contiguous range of virtual addresses in this process's
      * address space to a contiguous range of physical addresses.
-     * This function exists primarily to enable exposing the map
-     * operation to python, so that configuration scripts can set up
-     * mappings in SE mode.
+     * This function exists primarily to expose the map operation to
+     * python, so that configuration scripts can set up mappings in SE mode.
      *
      * @param vaddr The starting virtual address of the range.
      * @param paddr The starting physical address of the range.
      * @param size The length of the range in bytes.
+     * @param cacheable Specifies whether accesses are cacheable.
      * @return True if the map operation was successful.  (At this
      *           point in time, the map operation always succeeds.)
      */
-    bool map(Addr vaddr, Addr paddr, int size);
+    bool map(Addr vaddr, Addr paddr, int size, bool cacheable = true);
 
     void serialize(std::ostream &os);
     void unserialize(Checkpoint *cp, const std::string &section);