1 /*---------------------------------------------------------------------------*
2   Project:     MEM library
3   File:        mem_unitHeap.c
4   Programmers: Makoto Takano
5 
6   Copyright 2005 Nintendo.  All rights reserved.
7 
8   These coded instructions, statements, and computer programs contain
9   proprietary information of Nintendo of America Inc. and/or Nintendo
10   Company Ltd., and are protected by Federal copyright law.  They may
11   not be disclosed to third parties or copied or duplicated in any form,
12   in whole or in part, without the prior written consent of Nintendo.
13  *---------------------------------------------------------------------------*/
14 
15 #include <revolution/mem/unitHeap.h>
16 #include "heapCommoni.h"
17 
18 
19 /* ========================================================================
20     Macro constants
21    ======================================================================== */
22 
23 // Minimum alignment value
24 #define MIN_ALIGNMENT           4
25 
26 
27 /* ========================================================================
28     static functions
29    ======================================================================== */
30 
31 /* ------------------------------------------------------------------------
32     Memory Block List Operation
33    ------------------------------------------------------------------------ */
34 
35 /*---------------------------------------------------------------------------*
36   Name:         PopMBlock_
37 
38   Description:  Allocates the memory block from the top of the list.
39 
40   Arguments:    link:   pointer to list
41 
42   Returns:      None.
43  *---------------------------------------------------------------------------*/
44 static MEMiUntHeapMBlockHead*
PopMBlock_(MEMiUntMBlockList * list)45 PopMBlock_( MEMiUntMBlockList* list )
46 {
47     MEMiUntHeapMBlockHead*  block = list->head;
48     if ( block )
49     {
50         list->head = block->pMBlkHdNext;
51     }
52 
53     return block;
54 }
55 
56 /*---------------------------------------------------------------------------*
57   Name:         PushMBlock_
58 
59   Description:  Adds memory block to top of list.
60 
61   Arguments:    link:   The list to add
62                 block:  The memory block to add
63 
64   Returns:      None.
65  *---------------------------------------------------------------------------*/
66 static inline void
PushMBlock_(MEMiUntMBlockList * list,MEMiUntHeapMBlockHead * block)67 PushMBlock_(
68     MEMiUntMBlockList*       list,
69     MEMiUntHeapMBlockHead*   block
70 )
71 {
72     block->pMBlkHdNext = list->head;
73     list->head = block;
74 }
75 
76 
77 /*---------------------------------------------------------------------------*
78   Name:         GetUnitHeapHeadPtrFromHeapHead_
79 
80   Description:  Gets the unit heap header pointer from the heap header pointer.
81 
82   Arguments:    pHeapHd:  Pointer to the heap header.
83 
84   Returns:      Returns the unit heap header pointer.
85  *---------------------------------------------------------------------------*/
86 static inline MEMiUntHeapHead*
GetUnitHeapHeadPtrFromHeapHead_(MEMiHeapHead * pHeapHd)87 GetUnitHeapHeadPtrFromHeapHead_( MEMiHeapHead* pHeapHd )
88 {
89     return (MEMiUntHeapHead*)AddU32ToPtr( pHeapHd, sizeof(MEMiHeapHead) );
90 }
91 
92 
93 /*---------------------------------------------------------------------------*
94   Name:         IsValidUnitHeapHandle_
95 
96   Description:  Checks the signature to determine whether the heap handle is valid.
97 
98   Arguments:    handle:  The heap handle
99 
100   Returns:      TRUE		the heap handle is valid
101                 FALSE		the heap handle is not valid
102  *---------------------------------------------------------------------------*/
103 static inline BOOL
IsValidUnitHeapHandle_(MEMHeapHandle handle)104 IsValidUnitHeapHandle_( MEMHeapHandle handle )
105 {
106     if ( handle == MEM_HEAP_INVALID_HANDLE )
107     {
108         return FALSE;
109     }
110 
111     {
112         MEMiHeapHead* pHeapHd = handle;
113         return  pHeapHd->signature == MEMi_UNTHEAP_SIGNATURE;
114     }
115 }
116 
117 
118 /* ========================================================================
119     External Functions (Non-Public)
120    ======================================================================== */
121 
122 
123 /*---------------------------------------------------------------------------*
124   Name:         MEMiDumpUnitHeap
125 
126   Description:  Displays the information inside unit heap.
127                 This function is for debugging.
128 
129   Arguments:    heap :    Unit heap handle.
130 
131   Returns:      None.
132  *---------------------------------------------------------------------------*/
133 #if defined(_DEBUG)
134 
135 void
MEMiDumpUnitHeap(MEMHeapHandle heap)136 MEMiDumpUnitHeap( MEMHeapHandle heap )
137 {
138     ASSERT( IsValidUnitHeapHandle_( heap ) );
139 
140     {
141         MEMiHeapHead    *const pHeapHd     = heap;
142         MEMiUntHeapHead *const pUnitHeapHd = GetUnitHeapHeadPtrFromHeapHead_( pHeapHd );
143         const u32 heapSize = GetOffsetFromPtr( pHeapHd->heapStart, pHeapHd->heapEnd );
144         const u32 freeSize = MEMCountFreeBlockForUnitHeap( heap ) * pUnitHeapHd->mBlkSize;
145         const u32 usedSize = heapSize - freeSize;
146 
147         MEMiDumpHeapHead(pHeapHd);
148 
149         OSReport("    %d / %d bytes (%6.2f%%) used\n",
150                                                 usedSize, heapSize, 100.0f * usedSize / heapSize);
151     }
152 }
153 
154 // #if defined(_DEBUG)
155 #endif
156 
157 
158 /* ========================================================================
159     External functions (public)
160    ======================================================================== */
161 
162 /*---------------------------------------------------------------------------*
163   Name:         MEMCreateUnitHeapEx
164 
165   Description:  Creates unit heap
166 
167   Arguments:    startAddress:  Start address of heap area
168                 heapSize:      Size of heap area
169                 memBlockSize:  Memory block size
170                 alignment:     Memory block alignment.
171                                4, 8, 16, or 32 may be specified for the value.
172                 optFlag:       Option flag.
173 
174   Returns:      If the function succeeds, a handle for the created unit heap is returned.
175                 If the function fails, MEM_INVALID_HEAP_HANDLE is returned.
176  *---------------------------------------------------------------------------*/
177 MEMHeapHandle
MEMCreateUnitHeapEx(void * startAddress,u32 heapSize,u32 memBlockSize,int alignment,u16 optFlag)178 MEMCreateUnitHeapEx(
179     void*   startAddress,
180     u32     heapSize,
181     u32     memBlockSize,
182     int     alignment,
183     u16     optFlag
184 )
185 {
186     MEMiHeapHead* pHeapHd;
187     void* heapEnd;
188 
189     ASSERT(startAddress != NULL);
190 
191     // alignment check
192     ASSERT( alignment % MIN_ALIGNMENT == 0 );
193     ASSERT( MIN_ALIGNMENT <= alignment && alignment <= 32 );
194 
195     pHeapHd = (MEMiHeapHead*)RoundUpPtr( startAddress, MIN_ALIGNMENT );
196     heapEnd = RoundDownPtr( AddU32ToPtr( startAddress, heapSize ), MIN_ALIGNMENT );
197 
198     if ( ComparePtr( pHeapHd, heapEnd ) > 0 )
199     {
200         return MEM_HEAP_INVALID_HANDLE;
201     }
202 
203     memBlockSize = RoundUp( memBlockSize, alignment );    // Real block size
204 
205     {
206         MEMiUntHeapHead* pUntHeapHd = GetUnitHeapHeadPtrFromHeapHead_( pHeapHd );
207         void* heapStart = RoundUpPtr( AddU32ToPtr( pUntHeapHd, sizeof(MEMiUntHeapHead) ), alignment );
208         u32 elementNum;
209 
210         if ( ComparePtr( heapStart, heapEnd ) > 0 )
211         {
212             return MEM_HEAP_INVALID_HANDLE;
213         }
214 
215         elementNum = GetOffsetFromPtr( heapStart, heapEnd ) / memBlockSize;
216         if ( elementNum == 0 )
217         {
218             return MEM_HEAP_INVALID_HANDLE;
219         }
220 
221         heapEnd = AddU32ToPtr( heapStart, elementNum * memBlockSize );
222 
223         MEMiInitHeapHead(           // Heap common initialization
224                 pHeapHd,
225                 MEMi_UNTHEAP_SIGNATURE,
226                 heapStart,
227                 heapEnd,
228                 optFlag );
229 
230         pUntHeapHd->mbFreeList.head = (MEMiUntHeapMBlockHead*)heapStart;
231         pUntHeapHd->mBlkSize = memBlockSize;
232 
233         {
234             MEMiUntHeapMBlockHead* pMBlkHd = pUntHeapHd->mbFreeList.head;
235             int i;
236 
237             for ( i = 0; i < elementNum - 1; ++i, pMBlkHd = pMBlkHd->pMBlkHdNext )
238             {
239                 pMBlkHd->pMBlkHdNext = (MEMiUntHeapMBlockHead*)AddU32ToPtr( pMBlkHd, memBlockSize );
240             }
241 
242             pMBlkHd->pMBlkHdNext = NULL;
243         }
244 
245         return pHeapHd;
246     }
247 }
248 
249 /*---------------------------------------------------------------------------*
250   Name:         MEMDestroyUnitHeap
251 
252   Description:  Destroys unit heap.
253 
254   Arguments:    heap : Unit heap handle.
255 
256   Returns:      Returns a pointer to the region occupied by the destroyed heap.
257  *---------------------------------------------------------------------------*/
258 void*
MEMDestroyUnitHeap(MEMHeapHandle heap)259 MEMDestroyUnitHeap( MEMHeapHandle heap )
260 {
261     ASSERT( IsValidUnitHeapHandle_(heap) );
262 
263     MEMiFinalizeHeap(heap);
264     return (void*)heap;
265 }
266 
267 
268 /*---------------------------------------------------------------------------*
269   Name:         MEMAllocFromUnitHeap
270 
271   Description:  Allocates memory block from unit heap.
272 
273   Arguments:    heap :   Unit heap handle.
274 
275   Returns:      Returns the pointer
276                 to the allocated memory block if the allocation is successful.
277                 If fails, NULL is returned.
278  *---------------------------------------------------------------------------*/
279 void*
MEMAllocFromUnitHeap(MEMHeapHandle heap)280 MEMAllocFromUnitHeap( MEMHeapHandle heap )
281 {
282     MEMiUntHeapMBlockHead* pMBlkHd;
283 
284     ASSERT( IsValidUnitHeapHandle_( heap ) );
285 
286     {
287 
288         MEMiUntHeapHead* pUntHeapHd = GetUnitHeapHeadPtrFromHeapHead_( heap );
289 
290         LockHeap( heap );
291         pMBlkHd                     = PopMBlock_( &pUntHeapHd->mbFreeList );
292         UnlockHeap( heap );
293 
294         if ( pMBlkHd )
295         {
296             FillAllocMemory( heap, pMBlkHd, pUntHeapHd->mBlkSize );
297         }
298     }
299     return pMBlkHd;
300 }
301 
302 /*---------------------------------------------------------------------------*
303   Name:         MEMFreeToUnitHeap
304 
305   Description:  Returns unit heap to memory block.
306 
307   Arguments:    heap :     Unit heap handle.
308                 memBlock: Pointer to the memory block to be returned.
309 
310   Returns:      None.
311  *---------------------------------------------------------------------------*/
312 void
MEMFreeToUnitHeap(MEMHeapHandle heap,void * memBlock)313 MEMFreeToUnitHeap(
314     MEMHeapHandle   heap,
315     void*           memBlock
316 )
317 {
318     ASSERT( IsValidUnitHeapHandle_( heap ) );
319     if ( memBlock == NULL )
320     {
321         return;
322     }
323 
324     {
325         MEMiUntHeapHead* pUntHeapHd = GetUnitHeapHeadPtrFromHeapHead_( heap );
326 
327         FillFreeMemory( heap, memBlock, pUntHeapHd->mBlkSize );
328 
329         LockHeap( heap );
330         PushMBlock_( &pUntHeapHd->mbFreeList, (MEMiUntHeapMBlockHead*)memBlock );
331         UnlockHeap( heap );
332     }
333 }
334 
335 /*---------------------------------------------------------------------------*
336   Name:         MEMCountFreeBlockForUnitHeap
337 
338   Description:  Gets the number of empty memory blocks in the unit heap.
339 
340   Arguments:    heap :     Unit heap handle.
341 
342   Returns:      Returns the number of empty memory blocks in the unit heap.
343  *---------------------------------------------------------------------------*/
344 u32
MEMCountFreeBlockForUnitHeap(MEMHeapHandle heap)345 MEMCountFreeBlockForUnitHeap( MEMHeapHandle heap )
346 {
347     u32 cnt = 0;
348     ASSERT(IsValidUnitHeapHandle_(heap));
349 
350     LockHeap( heap );
351     {
352         MEMiUntHeapHead*       pUntHeapHd = GetUnitHeapHeadPtrFromHeapHead_( heap );
353         MEMiUntHeapMBlockHead* pMBlkHd    = pUntHeapHd->mbFreeList.head;
354 
355         for ( ; pMBlkHd; pMBlkHd = pMBlkHd->pMBlkHdNext )
356         {
357             ++cnt;
358         }
359     }
360     UnlockHeap( heap );
361     return cnt;
362 }
363 
364 /*---------------------------------------------------------------------------*
365   Name:         MEMCalcHeapSizeForUnitHeap
366 
367   Description:  Gets the size of the heap required from the size of the memory blocks and the number of blocks.
368 
369   Arguments:    memBlockSize:  Size of the memory block (in bytes).
370                 memBlockNum:   Total number of reserved memory blocks.
371                 alignment:     Memory block alignment.
372 
373   Returns:      Returns the required heap size.
374  *---------------------------------------------------------------------------*/
375 u32
MEMCalcHeapSizeForUnitHeap(u32 memBlockSize,u32 memBlockNum,int alignment)376 MEMCalcHeapSizeForUnitHeap(
377     u32     memBlockSize,
378     u32     memBlockNum,
379     int     alignment
380 )
381 {
382     return  sizeof(MEMiHeapHead) + sizeof(MEMiUntHeapHead)              // The size the heap uses internally
383             + (alignment - 4)                                   // The maximum size required for alignment adjustment
384             + memBlockNum * RoundUp( memBlockSize, alignment ); // The size required for all units
385 }
386 
387