summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/include/kernel/basesegment.H5
-rw-r--r--src/include/kernel/block.H14
-rw-r--r--src/include/kernel/cpu.H3
-rw-r--r--src/include/kernel/cpumgr.H14
-rw-r--r--src/include/kernel/pagemgr.H17
-rw-r--r--src/include/kernel/ptmgr.H10
-rw-r--r--src/include/kernel/segment.H6
-rw-r--r--src/include/kernel/segmentmgr.H10
-rw-r--r--src/include/kernel/vmmmgr.H23
-rw-r--r--src/kernel/basesegment.C9
-rw-r--r--src/kernel/block.C99
-rw-r--r--src/kernel/cpumgr.C32
-rw-r--r--src/kernel/pagemgr.C9
-rw-r--r--src/kernel/ptmgr.C22
-rw-r--r--src/kernel/scheduler.C2
-rw-r--r--src/kernel/segmentmgr.C18
-rw-r--r--src/kernel/vmmmgr.C28
-rw-r--r--src/usr/testcore/kernel/vmmbasetest.H20
18 files changed, 337 insertions, 4 deletions
diff --git a/src/include/kernel/basesegment.H b/src/include/kernel/basesegment.H
index da262c2a0..574be1a1f 100644
--- a/src/include/kernel/basesegment.H
+++ b/src/include/kernel/basesegment.H
@@ -106,6 +106,11 @@ class BaseSegment : public Segment
static int mmSetPermission(void* i_va,
uint64_t i_size,
PAGE_PERMISSIONS i_access_type);
+ /**
+ * @breif Cast out older physical memory pages
+ * @param[in] castout Constraint
+ */
+ virtual void castOutPages(uint64_t i_type);
private:
/**
diff --git a/src/include/kernel/block.H b/src/include/kernel/block.H
index 2421f97f9..88c6664c2 100644
--- a/src/include/kernel/block.H
+++ b/src/include/kernel/block.H
@@ -156,6 +156,20 @@ class Block
void updateRefCount( uint64_t i_vaddr,
PageTableManager::UsageStats_t i_stats );
+ /**
+ * @brief Cast out older phyiscal memory pages
+ * @param[in] i_type - Castout contraint @see VmmManager::castOutPages()
+ * @return number of pages cast out
+ */
+ size_t castOutPages(uint64_t i_type);
+
+ /**
+ * @brief Evict a memory page
+ * @param[in] i_pte shadow page table entry
+ * @return true of page was evicted
+ */
+ bool evictPage(ShadowPTE* i_pte);
+
friend class Segment;
friend class BaseSegment;
friend class StackSegment;
diff --git a/src/include/kernel/cpu.H b/src/include/kernel/cpu.H
index ee24bdd64..ac09da288 100644
--- a/src/include/kernel/cpu.H
+++ b/src/include/kernel/cpu.H
@@ -77,6 +77,9 @@ struct cpu_t
/** XSCOM mutex to serialize access per CPU */
mutex_t xscom_mutex;
+
+ /** counter for executePeriodics */
+ size_t periodic_count;
};
/** @fn getCpuId
diff --git a/src/include/kernel/cpumgr.H b/src/include/kernel/cpumgr.H
index 31759564b..b60c72bc6 100644
--- a/src/include/kernel/cpumgr.H
+++ b/src/include/kernel/cpumgr.H
@@ -29,7 +29,12 @@
class CpuManager
{
public:
- enum { MAXCPUS = KERNEL_MAX_SUPPORTED_CPUS };
+ enum
+ {
+ MAXCPUS = KERNEL_MAX_SUPPORTED_CPUS,
+ CPU_PERIODIC_CHECK_MEMORY = 64,
+ CPU_PERIODIC_FLUSH_PAGETABLE = 1024,
+ };
/** @fn getCurrentCPU
* Returns a pointer to the current CPU structure by using the
@@ -60,6 +65,13 @@ class CpuManager
*/
static uint32_t getShutdownStatus() { return cv_shutdown_status; }
+ /** @fn executePeriodics
+ * Perform periodic actions
+ * @param[in] cpu_t the CPU
+ */
+ static void executePeriodics(cpu_t * i_cpu);
+
+
protected:
CpuManager();
~CpuManager() {}
diff --git a/src/include/kernel/pagemgr.H b/src/include/kernel/pagemgr.H
index eeed535e0..6cb6fefc4 100644
--- a/src/include/kernel/pagemgr.H
+++ b/src/include/kernel/pagemgr.H
@@ -27,6 +27,8 @@
#include <limits.h>
#include <util/lockfree/stack.H>
#include <kernel/vmmmgr.H>
+#include <builtins.h>
+#include <kernel/console.H>
/** @class PageManager
* @brief Manages the allocation of memory pages.
@@ -40,6 +42,12 @@ class PageManager
static void* allocatePage(size_t n = 1);
static void freePage(void*, size_t n = 1);
+ /**
+ * Query state for available memory
+ * @returns percent of pages available
+ */
+ static uint64_t queryAvail();
+
enum
{
MEMLEN = VmmManager::HTABORG,
@@ -55,8 +63,17 @@ class PageManager
void* _allocatePage(size_t);
void _freePage(void*, size_t);
+ /** see queryAvail() */
+ ALWAYS_INLINE
+ uint64_t _queryAvail() const
+ {
+ return (100*iv_pagesAvail)/iv_pagesTotal;
+ }
+
/** Statistics on number of free pages (for debug) */
uint64_t iv_pagesAvail;
+ /** Total number of pages */
+ uint64_t iv_pagesTotal;
struct page_t
{
diff --git a/src/include/kernel/ptmgr.H b/src/include/kernel/ptmgr.H
index 8eca3f213..9ae092857 100644
--- a/src/include/kernel/ptmgr.H
+++ b/src/include/kernel/ptmgr.H
@@ -160,6 +160,11 @@ class PageTableManager
*/
static void printPT( void );
+ /**
+ * @brief Flush reference status & unload unused pages
+ */
+ static void flush( void );
+
protected:
/**
@@ -452,6 +457,11 @@ class PageTableManager
*/
void pushUsageStats( PageTableEntry* i_pte );
+ /**
+ * @brief see flush
+ */
+ void _flush( void );
+
// Allow testcase to see inside
friend class ptmgrtest;
};
diff --git a/src/include/kernel/segment.H b/src/include/kernel/segment.H
index d7a4a7547..798539309 100644
--- a/src/include/kernel/segment.H
+++ b/src/include/kernel/segment.H
@@ -89,6 +89,12 @@ class Segment
return;
};
+ /**
+ * @brief Cast out older physical memory pages
+ * @param[in] i_type Constraint @see VmmManager::castOutPages
+ */
+ virtual void castOutPages(uint64_t i_type) {} // default to NOOP
+
protected:
/** The base address of the segment. */
const uint64_t iv_baseAddress;
diff --git a/src/include/kernel/segmentmgr.H b/src/include/kernel/segmentmgr.H
index a8f4e002d..7232c7d4f 100644
--- a/src/include/kernel/segmentmgr.H
+++ b/src/include/kernel/segmentmgr.H
@@ -118,6 +118,12 @@ class SegmentManager
static void updateRefCount( uint64_t i_vaddr,
PageTableManager::UsageStats_t i_stats );
+ /**
+ * @brief Cast out oldest physical memory pages
+ * @param[in] castout type
+ */
+ static void castOutPages(uint64_t i_type);
+
private:
/** See handlePageFault. */
@@ -129,11 +135,13 @@ class SegmentManager
/** See updateRefCount. */
void _updateRefCount( uint64_t i_vaddr,
PageTableManager::UsageStats_t i_stats );
+ /** See castOutPages */
+ void _castOutPages(uint64_t i_type);
/** See findPhysicalAddress */
uint64_t _findPhysicalAddress(uint64_t i_vaddr) const;
- ALWAYS_INLINE inline
+ ALWAYS_INLINE
size_t getSegmentIdFromAddress(uint64_t i_addr) const
{
return i_addr >> SLBE_s;
diff --git a/src/include/kernel/vmmmgr.H b/src/include/kernel/vmmmgr.H
index ef8e6c362..5c7a75d5d 100644
--- a/src/include/kernel/vmmmgr.H
+++ b/src/include/kernel/vmmmgr.H
@@ -55,6 +55,12 @@ class VmmManager
RO_EXE_ACCESS,
};
+ enum castout_t
+ {
+ NORMAL,
+ CRITICAL,
+ };
+
static void init();
static void init_slb();
@@ -104,6 +110,17 @@ class VmmManager
* @return the physical address or -EFAULT @see errno.h
*/
static uint64_t findPhysicalAddress(uint64_t i_vaddr);
+
+ /**
+ * @brief Cast out older physical memory pages
+ * @param[in] castout constraint
+ */
+ static void castOutPages(castout_t i_ct);
+
+ /**
+ * @brief Flush pagetable, Update shadow page info
+ */
+ static void flushPageTable( void);
/**
* @brief Remove pages by a specified operation of the given size
@@ -157,6 +174,12 @@ class VmmManager
/* See mmSetPermission */
int _mmSetPermission(void* i_va,uint64_t i_size, PAGE_PERMISSIONS i_access_type);
+ /** See castOutPages */
+ void _castOutPages(castout_t i_ct);
+
+ /** See flushPageTable */
+ void _flushPageTable( void );
+
public:
friend class Block;
diff --git a/src/kernel/basesegment.C b/src/kernel/basesegment.C
index e59e41753..eab00accc 100644
--- a/src/kernel/basesegment.C
+++ b/src/kernel/basesegment.C
@@ -29,6 +29,7 @@
#include <kernel/segmentmgr.H>
#include <kernel/block.H>
#include <kernel/cpuid.H>
+#include <kernel/console.H>
BaseSegment::~BaseSegment()
@@ -147,3 +148,11 @@ int BaseSegment::mmSetPermission(void* i_va, uint64_t i_size,PAGE_PERMISSIONS i_
{
return 0;
}
+
+void BaseSegment::castOutPages(uint64_t i_type)
+{
+ size_t cast_out = 0;
+ cast_out = iv_block->castOutPages(i_type);
+ // Could try again with a more agressive constraint if cast_out == 0 ????
+ if(cast_out) printkd("Cast out %ld pages,Type=%ld\n",cast_out,i_type);
+}
diff --git a/src/kernel/block.C b/src/kernel/block.C
index 59a7892f2..63c1fae92 100644
--- a/src/kernel/block.C
+++ b/src/kernel/block.C
@@ -108,6 +108,15 @@ bool Block::handlePageFault(task_t* i_task, uint64_t i_addr)
}
else
{
+ // Test code @TODO remove - SET up ro pages to test cast out pages
+ //if(pte->getPage() == 0)
+ //{
+ // void* l_page = PageManager::allocatePage();
+ // memset(l_page,'U',PAGESIZE);
+ // pte->setPageAddr(reinterpret_cast<uint64_t>(l_page));
+ // pte->setPresent(true);
+ // pte->setWritable(false);
+ //}
return false; //TODO - Swap kernel base block pages for user pages
}
}
@@ -301,3 +310,93 @@ void Block::updateRefCount( uint64_t i_vaddr,
spte->setDirty( i_stats.C );
}
+
+bool Block::evictPage(ShadowPTE* i_pte)
+{
+ ShadowPTE* pte = i_pte;
+ bool do_cast_out = false;
+
+ if(!pte->isWritable()) // ro, executable
+ {
+ do_cast_out = true;
+ }
+ else // is writable...
+ {
+ // if pte->isWriteTracked() flush then cast out
+ }
+
+ if(do_cast_out)
+ {
+ PageTableManager::delEntry(pte->getPageAddr());
+ PageManager::freePage(reinterpret_cast<void*>(pte->getPageAddr()));
+ pte->setPresent(false);
+ pte->setPageAddr(NULL);
+ }
+
+ return do_cast_out;
+}
+
+size_t Block::castOutPages(uint64_t i_type)
+{
+ size_t cast_out = 0;
+ // drill down
+ if(iv_nextBlock)
+ {
+ cast_out += iv_nextBlock->castOutPages(i_type);
+ }
+
+ // TODO We will eventually need to skip other blocks as well, such as
+ // when the memory space grows.
+ if(iv_baseAddr != 0) // Skip base area
+ {
+ bool is_cast_out = false;
+ size_t rw_constraint = 5;
+ size_t ro_constraint = 3;
+
+ if(i_type == VmmManager::CRITICAL)
+ {
+ rw_constraint = 2;
+ ro_constraint = 1;
+ }
+ //printk("Block = %p:%ld\n",(void*)iv_baseAddr,iv_size / PAGESIZE);
+ for(uint64_t page = iv_baseAddr;
+ page < (iv_baseAddr + iv_size);
+ page += PAGESIZE)
+ {
+ ShadowPTE* pte = getPTE(page);
+ if (pte->isPresent() && (0 != pte->getPageAddr()))
+ {
+ //if(pte->isExecutable()) printk("x");
+ //else if(pte->isWritable()) printk("w");
+ //else printk("r");
+ //printk("%d",(int)pte->getLRU());
+
+ if(pte->isWritable())
+ {
+ if((pte->getLRU() > rw_constraint) && pte->isWriteTracked())
+ {
+ is_cast_out = evictPage(pte);
+ //printk("+");
+ }
+ }
+ else // ro and/or executable
+ {
+ if(pte->getLRU() > ro_constraint)
+ {
+ is_cast_out = evictPage(pte);
+ }
+ }
+
+ if(is_cast_out)
+ {
+ //printk("-");
+ ++cast_out;
+ is_cast_out = false;
+ }
+ }
+ }
+ //printk("\n");
+ }
+
+ return cast_out;
+}
diff --git a/src/kernel/cpumgr.C b/src/kernel/cpumgr.C
index d8a9960f6..01af160f1 100644
--- a/src/kernel/cpumgr.C
+++ b/src/kernel/cpumgr.C
@@ -33,6 +33,7 @@
#include <kernel/timemgr.H>
#include <sys/sync.h>
#include <kernel/cpuid.H>
+#include <kernel/ptmgr.H>
cpu_t* CpuManager::cv_cpus[CpuManager::MAXCPUS] = { NULL };
bool CpuManager::cv_shutdown_requested = false;
@@ -141,6 +142,7 @@ void CpuManager::startCPU(ssize_t i)
// Create idle task.
cpu->idle_task = TaskManager::createIdleTask();
cpu->idle_task->cpu = cpu;
+ cpu->periodic_count = 0;
printk("done\n");
}
@@ -160,3 +162,33 @@ void CpuManager::startSlaveCPU(cpu_t* cpu)
return;
}
+
+void CpuManager::executePeriodics(cpu_t * i_cpu)
+{
+ if(i_cpu->master)
+ {
+ ++(i_cpu->periodic_count);
+ if(0 == (i_cpu->periodic_count % CPU_PERIODIC_CHECK_MEMORY))
+ {
+ uint64_t pcntAvail = PageManager::queryAvail();
+ if(pcntAvail < 16) // Less than 16% pages left TODO 16 ok?
+ {
+ VmmManager::flushPageTable();
+ ++(i_cpu->periodic_count); // prevent another flush below
+ if(pcntAvail < 5) // TODO 5% ok
+ {
+ VmmManager::castOutPages(VmmManager::CRITICAL);
+ }
+ else
+ {
+ VmmManager::castOutPages(VmmManager::NORMAL);
+ }
+ }
+ }
+ if(0 == (i_cpu->periodic_count % CPU_PERIODIC_FLUSH_PAGETABLE))
+ {
+ VmmManager::flushPageTable();
+ }
+ }
+}
+
diff --git a/src/kernel/pagemgr.C b/src/kernel/pagemgr.C
index f74ee89c1..826e1bc4d 100644
--- a/src/kernel/pagemgr.C
+++ b/src/kernel/pagemgr.C
@@ -44,7 +44,12 @@ void PageManager::freePage(void* p, size_t n)
return pmgr._freePage(p, n);
}
-PageManager::PageManager() : iv_pagesAvail(0)
+uint64_t PageManager::queryAvail()
+{
+ return Singleton<PageManager>::instance()._queryAvail();
+}
+
+PageManager::PageManager() : iv_pagesAvail(0), iv_pagesTotal(0)
{
// Determine first page of un-allocated memory.
uint64_t addr = (uint64_t) VFS_LAST_ADDRESS;
@@ -55,6 +60,7 @@ PageManager::PageManager() : iv_pagesAvail(0)
page_t* page = (page_t*)((void*) addr);
size_t length = (MEMLEN - addr) / PAGESIZE;
+ iv_pagesTotal = length;
// Update statistics.
__sync_add_and_fetch(&iv_pagesAvail, length);
@@ -156,3 +162,4 @@ void PageManager::push_bucket(page_t* p, size_t n)
if (n >= BUCKETS) return;
first_page[n].push(p);
}
+
diff --git a/src/kernel/ptmgr.C b/src/kernel/ptmgr.C
index 0feffb7e6..92d211888 100644
--- a/src/kernel/ptmgr.C
+++ b/src/kernel/ptmgr.C
@@ -251,6 +251,10 @@ void PageTableManager::printPT( void )
Singleton<PageTableManager>::instance()._printPT();
}
+void PageTableManager::flush( void )
+{
+ Singleton<PageTableManager>::instance()._flush();
+}
/********************
Private/Protected Methods
@@ -1102,3 +1106,21 @@ void PageTableManager::pushUsageStats( PageTableEntry* i_pte )
uint64_t va = getVirtAddrFromPTE(i_pte);
SegmentManager::updateRefCount( va, stats );
}
+
+void PageTableManager::_flush( void )
+{
+ if( ivTABLE )
+ {
+ return;
+ }
+
+ PageTableEntry* pte = (PageTableEntry*)getAddress();
+ uint64_t num_ptes = getSize() / sizeof(PageTableEntry);
+ for (uint64_t i = 0; i < num_ptes; ++i)
+ {
+ updateLRU( pte );
+ pushUsageStats ( pte );
+ ++pte;
+ }
+}
+
diff --git a/src/kernel/scheduler.C b/src/kernel/scheduler.C
index 7b57792a5..28f70debd 100644
--- a/src/kernel/scheduler.C
+++ b/src/kernel/scheduler.C
@@ -77,6 +77,8 @@ void Scheduler::setNextRunnable()
task_t* t = NULL;
cpu_t* cpu = CpuManager::getCurrentCPU();
+ CpuManager::executePeriodics(cpu);
+
// Check for ready task in local run-queue, if it exists.
if (NULL != cpu->scheduler_extra)
{
diff --git a/src/kernel/segmentmgr.C b/src/kernel/segmentmgr.C
index 890bd1812..0b4370cfa 100644
--- a/src/kernel/segmentmgr.C
+++ b/src/kernel/segmentmgr.C
@@ -55,6 +55,11 @@ void SegmentManager::updateRefCount( uint64_t i_vaddr,
Singleton<SegmentManager>::instance()._updateRefCount(i_vaddr,i_stats);
}
+void SegmentManager::castOutPages(uint64_t i_type)
+{
+ Singleton<SegmentManager>::instance()._castOutPages(i_type);
+}
+
bool SegmentManager::_handlePageFault(task_t* i_task, uint64_t i_addr)
{
size_t segId = getSegmentIdFromAddress(i_addr);
@@ -122,7 +127,7 @@ void SegmentManager::_updateRefCount( uint64_t i_vaddr,
PageTableManager::UsageStats_t i_stats )
{
// Get segment ID from effective address.
- size_t segId = i_vaddr >> SLBE_s;
+ size_t segId = getSegmentIdFromAddress(i_vaddr);
// Call contained segment object to update the reference count
if ((segId < MAX_SEGMENTS) && (NULL != iv_segments[segId]))
@@ -130,3 +135,14 @@ void SegmentManager::_updateRefCount( uint64_t i_vaddr,
iv_segments[segId]->updateRefCount( i_vaddr, i_stats );
}
}
+
+void SegmentManager::_castOutPages(uint64_t i_type)
+{
+ for (size_t i = 0; i < MAX_SEGMENTS; i++)
+ {
+ if (NULL != iv_segments[i])
+ {
+ iv_segments[i]->castOutPages(i_type);
+ }
+ }
+}
diff --git a/src/kernel/vmmmgr.C b/src/kernel/vmmmgr.C
index 4009ff380..b2026944e 100644
--- a/src/kernel/vmmmgr.C
+++ b/src/kernel/vmmmgr.C
@@ -72,6 +72,16 @@ uint64_t VmmManager::findPhysicalAddress(uint64_t i_vaddr)
return Singleton<VmmManager>::instance()._findPhysicalAddress(i_vaddr);
}
+void VmmManager::castOutPages(VmmManager::castout_t i_ct)
+{
+ Singleton<VmmManager>::instance()._castOutPages(i_ct);
+}
+
+void VmmManager::flushPageTable( void )
+{
+ Singleton<VmmManager>::instance()._flushPageTable();
+}
+
/**
* STATIC
* @brief DEPRECATED
@@ -184,3 +194,21 @@ int VmmManager::_mmSetPermission(void* i_va, uint64_t i_size, PAGE_PERMISSIONS i
return rc;
}
+
+void VmmManager::_castOutPages(VmmManager::castout_t i_ct)
+{
+ lock.lock();
+
+ SegmentManager::castOutPages((uint64_t)i_ct);
+
+ lock.unlock();
+}
+
+void VmmManager::_flushPageTable( void )
+{
+ lock.lock();
+
+ PageTableManager::flush();
+
+ lock.unlock();
+}
diff --git a/src/usr/testcore/kernel/vmmbasetest.H b/src/usr/testcore/kernel/vmmbasetest.H
index 000e400ab..3e1e2fdcd 100644
--- a/src/usr/testcore/kernel/vmmbasetest.H
+++ b/src/usr/testcore/kernel/vmmbasetest.H
@@ -30,6 +30,7 @@
#include <sys/task.h>
#include <kernel/console.H>
#include <arch/ppc.H>
+#include <sys/mm.h>
class VmmBaseTest : public CxxTest::TestSuite
{
@@ -87,6 +88,25 @@ class VmmBaseTest : public CxxTest::TestSuite
// @TODO. VMM not ready.
}
+ void testCastOutPages()
+ {
+ //uint64_t vmemaddr = (1ul * 1024 * 1024 * 1024)/2;
+ //uint64_t vmsize = 4ul * 1024 * 500;
+ //printk("Test case: cast out pages\n");
+ //printk("Set up virtual block at %p\n",(void*)vmemaddr);
+ //size_t rc = mm_alloc_block(NULL, // need a msgq?
+ // (void*)vmemaddr,
+ // vmsize);
+ //if(rc) printk("RC=%ld\n",rc);
+ // touch something on every page
+ //for(uint64_t i = vmemaddr; i < (vmemaddr + vmsize); i += PAGESIZE)
+ //{
+ // if(*((char *)i) != 'U') printk("Yiks %p is %c\n",(void*)i,*((char *)i));
+ //}
+
+ // see printk buffer for cast out pages
+ }
+
private:
static void readFromNULL(void* unused)
OpenPOWER on IntegriCloud