14
14
* You should have received a copy of the GNU General Public License
15
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
20
FILE_LICENCE ( GPL2_OR_LATER );
30
31
#include <ipxe/uaccess.h>
31
32
#include <ipxe/hidemem.h>
32
33
#include <ipxe/io.h>
34
#include <ipxe/memblock.h>
33
35
#include <ipxe/umalloc.h>
35
37
/** Alignment of external allocated memory */
52
54
/** Bottom of heap (current lowest allocated block) */
53
55
static userptr_t bottom = UNULL;
57
/** Remaining space on heap */
58
static size_t heap_size;
56
61
* Initialise external heap
58
* @ret rc Return status code
60
static int init_eheap ( void ) {
61
struct memory_map memmap;
62
unsigned long heap_size = 0;
65
DBG ( "Allocating external heap\n" );
67
get_memmap ( &memmap );
68
for ( i = 0 ; i < memmap.count ; i++ ) {
69
struct memory_region *region = &memmap.regions[i];
70
unsigned long r_start, r_end;
73
DBG ( "Considering [%llx,%llx)\n", region->start, region->end);
75
/* Truncate block to 4GB */
76
if ( region->start > UINT_MAX ) {
77
DBG ( "...starts after 4GB\n" );
80
r_start = region->start;
81
if ( region->end > UINT_MAX ) {
82
DBG ( "...end truncated to 4GB\n" );
83
r_end = 0; /* =4GB, given the wraparound */
88
/* Use largest block */
89
r_size = ( r_end - r_start );
90
if ( r_size > heap_size ) {
91
DBG ( "...new best block found\n" );
92
top = bottom = phys_to_user ( r_end );
98
DBG ( "No external heap available\n" );
102
DBG ( "External heap grows downwards from %lx\n",
103
user_to_phys ( top, 0 ) );
64
static void init_eheap ( void ) {
67
heap_size = largest_memblock ( &base );
68
bottom = top = userptr_add ( base, heap_size );
69
DBG ( "External heap grows downwards from %lx (size %zx)\n",
70
user_to_phys ( top, 0 ), heap_size );
120
87
DBG ( "EXTMEM freeing [%lx,%lx)\n", user_to_phys ( bottom, 0 ),
121
88
user_to_phys ( bottom, extmem.size ) );
122
bottom = userptr_add ( bottom,
123
( extmem.size + sizeof ( extmem ) ) );
89
len = ( extmem.size + sizeof ( extmem ) );
90
bottom = userptr_add ( bottom, len );
138
106
struct external_memory extmem;
139
107
userptr_t new = ptr;
143
/* Initialise external memory allocator if necessary */
144
if ( bottom == top ) {
145
if ( ( rc = init_eheap() ) != 0 )
110
/* (Re)initialise external memory allocator if necessary */
149
114
/* Get block properties into extmem */
150
115
if ( ptr && ( ptr != UNOWHERE ) ) {
153
118
sizeof ( extmem ) );
155
120
/* Create a zero-length block */
121
if ( heap_size < sizeof ( extmem ) ) {
122
DBG ( "EXTMEM out of space\n" );
156
125
ptr = bottom = userptr_add ( bottom, -sizeof ( extmem ) );
126
heap_size -= sizeof ( extmem );
157
127
DBG ( "EXTMEM allocating [%lx,%lx)\n",
158
128
user_to_phys ( ptr, 0 ), user_to_phys ( ptr, 0 ) );
163
133
/* Expand/shrink block if possible */
164
134
if ( ptr == bottom ) {
165
135
/* Update block */
136
if ( new_size > ( heap_size - extmem.size ) ) {
137
DBG ( "EXTMEM out of space\n" );
166
140
new = userptr_add ( ptr, - ( new_size - extmem.size ) );
167
141
align = ( user_to_phys ( new, 0 ) & ( EM_ALIGN - 1 ) );
168
142
new_size += align;
174
148
user_to_phys ( new, new_size ));
175
149
memmove_user ( new, 0, ptr, 0, ( ( extmem.size < new_size ) ?
176
150
extmem.size : new_size ) );
152
heap_size -= ( new_size - extmem.size );
177
153
extmem.size = new_size;
180
155
/* Cannot expand; can only pretend to shrink */
181
156
if ( new_size > extmem.size ) {
194
169
/* Collect any free blocks and update hidden memory region */
196
hide_umalloc ( user_to_phys ( bottom, -sizeof ( extmem ) ),
171
hide_umalloc ( user_to_phys ( bottom, ( ( bottom == top ) ?
172
0 : -sizeof ( extmem ) ) ),
197
173
user_to_phys ( top, 0 ) );
199
175
return ( new_size ? new : UNOWHERE );