Tidied up init_heap()
authorMichael Brown <mcb30@etherboot.org>
Fri, 13 May 2005 11:16:14 +0000 (11:16 +0000)
committerMichael Brown <mcb30@etherboot.org>
Fri, 13 May 2005 11:16:14 +0000 (11:16 +0000)
src/core/heap.c

index 05fbb6b..26b25a4 100644 (file)
@@ -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;
+
+/*
+ * 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;
 
-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.
-        */
-
-       /* 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)
-                       continue;
-               if (meminfo.map[i].addr > ULONG_MAX)
+       
+       /* 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].size > ULONG_MAX)
+               if ( meminfo.map[i].addr > 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 );