2 * AcessOS Microkernel Version
13 #define HEAP_INIT_SIZE 0x8000 // 32 KiB
14 #define BLOCK_SIZE (sizeof(void*))*8 // 8 Machine Words
15 #define COMPACT_HEAP 0 // Use 4 byte header?
18 #define MAGIC_FOOT 0x2ACE5505
19 #define MAGIC_FREE 0xACE55000
20 #define MAGIC_USED 0x862B0505 // MAGIC_FOOT ^ MAGIC_FREE
23 void Heap_Install(void);
24 void *Heap_Extend(int Bytes);
25 void *Heap_Merge(tHeapHead *Head);
26 void *malloc(size_t Bytes);
36 void Heap_Install(void)
38 gHeapStart = (void*)MM_KHEAP_BASE;
39 gHeapEnd = (void*)MM_KHEAP_BASE;
40 Heap_Extend(HEAP_INIT_SIZE);
44 * \fn void *Heap_Extend(int Bytes)
45 * \brief Extend the size of the heap
47 void *Heap_Extend(int Bytes)
50 tHeapHead *head = gHeapEnd;
54 if( (tVAddr)gHeapEnd == MM_KHEAP_MAX )
58 if( (tVAddr)gHeapEnd + ((Bytes+0xFFF)&~0xFFF) > MM_KHEAP_MAX ) {
59 Bytes = MM_KHEAP_MAX - (tVAddr)gHeapEnd;
63 // Heap expands in pages
64 for(i=0;i<(Bytes+0xFFF)>>12;i++)
65 MM_Allocate( (tVAddr)gHeapEnd+(i<<12) );
71 head->Size = (Bytes+0xFFF)&~0xFFF;
72 head->Magic = MAGIC_FREE;
73 foot = (void*)( (Uint)gHeapEnd - sizeof(tHeapFoot) );
75 foot->Magic = MAGIC_FOOT;
77 return Heap_Merge(head); // Merge with previous block
81 * \fn void *Heap_Merge(tHeapHead *Head)
82 * \brief Merges two ajacent heap blocks
84 void *Heap_Merge(tHeapHead *Head)
90 //Log("Heap_Merge: (Head=%p)", Head);
92 thisFoot = (void*)( (Uint)Head + Head->Size - sizeof(tHeapFoot) );
93 if((Uint)thisFoot > (Uint)gHeapEnd) return NULL;
96 foot = (void*)( (Uint)Head - sizeof(tHeapFoot) );
97 if( ((Uint)foot < (Uint)gHeapEnd && (Uint)foot > (Uint)gHeapStart)
98 && foot->Head->Magic == MAGIC_FREE) {
99 foot->Head->Size += Head->Size; // Increase size
100 thisFoot->Head = foot->Head; // Change backlink
101 Head->Magic = 0; // Clear old head
103 Head = foot->Head; // Save new head address
104 foot->Head = NULL; // Clear central footer
108 // Merge Right (Upwards)
109 head = (void*)( (Uint)Head + Head->Size );
110 if((Uint)head < (Uint)gHeapEnd && head->Magic == MAGIC_FREE)
112 Head->Size += head->Size;
113 foot = (void*)( (Uint)Head + Head->Size - sizeof(tHeapFoot) );
114 foot->Head = Head; // Update Backlink
115 thisFoot->Head = NULL; // Clear old footer
117 head->Size = 0; // Clear old header
121 // Return new address
126 * \fn void *malloc(size_t Bytes)
127 * \brief Allocate memory from the heap
129 void *malloc(size_t Bytes)
131 tHeapHead *head, *newhead;
132 tHeapFoot *foot, *newfoot;
133 tHeapHead *best = NULL;
134 Uint bestSize = 0; // Speed hack
137 Bytes = (Bytes + sizeof(tHeapHead) + sizeof(tHeapFoot) + BLOCK_SIZE-1) & ~(BLOCK_SIZE-1);
140 // Debug("glHeap = %i", glHeap);
145 for( head = gHeapStart;
146 (Uint)head < (Uint)gHeapEnd;
147 head = (void*)((Uint)head + head->Size)
151 if( head->Size & (BLOCK_SIZE-1) ) {
152 RELEASE(&glHeap); // Release spinlock
154 Log_Warning("Heap", "Size of heap address %p is invalid not aligned (0x%x)", head, head->Size);
160 // Check if allocated
161 if(head->Magic == MAGIC_USED) continue;
163 if(head->Magic != MAGIC_FREE) {
164 RELEASE(&glHeap); // Release spinlock
166 Log_Warning("Heap", "Magic of heap address %p is invalid (0x%x)", head, head->Magic);
173 if(head->Size < Bytes) continue;
176 if(head->Size == Bytes) {
177 head->Magic = MAGIC_USED;
178 RELEASE(&glHeap); // Release spinlock
180 Log("[Heap ] Malloc'd %p (%i bytes), returning to %p", head->Data, head->Size, __builtin_return_address(0));
188 bestSize = head->Size;
191 // or check if the block is the best size
192 if(bestSize > head->Size) {
194 bestSize = head->Size;
199 // If no block large enough is found, create one
202 best = Heap_Extend( Bytes );
205 RELEASE(&glHeap); // Release spinlock
209 if(best->Size == Bytes) {
210 best->Magic = MAGIC_USED; // Mark block as used
211 RELEASE(&glHeap); // Release spinlock
213 Log("[Heap ] Malloc'd %p (%i bytes), returning to %p", best->Data, best->Size, __builtin_return_address(0));
220 newhead = (void*)( (Uint)best + Bytes );
221 newfoot = (void*)( (Uint)best + Bytes - sizeof(tHeapFoot) );
222 foot = (void*)( (Uint)best + best->Size - sizeof(tHeapFoot) );
224 newfoot->Head = best; // Create new footer
225 newfoot->Magic = MAGIC_FOOT;
226 newhead->Size = best->Size - Bytes; // Create new header
227 newhead->Magic = MAGIC_FREE;
228 foot->Head = newhead; // Update backlink in old footer
229 best->Size = Bytes; // Update size in old header
230 best->Magic = MAGIC_USED; // Mark block as used
232 RELEASE(&glHeap); // Release spinlock
234 Log("[Heap ] Malloc'd %p (%i bytes), returning to %p", best->Data, best->Size, __builtin_return_address(0));
240 * \fn void free(void *Ptr)
241 * \brief Free an allocated memory block
249 Log_Log("Heap", "free: Ptr = %p", Ptr);
250 Log_Log("Heap", "free: Returns to %p", __builtin_return_address(0));
254 if( (Uint)Ptr & (sizeof(Uint)-1) ) {
255 Log_Warning("Heap", "free - Passed a non-aligned address (%p)", Ptr);
260 if((Uint)Ptr < (Uint)gHeapStart || (Uint)Ptr > (Uint)gHeapEnd)
262 Log_Warning("Heap", "free - Passed a non-heap address (%p < %p < %p)\n",
263 gHeapStart, Ptr, gHeapEnd);
267 // Check memory block - Header
268 head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
269 if(head->Magic == MAGIC_FREE) {
270 Log_Warning("Heap", "free - Passed a freed block (%p) by %p", head, __builtin_return_address(0));
273 if(head->Magic != MAGIC_USED) {
274 Log_Warning("Heap", "free - Magic value is invalid (%p, 0x%x)\n", head, head->Magic);
278 // Check memory block - Footer
279 foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
280 if(foot->Head != head) {
281 Log_Warning("Heap", "free - Footer backlink is incorrect (%p, 0x%x)\n", head, foot->Head);
284 if(foot->Magic != MAGIC_FOOT) {
285 Log_Warning("Heap", "free - Footer magic is invalid (%p, %p = 0x%x)\n", head, &foot->Magic, foot->Magic);
293 head->Magic = MAGIC_FREE;
303 void *realloc(void *__ptr, size_t __size)
305 tHeapHead *head = (void*)( (Uint)__ptr-8 );
308 Uint newSize = (__size + sizeof(tHeapFoot)+sizeof(tHeapHead)+BLOCK_SIZE-1)&~(BLOCK_SIZE-1);
310 // Check for reallocating NULL
311 if(__ptr == NULL) return malloc(__size);
313 // Check if resize is needed
314 if(newSize <= head->Size) return __ptr;
316 // Check if next block is free
317 nextHead = (void*)( (Uint)head + head->Size );
319 // Extend into next block
320 if(nextHead->Magic == MAGIC_FREE && nextHead->Size+head->Size >= newSize)
322 Uint size = nextHead->Size + head->Size;
323 foot = (void*)( (Uint)nextHead + nextHead->Size - sizeof(tHeapFoot) );
325 if(size == newSize) {
326 head->Size = newSize;
332 // Create a new heap block
333 nextHead = (void*)( (Uint)head + newSize );
334 nextHead->Size = size - newSize;
335 nextHead->Magic = MAGIC_FREE;
336 foot->Head = nextHead; // Edit 2nd footer
337 head->Size = newSize; // Edit first header
339 foot = (void*)( (Uint)head + newSize - sizeof(tHeapFoot) );
341 foot->Magic = MAGIC_FOOT;
346 foot = (void*)( (Uint)head - sizeof(tHeapFoot) );
347 nextHead = foot->Head;
348 if(nextHead->Magic == MAGIC_FREE && nextHead->Size+head->Size >= newSize)
350 Uint size = nextHead->Size + head->Size;
351 // Inexact fit, split things up
355 Warning("[Heap ] TODO: Space efficient realloc when new size is smaller");
362 // Set 1st (new/lower) header
363 nextHead->Magic = MAGIC_USED;
364 nextHead->Size = newSize;
365 // Get 2nd (old) footer
366 foot = (void*)( (Uint)nextHead + newSize );
367 foot->Head = nextHead;
368 // Save old data size
369 oldDataSize = head->Size - sizeof(tHeapFoot) - sizeof(tHeapHead);
374 memcpy(nextHead->Data, __ptr, oldDataSize);
376 return nextHead->Data;
378 // On to the expensive then
382 nextHead = malloc( __size );
388 head->Size - sizeof(tHeapFoot) - sizeof(tHeapHead)
393 return nextHead->Data;
397 * \fn void *calloc(size_t num, size_t size)
398 * \brief Allocate and Zero a buffer in memory
399 * \param num Number of elements
400 * \param size Size of each element
402 void *calloc(size_t num, size_t size)
404 void *ret = malloc(num*size);
405 if(ret == NULL) return NULL;
407 memset( ret, 0, num*size );
413 * \fn int IsHeap(void *Ptr)
414 * \brief Checks if an address is a heap pointer
416 int IsHeap(void *Ptr)
419 if((Uint)Ptr < (Uint)gHeapStart) return 0;
420 if((Uint)Ptr > (Uint)gHeapEnd) return 0;
421 if((Uint)Ptr & (sizeof(Uint)-1)) return 0;
423 head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
424 if(head->Magic != MAGIC_USED && head->Magic != MAGIC_FREE)
437 while( (Uint)head < (Uint)gHeapEnd )
439 foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
440 Log_Log("Heap", "%p (0x%x): 0x%08lx 0x%lx",
441 head, MM_GetPhysAddr((Uint)head), head->Size, head->Magic);
442 Log_Log("Heap", "%p 0x%lx", foot->Head, foot->Magic);
445 // Sanity Check Header
446 if(head->Size == 0) {
447 Log_Warning("Heap", "HALTED - Size is zero");
450 if(head->Size & (BLOCK_SIZE-1)) {
451 Log_Warning("Heap", "HALTED - Size is malaligned");
454 if(head->Magic != MAGIC_FREE && head->Magic != MAGIC_USED) {
455 Log_Warning("Heap", "HALTED - Head Magic is Bad");
460 if(foot->Magic != MAGIC_FOOT) {
461 Log_Warning("Heap", "HALTED - Foot Magic is Bad");
464 if(head != foot->Head) {
465 Log_Warning("Heap", "HALTED - Footer backlink is invalid");
469 // All OK? Go to next
470 head = foot->NextHead;