4 * Very simple linked-list based malloc()/free().
7 #include <syslinux/firmware.h>
18 DECLARE_INIT_SEMAPHORE(__malloc_semaphore
, 1);
20 static void *__malloc_from_block(struct free_arena_header
*fp
,
21 size_t size
, malloc_tag_t tag
)
24 struct free_arena_header
*nfp
, *na
;
25 unsigned int heap
= ARENA_HEAP_GET(fp
->a
.attrs
);
27 fsize
= ARENA_SIZE_GET(fp
->a
.attrs
);
29 /* We need the 2* to account for the larger requirements of a free block */
30 if ( fsize
>= size
+2*sizeof(struct arena_header
) ) {
31 /* Bigger block than required -- split block */
32 nfp
= (struct free_arena_header
*)((char *)fp
+ size
);
35 ARENA_TYPE_SET(nfp
->a
.attrs
, ARENA_TYPE_FREE
);
36 ARENA_HEAP_SET(nfp
->a
.attrs
, heap
);
37 ARENA_SIZE_SET(nfp
->a
.attrs
, fsize
-size
);
38 nfp
->a
.tag
= MALLOC_FREE
;
40 nfp
->a
.magic
= ARENA_MAGIC
;
42 ARENA_TYPE_SET(fp
->a
.attrs
, ARENA_TYPE_USED
);
43 ARENA_SIZE_SET(fp
->a
.attrs
, size
);
46 /* Insert into all-block chain */
52 /* Replace current block on free chain */
53 nfp
->next_free
= fp
->next_free
;
54 nfp
->prev_free
= fp
->prev_free
;
55 fp
->next_free
->prev_free
= nfp
;
56 fp
->prev_free
->next_free
= nfp
;
58 /* Allocate the whole block */
59 ARENA_TYPE_SET(fp
->a
.attrs
, ARENA_TYPE_USED
);
62 /* Remove from free chain */
63 fp
->next_free
->prev_free
= fp
->prev_free
;
64 fp
->prev_free
->next_free
= fp
->next_free
;
67 return (void *)(&fp
->a
+ 1);
70 void *bios_malloc(size_t size
, enum heap heap
, malloc_tag_t tag
)
72 struct free_arena_header
*fp
;
73 struct free_arena_header
*head
= &__core_malloc_head
[heap
];
77 /* Add the obligatory arena header, and round up */
78 size
= (size
+ 2 * sizeof(struct arena_header
) - 1) & ARENA_SIZE_MASK
;
80 for ( fp
= head
->next_free
; fp
!= head
; fp
= fp
->next_free
) {
81 if ( ARENA_SIZE_GET(fp
->a
.attrs
) >= size
) {
82 /* Found fit -- allocate out of this block */
83 p
= __malloc_from_block(fp
, size
, tag
);
92 static void *_malloc(size_t size
, enum heap heap
, malloc_tag_t tag
)
96 dprintf("_malloc(%zu, %u, %u) @ %p = ",
97 size
, heap
, tag
, __builtin_return_address(0));
99 sem_down(&__malloc_semaphore
, 0);
100 p
= firmware
->mem
->malloc(size
, heap
, tag
);
101 sem_up(&__malloc_semaphore
);
107 __export
void *malloc(size_t size
)
109 return _malloc(size
, HEAP_MAIN
, MALLOC_CORE
);
112 __export
void *lmalloc(size_t size
)
116 p
= _malloc(size
, HEAP_LOWMEM
, MALLOC_CORE
);
122 void *pmapi_lmalloc(size_t size
)
124 return _malloc(size
, HEAP_LOWMEM
, MALLOC_MODULE
);
127 void *bios_realloc(void *ptr
, size_t size
)
129 struct free_arena_header
*ah
, *nah
;
130 struct free_arena_header
*head
;
133 size_t newsize
, oldsize
, xsize
;
143 ah
= (struct free_arena_header
*)
144 ((struct arena_header
*)ptr
- 1);
146 head
= &__core_malloc_head
[ARENA_HEAP_GET(ah
->a
.attrs
)];
149 if (ah
->a
.magic
!= ARENA_MAGIC
)
150 dprintf("failed realloc() magic check: %p\n", ptr
);
153 /* Actual size of the old block */
154 //oldsize = ah->a.size;
155 oldsize
= ARENA_SIZE_GET(ah
->a
.attrs
);
157 /* Add the obligatory arena header, and round up */
158 newsize
= (size
+ 2 * sizeof(struct arena_header
) - 1) & ARENA_SIZE_MASK
;
160 if (oldsize
>= newsize
&& newsize
>= (oldsize
>> 2) &&
161 oldsize
- newsize
< 4096) {
162 /* This allocation is close enough already. */
168 if ((char *)nah
== (char *)ah
+ ARENA_SIZE_GET(ah
->a
.attrs
) &&
169 ARENA_TYPE_GET(nah
->a
.attrs
) == ARENA_TYPE_FREE
&&
170 ARENA_SIZE_GET(nah
->a
.attrs
) + oldsize
>= newsize
) {
171 //nah->a.type == ARENA_TYPE_FREE &&
172 //oldsize + nah->a.size >= newsize) {
173 /* Merge in subsequent free block */
174 ah
->a
.next
= nah
->a
.next
;
175 ah
->a
.next
->a
.prev
= ah
;
176 nah
->next_free
->prev_free
= nah
->prev_free
;
177 nah
->prev_free
->next_free
= nah
->next_free
;
178 ARENA_SIZE_SET(ah
->a
.attrs
, ARENA_SIZE_GET(ah
->a
.attrs
) +
179 ARENA_SIZE_GET(nah
->a
.attrs
));
180 xsize
= ARENA_SIZE_GET(ah
->a
.attrs
);
183 if (xsize
>= newsize
) {
184 /* We can reallocate in place */
185 if (xsize
>= newsize
+ 2 * sizeof(struct arena_header
)) {
186 /* Residual free block at end */
187 nah
= (struct free_arena_header
*)((char *)ah
+ newsize
);
188 ARENA_TYPE_SET(nah
->a
.attrs
, ARENA_TYPE_FREE
);
189 ARENA_SIZE_SET(nah
->a
.attrs
, xsize
- newsize
);
190 ARENA_SIZE_SET(ah
->a
.attrs
, newsize
);
191 ARENA_HEAP_SET(nah
->a
.attrs
, ARENA_HEAP_GET(ah
->a
.attrs
));
194 nah
->a
.magic
= ARENA_MAGIC
;
197 //nah->a.type = ARENA_TYPE_FREE;
198 //nah->a.size = xsize - newsize;
199 //ah->a.size = newsize;
201 /* Insert into block list */
202 nah
->a
.next
= ah
->a
.next
;
204 nah
->a
.next
->a
.prev
= nah
;
207 /* Insert into free list */
208 if (newsize
> oldsize
) {
209 /* Hack: this free block is in the path of a memory object
210 which has already been grown at least once. As such, put
211 it at the *end* of the freelist instead of the beginning;
212 trying to save it for future realloc()s of the same block. */
213 nah
->prev_free
= head
->prev_free
;
214 nah
->next_free
= head
;
215 head
->prev_free
= nah
;
216 nah
->prev_free
->next_free
= nah
;
218 nah
->next_free
= head
->next_free
;
219 nah
->prev_free
= head
;
220 head
->next_free
= nah
;
221 nah
->next_free
->prev_free
= nah
;
224 /* otherwise, use up the whole block */
227 /* Last resort: need to allocate a new block and copy */
228 oldsize
-= sizeof(struct arena_header
);
229 newptr
= malloc(size
);
231 memcpy(newptr
, ptr
, min(size
, oldsize
));
239 __export
void *realloc(void *ptr
, size_t size
)
241 return firmware
->mem
->realloc(ptr
, size
);
244 __export
void *zalloc(size_t size
)
250 memset(ptr
, 0, size
);