// 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 #include #include #include #include #include #include void StackSegment::init() { Singleton::instance()._init(); } void* StackSegment::createStack(tid_t i_task) { return Singleton::instance()._createStack(i_task); } void StackSegment::deleteStack(tid_t i_task) { Singleton::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); /*using deallocated*/ // BEAM invalid error. } bool StackSegment::handlePageFault(task_t* i_task, uint64_t i_addr, bool i_store) { uint64_t l_addr_8mb = i_addr & ~((8*MEGABYTE) - 1); StackBlockNode* l_node = iv_blockList.find(l_addr_8mb); return (NULL == l_node ? false : l_node->block->handlePageFault(i_task, i_addr, i_store)); } uint64_t StackSegment::findPhysicalAddress(uint64_t i_vaddr) const { uint64_t l_addr_8mb = i_vaddr & ~((8*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 constraints 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 * (8*MEGABYTE) + VMM_VADDR_STACK_SEGMENT; // 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, WRITABLE | ALLOCATE_FROM_ZERO); } // 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(l_addr_top); } void StackSegment::_deleteStack(tid_t i_task) { VmmManager::getLock()->lock(); uint64_t l_addr_8mb = i_task * (8*MEGABYTE) + VMM_VADDR_STACK_SEGMENT; 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; VmmManager::getLock()->unlock(); return; }