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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user