4 * Very simple linked-list based malloc()/free().
7 #include <syslinux/firmware.h>
14 static struct free_arena_header
*
15 __free_block(struct free_arena_header
*ah
)
17 struct free_arena_header
*pah
, *nah
;
18 struct free_arena_header
*head
=
19 &__core_malloc_head
[ARENA_HEAP_GET(ah
->a
.attrs
)];
23 if ( ARENA_TYPE_GET(pah
->a
.attrs
) == ARENA_TYPE_FREE
&&
24 (char *)pah
+ARENA_SIZE_GET(pah
->a
.attrs
) == (char *)ah
) {
25 /* Coalesce into the previous block */
26 ARENA_SIZE_SET(pah
->a
.attrs
, ARENA_SIZE_GET(pah
->a
.attrs
) +
27 ARENA_SIZE_GET(ah
->a
.attrs
));
32 ARENA_TYPE_SET(ah
->a
.attrs
, ARENA_TYPE_DEAD
);
38 /* Need to add this block to the free chain */
39 ARENA_TYPE_SET(ah
->a
.attrs
, ARENA_TYPE_FREE
);
40 ah
->a
.tag
= MALLOC_FREE
;
42 ah
->next_free
= head
->next_free
;
45 ah
->next_free
->prev_free
= ah
;
48 /* In either of the previous cases, we might be able to merge
49 with the subsequent block... */
50 if ( ARENA_TYPE_GET(nah
->a
.attrs
) == ARENA_TYPE_FREE
&&
51 (char *)ah
+ARENA_SIZE_GET(ah
->a
.attrs
) == (char *)nah
) {
52 ARENA_SIZE_SET(ah
->a
.attrs
, ARENA_SIZE_GET(ah
->a
.attrs
) +
53 ARENA_SIZE_GET(nah
->a
.attrs
));
55 /* Remove the old block from the chains */
56 nah
->next_free
->prev_free
= nah
->prev_free
;
57 nah
->prev_free
->next_free
= nah
->next_free
;
58 ah
->a
.next
= nah
->a
.next
;
59 nah
->a
.next
->a
.prev
= ah
;
62 ARENA_TYPE_SET(nah
->a
.attrs
, ARENA_TYPE_DEAD
);
66 /* Return the block that contains the called block */
70 void bios_free(void *ptr
)
72 struct free_arena_header
*ah
;
74 ah
= (struct free_arena_header
*)
75 ((struct arena_header
*)ptr
- 1);
78 if (ah
->a
.magic
!= ARENA_MAGIC
)
79 dprintf("failed free() magic check: %p\n", ptr
);
81 if (ARENA_TYPE_GET(ah
->a
.attrs
) != ARENA_TYPE_USED
)
82 dprintf("invalid arena type: %d\n", ARENA_TYPE_GET(ah
->a
.attrs
));
88 __export
void free(void *ptr
)
90 dprintf("free(%p) @ %p\n", ptr
, __builtin_return_address(0));
95 sem_down(&__malloc_semaphore
, 0);
96 firmware
->mem
->free(ptr
);
97 sem_up(&__malloc_semaphore
);
99 /* Here we could insert code to return memory to the system. */
103 * This is used to insert a block which is not previously on the
104 * free list. Only the a.size field of the arena header is assumed
107 void __inject_free_block(struct free_arena_header
*ah
)
109 struct free_arena_header
*head
=
110 &__core_malloc_head
[ARENA_HEAP_GET(ah
->a
.attrs
)];
111 struct free_arena_header
*nah
;
112 size_t a_end
= (size_t) ah
+ ARENA_SIZE_GET(ah
->a
.attrs
);
115 dprintf("inject: %#zx bytes @ %p, heap %u (%p)\n",
116 ARENA_SIZE_GET(ah
->a
.attrs
), ah
,
117 ARENA_HEAP_GET(ah
->a
.attrs
), head
);
119 sem_down(&__malloc_semaphore
, 0);
121 for (nah
= head
->a
.next
; nah
!= head
; nah
= nah
->a
.next
) {
122 n_end
= (size_t) nah
+ ARENA_SIZE_GET(nah
->a
.attrs
);
124 /* Is nah entirely beyond this block? */
125 if ((size_t) nah
>= a_end
)
128 /* Is this block entirely beyond nah? */
129 if ((size_t) ah
>= n_end
)
132 printf("conflict:ah: %p, a_end: %p, nah: %p, n_end: %p\n", ah
, a_end
, nah
, n_end
);
134 /* Otherwise we have some sort of overlap - reject this block */
135 sem_up(&__malloc_semaphore
);
139 /* Now, nah should point to the successor block */
141 ah
->a
.prev
= nah
->a
.prev
;
143 ah
->a
.prev
->a
.next
= ah
;
147 sem_up(&__malloc_semaphore
);
151 * Free all memory which is tagged with a specific tag.
153 static void __free_tagged(malloc_tag_t tag
) {
154 struct free_arena_header
*fp
, *head
;
157 sem_down(&__malloc_semaphore
, 0);
159 for (i
= 0; i
< NHEAP
; i
++) {
160 dprintf("__free_tagged(%u) heap %d\n", tag
, i
);
161 head
= &__core_malloc_head
[i
];
162 for (fp
= head
->a
.next
; fp
!= head
; fp
= fp
->a
.next
) {
163 if (ARENA_TYPE_GET(fp
->a
.attrs
) == ARENA_TYPE_USED
&&
165 fp
= __free_block(fp
);
169 sem_up(&__malloc_semaphore
);
170 dprintf("__free_tagged(%u) done\n", tag
);
173 void comboot_cleanup_lowmem(com32sys_t
*regs
)
177 __free_tagged(MALLOC_MODULE
);