]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[umalloc] Split largest_memblock() function out from init_eheap()
authorMichael Brown <mcb30@ipxe.org>
Mon, 5 Nov 2012 23:19:16 +0000 (23:19 +0000)
committerMichael Brown <mcb30@ipxe.org>
Tue, 6 Nov 2012 17:44:40 +0000 (17:44 +0000)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/i386/interface/pcbios/memtop_umalloc.c
src/core/memblock.c [new file with mode: 0644]
src/include/ipxe/memblock.h [new file with mode: 0644]

index 1821faf2412d22f40af01c025a535fad35460179..c382e3c369ca46e796263b8a73bc350f5fa8204c 100644 (file)
@@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/uaccess.h>
 #include <ipxe/hidemem.h>
 #include <ipxe/io.h>
+#include <ipxe/memblock.h>
 #include <ipxe/umalloc.h>
 
 /** Alignment of external allocated memory */
@@ -59,53 +60,14 @@ static size_t heap_size;
 /**
  * Initialise external heap
  *
- * @ret rc             Return status code
  */
-static int init_eheap ( void ) {
-       struct memory_map memmap;
-       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;
-               unsigned long r_size;
-
-               DBG ( "Considering [%llx,%llx)\n", region->start, region->end);
-
-               /* Truncate block to 4GB */
-               if ( region->start > UINT_MAX ) {
-                       DBG ( "...starts after 4GB\n" );
-                       continue;
-               }
-               r_start = region->start;
-               if ( region->end > UINT_MAX ) {
-                       DBG ( "...end truncated to 4GB\n" );
-                       r_end = 0; /* =4GB, given the wraparound */
-               } else {
-                       r_end = region->end;
-               }
-
-               /* Use largest block */
-               r_size = ( r_end - r_start );
-               if ( r_size > heap_size ) {
-                       DBG ( "...new best block found\n" );
-                       top = bottom = phys_to_user ( r_end );
-                       heap_size = r_size;
-               }
-       }
-
-       if ( ! heap_size ) {
-               DBG ( "No external heap available\n" );
-               return -ENOMEM;
-       }
+static void init_eheap ( void ) {
+       userptr_t base;
 
+       heap_size = largest_memblock ( &base );
+       bottom = top = userptr_add ( base, heap_size );
        DBG ( "External heap grows downwards from %lx (size %zx)\n",
              user_to_phys ( top, 0 ), heap_size );
-       return 0;
 }
 
 /**
@@ -144,13 +106,10 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
        struct external_memory extmem;
        userptr_t new = ptr;
        size_t align;
-       int rc;
 
-       /* Initialise external memory allocator if necessary */
-       if ( bottom == top ) {
-               if ( ( rc = init_eheap() ) != 0 )
-                       return UNULL;
-       }
+       /* (Re)initialise external memory allocator if necessary */
+       if ( bottom == top )
+               init_eheap();
 
        /* Get block properties into extmem */
        if ( ptr && ( ptr != UNOWHERE ) ) {
diff --git a/src/core/memblock.c b/src/core/memblock.c
new file mode 100644 (file)
index 0000000..1fd89b8
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Largest memory block
+ *
+ */
+
+#include <stdint.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/io.h>
+#include <ipxe/memblock.h>
+
+/**
+ * Find largest usable memory region
+ *
+ * @ret start          Start of region
+ * @ret len            Length of region
+ */
+size_t largest_memblock ( userptr_t *start ) {
+       struct memory_map memmap;
+       struct memory_region *region;
+       physaddr_t max = ~( ( physaddr_t ) 0 );
+       physaddr_t region_start;
+       physaddr_t region_end;
+       size_t region_len;
+       unsigned int i;
+       size_t len = 0;
+
+       /* Avoid returning uninitialised data on error */
+       *start = UNULL;
+
+       /* Scan through all memory regions */
+       get_memmap ( &memmap );
+       for ( i = 0 ; i < memmap.count ; i++ ) {
+               region = &memmap.regions[i];
+               DBG ( "Considering [%llx,%llx)\n", region->start, region->end );
+
+               /* Truncate block to maximum physical address */
+               if ( region->start > max ) {
+                       DBG ( "...starts after maximum address %lx\n", max );
+                       continue;
+               }
+               region_start = region->start;
+               if ( region->end > max ) {
+                       DBG ( "...end truncated to maximum address %lx\n", max);
+                       region_end = 0; /* =max, given the wraparound */
+               } else {
+                       region_end = region->end;
+               }
+               region_len = ( region_end - region_start );
+
+               /* Use largest block */
+               if ( region_len > len ) {
+                       DBG ( "...new best block found\n" );
+                       *start = phys_to_user ( region_start );
+                       len = region_len;
+               }
+       }
+
+       return len;
+}
diff --git a/src/include/ipxe/memblock.h b/src/include/ipxe/memblock.h
new file mode 100644 (file)
index 0000000..13af3e4
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _IPXE_MEMBLOCK_H
+#define _IPXE_MEMBLOCK_H
+
+/** @file
+ *
+ * Largest memory block
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/uaccess.h>
+
+extern size_t largest_memblock ( userptr_t *start );
+
+#endif /* _IPXE_MEMBLOCK_H */