]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[uheap] Expose external heap region directly
authorMichael Brown <mcb30@ipxe.org>
Thu, 22 May 2025 10:58:11 +0000 (11:58 +0100)
committerMichael Brown <mcb30@ipxe.org>
Thu, 22 May 2025 15:28:15 +0000 (16:28 +0100)
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>
src/arch/x86/interface/pcbios/hidemem.c
src/core/uheap.c
src/image/initrd.c
src/include/ipxe/memmap.h
src/include/ipxe/uheap.h

index 9a445d0632106dd51576d46525e9a79ee54100e7..2b85459b650a7a68615dcc8af56e2f1272bb9ca2 100644 (file)
@@ -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 );
 }
 
 /**
index f5154a0d1dfe9b5dcc00d4a87204a16c9bc41b9a..3f93bc030281aadc1cf286aba5d29937cb3e6a69 100644 (file)
@@ -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 */
index 71634324dbe97c50e2e63c604be1c81f61a55885..511f95f10c2fca29ea5f1da3c34d6ef730c99557 100644 (file)
@@ -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 */
index 1283421bb34a8d9b4452c62cd8ada760e6e321a6..0175be11afc1cc2c0bc4b0b83af4a54b594ebe75 100644 (file)
@@ -228,8 +228,6 @@ static inline void memmap_dump_all ( int hide ) {
                memmap_dump ( &region );
 }
 
-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 );
index 194c1317529a422ffe899ecef3f0406b81a7bb56..d356786d352f09b55f153918367aa7c1169f7bc0 100644 (file)
@@ -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 */