iPXE
Data Structures | Macros | 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...
 

Macros

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

Functions

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

Variables

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

Detailed Description

External memory allocation.

Definition in file memtop_umalloc.c.

Macro Definition Documentation

◆ EM_MAX_ADDRESS

#define EM_MAX_ADDRESS   0xffffffffUL

Maximum usable address for external allocated memory.

Definition at line 42 of file memtop_umalloc.c.

◆ EM_ALIGN

#define EM_ALIGN   ( 4 * 1024 )

Alignment of external allocated memory.

Definition at line 45 of file memtop_umalloc.c.

◆ UNOWHERE

#define UNOWHERE   ( ~UNULL )

Equivalent of NOWHERE for user pointers.

Definition at line 48 of file memtop_umalloc.c.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )

◆ largest_memblock()

size_t largest_memblock ( userptr_t start)

Find largest usable memory region.

Return values
startStart of region
lenLength of region

Definition at line 73 of file memtop_umalloc.c.

73  {
74  struct memory_map memmap;
75  struct memory_region *region;
77  physaddr_t region_start;
78  physaddr_t region_end;
79  size_t region_len;
80  unsigned int i;
81  size_t len = 0;
82 
83  /* Avoid returning uninitialised data on error */
84  *start = UNULL;
85 
86  /* Scan through all memory regions */
87  get_memmap ( &memmap );
88  for ( i = 0 ; i < memmap.count ; i++ ) {
89  region = &memmap.regions[i];
90  DBG ( "Considering [%llx,%llx)\n", region->start, region->end );
91 
92  /* Truncate block to maximum physical address */
93  if ( region->start > max ) {
94  DBG ( "...starts after maximum address %lx\n", max );
95  continue;
96  }
97  region_start = region->start;
98  if ( region->end > max ) {
99  DBG ( "...end truncated to maximum address %lx\n", max);
100  region_end = 0; /* =max, given the wraparound */
101  } else {
102  region_end = region->end;
103  }
104  region_len = ( region_end - region_start );
105 
106  /* Use largest block */
107  if ( region_len > len ) {
108  DBG ( "...new best block found\n" );
109  *start = phys_to_user ( region_start );
110  len = region_len;
111  }
112  }
113 
114  return len;
115 }
void get_memmap(struct memory_map *memmap)
Get memory map.
#define max(x, y)
Definition: ath.h:39
userptr_t phys_to_user(unsigned long phys_addr)
Convert physical address to user pointer.
A memory map.
Definition: io.h:499
uint32_t start
Starting offset.
Definition: netvsc.h:12
#define EM_MAX_ADDRESS
Maximum usable address for external allocated memory.
A usable memory region.
Definition: io.h:488
unsigned long physaddr_t
Definition: stdint.h:20
#define UNULL
Equivalent of NULL for user pointers.
Definition: uaccess.h:36
uint32_t len
Length.
Definition: ena.h:14
uint64_t start
Physical start address.
Definition: io.h:490
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
uint64_t end
Physical end address.
Definition: io.h:492

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

Referenced by init_eheap(), and initrd_startup().

◆ init_eheap()

static void init_eheap ( void  )
static

Initialise external heap.

Definition at line 121 of file memtop_umalloc.c.

121  {
122  userptr_t base;
123 
126  DBG ( "External heap grows downwards from %lx (size %zx)\n",
127  user_to_phys ( top, 0 ), heap_size );
128 }
unsigned long user_to_phys(userptr_t userptr, off_t offset)
Convert user pointer to physical address.
static size_t heap_size
Remaining space on heap.
static userptr_t bottom
Bottom of heap (current lowest allocated block)
userptr_t userptr_add(userptr_t userptr, off_t offset)
Add offset to user pointer.
static userptr_t top
Top of heap.
uint16_t base
Base address.
Definition: edd.h:14
size_t largest_memblock(userptr_t *start)
Find largest usable memory region.
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
unsigned long userptr_t
A pointer to a user buffer.
Definition: uaccess.h:33

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

Referenced by memtop_urealloc().

◆ ecollect_free()

static void ecollect_free ( void  )
static

Collect free blocks.

Definition at line 134 of file memtop_umalloc.c.

134  {
135  struct external_memory extmem;
136  size_t len;
137 
138  /* Walk the free list and collect empty blocks */
139  while ( bottom != top ) {
140  copy_from_user ( &extmem, bottom, -sizeof ( extmem ),
141  sizeof ( extmem ) );
142  if ( extmem.used )
143  break;
144  DBG ( "EXTMEM freeing [%lx,%lx)\n", user_to_phys ( bottom, 0 ),
145  user_to_phys ( bottom, extmem.size ) );
146  len = ( extmem.size + sizeof ( extmem ) );
147  bottom = userptr_add ( bottom, len );
148  heap_size += len;
149  }
150 }
static __always_inline void copy_from_user(void *dest, userptr_t src, off_t src_off, size_t len)
Copy data from user buffer.
Definition: uaccess.h:337
unsigned long user_to_phys(userptr_t userptr, off_t offset)
Convert user pointer to physical address.
static size_t heap_size
Remaining space on heap.
static userptr_t bottom
Bottom of heap (current lowest allocated block)
userptr_t userptr_add(userptr_t userptr, off_t offset)
Add offset to user pointer.
An external memory block.
static userptr_t top
Top of heap.
uint32_t len
Length.
Definition: ena.h:14
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498

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().

