memtop_umalloc.c File Reference

External memory allocation. More...

#include <limits.h>
#include <errno.h>
#include <gpxe/uaccess.h>
#include <gpxe/hidemem.h>
#include <gpxe/memmap.h>
#include <gpxe/umalloc.h>

Go to the source code of this file.

Data Structures

struct  external_memory
 An external memory block. More...

Defines

#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)
static int 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

static userptr_t top = UNULL
 Top of heap.
static userptr_t bottom = UNULL
 Bottom of heap (current lowest allocated block).


Detailed Description

External memory allocation.

Definition in file memtop_umalloc.c.


Define Documentation

#define EM_ALIGN   ( 4 * 1024 )

Alignment of external allocated memory.

Definition at line 36 of file memtop_umalloc.c.

Referenced by memtop_urealloc().

#define UNOWHERE   ( ~UNULL )

Equivalent of NOWHERE for user pointers.

Definition at line 39 of file memtop_umalloc.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER   ) 

static int init_eheap ( void   )  [static]

Initialise external heap.

Return values:
rc Return status code

Definition at line 60 of file memtop_umalloc.c.

References bottom, memory_map::count, DBG, memory_region::end, ENOMEM, get_memmap(), phys_to_user(), memory_map::regions, memory_region::start, top, UINT_MAX, and user_to_phys().

Referenced by memtop_urealloc().

00060                                {
00061         struct memory_map memmap;
00062         unsigned long heap_size = 0;
00063         unsigned int i;
00064 
00065         DBG ( "Allocating external heap\n" );
00066 
00067         get_memmap ( &memmap );
00068         for ( i = 0 ; i < memmap.count ; i++ ) {
00069                 struct memory_region *region = &memmap.regions[i];
00070                 unsigned long r_start, r_end;
00071                 unsigned long r_size;
00072 
00073                 DBG ( "Considering [%llx,%llx)\n", region->start, region->end);
00074 
00075                 /* Truncate block to 4GB */
00076                 if ( region->start > UINT_MAX ) {
00077                         DBG ( "...starts after 4GB\n" );
00078                         continue;
00079                 }
00080                 r_start = region->start;
00081                 if ( region->end > UINT_MAX ) {
00082                         DBG ( "...end truncated to 4GB\n" );
00083                         r_end = 0; /* =4GB, given the wraparound */
00084                 } else {
00085                         r_end = region->end;
00086                 }
00087 
00088                 /* Use largest block */
00089                 r_size = ( r_end - r_start );
00090                 if ( r_size > heap_size ) {
00091                         DBG ( "...new best block found\n" );
00092                         top = bottom = phys_to_user ( r_end );
00093                         heap_size = r_size;
00094                 }
00095         }
00096 
00097         if ( ! heap_size ) {
00098                 DBG ( "No external heap available\n" );
00099                 return -ENOMEM;
00100         }
00101 
00102         DBG ( "External heap grows downwards from %lx\n",
00103               user_to_phys ( top, 0 ) );
00104         return 0;
00105 }

static void ecollect_free ( void   )  [static]

Collect free blocks.

Definition at line 111 of file memtop_umalloc.c.

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

Referenced by memtop_urealloc().

00111                                    {
00112         struct external_memory extmem;
00113 
00114         /* Walk the free list and collect empty blocks */
00115         while ( bottom != top ) {
00116                 copy_from_user ( &extmem, bottom, -sizeof ( extmem ),
00117                                  sizeof ( extmem ) );
00118                 if ( extmem.used )
00119                         break;
00120                 DBG ( "EXTMEM freeing [%lx,%lx)\n", user_to_phys ( bottom, 0 ),
00121                       user_to_phys ( bottom, extmem.size ) );
00122                 bottom = userptr_add ( bottom,
00123                                        ( extmem.size + sizeof ( extmem ) ) );
00124         }
00125 }

static userptr_t memtop_urealloc ( userptr_t  ptr,
size_t  new_size 
) [static]

Reallocate external memory.

Parameters:
old_ptr Memory previously allocated by umalloc(), or UNULL
new_size Requested size
Return values:
new_ptr Allocated memory, or UNULL
Calling realloc() with a new size of zero is a valid way to free a memory block.

Definition at line 137 of file memtop_umalloc.c.

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

00137                                                                     {
00138         struct external_memory extmem;
00139         userptr_t new = ptr;
00140         size_t align;
00141         int rc;
00142 
00143         /* Initialise external memory allocator if necessary */
00144         if ( bottom == top ) {
00145                 if ( ( rc = init_eheap() ) != 0 )
00146                         return UNULL;
00147         }
00148 
00149         /* Get block properties into extmem */
00150         if ( ptr && ( ptr != UNOWHERE ) ) {
00151                 /* Determine old size */
00152                 copy_from_user ( &extmem, ptr, -sizeof ( extmem ),
00153                                  sizeof ( extmem ) );
00154         } else {
00155                 /* Create a zero-length block */
00156                 ptr = bottom = userptr_add ( bottom, -sizeof ( extmem ) );
00157                 DBG ( "EXTMEM allocating [%lx,%lx)\n",
00158                       user_to_phys ( ptr, 0 ), user_to_phys ( ptr, 0 ) );
00159                 extmem.size = 0;
00160         }
00161         extmem.used = ( new_size > 0 );
00162 
00163         /* Expand/shrink block if possible */
00164         if ( ptr == bottom ) {
00165                 /* Update block */
00166                 new = userptr_add ( ptr, - ( new_size - extmem.size ) );
00167                 align = ( user_to_phys ( new, 0 ) & ( EM_ALIGN - 1 ) );
00168                 new_size += align;
00169                 new = userptr_add ( new, -align );
00170                 DBG ( "EXTMEM expanding [%lx,%lx) to [%lx,%lx)\n",
00171                       user_to_phys ( ptr, 0 ),
00172                       user_to_phys ( ptr, extmem.size ),
00173                       user_to_phys ( new, 0 ),
00174                       user_to_phys ( new, new_size ));
00175                 memmove_user ( new, 0, ptr, 0, ( ( extmem.size < new_size ) ?
00176                                                  extmem.size : new_size ) );
00177                 extmem.size = new_size;
00178                 bottom = new;
00179         } else {
00180                 /* Cannot expand; can only pretend to shrink */
00181                 if ( new_size > extmem.size ) {
00182                         /* Refuse to expand */
00183                         DBG ( "EXTMEM cannot expand [%lx,%lx)\n",
00184                               user_to_phys ( ptr, 0 ),
00185                               user_to_phys ( ptr, extmem.size ) );
00186                         return UNULL;
00187                 }
00188         }
00189 
00190         /* Write back block properties */
00191         copy_to_user ( new, -sizeof ( extmem ), &extmem,
00192                        sizeof ( extmem ) );
00193 
00194         /* Collect any free blocks and update hidden memory region */
00195         ecollect_free();
00196         hide_umalloc ( user_to_phys ( bottom, -sizeof ( extmem ) ),
00197                        user_to_phys ( top, 0 ) );
00198 
00199         return ( new_size ? new : UNOWHERE );
00200 }

PROVIDE_UMALLOC ( memtop  ,
urealloc  ,
memtop_urealloc   
)


Variable Documentation

userptr_t top = UNULL [static]

Top of heap.

Definition at line 50 of file memtop_umalloc.c.

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

userptr_t bottom = UNULL [static]

Bottom of heap (current lowest allocated block).

Definition at line 53 of file memtop_umalloc.c.

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


Generated on Tue Apr 6 20:01:13 2010 for gPXE by  doxygen 1.5.7.1