sim: Fix two bugs relating to software caching of PageTable entries.
authorMitch Hayenga <mitch.hayenga+gem5@gmail.com>
Tue, 23 Apr 2013 13:47:52 +0000 (09:47 -0400)
committerMitch Hayenga <mitch.hayenga+gem5@gmail.com>
Tue, 23 Apr 2013 13:47:52 +0000 (09:47 -0400)
The existing implementation can read uninitialized data or stale information
from the cached PageTable entries.

1) Add a valid bit for the cache entries.  Simply using zero for the virtual
address to signify invalid entries is not sufficient.  Speculative, wrong-path
accesses frequently access page zero.  The current implementation would return
a uninitialized TLB entry when address zero was accessed and the PageTable
cache entry was invalid.

2) When unmapping/mapping/remaping a page, invalidate the corresponding
PageTable cache entry if one already exists.

src/mem/page_table.cc
src/mem/page_table.hh

index be862e429baabf4ebd7ebee1cfd0a566a42093f3..cb7ddfe4bf29d5d26542d1d41a5db5f63229ffe2 100644 (file)
@@ -55,9 +55,9 @@ PageTable::PageTable(const std::string &__name, uint64_t _pid, Addr _pageSize)
       pid(_pid), _name(__name)
 {
     assert(isPowerOf2(pageSize));
-    pTableCache[0].vaddr = 0;
-    pTableCache[1].vaddr = 0;
-    pTableCache[2].vaddr = 0;
+    pTableCache[0].valid = false;
+    pTableCache[1].valid = false;
+    pTableCache[2].valid = false;
 }
 
 PageTable::~PageTable()
@@ -79,6 +79,7 @@ PageTable::map(Addr vaddr, Addr paddr, int64_t size, bool clobber)
         }
 
         pTable[vaddr] = TheISA::TlbEntry(pid, vaddr, paddr);
+        eraseCacheEntry(vaddr);
         updateCache(vaddr, pTable[vaddr]);
     }
 }
@@ -97,6 +98,7 @@ PageTable::remap(Addr vaddr, int64_t size, Addr new_vaddr)
 
         pTable[new_vaddr] = pTable[vaddr];
         pTable.erase(vaddr);
+        eraseCacheEntry(vaddr);
         pTable[new_vaddr].updateVaddr(new_vaddr);
         updateCache(new_vaddr, pTable[new_vaddr]);
     }
@@ -111,8 +113,8 @@ PageTable::unmap(Addr vaddr, int64_t size)
 
     for (; size > 0; size -= pageSize, vaddr += pageSize) {
         assert(pTable.find(vaddr) != pTable.end());
-
         pTable.erase(vaddr);
+        eraseCacheEntry(vaddr);
     }
 
 }
@@ -137,15 +139,15 @@ PageTable::lookup(Addr vaddr, TheISA::TlbEntry &entry)
 {
     Addr page_addr = pageAlign(vaddr);
 
-    if (pTableCache[0].vaddr == page_addr) {
+    if (pTableCache[0].valid && pTableCache[0].vaddr == page_addr) {
         entry = pTableCache[0].entry;
         return true;
     }
-    if (pTableCache[1].vaddr == page_addr) {
+    if (pTableCache[1].valid && pTableCache[1].vaddr == page_addr) {
         entry = pTableCache[1].entry;
         return true;
     }
-    if (pTableCache[2].vaddr == page_addr) {
+    if (pTableCache[2].valid && pTableCache[2].vaddr == page_addr) {
         entry = pTableCache[2].entry;
         return true;
     }
index b1b5227bed74a2faffb8a05b80e82fdb5c2c5a17..ce3bfa5e1a3309ee4aeabff180cd372000e91d89 100644 (file)
@@ -57,6 +57,7 @@ class PageTable
     PTable pTable;
 
     struct cacheElement {
+        bool valid;
         Addr vaddr;
         TheISA::TlbEntry entry;
     };
@@ -132,12 +133,32 @@ class PageTable
     {
         pTableCache[2].entry = pTableCache[1].entry;
         pTableCache[2].vaddr = pTableCache[1].vaddr;
+        pTableCache[2].valid = pTableCache[1].valid;
+
         pTableCache[1].entry = pTableCache[0].entry;
         pTableCache[1].vaddr = pTableCache[0].vaddr;
+        pTableCache[1].valid = pTableCache[0].valid;
+
         pTableCache[0].entry = entry;
         pTableCache[0].vaddr = vaddr;
+        pTableCache[0].valid = true;
     }
 
+    /**
+     * Erase an entry from the page table cache.
+     * @param vaddr virtual address (page aligned) to check
+     */
+    inline void eraseCacheEntry(Addr vaddr)
+    {
+        // Invalidate cached entries if necessary
+        if (pTableCache[0].valid && pTableCache[0].vaddr == vaddr) {
+            pTableCache[0].valid = false;
+        } else if (pTableCache[1].valid && pTableCache[1].vaddr == vaddr) {
+            pTableCache[1].valid = false;
+        } else if (pTableCache[2].valid && pTableCache[2].vaddr == vaddr) {
+            pTableCache[2].valid = false;
+        }
+    }
 
     void serialize(std::ostream &os);