summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRichard J. Knight <rjknight@us.ibm.com>2017-03-07 15:51:36 -0600
committerDaniel M. Crowell <dcrowell@us.ibm.com>2017-04-10 17:44:40 -0400
commitca1e3f7df35276b213a4453df289f376c2cbc618 (patch)
treee54dabbffee07677364edb6d6d08f79d197a8c73 /src
parentc703612bd907523a11169a7d30aca138a84ed673 (diff)
downloadtalos-hostboot-ca1e3f7df35276b213a4453df289f376c2cbc618.tar.gz
talos-hostboot-ca1e3f7df35276b213a4453df289f376c2cbc618.zip
Enhance heap consistency checking
-Add validation to heap allocations, marker used to detect buffer overruns to generate exception when memory segment is freed -Add additional debug to the heap bookkeeping data - owner tid, reserved size and an indicator to say it is an allocated chunk Change-Id: Iae522fc4c6157a32f5689ee1ec5fd9d552123eb4 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/37829 Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Martin Gloff <mgloff@us.ibm.com> Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/include/kernel/heapmgr.H21
-rw-r--r--src/kernel/heapmgr.C48
2 files changed, 55 insertions, 14 deletions
diff --git a/src/include/kernel/heapmgr.H b/src/include/kernel/heapmgr.H
index 6db70569b..bf4fe1cc7 100644
--- a/src/include/kernel/heapmgr.H
+++ b/src/include/kernel/heapmgr.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2010,2015 */
+/* Contributors Listed Below - COPYRIGHT 2010,2017 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -28,6 +28,7 @@
#include <stdint.h>
#include <util/lockfree/stack.H>
#include <builtins.h>
+#include <kernel/types.h>
extern "C"
void kernel_execute_decrementer();
@@ -53,6 +54,11 @@ class HeapManager
public:
enum
{
+ CHUNK_HEADER_PLUS_RESERVED = 9, //!< 8 Bytes header + 1 byte valid
+ };
+
+ enum
+ {
BUCKETS = 12, //!< number of buckets
MIN_BUCKET_SIZE = 16, //!< Smallest bucket size
FIB_START_INCR = 16, //!< Seed for the Fibonacci series
@@ -69,7 +75,10 @@ class HeapManager
BUCKET_SIZE10 = BUCKET_SIZE9 + BUCKET_SIZE8,
BUCKET_SIZE11 = BUCKET_SIZE10 + BUCKET_SIZE9,
- MAX_SMALL_ALLOC_SIZE = BUCKET_SIZE11 - 8,// last bucket size-8
+ // last bucket size, 8 byte chunk header + 1 byte for consistency
+ // checking
+ MAX_SMALL_ALLOC_SIZE = BUCKET_SIZE11 - CHUNK_HEADER_PLUS_RESERVED,
+
};
friend class CpuManager;
@@ -136,9 +145,11 @@ class HeapManager
{
struct
{
- char free:8; //!< Is chunk free
- char coalesce:8; //!< Is chunk being coalesced
- uint64_t bucket:48; //!< Which bucket this chunk belongs to
+ uint8_t free; //!< F=free, A=allocated
+ uint8_t coalesce; //!< C=chunk being coalesced
+ uint16_t size; //!< size of the data area
+ tid_t allocator; //!< task_id of allocating thread
+ uint16_t bucket; //!< Which bucket this chunk belongs to
} PACKED;
chunk_t* next; //!< Next chunk (for unallocated chunks only)
diff --git a/src/kernel/heapmgr.C b/src/kernel/heapmgr.C
index 69cd2663f..b473eb05c 100644
--- a/src/kernel/heapmgr.C
+++ b/src/kernel/heapmgr.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2010,2016 */
+/* Contributors Listed Below - COPYRIGHT 2010,2017 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -23,6 +23,7 @@
/* */
/* IBM_PROLOG_END_TAG */
#include <limits.h>
+#include <sys/task.h>
#include <kernel/heapmgr.H>
#include <util/singleton.H>
#include <kernel/console.H>
@@ -102,7 +103,8 @@ void HeapManager::coalesce( void )
void* HeapManager::_allocate(size_t i_sz)
{
- size_t which_bucket = bucketIndex(i_sz+8);
+ // 8 bytes book keeping, 1 byte validation
+ size_t which_bucket = bucketIndex(i_sz + CHUNK_HEADER_PLUS_RESERVED);
chunk_t* chunk = reinterpret_cast<chunk_t*>(NULL);
chunk = pop_bucket(which_bucket);
@@ -122,22 +124,35 @@ void* HeapManager::_allocate(size_t i_sz)
// test_pages();
#endif
crit_assert(chunk->free == 'F');
- chunk->free = '\0';
+
+ // Use the size of this chunk get to the end.
+ size_t size = bucketByteSize(chunk->bucket);
+
+ // set the last byte of the chunk to 'V' => valid
+ *(reinterpret_cast<uint8_t*>(chunk) + size - 1 ) = 'V';
+
+ // mark chunk as allocated
+ chunk->free = 'A';
+ chunk->size = i_sz;
+ chunk->allocator = task_gettid();
+
return &chunk->next;
}
}
-
void* HeapManager::_realloc(void* i_ptr, size_t i_sz)
{
void* new_ptr = _reallocBig(i_ptr,i_sz);
if(new_ptr) return new_ptr;
new_ptr = i_ptr;
- chunk_t* chunk = reinterpret_cast<chunk_t*>(((size_t*)i_ptr)-1);
- size_t asize = bucketByteSize(chunk->bucket)-8;
+ chunk_t* chunk = reinterpret_cast<chunk_t*>(((uint64_t*)i_ptr)-1);
+
+ // take into account the 8 byte header and valid byte
+ size_t asize = bucketByteSize(chunk->bucket) - CHUNK_HEADER_PLUS_RESERVED;
if(asize < i_sz)
{
+ // fyi.. MAX_SMALL_ALLOCATION_SIZE = BUCKET11 - 9 bytes
new_ptr = (i_sz > MAX_SMALL_ALLOC_SIZE) ?
_allocateBig(i_sz) : _allocate(i_sz);
memcpy(new_ptr, i_ptr, asize);
@@ -195,12 +210,25 @@ void HeapManager::_free(void * i_ptr)
if(!_freeBig(i_ptr))
{
- chunk_t* chunk = reinterpret_cast<chunk_t*>(((size_t*)i_ptr)-1);
+ chunk_t* chunk = reinterpret_cast<chunk_t*>(((uint64_t*)i_ptr)-1);
+
#ifdef HOSTBOOT_DEBUG
__sync_sub_and_fetch(&g_smallheap_count,1);
__sync_sub_and_fetch(&g_smallheap_allocated,bucketByteSize(chunk->bucket));
#endif
crit_assert(chunk->free != 'F');
+
+ // Use the size of this chunk to find next chunk.
+ size_t size = bucketByteSize(chunk->bucket);
+
+ // make sure the next block is still valid
+ if( *(reinterpret_cast<uint8_t*>(chunk) + size - 1 ) != 'V')
+ {
+ MAGIC_INSTRUCTION(MAGIC_BREAK_ON_ERROR);
+ // force a storage exception
+ task_crash();
+ }
+
push_bucket(chunk, chunk->bucket);
}
}
@@ -243,7 +271,9 @@ HeapManager::chunk_t* HeapManager::pop_bucket(size_t i_bucket)
void HeapManager::push_bucket(chunk_t* i_chunk, size_t i_bucket)
{
if (i_bucket >= BUCKETS) return;
- i_chunk->free = 'F';
+ i_chunk->free = 'F';
+ i_chunk->size = 0;
+ i_chunk->allocator = 0;
first_chunk[i_bucket].push(i_chunk);
}
@@ -365,7 +395,7 @@ void HeapManager::_coalesce()
// Use the size of this chunk to find next chunk.
size_t size = bucketByteSize(chunk->bucket);
chunk_t* buddy = reinterpret_cast<chunk_t*>(
- reinterpret_cast<size_t>(chunk) + size);
+ reinterpret_cast<uint64_t>(chunk) + size);
// The two chunks have to be on the same page in order to
// be considered for merge.
OpenPOWER on IntegriCloud