/** Bottom of heap (current lowest allocated block) */
static userptr_t bottom = UNULL;
+/** Remaining space on heap */
+static size_t heap_size;
+
/**
* Initialise external heap
*
*/
static int init_eheap ( void ) {
struct memory_map memmap;
- unsigned long heap_size = 0;
unsigned int i;
DBG ( "Allocating external heap\n" );
get_memmap ( &memmap );
+ heap_size = 0;
for ( i = 0 ; i < memmap.count ; i++ ) {
struct memory_region *region = &memmap.regions[i];
unsigned long r_start, r_end;
return -ENOMEM;
}
- DBG ( "External heap grows downwards from %lx\n",
- user_to_phys ( top, 0 ) );
+ DBG ( "External heap grows downwards from %lx (size %zx)\n",
+ user_to_phys ( top, 0 ), heap_size );
return 0;
}
*/
static void ecollect_free ( void ) {
struct external_memory extmem;
+ size_t len;
/* Walk the free list and collect empty blocks */
while ( bottom != top ) {
break;
DBG ( "EXTMEM freeing [%lx,%lx)\n", user_to_phys ( bottom, 0 ),
user_to_phys ( bottom, extmem.size ) );
- bottom = userptr_add ( bottom,
- ( extmem.size + sizeof ( extmem ) ) );
+ len = ( extmem.size + sizeof ( extmem ) );
+ bottom = userptr_add ( bottom, len );
+ heap_size += len;
}
}
sizeof ( extmem ) );
} else {
/* Create a zero-length block */
+ if ( heap_size < sizeof ( extmem ) ) {
+ DBG ( "EXTMEM out of space\n" );
+ return UNULL;
+ }
ptr = bottom = userptr_add ( bottom, -sizeof ( extmem ) );
+ heap_size -= sizeof ( extmem );
DBG ( "EXTMEM allocating [%lx,%lx)\n",
user_to_phys ( ptr, 0 ), user_to_phys ( ptr, 0 ) );
extmem.size = 0;
/* Expand/shrink block if possible */
if ( ptr == bottom ) {
/* Update block */
+ if ( new_size > ( heap_size - extmem.size ) ) {
+ DBG ( "EXTMEM out of space\n" );
+ return UNULL;
+ }
new = userptr_add ( ptr, - ( new_size - extmem.size ) );
align = ( user_to_phys ( new, 0 ) & ( EM_ALIGN - 1 ) );
new_size += align;
user_to_phys ( new, new_size ));
memmove_user ( new, 0, ptr, 0, ( ( extmem.size < new_size ) ?
extmem.size : new_size ) );
- extmem.size = new_size;
bottom = new;
+ heap_size -= ( new_size - extmem.size );
+ extmem.size = new_size;
} else {
/* Cannot expand; can only pretend to shrink */
if ( new_size > extmem.size ) {
/* Collect any free blocks and update hidden memory region */
ecollect_free();
- hide_umalloc ( user_to_phys ( bottom, -sizeof ( extmem ) ),
+ hide_umalloc ( user_to_phys ( bottom, 0 ),
user_to_phys ( top, 0 ) );
return ( new_size ? new : UNOWHERE );