◆ memtop_urealloc()

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.

162  {
163  struct external_memory extmem;
164  userptr_t new = ptr;
165  size_t align;
166 
167  /* (Re)initialise external memory allocator if necessary */
168  if ( bottom == top )
169  init_eheap();
170 
171  /* Get block properties into extmem */
172  if ( ptr && ( ptr != UNOWHERE ) ) {
173  /* Determine old size */
174  copy_from_user ( &extmem, ptr, -sizeof ( extmem ),
175  sizeof ( extmem ) );
176  } else {
177  /* Create a zero-length block */
178  if ( heap_size < sizeof ( extmem ) ) {
179  DBG ( "EXTMEM out of space\n" );
180  return UNULL;
181  }
182  ptr = bottom = userptr_add ( bottom, -sizeof ( extmem ) );
183  heap_size -= sizeof ( extmem );
184  DBG ( "EXTMEM allocating [%lx,%lx)\n",
185  user_to_phys ( ptr, 0 ), user_to_phys ( ptr, 0 ) );
186  extmem.size = 0;
187  }
188  extmem.used = ( new_size > 0 );
189 
190  /* Expand/shrink block if possible */
191  if ( ptr == bottom ) {
192  /* Update block */
193  if ( new_size > ( heap_size - extmem.size ) ) {
194  DBG ( "EXTMEM out of space\n" );
195  return UNULL;
196  }
197  new = userptr_add ( ptr, - ( new_size - extmem.size ) );
198  align = ( user_to_phys ( new, 0 ) & ( EM_ALIGN - 1 ) );
199  new_size += align;
200  new = userptr_add ( new, -align );
201  DBG ( "EXTMEM expanding [%lx,%lx) to [%lx,%lx)\n",
202  user_to_phys ( ptr, 0 ),
203  user_to_phys ( ptr, extmem.size ),
204  user_to_phys ( new, 0 ),
205  user_to_phys ( new, new_size ));
206  memmove_user ( new, 0, ptr, 0, ( ( extmem.size < new_size ) ?
207  extmem.size : new_size ) );
208  bottom = new;
209  heap_size -= ( new_size - extmem.size );
210  extmem.size = new_size;
211  } else {
212  /* Cannot expand; can only pretend to shrink */
213  if ( new_size > extmem.size ) {
214  /* Refuse to expand */
215  DBG ( "EXTMEM cannot expand [%lx,%lx)\n",
216  user_to_phys ( ptr, 0 ),
217  user_to_phys ( ptr, extmem.size ) );
218  return UNULL;
219  }
220  }
221 
222  /* Write back block properties */
223  copy_to_user ( new, -sizeof ( extmem ), &extmem,
224  sizeof ( extmem ) );
225 
226  /* Collect any free blocks and update hidden memory region */
227  ecollect_free();
228  hide_umalloc ( user_to_phys ( bottom, ( ( bottom == top ) ?
229  0 : -sizeof ( extmem ) ) ),
230  user_to_phys ( top, 0 ) );
231 
232  return ( new_size ? new : UNOWHERE );
233 }
static void init_eheap(void)
Initialise external heap.
void hide_umalloc(physaddr_t start, physaddr_t end)
Hide umalloc() region.
Definition: hidemem.c:119
static __always_inline void copy_from_user(void *dest, userptr_t src, off_t src_off, size_t len)
Copy data from user buffer.
Definition: uaccess.h:337
unsigned long user_to_phys(userptr_t userptr, off_t offset)
Convert user pointer to physical address.
static size_t heap_size
Remaining space on heap.
static userptr_t bottom
Bottom of heap (current lowest allocated block)
userptr_t userptr_add(userptr_t userptr, off_t offset)
Add offset to user pointer.
An external memory block.
static userptr_t top
Top of heap.
static __always_inline void copy_to_user(userptr_t dest, off_t dest_off, const void *src, size_t len)
Copy data to user buffer.
Definition: uaccess.h:324
#define EM_ALIGN
Alignment of external allocated memory.
#define UNOWHERE
Equivalent of NOWHERE for user pointers.
#define UNULL
Equivalent of NULL for user pointers.
Definition: uaccess.h:36
void memmove_user(userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, size_t len)
Copy data between user buffers, allowing for overlap.
static void ecollect_free(void)
Collect free blocks.
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
unsigned long userptr_t
A pointer to a user buffer.
Definition: uaccess.h:33

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().

◆ PROVIDE_UMALLOC()

PROVIDE_UMALLOC ( memtop  ,
urealloc  ,
memtop_urealloc   
)

Variable Documentation

◆ __attribute__

◆ top

userptr_t top = UNULL
static

◆ bottom

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(), initrd_reshuffle_check(), and memtop_urealloc().

◆ heap_size

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().