iPXE
Data Structures | Defines | Functions | Variables
memtop_umalloc.c File Reference

External memory allocation. More...

#include <limits.h>
#include <errno.h>
#include <ipxe/uaccess.h>
#include <ipxe/hidemem.h>
#include <ipxe/io.h>
#include <ipxe/memblock.h>
#include <ipxe/umalloc.h>

Go to the source code of this file.

Data Structures

struct  external_memory
 An external memory block. More...

Defines

#define EM_MAX_ADDRESS   0xffffffffUL
 Maximum usable address for external allocated memory.
#define EM_ALIGN   ( 4 * 1024 )
 Alignment of external allocated memory.
#define UNOWHERE   ( ~UNULL )
 Equivalent of NOWHERE for user pointers.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
size_t largest_memblock (userptr_t *start)
 Find largest usable memory region.
static void init_eheap (void)
 Initialise external heap.
static void ecollect_free (void)
 Collect free blocks.
static userptr_t memtop_urealloc (userptr_t ptr, size_t new_size)
 Reallocate external memory.
 PROVIDE_UMALLOC (memtop, urealloc, memtop_urealloc)

Variables

struct external_memory __attribute__
static userptr_t top = UNULL
 Top of heap.
static userptr_t bottom = UNULL
 Bottom of heap (current lowest allocated block)
static size_t heap_size
 Remaining space on heap.

Detailed Description

External memory allocation.

Definition in file memtop_umalloc.c.


Define Documentation

#define EM_MAX_ADDRESS   0xffffffffUL

Maximum usable address for external allocated memory.

Definition at line 42 of file memtop_umalloc.c.

Referenced by largest_memblock().

#define EM_ALIGN   ( 4 * 1024 )

Alignment of external allocated memory.

Definition at line 45 of file memtop_umalloc.c.

Referenced by memtop_urealloc().

#define UNOWHERE   ( ~UNULL )

Equivalent of NOWHERE for user pointers.

Definition at line 48 of file memtop_umalloc.c.

Referenced by memtop_urealloc().


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )

Find largest usable memory region.

Return values:
startStart of region
lenLength of region

Definition at line 73 of file memtop_umalloc.c.

References memory_map::count, DBG, EM_MAX_ADDRESS, memory_region::end, get_memmap(), len, max, phys_to_user(), memory_map::regions, memory_region::start, and UNULL.

Referenced by init_eheap(), and initrd_startup().

                                             {
        struct memory_map memmap;
        struct memory_region *region;
        physaddr_t max = EM_MAX_ADDRESS;
        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;
}
static void init_eheap ( void  ) [static]

Initialise external heap.

Definition at line 121 of file memtop_umalloc.c.

References base, bottom, DBG, heap_size, largest_memblock(), top, user_to_phys(), and userptr_add().

Referenced by memtop_urealloc().

                                {
        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 );
}
static void ecollect_free ( void  ) [static]

Collect free blocks.

Definition at line 134 of file memtop_umalloc.c.

References bottom, copy_from_user(), DBG, heap_size, len, external_memory::size, top, external_memory::used, user_to_phys(), and userptr_add().

Referenced by memtop_urealloc().

                                   {
        struct external_memory extmem;
        size_t len;

        /* Walk the free list and collect empty blocks */
        while ( bottom != top ) {
                copy_from_user ( &extmem, bottom, -sizeof ( extmem ),
                                 sizeof ( extmem ) );
                if ( extmem.used )
                        break;
                DBG ( "EXTMEM freeing [%lx,%lx)\n", user_to_phys ( bottom, 0 ),
                      user_to_phys ( bottom, extmem.size ) );
                len = ( extmem.size + sizeof ( extmem ) );
                bottom = userptr_add ( bottom, len );
                heap_size += len;
        }
}
static userptr_t memtop_urealloc ( userptr_t  ptr,
size_t  new_size 
) [static]

Reallocate external memory.

Parameters:
old_ptrMemory previously allocated by umalloc(), or UNULL
new_sizeRequested size
Return values:
new_ptrAllocated memory, or UNULL

