2 * AcessOS Microkernel Version
12 #define HEAP_BASE 0xE0800000
13 #define HEAP_MAX 0xF0000000 // 120MiB, Plenty
14 #define HEAP_INIT_SIZE 0x8000 // 32 KiB
15 #define BLOCK_SIZE (sizeof(void*)) // 8 Machine Words
16 #define COMPACT_HEAP 0 // Use 4 byte header?
19 #define MAGIC_FOOT 0x2ACE5505
20 #define MAGIC_FREE 0xACE55000
21 #define MAGIC_USED 0x862B0505 // MAGIC_FOOT ^ MAGIC_FREE
25 void *Heap_Extend(int Bytes);
26 void *Heap_Merge(tHeapHead *Head);
27 void *malloc(size_t Bytes);
39 gHeapStart = (void*)MM_KHEAP_BASE;
40 gHeapEnd = (void*)MM_KHEAP_BASE;
41 Heap_Extend(HEAP_INIT_SIZE);
45 * \fn void *Heap_Extend(int Bytes)
46 * \brief Extend the size of the heap
48 void *Heap_Extend(int Bytes)
51 tHeapHead *head = gHeapEnd;
55 if( (Uint)gHeapEnd == MM_KHEAP_MAX )
59 if( (Uint)gHeapEnd + ((Bytes+0xFFF)&~0xFFF) > MM_KHEAP_MAX ) {
60 Bytes = MM_KHEAP_MAX - (Uint)gHeapEnd;
64 // Heap expands in pages
65 for(i=0;i<(Bytes+0xFFF)>>12;i++)
66 MM_Allocate( (Uint)gHeapEnd+(i<<12) );
72 head->Size = (Bytes+0xFFF)&~0xFFF;
73 head->Magic = MAGIC_FREE;
74 foot = (void*)( (Uint)gHeapEnd - sizeof(tHeapFoot) );
76 foot->Magic = MAGIC_FOOT;
78 //Log(" Heap_Extend: head = %p", head);
79 return Heap_Merge(head); // Merge with previous block
83 * \fn void *Heap_Merge(tHeapHead *Head)
84 * \brief Merges two ajacent heap blocks
86 void *Heap_Merge(tHeapHead *Head)
92 //Log("Heap_Merge: (Head=%p)", Head);
94 thisFoot = (void*)( (Uint)Head + Head->Size - sizeof(tHeapFoot) );
95 if((Uint)thisFoot > (Uint)gHeapEnd) return NULL;
98 foot = (void*)( (Uint)Head - sizeof(tHeapFoot) );
99 if( ((Uint)foot < (Uint)gHeapEnd && (Uint)foot > HEAP_BASE)
100 && foot->Head->Magic == MAGIC_FREE) {
101 foot->Head->Size += Head->Size; // Increase size
102 thisFoot->Head = foot->Head; // Change backlink
103 Head->Magic = 0; // Clear old head
105 Head = foot->Head; // Save new head address
106 foot->Head = NULL; // Clear central footer
110 // Merge Right (Upwards)
111 head = (void*)( (Uint)Head + Head->Size );
112 if((Uint)head < (Uint)gHeapEnd && head->Magic == MAGIC_FREE)
114 Head->Size += head->Size;
115 foot = (void*)( (Uint)Head + Head->Size - sizeof(tHeapFoot) );
116 foot->Head = Head; // Update Backlink
117 thisFoot->Head = NULL; // Clear old footer
119 head->Size = 0; // Clear old header
123 // Return new address
128 * \fn void *malloc(size_t Bytes)
129 * \brief Allocate memory from the heap
131 void *malloc(size_t Bytes)
133 tHeapHead *head, *newhead;
134 tHeapFoot *foot, *newfoot;
135 tHeapHead *best = NULL;
136 Uint bestSize = 0; // Speed hack
139 Bytes = (Bytes + sizeof(tHeapHead) + sizeof(tHeapFoot) + BLOCK_SIZE-1) & ~(BLOCK_SIZE-1);
142 LOCK(&giHeapSpinlock);
145 for( head = gHeapStart;
146 (Uint)head < (Uint)gHeapEnd;
147 head = (void*)((Uint)head + head->Size)
151 if( head->Size & (BLOCK_SIZE-1) ) {
153 Warning("Size of heap address %p is invalid not aligned (0x%x)", head, head->Size);
159 // Check if allocated
160 if(head->Magic == MAGIC_USED) continue;
162 if(head->Magic != MAGIC_FREE) {
164 Warning("Magic of heap address %p is invalid (0x%x)", head, head->Magic);
167 RELEASE(&giHeapSpinlock); // Release spinlock
172 if(head->Size < Bytes) continue;
175 if(head->Size == Bytes) {
176 head->Magic = MAGIC_USED;
177 RELEASE(&giHeapSpinlock); // Release spinlock
178 LOG("RETURN %p", best->Data);
185 bestSize = head->Size;
188 // or check if the block is the best size
189 if(bestSize > head->Size) {
191 bestSize = head->Size;
196 // If no block large enough is found, create one
199 best = Heap_Extend( Bytes );
202 RELEASE(&giHeapSpinlock); // Release spinlock
206 if(best->Size == Bytes) {
207 RELEASE(&giHeapSpinlock); // Release spinlock
208 LOG("RETURN %p", best->Data);
214 newhead = (void*)( (Uint)best + Bytes );
215 newfoot = (void*)( (Uint)best + Bytes - sizeof(tHeapFoot) );
216 foot = (void*)( (Uint)best + best->Size - sizeof(tHeapFoot) );
218 newfoot->Head = best; // Create new footer
219 newfoot->Magic = MAGIC_FOOT;
220 newhead->Size = best->Size - Bytes; // Create new header
221 newhead->Magic = MAGIC_FREE;
222 foot->Head = newhead; // Update backlink in old footer
223 best->Size = Bytes; // Update size in old header
224 best->Magic = MAGIC_USED; // Mark block as used
226 RELEASE(&giHeapSpinlock); // Release spinlock
227 LOG("RETURN %p", best->Data);
232 * \fn void free(void *Ptr)
233 * \brief Free an allocated memory block
240 LOG("Ptr = %p", Ptr);
241 LOG("Returns to %p", __builtin_return_address(0));
244 if( (Uint)Ptr & (sizeof(Uint)-1) ) {
245 Warning("free - Passed a non-aligned address (%p)\n", Ptr);
250 if((Uint)Ptr < (Uint)gHeapStart || (Uint)Ptr > (Uint)gHeapEnd)
252 Warning("free - Passed a non-heap address (%p)\n", Ptr);
256 // Check memory block - Header
257 head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
258 if(head->Magic == MAGIC_FREE) {
259 Warning("free - Passed a freed block (%p)\n", head);
262 if(head->Magic != MAGIC_USED) {
263 Warning("free - Magic value is invalid (%p, 0x%x)\n", head, head->Magic);
267 // Check memory block - Footer
268 foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
269 if(foot->Head != head) {
270 Warning("free - Footer backlink is incorrect (%p, 0x%x)\n", head, foot->Head);
273 if(foot->Magic != MAGIC_FOOT) {
274 Warning("free - Footer magic is invalid (%p, 0x%x)\n", head, foot->Magic);
279 LOCK( &giHeapSpinlock );
282 head->Magic = MAGIC_FREE;
287 RELEASE( &giHeapSpinlock );
292 void *realloc(void *__ptr, size_t __size)
294 tHeapHead *head = (void*)( (Uint)__ptr-8 );
297 Uint newSize = (__size + sizeof(tHeapFoot)+sizeof(tHeapHead)+BLOCK_SIZE-1)&~(BLOCK_SIZE-1);
299 // Check for reallocating NULL
300 if(__ptr == NULL) return malloc(__size);
302 // Check if resize is needed
303 if(newSize <= head->Size) return __ptr;
305 // Check if next block is free
306 nextHead = (void*)( (Uint)head + head->Size );
308 // Extend into next block
309 if(nextHead->Magic == MAGIC_FREE && nextHead->Size+head->Size >= newSize)
311 Uint size = nextHead->Size + head->Size;
312 foot = (void*)( (Uint)nextHead + nextHead->Size - sizeof(tHeapFoot) );
314 if(size == newSize) {
315 head->Size = newSize;
321 // Create a new heap block
322 nextHead = (void*)( (Uint)head + newSize );
323 nextHead->Size = size - newSize;
324 nextHead->Magic = MAGIC_FREE;
325 foot->Head = nextHead; // Edit 2nd footer
326 head->Size = newSize; // Edit first header
328 foot = (void*)( (Uint)head + newSize - sizeof(tHeapFoot) );
330 foot->Magic = MAGIC_FOOT;
335 foot = (void*)( (Uint)head - sizeof(tHeapFoot) );
336 nextHead = foot->Head;
337 if(nextHead->Magic == MAGIC_FREE && nextHead->Size+head->Size >= newSize)
339 Uint size = nextHead->Size + head->Size;
344 // Set 1st (new/lower) header
345 nextHead->Magic = MAGIC_USED;
346 nextHead->Size = newSize;
347 // Get 2nd (old) footer
348 foot = (void*)( (Uint)nextHead + newSize );
349 foot->Head = nextHead;
350 // Save old data size
351 oldDataSize = head->Size - sizeof(tHeapFoot) - sizeof(tHeapHead);
355 memcpy(nextHead->Data, __ptr, oldDataSize);
363 * \fn int IsHeap(void *Ptr)
364 * \brief Checks if an address is a heap address
366 int IsHeap(void *Ptr)
369 if((Uint)Ptr < (Uint)gHeapStart) return 0;
370 if((Uint)Ptr > (Uint)gHeapEnd) return 0;
372 head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
373 if(head->Magic != MAGIC_USED && head->Magic != MAGIC_FREE)
386 while( (Uint)head < (Uint)gHeapEnd )
388 foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
389 Log("%p (0x%x): 0x%08lx 0x%lx", head, MM_GetPhysAddr((Uint)head), head->Size, head->Magic);
390 Log("%p 0x%lx", foot->Head, foot->Magic);
393 // Sanity Check Header
394 if(head->Size == 0) {
395 Log("HALTED - Size is zero");
398 if(head->Size & (BLOCK_SIZE-1)) {
399 Log("HALTED - Size is malaligned");
402 if(head->Magic != MAGIC_FREE && head->Magic != MAGIC_USED) {
403 Log("HALTED - Head Magic is Bad");
408 if(foot->Magic != MAGIC_FOOT) {
409 Log("HALTED - Foot Magic is Bad");
412 if(head != foot->Head) {
413 Log("HALTED - Footer backlink is invalid");
417 // All OK? Go to next
418 head = foot->NextHead;