summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick Williams <iawillia@us.ibm.com>2012-07-06 15:40:43 -0500
committerA. Patrick Williams III <iawillia@us.ibm.com>2012-07-11 08:18:41 -0500
commit14a2721d2c87dc13f1ef66818c41cd0848dd52db (patch)
tree66ae0220b0443f9a87d87075279ba9a5c08ba412
parenta23283c6facfee055c9c6d43e23a04ca02edc467 (diff)
downloadtalos-hostboot-14a2721d2c87dc13f1ef66818c41cd0848dd52db.tar.gz
talos-hostboot-14a2721d2c87dc13f1ef66818c41cd0848dd52db.zip
Live-lock issues in memory allocator.
* Debug tool for PageManager. * Support PageMgr allocations of non-2^k size. * Switch page-allocation to always be in kernel-mode. While investigating issue 44511, I noticed two problesm with the memory page allocator (PageManager). First, the allocator did not support allocations of pages which were not a power of 2, which would result in pages appearing to "leak". Second, in situations where a large allocation was requested and there was not a large chunk available, the allocation would enter a live-lock condition where coalescing would never occur. Switched the PageManager so that all allocations happen in kernel space. This allows us to force memory-release operations on the syscall path when we are out of memory and also put in place a task_yield call which will allow coalescing to eventually occur. Issue 44523 is suppose to fully resolve any of these live-lock paths. RTC: 44511 Change-Id: Ifefd5d0996ee6914e291c862fac0c7b76980717f Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/1330 Tested-by: Jenkins Server Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com> Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
-rw-r--r--src/build/debug/Hostboot/PageMgr.pm100
-rw-r--r--src/include/kernel/devicesegment.H47
-rw-r--r--src/include/kernel/misc.H63
-rw-r--r--src/include/kernel/pagemgr.H22
-rw-r--r--src/include/kernel/syscalls.H4
-rw-r--r--src/include/sys/mm.h6
-rw-r--r--src/include/usr/vmmconst.h15
-rw-r--r--src/kernel/cpumgr.C4
-rw-r--r--src/kernel/pagemgr.C179
-rw-r--r--src/kernel/syscall.C36
-rw-r--r--src/lib/syscall_mm.C8
-rw-r--r--src/usr/testcore/kernel/segmenttest.H47
12 files changed, 332 insertions, 199 deletions
diff --git a/src/build/debug/Hostboot/PageMgr.pm b/src/build/debug/Hostboot/PageMgr.pm
new file mode 100644
index 000000000..5f8f24533
--- /dev/null
+++ b/src/build/debug/Hostboot/PageMgr.pm
@@ -0,0 +1,100 @@
+#!/usr/bin/perl
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/build/debug/Hostboot/PageMgr.pm $
+#
+# IBM CONFIDENTIAL
+#
+# COPYRIGHT International Business Machines Corp. 2012
+#
+# p1
+#
+# Object Code Only (OCO) source materials
+# Licensed Internal Code Source Materials
+# IBM HostBoot Licensed Internal Code
+#
+# The source code for this program is not published or other-
+# wise divested of its trade secrets, irrespective of what has
+# been deposited with the U.S. Copyright Office.
+#
+# Origin: 30
+#
+# IBM_PROLOG_END_TAG
+
+use strict;
+
+package Hostboot::PageMgr;
+use Exporter;
+our @EXPORT_OK = ('main');
+
+use constant PAGEMGR_INSTANCE_NAME =>
+ "Singleton<PageManager>::instance()::instance";
+use constant PAGEMGR_CORE_OFFSET => 3 * 8;
+use constant PAGEMGR_PAGES_AVAIL_OFFSET => 0;
+use constant PAGEMGR_BUCKETS_OFFSET => 8;
+use constant PAGEMGR_NUMBER_OF_BUCKETS => 16;
+
+
+sub main
+{
+ my ($packName, $args) = @_;
+
+ # Parse 'debug' option.
+ my $debug = 0;
+ if (defined $args->{"debug"})
+ {
+ $debug = 1;
+ }
+
+ # Find the PageManager
+ my ($symAddr, $symSize) = ::findSymbolAddress(PAGEMGR_INSTANCE_NAME);
+ if (not defined $symAddr)
+ {
+ ::userDisplay "Couldn't find ".PAGEMGR_INSTANCE_NAME;
+ die;
+ }
+ # Increment to the PageManagerCore for the general heap.
+ $symAddr = $symAddr + PAGEMGR_CORE_OFFSET;
+
+ # Read pages available.
+ my $pagesAvail = ::read64($symAddr + PAGEMGR_PAGES_AVAIL_OFFSET);
+ ::userDisplay "Pages available: ".$pagesAvail."\n";
+
+ # Parse through buckets and count pages in buckets.
+ my $pagesInBuckets = 0;
+
+ for (my $bucket = 0; $bucket < PAGEMGR_NUMBER_OF_BUCKETS; $bucket++)
+ {
+ my $stackAddr = ::read32($symAddr + PAGEMGR_BUCKETS_OFFSET +
+ (8 * $bucket) + 4);
+
+ my $stackCount = countItemsInStack($stackAddr);
+ my $size = (1 << $bucket) * $stackCount;
+
+ $pagesInBuckets = $pagesInBuckets + $size;
+
+ ::userDisplay "Bucket $bucket has $stackCount blocks for ".
+ "$size pages.\n" if $debug;
+ }
+
+ ::userDisplay "Pages in buckets: ".$pagesInBuckets."\n";
+
+ # Compare if they match. Hopefully they do.
+ if ($pagesAvail != $pagesInBuckets)
+ {
+ my $difference = abs ($pagesAvail - $pagesInBuckets);
+ ::userDisplay "WARNING: Values differ by $difference!!\n";
+ }
+}
+
+sub countItemsInStack
+{
+ my $stack = shift;
+
+ return 0 if (0 == $stack);
+
+ return 1 + countItemsInStack(::read64($stack));
+}
+
+
diff --git a/src/include/kernel/devicesegment.H b/src/include/kernel/devicesegment.H
index c300eedde..2b87c9161 100644
--- a/src/include/kernel/devicesegment.H
+++ b/src/include/kernel/devicesegment.H
@@ -1,25 +1,26 @@
-// IBM_PROLOG_BEGIN_TAG
-// This is an automatically generated prolog.
-//
-// $Source: src/include/kernel/devicesegment.H $
-//
-// IBM CONFIDENTIAL
-//
-// COPYRIGHT International Business Machines Corp. 2011
-//
-// p1
-//
-// Object Code Only (OCO) source materials
-// Licensed Internal Code Source Materials
-// IBM HostBoot Licensed Internal Code
-//
-// The source code for this program is not published or other-
-// wise divested of its trade secrets, irrespective of what has
-// been deposited with the U.S. Copyright Office.
-//
-// Origin: 30
-//
-// IBM_PROLOG_END
+/* IBM_PROLOG_BEGIN_TAG
+ * This is an automatically generated prolog.
+ *
+ * $Source: src/include/kernel/devicesegment.H $
+ *
+ * IBM CONFIDENTIAL
+ *
+ * COPYRIGHT International Business Machines Corp. 2011-2012
+ *
+ * p1
+ *
+ * Object Code Only (OCO) source materials
+ * Licensed Internal Code Source Materials
+ * IBM HostBoot Licensed Internal Code
+ *
+ * The source code for this program is not published or other-
+ * wise divested of its trade secrets, irrespective of what has
+ * been deposited with the U.S. Copyright Office.
+ *
+ * Origin: 30
+ *
+ * IBM_PROLOG_END_TAG
+ */
#ifndef __KERNEL_DEVICESEGMENT_H
#define __KERNEL_DEVICESEGMENT_H
@@ -41,7 +42,7 @@ class DeviceSegment : public Segment
*
* Associates itself with the SegmentManager.
*/
- explicit DeviceSegment(size_t segId) : Segment(segId * TERABYTE)
+ explicit DeviceSegment(size_t segId) : Segment(segId * VMM_SEGMENT_SIZE)
{ init(segId); };
/**
diff --git a/src/include/kernel/misc.H b/src/include/kernel/misc.H
index f04439748..ebec9cc48 100644
--- a/src/include/kernel/misc.H
+++ b/src/include/kernel/misc.H
@@ -1,25 +1,26 @@
-// IBM_PROLOG_BEGIN_TAG
-// This is an automatically generated prolog.
-//
-// $Source: src/include/kernel/misc.H $
-//
-// IBM CONFIDENTIAL
-//
-// COPYRIGHT International Business Machines Corp. 2011
-//
-// p1
-//
-// Object Code Only (OCO) source materials
-// Licensed Internal Code Source Materials
-// IBM HostBoot Licensed Internal Code
-//
-// The source code for this program is not published or other-
-// wise divested of its trade secrets, irrespective of what has
-// been deposited with the U.S. Copyright Office.
-//
-// Origin: 30
-//
-// IBM_PROLOG_END
+/* IBM_PROLOG_BEGIN_TAG
+ * This is an automatically generated prolog.
+ *
+ * $Source: src/include/kernel/misc.H $
+ *
+ * IBM CONFIDENTIAL
+ *
+ * COPYRIGHT International Business Machines Corp. 2011-2012
+ *
+ * p1
+ *
+ * Object Code Only (OCO) source materials
+ * Licensed Internal Code Source Materials
+ * IBM HostBoot Licensed Internal Code
+ *
+ * The source code for this program is not published or other-
+ * wise divested of its trade secrets, irrespective of what has
+ * been deposited with the U.S. Copyright Office.
+ *
+ * Origin: 30
+ *
+ * IBM_PROLOG_END_TAG
+ */
/** @file misc.H
* @brief Misc. Kernel functions and utilities.
*/
@@ -28,6 +29,7 @@
#define __KERNEL_MISC_H
#include <stdint.h>
+#include <usr/vmmconst.h>
namespace KernelMisc
{
@@ -40,5 +42,22 @@ namespace KernelMisc
extern uint64_t g_payload_base;
/** @brief Address from base of payload entry-point. */
extern uint64_t g_payload_entry;
+
+ /** @fn in_kernel_mode
+ * @brief Determine if the code is currently in kernel mode or not.
+ *
+ * @return [true | false]
+ */
+ inline bool in_kernel_mode()
+ {
+ uint64_t stack = 0;
+ asm volatile("mr %0, 1" : "=r"(stack));
+ if((stack >= VMM_VADDR_STACK_SEGMENT) &&
+ (stack < (VMM_VADDR_STACK_SEGMENT + VMM_SEGMENT_SIZE)))
+ {
+ return false;
+ }
+ return true;
+ }
};
#endif
diff --git a/src/include/kernel/pagemgr.H b/src/include/kernel/pagemgr.H
index 6676a469c..93cd82bb5 100644
--- a/src/include/kernel/pagemgr.H
+++ b/src/include/kernel/pagemgr.H
@@ -54,7 +54,7 @@ class PageManagerCore
/**
* Default Constructor
*/
- PageManagerCore()
+ PageManagerCore()
: iv_available(0) {}
/**
@@ -76,7 +76,7 @@ class PageManagerCore
* @return a pointer to the requested allocation | NULL
* if the request could not be satisfied.
*/
- page_t * allocatePage( size_t i_pageCount );
+ page_t * allocatePage( size_t i_pageCount );
/**
* Return page allocations to the page manager
@@ -136,9 +136,10 @@ class PageManager
/**
* Allocate pages
* @param[in] n, Requested allocation in pages
+ * @param[in] userspace - Request to allocate came from userspace
* @return pointer to requested memory
*/
- static void* allocatePage(size_t n = 1);
+ static void* allocatePage(size_t n = 1, bool userspace = false);
/**
* Return pages to the pagemanager
@@ -170,6 +171,9 @@ class PageManager
{
MEMLEN = VmmManager::MBOX_DMA_ADDR,
RESERVED_PAGES = 4,
+
+ LOWMEM_NORM_LIMIT = 16,
+ LOWMEM_CRIT_LIMIT = 5,
};
static size_t cv_coalesce_count; //!< running coalesced counter
@@ -182,15 +186,9 @@ class PageManager
private:
- void* _allocatePage(size_t); //!< see allocatePage()
- void _freePage(void*, size_t); //!< see freePage()
- void _coalesce( void ); //!< see coalesce()
-
- /**
- * Query if in kernel mode
- * @return [true | false]
- */
- bool queryKernelMode() const;
+ void* _allocatePage(size_t,bool); //!< see allocatePage()
+ void _freePage(void*, size_t); //!< see freePage()
+ void _coalesce( void ); //!< see coalesce()
/** see queryAvail() */
ALWAYS_INLINE uint64_t _queryAvail() const
diff --git a/src/include/kernel/syscalls.H b/src/include/kernel/syscalls.H
index 20cfd4e65..a46fde703 100644
--- a/src/include/kernel/syscalls.H
+++ b/src/include/kernel/syscalls.H
@@ -97,8 +97,8 @@ namespace Systemcalls
/** mm_set_permission() */
MM_SET_PERMISSION,
- /** mm_flush_pages() */
- MM_FLUSH_PAGES,
+ /** mm_alloc_pages() */
+ MM_ALLOC_PAGES,
SYSCALL_MAX
};
diff --git a/src/include/sys/mm.h b/src/include/sys/mm.h
index 105b145be..d9b5536a1 100644
--- a/src/include/sys/mm.h
+++ b/src/include/sys/mm.h
@@ -97,12 +97,6 @@ int mm_remove_pages(PAGE_REMOVAL_OPS i_op, void* i_vaddr, uint64_t i_size);
*/
int mm_set_permission(void* va, uint64_t size, uint64_t access_type);
-/** @fn mm_flush_pages()
- * @brief System call to flush pages
- * @param[in] i_sev - [VmmManager::NORMAL | VmmManager::CRITIAL]
- */
-void mm_flush_pages(uint64_t i_sev);
-
#ifdef __cplusplus
}
#endif
diff --git a/src/include/usr/vmmconst.h b/src/include/usr/vmmconst.h
index a43a70a7a..1997b9276 100644
--- a/src/include/usr/vmmconst.h
+++ b/src/include/usr/vmmconst.h
@@ -35,14 +35,21 @@
* Segments
*/
+/** Stacks are all 1TB in size. */
+#define VMM_SEGMENT_SIZE (1 * TERABYTE)
+
+/** Base Segment is at 0 TB */
+#define VMM_VADDR_BASE_SEGMENT (0 * TERABYTE)
+
/** Stack Segment is at 1 TB */
-#define VMM_VADDR_STACK_SEGMENT (1 * TERABYTE)
+#define VMM_VADDR_STACK_SEGMENT (VMM_VADDR_BASE_SEGMENT + VMM_SEGMENT_SIZE)
/** Device Segments are at 2 TB - 10 TB */
-#define VMM_VADDR_DEVICE_SEGMENT_FIRST (2 * TERABYTE)
-#define VMM_VADDR_DEVICE_SEGMENT_LAST (VMM_VADDR_DEVICE_SEGMENT_FIRST + \
- (8 * TERABYTE))
+#define VMM_VADDR_DEVICE_SEGMENT_FIRST \
+ (VMM_VADDR_STACK_SEGMENT + VMM_SEGMENT_SIZE)
+#define VMM_VADDR_DEVICE_SEGMENT_LAST \
+ (VMM_VADDR_DEVICE_SEGMENT_FIRST + (8 * VMM_SEGMENT_SIZE))
/**
* Resource Providers
diff --git a/src/kernel/cpumgr.C b/src/kernel/cpumgr.C
index 3bb52b63c..2a5c2edcc 100644
--- a/src/kernel/cpumgr.C
+++ b/src/kernel/cpumgr.C
@@ -192,11 +192,11 @@ void CpuManager::executePeriodics(cpu_t * i_cpu)
if(0 == (i_cpu->periodic_count % CPU_PERIODIC_CHECK_MEMORY))
{
uint64_t pcntAvail = PageManager::queryAvail();
- if(pcntAvail < 16)
+ if(pcntAvail < PageManager::LOWMEM_NORM_LIMIT)
{
VmmManager::flushPageTable();
++(i_cpu->periodic_count); // prevent another flush below
- if(pcntAvail < 5)
+ if(pcntAvail < PageManager::LOWMEM_CRIT_LIMIT)
{
VmmManager::castOutPages(VmmManager::CRITICAL);
}
diff --git a/src/kernel/pagemgr.C b/src/kernel/pagemgr.C
index 3991ff920..60db55e12 100644
--- a/src/kernel/pagemgr.C
+++ b/src/kernel/pagemgr.C
@@ -29,10 +29,11 @@
#include <util/locked/pqueue.H>
#include <kernel/task.H>
#include <kernel/taskmgr.H>
-#include <usr/vmmconst.h>
#include <kernel/vmmmgr.H>
#include <sys/task.h>
-#include <sys/mm.h>
+#include <kernel/misc.H>
+#include <sys/syscall.h>
+#include <assert.h>
size_t PageManager::cv_coalesce_count = 0;
size_t PageManager::cv_low_page_count = -1;
@@ -47,14 +48,14 @@ void PageManagerCore::addMemory( size_t i_addr, size_t i_pageCount )
size_t page_length = BUCKETS-1;
while(length > 0)
{
- while (length < (size_t)(1 << page_length))
+ while (length < (size_t)(1 << page_length))
{
- page_length--;
+ page_length--;
}
- iv_heap[page_length].push(page);
- page = (page_t*)((uint64_t)page + (1 << page_length)*PAGESIZE);
- length -= (1 << page_length);
+ iv_heap[page_length].push(page);
+ page = (page_t*)((uint64_t)page + (1 << page_length)*PAGESIZE);
+ length -= (1 << page_length);
}
__sync_add_and_fetch(&iv_available, i_pageCount);
}
@@ -63,8 +64,15 @@ void PageManagerCore::addMemory( size_t i_addr, size_t i_pageCount )
PageManagerCore::page_t * PageManagerCore::allocatePage( size_t i_pageCount )
{
- size_t which_bucket = 0;
- while (i_pageCount > (size_t)(1 << which_bucket)) which_bucket++;
+ size_t which_bucket = ((sizeof(size_t)*8 - 1) -
+ __builtin_clzl(i_pageCount));
+ size_t bucket_size = ((size_t)1) << which_bucket;
+
+ if (bucket_size != i_pageCount)
+ {
+ ++which_bucket;
+ bucket_size <<= 1;
+ }
page_t* page = (page_t*)NULL;
int retries = 0;
@@ -77,7 +85,18 @@ PageManagerCore::page_t * PageManagerCore::allocatePage( size_t i_pageCount )
// Update statistics.
if(page)
{
- __sync_sub_and_fetch(&iv_available, i_pageCount);
+ __sync_sub_and_fetch(&iv_available, bucket_size);
+
+ // Buckets are 2^k in size so if i_pageCount is not 2^k we have some
+ // extra pages allocated. ie. the non-2^k portion of i_pageCount.
+ // Return that portion by freeing.
+ if (bucket_size != i_pageCount)
+ {
+ freePage(reinterpret_cast<void*>(
+ reinterpret_cast<uintptr_t>(page) +
+ (i_pageCount*PAGESIZE)),
+ bucket_size - i_pageCount);
+ }
}
return page;
@@ -89,13 +108,24 @@ void PageManagerCore::freePage( void * i_page, size_t i_pageCount )
{
if ((NULL == i_page) || (0 == i_pageCount)) return;
- size_t which_bucket = 0;
- while (i_pageCount > (size_t)(1 << which_bucket)) which_bucket++;
+ size_t which_bucket = ((sizeof(size_t)*8 - 1) -
+ __builtin_clzl(i_pageCount));
+ size_t bucket_size = ((size_t)1) << which_bucket;
push_bucket((page_t*)i_page, which_bucket);
// Update statistics.
- __sync_add_and_fetch(&iv_available, i_pageCount);
+ __sync_add_and_fetch(&iv_available, bucket_size);
+
+ // Buckets are 2^k in size so if i_pageCount is not 2^k we have some
+ // spare pages to free. ie. the non-2^k portion of i_pageCount.
+ if (bucket_size != i_pageCount)
+ {
+ freePage(reinterpret_cast<void*>(
+ reinterpret_cast<uintptr_t>(i_page) +
+ (bucket_size*PAGESIZE)),
+ i_pageCount - bucket_size);
+ }
return;
}
@@ -107,10 +137,34 @@ void PageManager::init()
Singleton<PageManager>::instance();
}
-void* PageManager::allocatePage(size_t n)
+void* PageManager::allocatePage(size_t n, bool userspace)
{
- PageManager& pmgr = Singleton<PageManager>::instance();
- return pmgr._allocatePage(n);
+ void* page = NULL;
+
+ // In non-kernel mode, make a system-call to allocate in kernel-mode.
+ if (!KernelMisc::in_kernel_mode())
+ {
+ while (NULL == page)
+ {
+ page = _syscall1(Systemcalls::MM_ALLOC_PAGES,
+ reinterpret_cast<void*>(n));
+
+ // Didn't successfully allocate, so yield in hopes that memory
+ // will eventually free up (ex. VMM flushes).
+ if (NULL == page)
+ {
+ task_yield();
+ }
+ }
+ }
+ else
+ {
+ // In kernel mode. Do a normal call to the PageManager.
+ PageManager& pmgr = Singleton<PageManager>::instance();
+ page = pmgr._allocatePage(n, userspace);
+ }
+
+ return page;
}
void PageManager::freePage(void* p, size_t n)
@@ -140,8 +194,8 @@ PageManager::PageManager()
// Display.
printk("Initializing PageManager with %zd pages starting at %lx...",
- length,
- addr);
+ length,
+ addr);
// Populate L3 cache lines.
uint64_t* cache_line = reinterpret_cast<uint64_t*>(addr);
@@ -172,62 +226,27 @@ PageManager::PageManager()
printk("done\n");
}
-void* PageManager::_allocatePage(size_t n)
+void* PageManager::_allocatePage(size_t n, bool userspace)
{
- PageManagerCore::page_t* page = NULL;
+ PageManagerCore::page_t* page = iv_heap.allocatePage(n);
- // Initiate a page cast out if low
- if(_queryAvail() < 16 && queryKernelMode() == false)
+ // If the allocation came from kernel-space and normal allocation
+ // was unsuccessful, pull a page off the reserve heap.
+ if ((NULL == page) && (!userspace))
{
- // Kernel mode might have Vmm mutex lock which would cause deadlock
- // were VmmManager functions called to flush and cast out.
-
- // Only want one thread testing and flushing
- if(__sync_bool_compare_and_swap(&(iv_lock),0,1))
- {
- if(_queryAvail() < 5)
- {
- mm_flush_pages(VmmManager::CRITICAL);
- }
- else
- {
- mm_flush_pages(VmmManager::NORMAL);
- }
- iv_lock = 0;
- }
+ printkd("PAGEMANAGER: kernel heap used\n");
+ page = iv_heapKernel.allocatePage(n);
}
- while(page == NULL)
- {
- page = iv_heap.allocatePage(n);
-
- if(NULL == page)
- {
- if(queryKernelMode() == true)
- {
- printkd("PAGEMANAGER: kernel heap used\n");
- page = iv_heapKernel.allocatePage(n);
- break;
- }
- else
- {
- //task yield and hope there is more memory available
- //when execution continues
- printkd("PAGEMANAGER: Task held off\n");
- task_yield();
-
- //Possible Loop forever? or is there a break condition??
- }
- }
- }
-
- if (NULL == page)
+ // If still not successful, we're out of memory. Assert.
+ if ((NULL == page) && (!userspace))
{
register task_t* t;
asm volatile("mr %0, 13" : "=r"(t));
- printk("Insufficient memory for alloc of size %zd page on tid=%d!\n", n, t->tid);
+ printk("Insufficient memory for alloc %zd pages on tid=%d!\n",
+ n, t->tid);
printk("Pages available=%ld\n",iv_pagesAvail);
- while(1);
+ kassert(false);
}
// Update statistics.
@@ -257,7 +276,6 @@ void PageManager::_freePage(void* p, size_t n)
if(page)
{
iv_heapKernel.addMemory(reinterpret_cast<size_t>(page), ks);
- __sync_sub_and_fetch(&iv_pagesAvail, ks);
}
}
@@ -273,14 +291,14 @@ PageManagerCore::page_t* PageManagerCore::pop_bucket(size_t i_n)
if (NULL == p)
{
- // Couldn't allocate from the correct size bucket, so split up an
- // item from the next sized bucket.
- p = pop_bucket(i_n+1);
- if (NULL != p)
- {
- push_bucket((page_t*) (((uint64_t)p) + (PAGESIZE * (1 << i_n))),
- i_n);
- }
+ // Couldn't allocate from the correct size bucket, so split up an
+ // item from the next sized bucket.
+ p = pop_bucket(i_n+1);
+ if (NULL != p)
+ {
+ push_bucket((page_t*) (((uint64_t)p) + (PAGESIZE * (1 << i_n))),
+ i_n);
+ }
}
return p;
}
@@ -304,9 +322,6 @@ void PageManager::_coalesce( void )
// Coalsesce adjacent free memory blocks
void PageManagerCore::coalesce( void )
{
- // TODO: Issue 44511 - Function appears to leak memory.
- return;
-
// Look at all the "free buckets" and find blocks to merge
// Since this is binary, all merges will be from the same free bucket
// Each bucket is a stack of non-allocated memory blocks of the same size
@@ -371,13 +386,3 @@ void PageManagerCore::coalesce( void )
printkd("PAGEMGR low page count %ld\n", PageManager::cv_low_page_count);
}
-bool PageManager::queryKernelMode() const
-{
- uint64_t stack = 0;
- asm volatile("mr %0, 1" : "=r"(stack));
- if(stack >= VMM_VADDR_STACK_SEGMENT && stack < VMM_VADDR_DEVICE_SEGMENT_FIRST)
- {
- return false;
- }
- return true;
-}
diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C
index 1ed68624e..b6fa46f8a 100644
--- a/src/kernel/syscall.C
+++ b/src/kernel/syscall.C
@@ -89,8 +89,6 @@ namespace Systemcalls
void MsgSendRecv(task_t*);
void MsgRespond(task_t*);
void MsgWait(task_t*);
- void MmioMap(task_t*);
- void MmioUnmap(task_t*);
void DevMap(task_t*);
void DevUnmap(task_t*);
void TimeNanosleep(task_t*);
@@ -101,7 +99,7 @@ namespace Systemcalls
void MmAllocBlock(task_t *t);
void MmRemovePages(task_t *t);
void MmSetPermission(task_t *t);
- void MmFlushPages(task_t *t);
+ void MmAllocPages(task_t *t);
syscall syscalls[] =
@@ -135,7 +133,7 @@ namespace Systemcalls
&MmAllocBlock, // MM_ALLOC_BLOCK
&MmRemovePages, // MM_REMOVE_PAGES
&MmSetPermission, // MM_SET_PERMISSION
- &MmFlushPages, // MM_FLUSH_PAGES
+ &MmAllocPages, // MM_ALLOC_PAGES
};
};
@@ -165,6 +163,9 @@ namespace Systemcalls
Scheduler* s = t->cpu->scheduler;
s->returnRunnable();
s->setNextRunnable();
+
+ // TODO: Issue 44523 - Temporary workaround for live-lock situation.
+ CpuManager::executePeriodics(CpuManager::getCurrentCPU());
}
void TaskStart(task_t* t)
@@ -671,15 +672,30 @@ namespace Systemcalls
}
/**
- * Flush and Cast out 'old' pages
+ * Call PageManager to allocate a number of pages.
* @param[in] t: The task used.
*/
- void MmFlushPages(task_t* t)
+ void MmAllocPages(task_t* t)
{
- VmmManager::castout_t sev = (VmmManager::castout_t)TASK_GETARG0(t);
- VmmManager::flushPageTable();
- VmmManager::castOutPages(sev);
- TASK_SETRTN(t,0);
+ // Attempt to allocate the page(s).
+ void* page = PageManager::allocatePage(TASK_GETARG0(t), true);
+ TASK_SETRTN(t, reinterpret_cast<uint64_t>(page));
+
+ // If we are low on memory, call into the VMM to free some up.
+ uint64_t pcntAvail = PageManager::queryAvail();
+ if (pcntAvail < PageManager::LOWMEM_NORM_LIMIT)
+ {
+ static uint64_t one_at_a_time = 0;
+ if (!__sync_lock_test_and_set(&one_at_a_time, 1))
+ {
+ VmmManager::flushPageTable();
+ VmmManager::castout_t sev =
+ (pcntAvail < PageManager::LOWMEM_CRIT_LIMIT) ?
+ VmmManager::CRITICAL : VmmManager::NORMAL;
+ VmmManager::castOutPages(sev);
+ __sync_lock_release(&one_at_a_time);
+ }
+ }
}
};
diff --git a/src/lib/syscall_mm.C b/src/lib/syscall_mm.C
index 006586f81..b539cf05a 100644
--- a/src/lib/syscall_mm.C
+++ b/src/lib/syscall_mm.C
@@ -81,11 +81,3 @@ int mm_set_permission(void* va, uint64_t size, uint64_t access_type)
{
return (int64_t)_syscall3(MM_SET_PERMISSION, va, (void*)size, (void*)access_type);
}
-
-/**
- * System call to flush pages
- */
-void mm_flush_pages(uint64_t i_sev)
-{
- _syscall1(MM_FLUSH_PAGES, (void*)i_sev);
-}
diff --git a/src/usr/testcore/kernel/segmenttest.H b/src/usr/testcore/kernel/segmenttest.H
index e5b9ff64a..72ae8f23a 100644
--- a/src/usr/testcore/kernel/segmenttest.H
+++ b/src/usr/testcore/kernel/segmenttest.H
@@ -1,25 +1,26 @@
-// IBM_PROLOG_BEGIN_TAG
-// This is an automatically generated prolog.
-//
-// $Source: src/usr/testcore/kernel/segmenttest.H $
-//
-// IBM CONFIDENTIAL
-//
-// COPYRIGHT International Business Machines Corp. 2011
-//
-// p1
-//
-// Object Code Only (OCO) source materials
-// Licensed Internal Code Source Materials
-// IBM HostBoot Licensed Internal Code
-//
-// The source code for this program is not published or other-
-// wise divested of its trade secrets, irrespective of what has
-// been deposited with the U.S. Copyright Office.
-//
-// Origin: 30
-//
-// IBM_PROLOG_END
+/* IBM_PROLOG_BEGIN_TAG
+ * This is an automatically generated prolog.
+ *
+ * $Source: src/usr/testcore/kernel/segmenttest.H $
+ *
+ * IBM CONFIDENTIAL
+ *
+ * COPYRIGHT International Business Machines Corp. 2011-2012
+ *
+ * p1
+ *
+ * Object Code Only (OCO) source materials
+ * Licensed Internal Code Source Materials
+ * IBM HostBoot Licensed Internal Code
+ *
+ * The source code for this program is not published or other-
+ * wise divested of its trade secrets, irrespective of what has
+ * been deposited with the U.S. Copyright Office.
+ *
+ * Origin: 30
+ *
+ * IBM_PROLOG_END_TAG
+ */
#ifndef __SEGMENTTEST_H
#define __SEGMENTTEST_H
/**
@@ -91,7 +92,7 @@ class segmenttest: public CxxTest::TestSuite
void* block = NULL;
while (reinterpret_cast<uint64_t>(block)
- < (VMM_VADDR_DEVICE_SEGMENT_FIRST + TERABYTE))
+ < (VMM_VADDR_DEVICE_SEGMENT_FIRST + VMM_SEGMENT_SIZE))
{
block = mmio_dev_map(reinterpret_cast<void*>(10 * TERABYTE),
THIRTYTWO_GB);
OpenPOWER on IntegriCloud