summaryrefslogtreecommitdiffstats
path: root/src/kernel/block.C
diff options
context:
space:
mode:
authorPatrick Williams <iawillia@us.ibm.com>2012-04-12 22:11:51 -0500
committerA. Patrick Williams III <iawillia@us.ibm.com>2012-04-18 16:21:11 -0500
commit55401cde54ca769a382a9c64f1db13b87bc24ea0 (patch)
tree79aaba5345f31a2f409d788fb17f6a52ec24bbfa /src/kernel/block.C
parentb97e806c5c044abd0cc12cbca41c8358c67eade1 (diff)
downloadtalos-hostboot-55401cde54ca769a382a9c64f1db13b87bc24ea0.tar.gz
talos-hostboot-55401cde54ca769a382a9c64f1db13b87bc24ea0.zip
Optimize PageTableManager and associated VMM.
- Changed overall page table behavior to no longer use C bits in page table entries. Instead, individual blocks mark pages as dirty based on stores during page faults. Initially all writable pages are marked read-only until the first store to it. At that time the block gets an exception and changes the permission on the page table entry to writable and marks its own SPTE to dirty. - Greatly reduced the number of tlbie's and page table accesses. Accomplished this by: * Skipping many of the page table manipulations, such as LRU updates, when the PTE is invalid. * Converting most of the previously general-case of "Modifying a PTE" to specific cases such as "Resetting the Reference Bit" and "Modifying the SW field". - Fixed the LRU-flush algorithm so that it is O(n) instead of O(n^2), where n = size of page table. Change-Id: I2520fa88970fd7f656e6348bf6b34d5db82fd3db Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/892 Tested-by: Jenkins Server Reviewed-by: Douglas R. Gilbert <dgilbert@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com> Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/kernel/block.C')
-rw-r--r--src/kernel/block.C36
1 files changed, 22 insertions, 14 deletions
diff --git a/src/kernel/block.C b/src/kernel/block.C
index 221d536e1..8afc39ae7 100644
--- a/src/kernel/block.C
+++ b/src/kernel/block.C
@@ -78,13 +78,15 @@ ShadowPTE* Block::getPTE(uint64_t i_addr) const
return &iv_ptes[(i_addr - iv_baseAddr) / PAGESIZE];
};
-bool Block::handlePageFault(task_t* i_task, uint64_t i_addr)
+
+bool Block::handlePageFault(task_t* i_task, uint64_t i_addr, bool i_store)
{
// Check containment, call down chain if address isn't in this block.
if (!isContained(i_addr))
{
return (iv_nextBlock ?
- iv_nextBlock->handlePageFault(i_task, i_addr) : false);
+ iv_nextBlock->handlePageFault(i_task, i_addr, i_store) :
+ false);
}
// Calculate page aligned virtual address.
@@ -101,6 +103,19 @@ bool Block::handlePageFault(task_t* i_task, uint64_t i_addr)
return false;
}
+ // Mark the page as dirty if this is a store to it.
+ if (i_store)
+ {
+ if (pte->isWritable())
+ {
+ pte->setDirty(true);
+ }
+ else // Store to non-writable page! This is a permission fault, so
+ // return unhandled.
+ {
+ return false;
+ }
+ }
if (!pte->isPresent())
{
@@ -152,7 +167,7 @@ bool Block::handlePageFault(task_t* i_task, uint64_t i_addr)
l_addr_palign,
pte->getPage(),
(pte->isExecutable() ? EXECUTABLE :
- (pte->isWritable() ? WRITABLE :
+ ((pte->isWritable() && pte->isDirty()) ? WRITABLE :
READ_ONLY)));
return true;
@@ -217,8 +232,9 @@ void Block::attachSPTE(void *i_vaddr)
PageTableManager::addEntry((l_vaddr / PAGESIZE) * PAGESIZE,
l_pte->getPage(),
(l_pte->isExecutable() ? EXECUTABLE :
- (l_pte->isWritable() ? WRITABLE :
- READ_ONLY)));
+ ((l_pte->isWritable() && l_pte->isDirty()) ?
+ WRITABLE :
+ READ_ONLY)));
// update permission for the page that corresponds to the physical page
// addr now that we have handled the page fault.
@@ -257,9 +273,6 @@ uint64_t Block::findPhysicalAddress(uint64_t i_vaddr) const
void Block::releaseAllPages()
{
- // Release all pages from page table.
- PageTableManager::delRangeVA(iv_baseAddr, iv_baseAddr + iv_size);
-
// Free all pages back to page manager.
for(uint64_t page = iv_baseAddr;
page < (iv_baseAddr + iv_size);
@@ -268,6 +281,7 @@ void Block::releaseAllPages()
ShadowPTE* pte = getPTE(page);
if (pte->isPresent())
{
+ PageTableManager::delEntry(page);
uint64_t addr = pte->getPageAddr();
if (0 != addr)
{
@@ -308,12 +322,6 @@ void Block::updateRefCount( uint64_t i_vaddr,
{
spte->incLRU();
}
-
- // track the changed/dirty bit
- if (i_stats.C)
- {
- spte->setDirty( i_stats.C );
- }
}
OpenPOWER on IntegriCloud