sim: Fix two bugs relating to software caching of PageTable entries.

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.
This commit is contained in:
Mitch Hayenga
2013-04-23 09:47:52 -04:00
parent 3e35fa5dcc
commit b222ba2fd3
2 changed files with 30 additions and 7 deletions

View 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;
}

View 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);