summaryrefslogtreecommitdiffstats
path: root/src/kernel/stacksegment.C
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/stacksegment.C')
-rw-r--r--src/kernel/stacksegment.C163
1 files changed, 163 insertions, 0 deletions
diff --git a/src/kernel/stacksegment.C b/src/kernel/stacksegment.C
new file mode 100644
index 000000000..91b16e6a9
--- /dev/null
+++ b/src/kernel/stacksegment.C
@@ -0,0 +1,163 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/kernel/stacksegment.C $
+//
+// 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
+
+#include <assert.h>
+#include <util/singleton.H>
+
+#include <kernel/stacksegment.H>
+#include <kernel/segmentmgr.H>
+#include <kernel/block.H>
+#include <errno.h>
+
+void StackSegment::init()
+{
+ Singleton<StackSegment>::instance()._init();
+}
+
+void* StackSegment::createStack(tid_t i_task)
+{
+ return Singleton<StackSegment>::instance()._createStack(i_task);
+}
+
+void StackSegment::deleteStack(tid_t i_task)
+{
+ Singleton<StackSegment>::instance()._deleteStack(i_task);
+}
+
+StackSegment::~StackSegment()
+{
+ // Release all blocks and associated pages.
+ StackBlockNode* l_node = NULL;
+ do
+ {
+ l_node = iv_blockList.remove();
+ if (NULL != l_node)
+ {
+ l_node->block->releaseAllPages();
+ delete l_node->block;
+ delete l_node;
+ }
+ } while (l_node != NULL);
+}
+
+bool StackSegment::handlePageFault(task_t* i_task, uint64_t i_addr)
+{
+ uint64_t l_addr_8mb = i_addr & ~((EIGHT_MEGABYTE) - 1);
+
+ StackBlockNode* l_node = iv_blockList.find(l_addr_8mb);
+
+ return (NULL == l_node ?
+ false :
+ l_node->block->handlePageFault(i_task, i_addr));
+}
+
+uint64_t StackSegment::findPhysicalAddress(uint64_t i_vaddr) const
+{
+ uint64_t l_addr_8mb = i_vaddr & ~((EIGHT_MEGABYTE) - 1);
+
+ StackBlockNode* l_node = iv_blockList.find(l_addr_8mb);
+
+ return (NULL == l_node ?
+ -EFAULT :
+ l_node->block->findPhysicalAddress(i_vaddr));
+}
+
+void StackSegment::_init()
+{
+ // Assign segment to segment manager.
+ SegmentManager::addSegment(this, SegmentManager::STACK_SEGMENT_ID);
+}
+
+void* StackSegment::_createStack(tid_t i_task)
+{
+ /* The segment is broken out into 8MB blocks so we need to place the
+ * stack somewhere within an 8MB range. The constrants are ensuring
+ * we have adequate protection and that the hashed page table does not
+ * have a large number of collisions. If we were to place all of the
+ * stacks at (8MB - 64k) there would be a large amount of contention on
+ * the same PTEG in the hashed page table.
+ *
+ * Design:
+ * - Provide 64k of protection minimum at the top and bottom of the
+ * stack.
+ * - Allow stack sizes up to 256k.
+ * - Expect typical (well performing) stacks of under 128k.
+ *
+ * Therefore, place stacks at:
+ * Bottom = 64k + 128k * (tid % 61).
+ * Top = Bottom + 256k - 8.
+ *
+ * This provides a possible range of 64k to (8MB - 64k), giving 64k of
+ * protection at each end. It also cycles the stacks through the 8MB
+ * range, and therefore the hashed page table, at 128k blocks. Finally,
+ * it provides for stack sizes up to 256k.
+ *
+ * Any attempt to grow the stack above 256k can be caught by killing the
+ * task (so we can re-write the offending code to not waste so much stack
+ * space).
+ */
+
+ uint64_t l_addr_8mb = i_task * EIGHT_MEGABYTE + ONE_TERABYTE;
+ // Ensure block doesn't already exist.
+ kassert(NULL == iv_blockList.find(l_addr_8mb));
+
+ // Calculate offset bounds of stack.
+ uint64_t l_offset_bottom = (64 + 128 * (i_task % 61)) * 1024;
+ uint64_t l_offset_top = l_offset_bottom + (256 * 1024) - 8;
+
+ uint64_t l_addr_bottom = l_addr_8mb + l_offset_bottom;
+ uint64_t l_addr_top = l_addr_8mb + l_offset_top;
+
+ // Create block.
+ Block* l_block = new Block(l_addr_bottom, 256 * 1024);
+ // Set pages to be allocate-from-zero.
+ for(uint64_t i = l_addr_bottom; i <= l_addr_top; i += PAGE_SIZE)
+ {
+ l_block->setPhysicalPage(i, 0, VmmManager::NORMAL_ACCESS);
+ l_block->setPageAllocateFromZero(i);
+ }
+
+ // Insert block to list.
+ StackBlockNode* l_node = new StackBlockNode();
+ l_node->key = l_addr_8mb;
+ l_node->block = l_block;
+ iv_blockList.insert(l_node);
+
+ // Return pointer to top of stack, since stacks grow down.
+ return reinterpret_cast<void*>(l_addr_top);
+}
+
+void StackSegment::_deleteStack(tid_t i_task)
+{
+ uint64_t l_addr_8mb = i_task * EIGHT_MEGABYTE + ONE_TERABYTE;
+
+ StackBlockNode* l_node = iv_blockList.find(l_addr_8mb);
+ kassert(NULL != l_node);
+ iv_blockList.erase(l_node);
+
+ l_node->block->releaseAllPages();
+ delete l_node->block;
+ delete l_node;
+
+ return;
+}
OpenPOWER on IntegriCloud