From 42250e9b1a1c2f0d030cd102e8a6e14975e004af Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 13 May 2005 11:16:14 +0000 Subject: [PATCH] Tidied up init_heap() --- src/core/heap.c | 133 ++++++++++++++++++++++-------------------------- 1 file changed, 60 insertions(+), 73 deletions(-) diff --git a/src/core/heap.c b/src/core/heap.c index 05fbb6ba..26b25a43 100644 --- a/src/core/heap.c +++ b/src/core/heap.c @@ -8,88 +8,75 @@ struct heap_block { char data[0]; }; -size_t heap_ptr, heap_top, heap_bot; +/* Linker symbols */ +extern char _text[]; +extern char _end[]; -#define _virt_start 0 +static unsigned long heap_start, heap_end, heap_ptr; -static void init_heap(void) -{ - size_t size; - size_t start, end; - unsigned i; - /* Find the largest contiguous area of memory that - * I can use for the heap, which is organized as - * a stack that grows backwards through memory. - */ +/* + * Find the largest contiguous area of memory that I can use for the + * heap. + * + */ +static void init_heap ( void ) { + unsigned int i; + unsigned long eb_start, eb_end; + unsigned long size; - /* If I have virtual address that do not equal physical addresses - * there is a change I will try to use memory from both sides of - * the virtual address space simultaneously, which can cause all kinds - * of interesting problems. - * Avoid it by logically extending etherboot. Once I know that relocation - * works I can just start the virtual address space at 0, and this problem goes - * away so that is probably a better solution. - */ -#if 0 - start = virt_to_phys(_text); -#else - /* segment wrap around is nasty don't chance it. */ - start = virt_to_phys(_virt_start); -#endif - end = virt_to_phys(_end); size = 0; - for(i = 0; i < meminfo.map_count; i++) { - unsigned long r_start, r_end; - if (meminfo.map[i].type != E820_RAM) + + /* Region occupied by Etherboot */ + eb_start = virt_to_phys ( _text ); + eb_end = virt_to_phys ( _end ); + + for ( i = 0 ; i < meminfo.map_count ; i++ ) { + unsigned long r_start, r_end, r_size; + unsigned long pre_eb, post_eb; + + /* Get start and end addresses of the region */ + if ( meminfo.map[i].type != E820_RAM ) continue; - if (meminfo.map[i].addr > ULONG_MAX) + if ( meminfo.map[i].addr > ULONG_MAX ) continue; - if (meminfo.map[i].size > ULONG_MAX) - continue; - r_start = meminfo.map[i].addr; - r_end = r_start + meminfo.map[i].size; - if (r_end < r_start) { + if ( r_start + meminfo.map[i].size > ULONG_MAX ) { r_end = ULONG_MAX; + } else { + r_end = r_start + meminfo.map[i].size; } - /* Handle areas that overlap etherboot */ - if ((end > r_start) && (start < r_end)) { - /* Etherboot completely covers the region */ - if ((start <= r_start) && (end >= r_end)) - continue; - /* Etherboot is completely contained in the region */ - if ((start > r_start) && (end < r_end)) { - /* keep the larger piece */ - if ((r_end - end) >= (r_start - start)) { - r_start = end; - } - else { - r_end = start; - } - } - /* Etherboot covers one end of the region. - * Shrink the region. - */ - else if (end >= r_end) { - r_end = start; - } - else if (start <= r_start) { - r_start = end; + + /* Avoid overlap with Etherboot. When Etherboot is + * completely contained within the region, choose the + * larger of the two remaining portions. + */ + if ( ( eb_start < r_end ) && ( eb_end > r_start ) ) { + pre_eb = ( eb_start > r_start ) ? + ( eb_start - r_start ) : 0; + post_eb = ( r_end > eb_end ) ? + ( r_end - eb_end ) : 0; + if ( pre_eb > post_eb ) { + r_end = eb_start; + } else { + r_start = eb_end; } } - /* If two areas are the size prefer the greater address */ - if (((r_end - r_start) > size) || - (((r_end - r_start) == size) && (r_start > heap_top))) { - size = r_end - r_start; - heap_top = r_start; - heap_bot = r_end; + + /* Use the biggest region. Where two regions are the + * same size, use the later region. (Provided that + * the memory map is laid out in a sensible order, + * this should give us the higher region.) + */ + r_size = r_end - r_start; + if ( r_size >= size ) { + heap_start = r_start; + heap_end = r_end; + size = r_size; } } - if (size == 0) { - printf("init_heap: No heap found.\n"); - exit(1); - } - heap_ptr = heap_bot; + + ASSERT ( size != 0 ); + heap_ptr = heap_end; } /* @@ -104,7 +91,7 @@ void * emalloc ( size_t size, unsigned int align ) { addr = ( ( ( heap_ptr - size ) & ~( align - 1 ) ) - sizeof ( struct heap_block ) ); - if ( addr < heap_top ) { + if ( addr < heap_start ) { return NULL; } @@ -119,7 +106,7 @@ void * emalloc ( size_t size, unsigned int align ) { * */ void * emalloc_all ( size_t *size ) { - *size = heap_ptr - heap_top - sizeof ( struct heap_block ); + *size = heap_ptr - heap_start - sizeof ( struct heap_block ); return emalloc ( *size, sizeof ( void * ) ); } @@ -136,7 +123,7 @@ void efree ( void *ptr ) { ( ptr - offsetof ( struct heap_block, data ) ); heap_ptr += block->size; - ASSERT ( heap_ptr <= heap_bot ); + ASSERT ( heap_ptr <= heap_end ); } /* @@ -144,7 +131,7 @@ void efree ( void *ptr ) { * */ void efree_all ( void ) { - heap_ptr = heap_bot; + heap_ptr = heap_end; } INIT_FN ( INIT_HEAP, init_heap, efree_all, NULL );