mirror of
https://github.com/ipxe/ipxe
synced 2025-12-08 10:20:24 +03:00
[uheap] Expose external heap region directly
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>
This commit is contained in:
@@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#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 */
|
||||
@@ -132,18 +133,18 @@ void hide_textdata ( void ) {
|
||||
*/
|
||||
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 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -50,31 +50,38 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
@@ -91,8 +98,9 @@ static void uheap_find ( void ) {
|
||||
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 );
|
||||
@@ -112,12 +120,10 @@ static void uheap_find ( void ) {
|
||||
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 );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,15 +136,15 @@ static unsigned int uheap_grow ( size_t size ) {
|
||||
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 );
|
||||
|
||||
@@ -155,7 +161,7 @@ static unsigned int uheap_grow ( size_t 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 */
|
||||
|
||||
@@ -28,8 +28,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#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
|
||||
@@ -41,9 +41,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
/** 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
|
||||
*
|
||||
@@ -236,9 +233,8 @@ void initrd_reshuffle ( physaddr_t bottom ) {
|
||||
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 );
|
||||
@@ -270,9 +266,8 @@ int initrd_reshuffle_check ( size_t len, physaddr_t bottom ) {
|
||||
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 */
|
||||
@@ -287,19 +282,19 @@ int initrd_reshuffle_check ( size_t len, physaddr_t bottom ) {
|
||||
*
|
||||
*/
|
||||
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 */
|
||||
|
||||
@@ -228,8 +228,6 @@ static inline void memmap_dump_all ( int hide ) {
|
||||
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 );
|
||||
|
||||
@@ -15,4 +15,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#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 */
|
||||
|
||||
Reference in New Issue
Block a user