We currently rely on implicit detection of the external heap region.
The INT 15 memory map mangler relies on examining the corresponding
in-use memory region, and the initrd reshuffler relies on performing a
separate detection of the largest free memory block after startup has
completed.
Replace these with explicit public symbols to describe the external
heap region.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
#include <fakee820.h>
#include <ipxe/init.h>
#include <ipxe/io.h>
+#include <ipxe/uheap.h>
#include <ipxe/memmap.h>
/** Set to true if you want to test a fake E820 map */
*/
static void int15_sync ( void ) {
physaddr_t start;
- size_t size;
+ physaddr_t end;
/* Besides our fixed base memory and textdata regions, we
* support hiding only a single in-use memory region (the
* umalloc region), which must be placed before the hidden
* textdata region (even if zero-length).
*/
- start = uheap_used.start;
- size = uheap_used.size;
- if ( ! size )
- start = virt_to_phys ( _textdata );
- hide_region ( &hidemem_umalloc, start, ( start + size ) );
+ start = uheap_start;
+ end = uheap_end;
+ if ( start == end )
+ start = end = virt_to_phys ( _textdata );
+ hide_region ( &hidemem_umalloc, start, end );
}
/**
static struct heap uheap;
+/** Minimum possible start of external heap */
+physaddr_t uheap_limit;
+
+/** Start of external heap */
+physaddr_t uheap_start;
+
+/** End of external heap */
+physaddr_t uheap_end;
+
/** In-use memory region */
struct used_region uheap_used __used_region = {
.name = "uheap",
};
-/** External heap maximum size */
-static size_t uheap_max;
-
/**
* Adjust size of external heap in-use memory region
*
* @v delta Size change
*/
static void uheap_resize ( ssize_t delta ) {
- physaddr_t top;
/* Update in-use memory region */
- assert ( ( uheap_used.start & ( UHEAP_ALIGN - 1 ) ) == 0 );
- assert ( ( uheap_used.size & ( UHEAP_ALIGN - 1 ) ) == 0 );
assert ( ( delta & ( UHEAP_ALIGN - 1 ) ) == 0 );
- memmap_use ( &uheap_used, ( uheap_used.start - delta ),
- ( uheap_used.size + delta ) );
- top = ( uheap_used.start + uheap_used.size );
- DBGC ( &uheap, "UHEAP now at [%#08lx,%#08lx)\n",
- uheap_used.start, top );
+ uheap_start -= delta;
+ assert ( uheap_limit <= uheap_start );
+ assert ( uheap_start <= uheap_end );
+ assert ( ( uheap_limit & ( UHEAP_ALIGN - 1 ) ) == 0 );
+ assert ( ( uheap_start & ( UHEAP_ALIGN - 1 ) ) == 0 );
+ assert ( ( uheap_end & ( UHEAP_ALIGN - 1 ) ) == 0 );
+ memmap_use ( &uheap_used, uheap_start, ( uheap_end - uheap_start ) );
+ DBGC ( &uheap, "UHEAP now at (%#08lx)...[%#08lx,%#08lx)\n",
+ uheap_limit, uheap_start, uheap_end );
memmap_dump_all ( 1 );
}
size_t size;
/* Sanity checks */
+ assert ( uheap_start == uheap_end );
+ assert ( uheap_limit == uheap_end );
assert ( uheap_used.size == 0 );
- assert ( uheap_max == 0 );
/* Find the largest region within the system memory map */
size = memmap_largest ( &start );
assert ( ( end - start ) == size );
/* Record region */
- assert ( ( start & ( UHEAP_ALIGN - 1 ) ) == 0 );
- assert ( ( size & ( UHEAP_ALIGN - 1 ) ) == 0 );
- assert ( ( end & ( UHEAP_ALIGN - 1 ) ) == 0 );
- uheap_max = size;
- uheap_used.start = end;
- DBGC ( &uheap, "UHEAP grows downwards from %#08lx\n", end );
+ uheap_limit = start;
+ uheap_start = end;
+ uheap_end = end;
+ uheap_resize ( 0 );
}
/**
void *new;
/* Initialise heap, if it does not yet exist */
- if ( ! uheap_max )
+ if ( uheap_limit == uheap_end )
uheap_find();
/* Fail if insufficient space remains */
- if ( size > ( uheap_max - uheap_used.size ) )
+ if ( size > ( uheap_start - uheap_limit ) )
return 0;
/* Grow heap */
- new = ( phys_to_virt ( uheap_used.start ) - size );
+ new = ( phys_to_virt ( uheap_start ) - size );
heap_populate ( &uheap, new, size );
uheap_resize ( size );
static unsigned int uheap_shrink ( void *ptr, size_t size ) {
/* Do nothing unless this is the lowest block in the heap */
- if ( virt_to_phys ( ptr ) != uheap_used.start )
+ if ( virt_to_phys ( ptr ) != uheap_start )
return 0;
/* Shrink heap */
#include <ipxe/image.h>
#include <ipxe/uaccess.h>
#include <ipxe/init.h>
-#include <ipxe/memmap.h>
#include <ipxe/cpio.h>
+#include <ipxe/uheap.h>
#include <ipxe/initrd.h>
/** @file
/** Maximum address available for initrd */
static physaddr_t initrd_top;
-/** Minimum address available for initrd */
-static physaddr_t initrd_bottom;
-
/**
* Squash initrds as high as possible in memory
*
size_t free_len;
/* Calculate limits of available space for initrds */
- top = initrd_top;
- if ( initrd_bottom > bottom )
- bottom = initrd_bottom;
+ top = ( initrd_top ? initrd_top : uheap_end );
+ assert ( bottom >= uheap_limit );
/* Debug */
DBGC ( &images, "INITRD region [%#08lx,%#08lx)\n", bottom, top );
size_t available;
/* Calculate limits of available space for initrds */
- top = initrd_top;
- if ( initrd_bottom > bottom )
- bottom = initrd_bottom;
+ top = ( initrd_top ? initrd_top : uheap_end );
+ assert ( bottom >= uheap_limit );
available = ( top - bottom );
/* Allow for a sensible minimum amount of free space */
*
*/
static void initrd_startup ( void ) {
- size_t len;
- /* Record largest memory block available. Do this after any
- * allocations made during driver startup (e.g. large host
- * memory blocks for Infiniband devices, which may still be in
- * use at the time of rearranging if a SAN device is hooked)
- * but before any allocations for downloaded images (which we
- * can safely reuse when rearranging).
+ /* Record address above which reshuffling cannot take place.
+ * If any external heap allocations have been made during
+ * driver startup (e.g. large host memory blocks for
+ * Infiniband devices, which may still be in use at the time
+ * of rearranging if a SAN device is hooked), then we must not
+ * overwrite these allocations during reshuffling.
*/
- len = memmap_largest ( &initrd_bottom );
- initrd_top = ( initrd_bottom + len );
- DBGC ( &images, "INITRD largest memory block is [%#08lx,%#08lx)\n",
- initrd_bottom, initrd_top );
+ initrd_top = uheap_start;
+ if ( initrd_top ) {
+ DBGC ( &images, "INITRD limiting reshuffling to below "
+ "%#08lx\n", initrd_top );
+ }
}
/** initrd startup function */
memmap_dump ( ®ion );
}
-extern struct used_region uheap_used __used_region;
-
extern void memmap_update ( struct memmap_region *region, uint64_t start,
uint64_t size, unsigned int flags,
const char *name );
#define UMALLOC_PREFIX_uheap __uheap_
#endif
+extern physaddr_t uheap_limit;
+extern physaddr_t uheap_start;
+extern physaddr_t uheap_end;
+
#endif /* _IPXE_UHEAP_H */