Calling realloc() with a new size of zero is a valid way to free a memory block.

Definition at line 162 of file memtop_umalloc.c.

References bottom, copy_from_user(), copy_to_user(), DBG, ecollect_free(), EM_ALIGN, heap_size, hide_umalloc(), init_eheap(), memmove_user(), external_memory::size, top, UNOWHERE, UNULL, external_memory::used, user_to_phys(), and userptr_add().

                                                                    {
        struct external_memory extmem;
        userptr_t new = ptr;
        size_t align;

        /* (Re)initialise external memory allocator if necessary */
        if ( bottom == top )
                init_eheap();

        /* Get block properties into extmem */
        if ( ptr && ( ptr != UNOWHERE ) ) {
                /* Determine old size */
                copy_from_user ( &extmem, ptr, -sizeof ( extmem ),
                                 sizeof ( extmem ) );
        } else {
                /* Create a zero-length block */
                if ( heap_size < sizeof ( extmem ) ) {
                        DBG ( "EXTMEM out of space\n" );
                        return UNULL;
                }
                ptr = bottom = userptr_add ( bottom, -sizeof ( extmem ) );
                heap_size -= sizeof ( extmem );
                DBG ( "EXTMEM allocating [%lx,%lx)\n",
                      user_to_phys ( ptr, 0 ), user_to_phys ( ptr, 0 ) );
                extmem.size = 0;
        }
        extmem.used = ( new_size > 0 );

        /* Expand/shrink block if possible */
        if ( ptr == bottom ) {
                /* Update block */
                if ( new_size > ( heap_size - extmem.size ) ) {
                        DBG ( "EXTMEM out of space\n" );
                        return UNULL;
                }
                new = userptr_add ( ptr, - ( new_size - extmem.size ) );
                align = ( user_to_phys ( new, 0 ) & ( EM_ALIGN - 1 ) );
                new_size += align;
                new = userptr_add ( new, -align );
                DBG ( "EXTMEM expanding [%lx,%lx) to [%lx,%lx)\n",
                      user_to_phys ( ptr, 0 ),
                      user_to_phys ( ptr, extmem.size ),
                      user_to_phys ( new, 0 ),
                      user_to_phys ( new, new_size ));
                memmove_user ( new, 0, ptr, 0, ( ( extmem.size < new_size ) ?
                                                 extmem.size : new_size ) );
                bottom = new;
                heap_size -= ( new_size - extmem.size );
                extmem.size = new_size;
        } else {
                /* Cannot expand; can only pretend to shrink */
                if ( new_size > extmem.size ) {
                        /* Refuse to expand */
                        DBG ( "EXTMEM cannot expand [%lx,%lx)\n",
                              user_to_phys ( ptr, 0 ),
                              user_to_phys ( ptr, extmem.size ) );
                        return UNULL;
                }
        }

        /* Write back block properties */
        copy_to_user ( new, -sizeof ( extmem ), &extmem,
                       sizeof ( extmem ) );

        /* Collect any free blocks and update hidden memory region */
        ecollect_free();
        hide_umalloc ( user_to_phys ( bottom, ( ( bottom == top ) ?
                                                0 : -sizeof ( extmem ) ) ),
                       user_to_phys ( top, 0 ) );

        return ( new_size ? new : UNOWHERE );
}
PROVIDE_UMALLOC ( memtop  ,
urealloc  ,
memtop_urealloc   
)

Variable Documentation

userptr_t top = UNULL [static]
userptr_t bottom = UNULL [static]

Bottom of heap (current lowest allocated block)

Definition at line 62 of file memtop_umalloc.c.

Referenced by bzimage_check_initrds(), ecollect_free(), fbcon_init(), init_eheap(), initrd_reshuffle(), and memtop_urealloc().

size_t heap_size [static]

Remaining space on heap.

Definition at line 65 of file memtop_umalloc.c.

Referenced by ecollect_free(), init_eheap(), and memtop_urealloc().