Add memtest support.
[syslinux-debian/hramrach.git] / core / mem / free.c
blob2d16cd1c703e21a12974fb976cf3e3d6bd58d5a9
1 /*
2 * free.c
4 * Very simple linked-list based malloc()/free().
5 */
7 #include <syslinux/firmware.h>
8 #include <stdlib.h>
9 #include <dprintf.h>
10 #include "malloc.h"
12 #include <stdio.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)];
21 pah = ah->a.prev;
22 nah = ah->a.next;
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));
28 pah->a.next = nah;
29 nah->a.prev = pah;
31 #ifdef DEBUG_MALLOC
32 ARENA_TYPE_SET(ah->a.attrs, ARENA_TYPE_DEAD);
33 #endif
35 ah = pah;
36 pah = ah->a.prev;
37 } else {
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;
43 ah->prev_free = head;
44 head->next_free = ah;
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;
61 #ifdef DEBUG_MALLOC
62 ARENA_TYPE_SET(nah->a.attrs, ARENA_TYPE_DEAD);
63 #endif
66 /* Return the block that contains the called block */
67 return ah;
70 void bios_free(void *ptr)
72 struct free_arena_header *ah;
74 ah = (struct free_arena_header *)
75 ((struct arena_header *)ptr - 1);
77 #ifdef DEBUG_MALLOC
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));
83 #endif
85 __free_block(ah);
88 __export void free(void *ptr)
90 dprintf("free(%p) @ %p\n", ptr, __builtin_return_address(0));
92 if ( !ptr )
93 return;
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
105 * to be valid.
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);
113 size_t n_end;
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)
126 break;
128 /* Is this block entirely beyond nah? */
129 if ((size_t) ah >= n_end)
130 continue;
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);
136 return;
139 /* Now, nah should point to the successor block */
140 ah->a.next = nah;
141 ah->a.prev = nah->a.prev;
142 nah->a.prev = ah;
143 ah->a.prev->a.next = ah;
145 __free_block(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;
155 int i;
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 &&
164 fp->a.tag == tag)
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)
175 (void)regs;
177 __free_tagged(MALLOC_MODULE);