00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020
00021 #include <stddef.h>
00022 #include <stdint.h>
00023 #include <string.h>
00024 #include <strings.h>
00025 #include <gpxe/io.h>
00026 #include <gpxe/list.h>
00027 #include <gpxe/init.h>
00028 #include <gpxe/malloc.h>
00029
00030
00031
00032
00033
00034
00035
00036
00037 struct memory_block {
00038
00039 struct list_head list;
00040
00041 size_t size;
00042 };
00043
00044 #define MIN_MEMBLOCK_SIZE \
00045 ( ( size_t ) ( 1 << ( fls ( sizeof ( struct memory_block ) - 1 ) ) ) )
00046
00047
00048 struct autosized_block {
00049
00050 size_t size;
00051
00052 char data[0];
00053 };
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070 #define NOWHERE ( ( void * ) ~( ( intptr_t ) 0 ) )
00071
00072
00073 static LIST_HEAD ( free_blocks );
00074
00075
00076 size_t freemem;
00077
00078
00079
00080
00081
00082
00083 #define HEAP_SIZE ( 128 * 1024 )
00084
00085
00086 static char heap[HEAP_SIZE] __attribute__ (( aligned ( __alignof__(void *) )));
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 void * alloc_memblock ( size_t size, size_t align ) {
00101 struct memory_block *block;
00102 size_t align_mask;
00103 size_t pre_size;
00104 ssize_t post_size;
00105 struct memory_block *pre;
00106 struct memory_block *post;
00107
00108
00109
00110
00111 size = ( size + MIN_MEMBLOCK_SIZE - 1 ) & ~( MIN_MEMBLOCK_SIZE - 1 );
00112 align_mask = ( align - 1 ) | ( MIN_MEMBLOCK_SIZE - 1 );
00113
00114 DBG ( "Allocating %#zx (aligned %#zx)\n", size, align );
00115
00116
00117 list_for_each_entry ( block, &free_blocks, list ) {
00118 pre_size = ( - virt_to_phys ( block ) ) & align_mask;
00119 post_size = block->size - pre_size - size;
00120 if ( post_size >= 0 ) {
00121
00122
00123
00124
00125
00126 pre = block;
00127 block = ( ( ( void * ) pre ) + pre_size );
00128 post = ( ( ( void * ) block ) + size );
00129 DBG ( "[%p,%p) -> [%p,%p) + [%p,%p)\n", pre,
00130 ( ( ( void * ) pre ) + pre->size ), pre, block,
00131 post, ( ( ( void * ) pre ) + pre->size ) );
00132
00133
00134
00135
00136
00137 if ( ( size_t ) post_size >= MIN_MEMBLOCK_SIZE ) {
00138 post->size = post_size;
00139 list_add ( &post->list, &pre->list );
00140 }
00141
00142
00143
00144
00145 pre->size = pre_size;
00146
00147
00148
00149
00150
00151 if ( pre_size < MIN_MEMBLOCK_SIZE )
00152 list_del ( &pre->list );
00153
00154 freemem -= size;
00155
00156 DBG ( "Allocated [%p,%p)\n", block,
00157 ( ( ( void * ) block ) + size ) );
00158 return block;
00159 }
00160 }
00161
00162 DBG ( "Failed to allocate %#zx (aligned %#zx)\n", size, align );
00163 return NULL;
00164 }
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174 void free_memblock ( void *ptr, size_t size ) {
00175 struct memory_block *freeing;
00176 struct memory_block *block;
00177 ssize_t gap_before;
00178 ssize_t gap_after = -1;
00179
00180
00181 if ( ! ptr )
00182 return;
00183
00184
00185
00186
00187 size = ( size + MIN_MEMBLOCK_SIZE - 1 ) & ~( MIN_MEMBLOCK_SIZE - 1 );
00188 freeing = ptr;
00189 freeing->size = size;
00190 DBG ( "Freeing [%p,%p)\n", freeing, ( ( ( void * ) freeing ) + size ));
00191
00192
00193 list_for_each_entry ( block, &free_blocks, list ) {
00194
00195 gap_before = ( ( ( void * ) freeing ) -
00196 ( ( ( void * ) block ) + block->size ) );
00197 gap_after = ( ( ( void * ) block ) -
00198 ( ( ( void * ) freeing ) + freeing->size ) );
00199
00200 if ( gap_before == 0 ) {
00201 DBG ( "[%p,%p) + [%p,%p) -> [%p,%p)\n", block,
00202 ( ( ( void * ) block ) + block->size ), freeing,
00203 ( ( ( void * ) freeing ) + freeing->size ),block,
00204 ( ( ( void * ) freeing ) + freeing->size ) );
00205 block->size += size;
00206 list_del ( &block->list );
00207 freeing = block;
00208 }
00209
00210 if ( gap_after >= 0 )
00211 break;
00212 }
00213
00214
00215
00216
00217
00218 DBG ( "[%p,%p)\n", freeing, ( ( ( void * ) freeing ) + freeing->size));
00219 list_add_tail ( &freeing->list, &block->list );
00220 if ( gap_after == 0 ) {
00221 DBG ( "[%p,%p) + [%p,%p) -> [%p,%p)\n", freeing,
00222 ( ( ( void * ) freeing ) + freeing->size ), block,
00223 ( ( ( void * ) block ) + block->size ), freeing,
00224 ( ( ( void * ) block ) + block->size ) );
00225 freeing->size += block->size;
00226 list_del ( &block->list );
00227 }
00228
00229
00230 freemem += size;
00231 }
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253 void * realloc ( void *old_ptr, size_t new_size ) {
00254 struct autosized_block *old_block;
00255 struct autosized_block *new_block;
00256 size_t old_total_size;
00257 size_t new_total_size;
00258 size_t old_size;
00259 void *new_ptr = NOWHERE;
00260
00261
00262
00263
00264 if ( new_size ) {
00265 new_total_size = ( new_size +
00266 offsetof ( struct autosized_block, data ) );
00267 new_block = alloc_memblock ( new_total_size, 1 );
00268 if ( ! new_block )
00269 return NULL;
00270 new_block->size = new_total_size;
00271 new_ptr = &new_block->data;
00272 }
00273
00274
00275
00276
00277
00278
00279 if ( old_ptr && ( old_ptr != NOWHERE ) ) {
00280 old_block = container_of ( old_ptr, struct autosized_block,
00281 data );
00282 old_total_size = old_block->size;
00283 old_size = ( old_total_size -
00284 offsetof ( struct autosized_block, data ) );
00285 memcpy ( new_ptr, old_ptr,
00286 ( ( old_size < new_size ) ? old_size : new_size ) );
00287 free_memblock ( old_block, old_total_size );
00288 }
00289
00290 return new_ptr;
00291 }
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 void * malloc ( size_t size ) {
00303 return realloc ( NULL, size );
00304 }
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316 void free ( void *ptr ) {
00317 realloc ( ptr, 0 );
00318 }
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331 void * zalloc ( size_t size ) {
00332 void *data;
00333
00334 data = malloc ( size );
00335 if ( data )
00336 memset ( data, 0, size );
00337 return data;
00338 }
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351 void mpopulate ( void *start, size_t len ) {
00352
00353
00354
00355 free_memblock ( start, ( len & ~( MIN_MEMBLOCK_SIZE - 1 ) ) );
00356 }
00357
00358
00359
00360
00361
00362 static void init_heap ( void ) {
00363 mpopulate ( heap, sizeof ( heap ) );
00364 }
00365
00366
00367 struct init_fn heap_init_fn __init_fn ( INIT_EARLY ) = {
00368 .initialise = init_heap,
00369 };
00370
00371 #if 0
00372 #include <stdio.h>
00373
00374
00375
00376
00377 void mdumpfree ( void ) {
00378 struct memory_block *block;
00379
00380 printf ( "Free block list:\n" );
00381 list_for_each_entry ( block, &free_blocks, list ) {
00382 printf ( "[%p,%p] (size %#zx)\n", block,
00383 ( ( ( void * ) block ) + block->size ), block->size );
00384 }
00385 }
00386 #endif