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