1 /*---------------------------------------------------------------------------*
2   Project:     MEM library
3   File:        mem_expHeap.c
4   Programmers: Makoto Takano
5 
6   Copyright (C)2005-2006 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 #include <revolution/mem/expHeap.h>
15 #include "heapCommoni.h"
16 #include <stdlib.h>
17 
18 
19 /* ========================================================================
20     Macro constants
21    ======================================================================== */
22 
23 // Free memory block signature
24 #define MBLOCK_FREE_SIGNATURE   ('FR')
25 
26 // Signature for the memory block being used
27 #define MBLOCK_USED_SIGNATURE   ('UD')
28 
29 // Maximum group ID value
30 #define MAX_GROUPID             0xff
31 
32 // Default value for the group ID
33 #define DEFAULT_GROUPID         0
34 
35 // Minimum alignment value
36 #define MIN_ALIGNMENT           4
37 
38 // Default memory allocation mode
39 #define DEFAULT_ALLOC_MODE      MEM_EXPHEAP_ALLOC_MODE_FIRST
40 
41 // minimum size for registration as a free block (exclusive of header)
42 #define MIN_FREE_BLOCK_SIZE     4
43 // #define MIN_FREE_BLOCK_SIZE 16
44 
45 /* ========================================================================
46     structure definitions
47    ======================================================================== */
48 
49 typedef struct MemRegion MemRegion;
50 
51 struct MemRegion
52 {
53     void*       start;
54     void*       end;
55 };
56 
57 /* ========================================================================
58     Macro functions
59    ======================================================================== */
60 
61 #if defined(_DEBUG)
62 
63 // For outputting warnings when checking the heap
64 #define HEAP_WARNING(exp, ...) \
65             (void) ((exp) && (OSReport(__VA_ARGS__), 0))
66 
67 // #if defined(_DEBUG)
68 #endif
69 
70 
71 /* ========================================================================
72     static functions
73    ======================================================================== */
74 
75 /* ------------------------------------------------------------------------
76     Pointer Operations
77    ------------------------------------------------------------------------ */
78 
79 /*---------------------------------------------------------------------------*
80   Name:         MaxPtr_
81 
82   Description:  Gets the larger of two pointers' addresses.
83 
84   Arguments:    a, b	pointers to be compared
85 
86   Returns:      a	if the a address is larger
87                 b	if the b address is larger
88  *---------------------------------------------------------------------------*/
89 static inline void*
MaxPtr_(void * a,void * b)90 MaxPtr_( void* a, void* b )
91 {
92     return GetUIntPtr(a) > GetUIntPtr(b) ? a: b;
93 }
94 
95 /*---------------------------------------------------------------------------*
96   Name:         IsValidExpHeapHandle_
97 
98   Description:  Checks the signature to determine whether the expansion heap handle is valid.
99 
100   Arguments:    handle:  The heap handle
101 
102   Returns:      TRUE		the heap handle is valid
103                 FALSE		the heap handle is not valid
104  *---------------------------------------------------------------------------*/
105 static inline BOOL
IsValidExpHeapHandle_(MEMHeapHandle handle)106 IsValidExpHeapHandle_( MEMHeapHandle handle )
107 {
108     if ( handle == MEM_HEAP_INVALID_HANDLE )
109     {
110         return FALSE;
111     }
112 
113     {
114         MEMiHeapHead* pHeapHd = handle;
115         return pHeapHd->signature == MEMi_EXPHEAP_SIGNATURE;
116     }
117 }
118 
119 /*---------------------------------------------------------------------------*
120   Name:         GetExpHeapHeadPtrFromHeapHead_
121 
122   Description:  Gets the pointer to the expanded heap header from the pointer to the heap header.
123 
124   Arguments:    pHHead:  Pointer to the heap header.
125 
126   Returns:      Returns the pointer to the expanded heap header.
127  *---------------------------------------------------------------------------*/
128 static inline MEMiExpHeapHead*
GetExpHeapHeadPtrFromHeapHead_(MEMiHeapHead * pHHead)129 GetExpHeapHeadPtrFromHeapHead_( MEMiHeapHead* pHHead )
130 {
131     return (MEMiExpHeapHead*)AddU32ToPtr( pHHead, sizeof(MEMiHeapHead) );
132 }
133 
134 /*---------------------------------------------------------------------------*
135   Name:         GetHeapHeadPtrFromExpHeapHead_
136 
137   Description:  Gets the pointer to the heap header from the pointer to the expanded heap header.
138 
139   Arguments:    pEHHead:  Pointer to the expanded heap header.
140 
141   Returns:      Returns the pointer to the heap header.
142  *---------------------------------------------------------------------------*/
143 static inline MEMiHeapHead*
GetHeapHeadPtrFromExpHeapHead_(MEMiExpHeapHead * pEHHead)144 GetHeapHeadPtrFromExpHeapHead_( MEMiExpHeapHead* pEHHead )
145 {
146     return (MEMiHeapHead*)SubU32ToPtr( pEHHead, sizeof(MEMiHeapHead) );
147 }
148 
149 /*---------------------------------------------------------------------------*
150   Name:         GetExpHeapHeadPtrFromHandle_
151 
152   Description:  Gets the pointer to the expanded heap header from the expanded heap handle.
153 
154   Arguments:    heap :  Expanded heap handle.
155 
156   Returns:      Returns the pointer to the expanded heap header.
157  *---------------------------------------------------------------------------*/
158 static inline MEMiExpHeapHead*
GetExpHeapHeadPtrFromHandle_(MEMHeapHandle heap)159 GetExpHeapHeadPtrFromHandle_( MEMHeapHandle heap )
160 {
161     return (MEMiExpHeapHead*)GetExpHeapHeadPtrFromHeapHead_( heap );
162 }
163 
164 /*---------------------------------------------------------------------------*
165   Name:         GetMemPtrForMBlock_
166 
167   Description:  Gets the pointer to the memory block
168                 from the pointer to the NNSiFndExpHeapMBlockHead structure.
169 
170   Arguments:    pMBlkHd:  pointer to the MEMiExpHeapMBlockHead structure
171 
172   Returns:      Returns the pointer to the memory block.
173  *---------------------------------------------------------------------------*/
174 static inline void*
GetMemPtrForMBlock_(MEMiExpHeapMBlockHead * pMBlkHd)175 GetMemPtrForMBlock_( MEMiExpHeapMBlockHead* pMBlkHd )
176 {
177     return AddU32ToPtr( pMBlkHd, sizeof(MEMiExpHeapMBlockHead) );
178 }
179 
180 static inline const void*
GetMemCPtrForMBlock_(const MEMiExpHeapMBlockHead * pMBlkHd)181 GetMemCPtrForMBlock_( const MEMiExpHeapMBlockHead* pMBlkHd )
182 {
183     return AddU32ToCPtr( pMBlkHd, sizeof(MEMiExpHeapMBlockHead) );
184 }
185 
186 /*---------------------------------------------------------------------------*
187   Name:         GetMBlockHeadPtr_
188 
189   Description:  Gets the pointer to the NNSiFndExpHeapMBlockHead structure
190                 from the pointer to the memory block.
191                 from the pointer to the NNSiFndExpHeapMBlockHead structure.
192 
193   Arguments:    memBlock:  Pointer to the memory block.
194 
195   Returns:      Returns the pointer to the MEMiExpHeapMBlockHead structure.
196  *---------------------------------------------------------------------------*/
197 static inline MEMiExpHeapMBlockHead*
GetMBlockHeadPtr_(void * memBlock)198 GetMBlockHeadPtr_( void* memBlock )
199 {
200     return (MEMiExpHeapMBlockHead*)SubU32ToPtr(memBlock, sizeof(MEMiExpHeapMBlockHead));
201 }
202 
203 static inline const MEMiExpHeapMBlockHead*
GetMBlockHeadCPtr_(const void * memBlock)204 GetMBlockHeadCPtr_( const void* memBlock )
205 {
206     return (const MEMiExpHeapMBlockHead*)SubU32ToCPtr(memBlock, sizeof(MEMiExpHeapMBlockHead));
207 }
208 
209 /*---------------------------------------------------------------------------*
210   Name:         GetMBlockEndAddr_
211 
212   Description:  Gets the pointer to the NNSiFndExpHeapMBlockHead structure
213                 gets the end address of the memory block.
214 
215   Arguments:    pMBHead:  pointer to the MEMiExpHeapMBlockHead structure
216 
217   Returns:      Returns the terminal address of the memory block.
218  *---------------------------------------------------------------------------*/
219 static inline void*
GetMBlockEndAddr_(MEMiExpHeapMBlockHead * pMBHead)220 GetMBlockEndAddr_( MEMiExpHeapMBlockHead* pMBHead )
221 {
222     return AddU32ToPtr( GetMemPtrForMBlock_(pMBHead), pMBHead->blockSize );
223 }
224 
225 /* ------------------------------------------------------------------------
226     MEMiExpHeapMBlockHead Structure Access Function
227    ------------------------------------------------------------------------ */
228 
229 /*---------------------------------------------------------------------------*
230   Name:         GetAlignmentForMBlock_
231 
232   Description:  Gets the alignment value for the MEMiExpHeapMBlockHead structure.
233 
234   Arguments:    pMBlkHd:  pointer to the MEMiExpHeapMBlockHead structure
235 
236   Returns:      Returns the alignment value for the MEMiExpHeapMBlockHead structure.
237  *---------------------------------------------------------------------------*/
238 static inline u16
GetAlignmentForMBlock_(const MEMiExpHeapMBlockHead * pMBlkHd)239 GetAlignmentForMBlock_( const MEMiExpHeapMBlockHead* pMBlkHd )
240 {
241     return pMBlkHd->attribute.fields.alignment;
242 }
243 
244 /*---------------------------------------------------------------------------*
245   Name:         SetAlignmentForMBlock_
246 
247   Description:  Sets the alignment value for the MEMiExpHeapMBlockHead structure.
248 
249   Arguments:    pMBlkHd:    pointer to the MEMiExpHeapMBlockHead structure
250                 alignment:  Alignment value to be set
251 
252   Returns:      None.
253  *---------------------------------------------------------------------------*/
254 static inline void
SetAlignmentForMBlock_(MEMiExpHeapMBlockHead * pMBlkHd,u16 alignment)255 SetAlignmentForMBlock_(
256     MEMiExpHeapMBlockHead*    pMBlkHd,
257     u16                       alignment
258 )
259 {
260     pMBlkHd->attribute.fields.alignment = alignment;
261 }
262 
263 
264 /*---------------------------------------------------------------------------*
265   Name:         GetGroupIDForMBlock_
266 
267   Description:  Gets the group ID for the MEMiExpHeapMBlockHead structure.
268 
269   Arguments:    pMBlkHd:    pointer to the MEMiExpHeapMBlockHead structure
270 
271   Returns:      Returns the group ID value.
272  *---------------------------------------------------------------------------*/
273 static inline u16
GetGroupIDForMBlock_(const MEMiExpHeapMBlockHead * pMBHead)274 GetGroupIDForMBlock_( const MEMiExpHeapMBlockHead* pMBHead )
275 {
276     return pMBHead->attribute.fields.groupID;
277 }
278 
279 /*---------------------------------------------------------------------------*
280   Name:         SetGroupIDForMBlock_
281 
282   Description:  Sets the group ID for the MEMiExpHeapMBlockHead structure.
283 
284   Arguments:    pMBlkHd:    pointer to the MEMiExpHeapMBlockHead structure
285                 id   :         the group ID value to be set
286 
287   Returns:      None.
288  *---------------------------------------------------------------------------*/
289 static inline void
SetGroupIDForMBlock_(MEMiExpHeapMBlockHead * pMBHead,u16 id)290 SetGroupIDForMBlock_(
291     MEMiExpHeapMBlockHead*    pMBHead,
292     u16                       id
293 )
294 {
295     pMBHead->attribute.fields.groupID = (u8)id;
296 }
297 
298 
299 /*---------------------------------------------------------------------------*
300   Name:         GetAllocDirForMBlock_
301 
302   Description:  Gets the memory allocation direction for the MEMiExpHeapMBlockHead structure.
303 
304   Arguments:    pMBlkHd:    pointer to the MEMiExpHeapMBlockHead structure
305 
306   Returns:      Returns the direction for memory allocation.
307  *---------------------------------------------------------------------------*/
308 static inline u16
GetAllocDirForMBlock_(const MEMiExpHeapMBlockHead * pMBHead)309 GetAllocDirForMBlock_( const MEMiExpHeapMBlockHead* pMBHead )
310 {
311     return pMBHead->attribute.fields.allocDir;
312 }
313 
314 
315 /*---------------------------------------------------------------------------*
316   Name:         SetAllocDirForMBlock_
317 
318   Description:  Sets the memory allocation direction for the MEMiExpHeapMBlockHead structure.
319 
320   Arguments:    pMBlkHd:    pointer to the MEMiExpHeapMBlockHead structure
321                 mode:       the memory allocation direction to be set
322 
323   Returns:      None.
324  *---------------------------------------------------------------------------*/
325 static inline void
SetAllocDirForMBlock_(MEMiExpHeapMBlockHead * pMBHead,u16 mode)326 SetAllocDirForMBlock_(
327     MEMiExpHeapMBlockHead*    pMBHead,
328     u16                       mode
329 )
330 {
331     pMBHead->attribute.fields.allocDir = mode;
332 }
333 
334 
335 /* ------------------------------------------------------------------------
336     MEMiExpHeapHead Structure Access Function
337    ------------------------------------------------------------------------ */
338 
339 /*---------------------------------------------------------------------------*
340   Name:         GetAllocMode_
341 
342   Description:  Gets the memory allocation mode for the expanded heap.
343 
344   Arguments:    pEHHead:  Pointer to the expanded heap header.
345 
346   Returns:      Returns the memory allocation mode for the expanded heap.
347  *---------------------------------------------------------------------------*/
348 static inline u16
GetAllocMode_(MEMiExpHeapHead * pEHHead)349 GetAllocMode_( MEMiExpHeapHead* pEHHead )
350 {
351     return pEHHead->feature.fields.allocMode;
352 }
353 
354 /*---------------------------------------------------------------------------*
355   Name:         SetAllocMode_
356 
357   Description:  Sets the memory allocation mode for the expanded heap.
358 
359   Arguments:    pEHHead:  Pointer to the expanded heap header.
360                 mode:     Memory allocation mode.
361 
362   Returns:      None.
363  *---------------------------------------------------------------------------*/
364 static inline void
SetAllocMode_(MEMiExpHeapHead * pEHHead,u16 mode)365 SetAllocMode_(
366     MEMiExpHeapHead*      pEHHead,
367     u16                   mode
368 )
369 {
370     pEHHead->feature.fields.allocMode = mode;
371 }
372 
373 
374 /*---------------------------------------------------------------------------*
375   Name:         GetRegionOfMBlock_
376 
377   Description:  Generates the region data from the MEMiExpHeapMBlockHead structure.
378 
379   Arguments:    region		pointer to the region data to be generated
380                 block		pointer to the memory block header
381 
382   Returns:      None.
383  *---------------------------------------------------------------------------*/
384 static void
GetRegionOfMBlock_(MemRegion * region,MEMiExpHeapMBlockHead * block)385 GetRegionOfMBlock_(
386     MemRegion*                region,
387     MEMiExpHeapMBlockHead*    block
388 )
389 {
390     region->start = SubU32ToPtr( block, GetAlignmentForMBlock_(block) );
391     region->end   = GetMBlockEndAddr_(block);
392 }
393 
394 
395 /* ------------------------------------------------------------------------
396     Memory Block List Operation
397    ------------------------------------------------------------------------ */
398 
399 /*---------------------------------------------------------------------------*
400   Name:         RemoveMBlock_
401 
402   Description:  Deletes the specified memory block from the memory block list.
403 
404   Arguments:    list		pointer to the block list
405                 block		pointer to the memory block to be deleted
406 
407   Returns:      a pointer to the prior memory block
408  *---------------------------------------------------------------------------*/
409 static MEMiExpHeapMBlockHead*
RemoveMBlock_(MEMiExpMBlockList * list,MEMiExpHeapMBlockHead * block)410 RemoveMBlock_(
411     MEMiExpMBlockList*       list,
412     MEMiExpHeapMBlockHead*   block
413 )
414 {
415     MEMiExpHeapMBlockHead *const prev = block->pMBHeadPrev;
416     MEMiExpHeapMBlockHead *const next = block->pMBHeadNext;
417 
418     // previous reference link
419     if ( prev )
420     {
421         prev->pMBHeadNext = next;
422     }
423     else
424     {
425         list->head = next;
426     }
427 
428     // next reference link
429     if ( next )
430     {
431         next->pMBHeadPrev = prev;
432     }
433     else
434     {
435         list->tail = prev;
436     }
437 
438     return prev;
439 }
440 
441 /*---------------------------------------------------------------------------*
442   Name:         InsertMBlock_
443 
444   Description:  Inserts a memory block into the memory block list.
445 
446   Arguments:    list		pointer to the memory block list
447                 target		pointer to the memory block to be inserted
448                 prev		pointer to the block at which the memory block will be inserted
449 
450   Returns:      a pointer to the target
451  *---------------------------------------------------------------------------*/
452 static MEMiExpHeapMBlockHead*
InsertMBlock_(MEMiExpMBlockList * list,MEMiExpHeapMBlockHead * target,MEMiExpHeapMBlockHead * prev)453 InsertMBlock_(
454     MEMiExpMBlockList*       list,
455     MEMiExpHeapMBlockHead*   target,
456     MEMiExpHeapMBlockHead*   prev
457 )
458 {
459     MEMiExpHeapMBlockHead* next;
460 
461     // previous reference link
462     target->pMBHeadPrev = prev;
463     if ( prev )
464     {
465         next = prev->pMBHeadNext;
466         prev->pMBHeadNext = target;
467     }
468     else
469     {
470         next = list->head;
471         list->head = target;
472     }
473 
474     // next reference link
475     target->pMBHeadNext = next;
476     if ( next )
477     {
478         next->pMBHeadPrev = target;
479     }
480     else
481     {
482         list->tail = target;
483     }
484 
485     return target;
486 }
487 
488 /*---------------------------------------------------------------------------*
489   Name:         AppendMBlock_
490 
491   Description:  Adds a memory block to the end of the list.
492 
493   Arguments:    link:   The list to add
494                 block:  The memory block to add
495 
496   Returns:      None.
497  *---------------------------------------------------------------------------*/
498 static inline void
AppendMBlock_(MEMiExpMBlockList * list,MEMiExpHeapMBlockHead * block)499 AppendMBlock_(
500     MEMiExpMBlockList*       list,
501     MEMiExpHeapMBlockHead*   block
502 )
503 {
504     (void)InsertMBlock_( list, block, list->tail );
505 }
506 
507 /*---------------------------------------------------------------------------*
508   Name:         InitMBlock_
509 
510   Description:  Initializes the memory block.
511 
512   Arguments:    pRegion:    Pointer to the structure representing the region used for the memory block.
513                 signature:  Memory block signature
514 
515   Returns:      Returns the pointer to the initialized memory block.
516  *---------------------------------------------------------------------------*/
517 static MEMiExpHeapMBlockHead*
InitMBlock_(MemRegion * pRegion,u16 signature)518 InitMBlock_(
519     MemRegion*              pRegion,
520     u16                     signature
521 )
522 {
523     MEMiExpHeapMBlockHead* block = (MEMiExpHeapMBlockHead*)pRegion->start;
524 
525     block->signature = signature;   /* embeds the signature*/
526     block->attribute.val = 0;       /* clears the attribute parameters*/
527 
528     // sets the size from the memory block's starting position to the next region as blockSize
529     block->blockSize = GetOffsetFromPtr( GetMemPtrForMBlock_(block), pRegion->end );
530 
531     block->pMBHeadPrev = NULL;
532     block->pMBHeadNext = NULL;
533 
534     return block;
535 }
536 
537 /*---------------------------------------------------------------------------*
538   Name:         InitFreeMBlock_
539 
540   Description:  Initializes the memory block for use as a free block.
541 
542   Arguments:    pRegion:    Pointer to the structure representing the region used for the memory block.
543 
544   Returns:      Returns the pointer to the initialized memory block.
545  *---------------------------------------------------------------------------*/
546 static inline MEMiExpHeapMBlockHead*
InitFreeMBlock_(MemRegion * pRegion)547 InitFreeMBlock_( MemRegion* pRegion )
548 {
549     return InitMBlock_( pRegion, MBLOCK_FREE_SIGNATURE );
550 }
551 
552 /*---------------------------------------------------------------------------*
553   Name:         InitExpHeap_
554 
555   Description:  Initializes the expanded heap.
556 
557   Arguments:    startAddress:  Memory start address for the expanded heap.
558                 endAddress:    The memory end address for the expanded heap is incremented by one.
559                 optFlag:       Option flag.
560 
561   Returns:      Returns the pointer to the heap header.
562  *---------------------------------------------------------------------------*/
563 static MEMiHeapHead*
InitExpHeap_(void * startAddress,void * endAddress,u16 optFlag)564 InitExpHeap_(
565     void*   startAddress,
566     void*   endAddress,
567     u16     optFlag
568 )
569 {
570     MEMiHeapHead*    pHeapHd    = (MEMiHeapHead*)startAddress;
571     MEMiExpHeapHead* pExpHeapHd = GetExpHeapHeadPtrFromHeapHead_( pHeapHd );
572 
573     MEMiInitHeapHead(           // Heap common initialization
574         pHeapHd,
575         MEMi_EXPHEAP_SIGNATURE,
576         AddU32ToPtr( pExpHeapHd, sizeof(MEMiExpHeapHead) ),    // heapStart
577         endAddress,                                            // heapEnd
578         optFlag );
579 
580     pExpHeapHd->groupID = DEFAULT_GROUPID;      // Group ID
581     pExpHeapHd->feature.val = 0;
582     SetAllocMode_( pExpHeapHd, DEFAULT_ALLOC_MODE );
583 
584     // Creates a free block
585     {
586         MEMiExpHeapMBlockHead* pMBHead;
587         MemRegion region;
588 
589         region.start = pHeapHd->heapStart;
590         region.end   = pHeapHd->heapEnd;
591         pMBHead = InitFreeMBlock_( &region );
592 
593         // Block list
594         pExpHeapHd->mbFreeList.head = pMBHead;
595         pExpHeapHd->mbFreeList.tail = pMBHead;
596         pExpHeapHd->mbUsedList.head = NULL;
597         pExpHeapHd->mbUsedList.tail = NULL;
598 
599         return pHeapHd;
600     }
601 }
602 
603 /*---------------------------------------------------------------------------*
604   Name:         AllocUsedBlockFromFreeBlock_
605 
606   Description:  Allocates a new memory block from the free blocks.
607 
608   Arguments:    pEHHead:      Pointer to the expanded heap header.
609                 pMBHeadFree:  Pointer to the free block header.
610                 mblock:       Address for the memory block to be allocated.
611                 size   :         Size of the memory block to be allocated.
612                 direction:    Allocation direction.
613 
614   Returns:      Returns a pointer to the top of the allocated memory block.
615  *---------------------------------------------------------------------------*/
616 static void*
AllocUsedBlockFromFreeBlock_(MEMiExpHeapHead * pEHHead,MEMiExpHeapMBlockHead * pMBHeadFree,void * mblock,u32 size,u16 direction)617 AllocUsedBlockFromFreeBlock_(
618     MEMiExpHeapHead*          pEHHead,
619     MEMiExpHeapMBlockHead*    pMBHeadFree,
620     void*                     mblock,
621     u32                       size,
622     u16                       direction
623 )
624 {
625     MemRegion freeRgnT;
626     MemRegion freeRgnB;
627     MEMiExpHeapMBlockHead* pMBHeadFreePrev;
628 
629     GetRegionOfMBlock_( &freeRgnT, pMBHeadFree );
630     freeRgnB.end   = freeRgnT.end;
631     freeRgnB.start = AddU32ToPtr( mblock, size );
632     freeRgnT.end   = SubU32ToPtr( mblock, sizeof(MEMiExpHeapMBlockHead) );
633 
634     pMBHeadFreePrev = RemoveMBlock_( &pEHHead->mbFreeList, pMBHeadFree );  // Deletes the free block
635 
636     // If there is no space for creating a free block
637     if ( GetOffsetFromPtr(freeRgnT.start, freeRgnT.end) < sizeof(MEMiExpHeapMBlockHead) + MIN_FREE_BLOCK_SIZE )
638     {
639         freeRgnT.end = freeRgnT.start;  // Includes the alignment value for the block being used
640     }
641     else
642     {
643         pMBHeadFreePrev = InsertMBlock_( &pEHHead->mbFreeList, InitFreeMBlock_(&freeRgnT), pMBHeadFreePrev );
644     }
645 
646     // If there is no space for creating a free block
647     if ( GetOffsetFromPtr(freeRgnB.start, freeRgnB.end) < sizeof(MEMiExpHeapMBlockHead) + MIN_FREE_BLOCK_SIZE )
648     {
649         freeRgnB.start= freeRgnB.end;   // Includes the block being used
650     }
651     else
652     {
653         (void)InsertMBlock_( &pEHHead->mbFreeList, InitFreeMBlock_(&freeRgnB), pMBHeadFreePrev );
654     }
655 
656     // Fills the memory for debugging
657     FillAllocMemory(
658             GetHeapHeadPtrFromExpHeapHead_(pEHHead),
659             freeRgnT.end,
660             GetOffsetFromPtr(freeRgnT.end, freeRgnB.start)
661     );
662 
663     // Creates a new block
664     {
665         MEMiExpHeapMBlockHead* pMBHeadNewUsed;
666         MemRegion region;
667 
668         region.start = SubU32ToPtr( mblock, sizeof(MEMiExpHeapMBlockHead) );
669         region.end   = freeRgnB.start;
670 
671         pMBHeadNewUsed = InitMBlock_(&region, MBLOCK_USED_SIGNATURE );
672         SetAllocDirForMBlock_( pMBHeadNewUsed, direction );
673         SetAlignmentForMBlock_( pMBHeadNewUsed, (u16)GetOffsetFromPtr(freeRgnT.end, pMBHeadNewUsed) );
674         SetGroupIDForMBlock_( pMBHeadNewUsed, pEHHead->groupID );
675         AppendMBlock_( &pEHHead->mbUsedList, pMBHeadNewUsed );
676     }
677 
678     return mblock;
679 }
680 
681 /*---------------------------------------------------------------------------*
682   Name:         AllocFromHead_
683 
684   Description:  Allocates the memory block from the top of the heap.
685 
686   Arguments:    pHeapHd:    Pointer to the heap header.
687                 size   :       Size of the memory block to be allocated.
688                 alignment:  Alignment value.
689 
690   Returns:      Returns the pointer
691                 to the allocated memory block if the allocation is successful.
692                 If fails, NULL is returned.
693  *---------------------------------------------------------------------------*/
694 static void*
AllocFromHead_(MEMiHeapHead * pHeapHd,u32 size,int alignment)695 AllocFromHead_(
696     MEMiHeapHead*   pHeapHd,
697     u32             size,
698     int             alignment
699 )
700 {
701     MEMiExpHeapHead* pExpHeapHd = GetExpHeapHeadPtrFromHeapHead_(pHeapHd);
702 
703     // Allocate the first one found?
704     const BOOL bAllocFirst = GetAllocMode_(pExpHeapHd) == MEM_EXPHEAP_ALLOC_MODE_FIRST;
705 
706     MEMiExpHeapMBlockHead* pMBlkHd      = NULL;
707     MEMiExpHeapMBlockHead* pMBlkHdFound = NULL;
708     u32 foundSize = 0xffffffff;
709     void* foundMBlock = NULL;
710 
711     // Search for free block
712     for ( pMBlkHd = pExpHeapHd->mbFreeList.head; pMBlkHd; pMBlkHd = pMBlkHd->pMBHeadNext )
713     {
714         void *const mblock    = GetMemPtrForMBlock_(pMBlkHd);
715         void *const reqMBlock = RoundUpPtr( mblock, alignment );
716         const u32 offset      = GetOffsetFromPtr( mblock, reqMBlock );    // Generated offset
717 
718         if ( pMBlkHd->blockSize >= size + offset
719              &&  foundSize > pMBlkHd->blockSize )
720         {
721             pMBlkHdFound  = pMBlkHd;
722             foundSize     = pMBlkHd->blockSize;
723             foundMBlock   = reqMBlock;
724 
725             if ( bAllocFirst || foundSize == size )
726             {
727                 break;
728             }
729         }
730     }
731 
732     if ( ! pMBlkHdFound ) // No blocks matching the conditions were found
733     {
734         return NULL;
735     }
736 
737     return AllocUsedBlockFromFreeBlock_( // Allocates a region from the free block that was found
738                     pExpHeapHd,
739                     pMBlkHdFound,
740                     foundMBlock,
741                     size,
742                     MEM_EXPHEAP_ALLOC_DIR_FRONT
743            );
744 }
745 
746 /*---------------------------------------------------------------------------*
747   Name:         AllocFromTail_
748 
749   Description:  Allocates a memory block from the tail of the heap.
750 
751   Arguments:    pHeapHd:    Pointer to the heap header.
752                 size   :       Size of the memory block to be allocated.
753                 alignment:  Alignment value.
754 
755   Returns:      Returns the pointer
756                 to the allocated memory block if the allocation is successful.
757                 If fails, NULL is returned.
758  *---------------------------------------------------------------------------*/
759 static void*
AllocFromTail_(MEMiHeapHead * pHeapHd,u32 size,int alignment)760 AllocFromTail_(
761     MEMiHeapHead*   pHeapHd,
762     u32             size,
763     int             alignment
764 )
765 {
766     MEMiExpHeapHead* pExpHeapHd = GetExpHeapHeadPtrFromHeapHead_(pHeapHd);
767 
768     // Allocate the first one found?
769     const BOOL bAllocFirst = GetAllocMode_(pExpHeapHd) == MEM_EXPHEAP_ALLOC_MODE_FIRST;
770 
771     MEMiExpHeapMBlockHead* pMBlkHd      = NULL;
772     MEMiExpHeapMBlockHead* pMBlkHdFound = NULL;
773     u32 foundSize = 0xffffffff;
774     void* foundMBlock = NULL;
775 
776     // Search for free block
777     for ( pMBlkHd = pExpHeapHd->mbFreeList.tail; pMBlkHd; pMBlkHd = pMBlkHd->pMBHeadPrev )
778     {
779         void *const mblock    = GetMemPtrForMBlock_(pMBlkHd);
780         void *const mblockEnd = AddU32ToPtr( mblock, pMBlkHd->blockSize );
781         void *const reqMBlock = RoundDownPtr( SubU32ToPtr(mblockEnd, size), alignment );  // Aligned address
782 
783         if ( ComparePtr( reqMBlock, mblock ) >= 0
784              &&  foundSize > pMBlkHd->blockSize )
785         {
786             pMBlkHdFound = pMBlkHd;
787             foundSize    = pMBlkHd->blockSize;
788             foundMBlock  = reqMBlock;
789 
790             if ( bAllocFirst || foundSize == size )
791             {
792                 break;
793             }
794         }
795     }
796 
797     if ( ! pMBlkHdFound ) // No blocks matching the conditions were found
798     {
799         return NULL;
800     }
801 
802     return AllocUsedBlockFromFreeBlock_( // Allocates a region from the free block that was found
803                     pExpHeapHd,
804                     pMBlkHdFound,
805                     foundMBlock,
806                     size,
807                     MEM_EXPHEAP_ALLOC_DIR_REAR
808            );
809 }
810 
811 /*---------------------------------------------------------------------------*
812   Name:         RecycleRegion_
813 
814   Description:  Inserts the empty region in the free memory block.
815                 If it is adjacent to the free block it expands the free block.
816                 If there is no adjacent block, or the block is not large enough
817                 to be used as a free block, the alignment value of the used block adjacent to the end of the memory space is used.
818                 If there is no used block next to the end of the free block the function fails.
819 
820   Arguments:    pEHHead:  Pointer to the expanded heap header.
821                 pRegion:  Pointer to the free region.
822 
823   Returns:      Returns TRUE if the function is successful.
824                 Returns FALSE if it fails.
825  *---------------------------------------------------------------------------*/
826 static BOOL
RecycleRegion_(MEMiExpHeapHead * pEHHead,const MemRegion * pRegion)827 RecycleRegion_(
828     MEMiExpHeapHead*    pEHHead,
829     const MemRegion*    pRegion
830 )
831 {
832     MEMiExpHeapMBlockHead* pBlkPrFree  = NULL;   // Immediately preceding free block
833     MemRegion freeRgn = *pRegion;
834 
835     // Searches for free area next to the specified one.
836     {
837         MEMiExpHeapMBlockHead* pBlk;
838 
839         for ( pBlk = pEHHead->mbFreeList.head; pBlk; pBlk = pBlk->pMBHeadNext )
840         {
841             if ( pBlk < pRegion->start )
842             {
843                 pBlkPrFree = pBlk;
844                 continue;
845             }
846 
847             if ( pBlk == pRegion->end )   // Is the block next to the end?
848             {
849                 // Combines the available regions
850                 freeRgn.end = GetMBlockEndAddr_(pBlk);
851                 (void)RemoveMBlock_( &pEHHead->mbFreeList, pBlk );
852 
853                 // Pads the header with NoUse
854                 FillNoUseMemory( GetHeapHeadPtrFromExpHeapHead_(pEHHead), pBlk, sizeof(MEMiExpHeapMBlockHead) );
855             }
856             break;
857         }
858     }
859 
860     // Is the immediately preceding free block adjacent to the front?
861     if ( pBlkPrFree && GetMBlockEndAddr_(pBlkPrFree) == pRegion->start )
862     {
863         // Combines the available regions
864         freeRgn.start = pBlkPrFree;
865         pBlkPrFree = RemoveMBlock_(&pEHHead->mbFreeList, pBlkPrFree);
866     }
867 
868     if ( GetOffsetFromPtr(freeRgn.start, freeRgn.end) < sizeof(MEMiExpHeapMBlockHead) ) // Size not suitable for use as a block
869     {
870         return FALSE;   // Control reaches this point if an attempt is made to shrink a small-size block using ResizeForMBlockExpHeap() and
871                         // there is no free block after it.
872     }
873 
874     // Fills the memory for debugging
875     FillFreeMemory( GetHeapHeadPtrFromExpHeapHead_(pEHHead), pRegion->start, GetOffsetFromPtr(pRegion->start, pRegion->end) );
876 
877     (void)InsertMBlock_(
878                 &pEHHead->mbFreeList,
879                 InitFreeMBlock_(&freeRgn),   // Creates the free block
880                 pBlkPrFree
881           );
882 
883     return TRUE;
884 }
885 
886 
887 
888 
889 
890 /* ========================================================================
891     operation checking functions
892    ======================================================================== */
893 #if defined(_DEBUG)
894 
895 /*---------------------------------------------------------------------------*
896   Name:         CheckMBlock_
897 
898   Description:  Checks whether the header contents for the memory block are appropriate.
899 
900   Arguments:    pMBHead:    Pointer to the header for the memory block to be checked.
901                 pHeapHd:    Pointer to the expanded heap header.
902                 signature:  Memory block signature
903                 heapType:   Memory block type (used or free)
904                 flag   :       Flag.
905 
906   Returns:      Returns TRUE if the header contents for the memory block are appropriate,
907                 otherwise returns FALSE.
908  *---------------------------------------------------------------------------*/
909 static BOOL
CheckMBlock_(const MEMiExpHeapMBlockHead * pMBHead,MEMiHeapHead * pHeapHd,u16 signature,const char * heapType,u32 flag)910 CheckMBlock_(
911     const MEMiExpHeapMBlockHead*    pMBHead,
912     MEMiHeapHead*                   pHeapHd,
913     u16                             signature,
914     const char*                     heapType,
915     u32                             flag
916 )
917 {
918     const BOOL bPrint = ( 0 != (flag & MEM_HEAP_ERROR_PRINT) );
919     const void *const memBlock = GetMemCPtrForMBlock_(pMBHead);
920 
921     if ( pHeapHd )
922     {
923         if ( GetUIntPtr(pMBHead) < GetUIntPtr(pHeapHd->heapStart)
924              || GetUIntPtr(memBlock) > GetUIntPtr(pHeapHd->heapEnd)
925         )
926         {
927             HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Bad %s memory block address. - address %08X, heap area [%08X - %08X)\n",
928                          heapType, memBlock, pHeapHd->heapStart, pHeapHd->heapEnd);
929             return FALSE;
930         }
931     }
932     else
933     {
934         if ( GetUIntPtr(pMBHead) < 0x80000000 )
935         {
936             HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Bad %s memory block address. - address %08X\n",
937                          heapType, memBlock);
938             return FALSE;
939         }
940     }
941 
942     if ( pMBHead->signature != signature )    // Is the signature different?
943     {
944         HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Bad %s memory block signature. - address %08X, signature %04X\n",
945                      heapType, memBlock, pMBHead->signature);
946         return FALSE;
947     }
948 
949     if ( pMBHead->blockSize >= 0x08000000 )   // Size too big? (128MB or more)
950     {
951         HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Too large %s memory block. - address %08X, block size %08X\n",
952                      heapType, memBlock, pMBHead->blockSize);
953         return FALSE;
954     }
955 
956     if ( pHeapHd )
957     {
958         if ( GetUIntPtr(memBlock) + pMBHead->blockSize > GetUIntPtr(pHeapHd->heapEnd) )
959         {
960             HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " wrong size %s memory block. - address %08X, block size %08X\n",
961                          heapType, memBlock, pMBHead->blockSize);
962             return FALSE;
963         }
964     }
965 
966     return TRUE;
967 }
968 
969 
970 /*---------------------------------------------------------------------------*
971   Name:         CheckUsedMBlock_
972 
973   Description:  Checks whether the header contents for the memory block being used are appropriate.
974 
975   Arguments:    pMBHead:  Pointer to the header for the memory block to be checked.
976                 pHeapHd:  Pointer to the expanded heap header.
977                 flag   :     Flag.
978 
979   Returns:      Returns TRUE if the header contents for the memory block are appropriate,
980                 otherwise returns FALSE.
981  *---------------------------------------------------------------------------*/
982 static inline BOOL
CheckUsedMBlock_(const MEMiExpHeapMBlockHead * pMBHead,MEMiHeapHead * pHeapHd,u32 flag)983 CheckUsedMBlock_(
984     const MEMiExpHeapMBlockHead*    pMBHead,
985     MEMiHeapHead*                   pHeapHd,
986     u32                             flag
987 )
988 {
989     if ( pHeapHd )
990     {
991         MEMiExpHeapHead* pExpHeapHd = GetExpHeapHeadPtrFromHeapHead_(pHeapHd);
992         MEMiExpHeapMBlockHead* pMBlkHd      = NULL;
993         for ( pMBlkHd = pExpHeapHd->mbUsedList.head; pMBlkHd; pMBlkHd = pMBlkHd->pMBHeadNext )
994         {
995             if ( pMBHead == pMBlkHd )
996             {
997                 break;
998             }
999         }
1000         if ( pMBlkHd == NULL )
1001         {
1002             return FALSE;
1003         }
1004     }
1005     return CheckMBlock_( pMBHead, pHeapHd, MBLOCK_USED_SIGNATURE, "used", flag );
1006 }
1007 
1008 /*---------------------------------------------------------------------------*
1009   Name:         CheckFreeMBlock_
1010 
1011   Description:  Checks whether the header contents for the free memory block are appropriate.
1012 
1013   Arguments:    pMBHead:  Pointer to the header for the memory block to be checked.
1014                 pHeapHd:  Pointer to the expanded heap header.
1015                 flag   :     Flag.
1016 
1017   Returns:      Returns TRUE if the header contents for the memory block are appropriate,
1018                 otherwise returns FALSE.
1019  *---------------------------------------------------------------------------*/
1020 static inline BOOL
CheckFreeMBlock_(const MEMiExpHeapMBlockHead * pMBHead,MEMiHeapHead * pHeapHd,u32 flag)1021 CheckFreeMBlock_(
1022     const MEMiExpHeapMBlockHead*    pMBHead,
1023     MEMiHeapHead*                   pHeapHd,
1024     u32                             flag
1025 )
1026 {
1027     return CheckMBlock_( pMBHead, pHeapHd, MBLOCK_FREE_SIGNATURE, "free", flag );
1028 }
1029 
1030 
1031 /*---------------------------------------------------------------------------*
1032   Name:         CheckMBlockPrevPtr_
1033 
1034   Description:  Checks whether the link to the front of the memory block is correct.
1035 
1036   Arguments:    pMBHead:      Pointer to the header for the memory block to be checked.
1037                 pMBHeadPrev:  Pointer to the header for the memory block before the one to be checked.
1038                 flag   :         Flag.
1039 
1040   Returns:      Returns TRUE if the link to the front of the memory block is correct,
1041                 otherwise returns FALSE.
1042  *---------------------------------------------------------------------------*/
1043 static BOOL
CheckMBlockPrevPtr_(const MEMiExpHeapMBlockHead * pMBHead,const MEMiExpHeapMBlockHead * pMBHeadPrev,u32 flag)1044 CheckMBlockPrevPtr_(
1045     const MEMiExpHeapMBlockHead*    pMBHead,
1046     const MEMiExpHeapMBlockHead*    pMBHeadPrev,
1047     u32                             flag
1048 )
1049 {
1050     const BOOL bPrint = ( 0 != (flag & MEM_HEAP_ERROR_PRINT) );
1051 
1052     if ( pMBHead->pMBHeadPrev != pMBHeadPrev )
1053     {
1054         HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Wrong link memory block. - address %08X, previous address %08X != %08X\n",
1055                      GetMemCPtrForMBlock_(pMBHead), pMBHead->pMBHeadPrev, pMBHeadPrev);
1056         return FALSE;
1057     }
1058 
1059     return TRUE;
1060 }
1061 
1062 
1063 /*---------------------------------------------------------------------------*
1064   Name:         CheckMBlockNextPtr_
1065 
1066   Description:  Checks whether the link to the next memory block is correct.
1067 
1068   Arguments:    pMBHead:      Pointer to the header for the memory block to be checked.
1069                 pMBHeadNext:  Pointer to the header for the memory block after the one to be checked.
1070                 flag   :         Flag.
1071 
1072   Returns:      Returns TRUE if the link to the next memory block is correct,
1073                 otherwise returns FALSE.
1074  *---------------------------------------------------------------------------*/
1075 static BOOL
CheckMBlockNextPtr_(const MEMiExpHeapMBlockHead * pMBHead,const MEMiExpHeapMBlockHead * pMBHeadNext,u32 flag)1076 CheckMBlockNextPtr_(
1077     const MEMiExpHeapMBlockHead*   pMBHead,
1078     const MEMiExpHeapMBlockHead*   pMBHeadNext,
1079     u32                            flag
1080 )
1081 {
1082     const BOOL bPrint = ( 0 != (flag & MEM_HEAP_ERROR_PRINT) );
1083 
1084     if (pMBHead->pMBHeadNext != pMBHeadNext)
1085     {
1086         HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Wrong link memory block. - address %08X, next address %08X != %08X\n",
1087                      GetMemCPtrForMBlock_(pMBHead), pMBHead->pMBHeadNext, pMBHeadNext);
1088         return FALSE;
1089     }
1090 
1091     return TRUE;
1092 }
1093 
1094 
1095 /*---------------------------------------------------------------------------*
1096   Name:         CheckMBlockLinkTail_
1097 
1098   Description:  Checks whether the memory block pointer is at the head or tail of the memory block list.
1099 
1100   Arguments:    pMBHead:      Pointer to the header for the memory block to be checked.
1101                 pMBHeadTail:  Pointer to the memory block at the head or tail of the memory block list.
1102                 headType:     String indicating the head or tail.
1103                 flag   :         Flag.
1104 
1105   Returns:      Returns TRUE if the memory block pointer is at the head or tail of the memory block list,
1106                 otherwise returns FALSE.
1107  *---------------------------------------------------------------------------*/
1108 static BOOL
CheckMBlockLinkTail_(const MEMiExpHeapMBlockHead * pMBHead,const MEMiExpHeapMBlockHead * pMBHeadTail,const char * heapType,u32 flag)1109 CheckMBlockLinkTail_(
1110     const MEMiExpHeapMBlockHead*    pMBHead,
1111     const MEMiExpHeapMBlockHead*    pMBHeadTail,
1112     const char*                     heapType,
1113     u32                             flag
1114 )
1115 {
1116     const BOOL bPrint = 0 != (flag & MEM_HEAP_ERROR_PRINT);
1117 
1118     if ( pMBHead != pMBHeadTail )
1119     {
1120         HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Wrong memory brock list %s pointer. - address %08X, %s address %08X != %08X\n",
1121                      heapType, GetMemCPtrForMBlock_(pMBHead), heapType, pMBHead, pMBHeadTail);
1122         return FALSE;
1123     }
1124 
1125     return TRUE;
1126 }
1127 
1128 
1129 /*---------------------------------------------------------------------------*
1130   Name:         IsValidUsedMBlock_
1131 
1132   Description:  Checks whether the memory block being used is appropriate.
1133 
1134   Arguments:    memBlock:  The memory block to be checked.
1135                 heap :      The handle for the expanded heap containing the memory block.
1136                            If NULL is specified, no check is run to see whether
1137                            the memory block is included in the heap.
1138 
1139   Returns:      Returns TRUE if there is no problem with the specified memory block.
1140                 Returns FALSE if there is a problem.
1141  *---------------------------------------------------------------------------*/
1142 static BOOL
IsValidUsedMBlock_(const void * memBlock,MEMHeapHandle heap)1143 IsValidUsedMBlock_(
1144     const void*       memBlock,
1145     MEMHeapHandle     heap
1146 )
1147 {
1148     MEMiHeapHead* pHeapHd = heap;
1149 
1150     if ( ! memBlock)
1151     {
1152         return FALSE;
1153     }
1154 
1155     return CheckUsedMBlock_(GetMBlockHeadCPtr_(memBlock), pHeapHd, 0);
1156 }
1157 
1158 // #if defined(_DEBUG)
1159 #endif
1160 
1161 
1162 
1163 /* ========================================================================
1164     External Functions (Non-Public)
1165    ======================================================================== */
1166 
1167 /*---------------------------------------------------------------------------*
1168   Name:         MEMiDumpExpHeap
1169 
1170   Description:  Shows internal expanded heap information.
1171                 This function is for debugging.
1172 
1173   Arguments:    heap :    Handle for expanded heap
1174 
1175   Returns:      None.
1176  *---------------------------------------------------------------------------*/
1177 #if defined(_DEBUG)
1178 
1179 void
MEMiDumpExpHeap(MEMHeapHandle heap)1180 MEMiDumpExpHeap( MEMHeapHandle heap )
1181 {
1182     ASSERT(IsValidExpHeapHandle_(heap));
1183 
1184     {
1185         u32  usedSize = 0;
1186         u32  usedCnt = 0;
1187         u32  freeSize = 0;
1188         u32  freeCnt = 0;
1189 
1190         MEMiHeapHead* pHeapHd = heap;
1191         MEMiExpHeapHead* pExpHeapHd = GetExpHeapHeadPtrFromHandle_(pHeapHd);
1192 
1193         MEMiDumpHeapHead(pHeapHd);
1194 
1195         OSReport("     attr  address:   size    gid aln   prev_ptr next_ptr\n");   // Header line
1196 
1197         // ---------------- UsedBlock Dump ----------------
1198         OSReport("    (Used Blocks)\n" );
1199 
1200         if ( pExpHeapHd->mbUsedList.head == NULL )
1201         {
1202             OSReport("     NONE\n");
1203         }
1204         else
1205         {
1206             MEMiExpHeapMBlockHead* pMBHead;
1207 
1208             for ( pMBHead = pExpHeapHd->mbUsedList.head; pMBHead; pMBHead = pMBHead->pMBHeadNext )
1209             {
1210                 if ( pMBHead->signature != MBLOCK_USED_SIGNATURE )
1211                 {
1212                     OSReport("    xxxxx %08x: --------  --- ---  (-------- --------)\nabort\n", pMBHead);
1213                     break;
1214                 }
1215 
1216                 OSReport("    %s %08x: %8d  %3d %3d  (%08x %08x)\n",
1217                     GetAllocDirForMBlock_(pMBHead) == MEM_EXPHEAP_ALLOC_DIR_REAR ? " rear" : "front",
1218                     GetMemPtrForMBlock_(pMBHead),
1219                     pMBHead->blockSize,
1220                     GetGroupIDForMBlock_( pMBHead ),
1221                     GetAlignmentForMBlock_( pMBHead ),
1222                     pMBHead->pMBHeadPrev ? GetMemPtrForMBlock_(pMBHead->pMBHeadPrev): NULL,
1223                     pMBHead->pMBHeadNext ? GetMemPtrForMBlock_(pMBHead->pMBHeadNext): NULL
1224                 );
1225 
1226                 // ---- Use Quantity
1227                 usedSize += sizeof(MEMiExpHeapMBlockHead) + pMBHead->blockSize + GetAlignmentForMBlock_(pMBHead);
1228 
1229                 usedCnt ++;
1230             }
1231         }
1232 
1233         // ---------------- FreeBlock Dump ----------------
1234         OSReport("    (Free Blocks)\n" );
1235 
1236         if ( pExpHeapHd->mbFreeList.head == NULL )
1237         {
1238             OSReport("     NONE\n" );
1239         }
1240         else
1241         {
1242             MEMiExpHeapMBlockHead* pMBHead;
1243 
1244             for ( pMBHead = pExpHeapHd->mbFreeList.head; pMBHead; pMBHead = pMBHead->pMBHeadNext )
1245             {
1246                 if ( pMBHead->signature != MBLOCK_FREE_SIGNATURE )
1247                 {
1248                     OSReport("    xxxxx %08x: --------  --- ---  (-------- --------)\nabort\n", pMBHead);
1249                     break;
1250                 }
1251 
1252                 OSReport("    %s %08x: %8d  %3d %3d  (%08x %08x)\n",
1253                     " free",
1254                     GetMemPtrForMBlock_(pMBHead),
1255                     pMBHead->blockSize,
1256                     GetGroupIDForMBlock_( pMBHead ),
1257                     GetAlignmentForMBlock_( pMBHead ),
1258                     pMBHead->pMBHeadPrev ? GetMemPtrForMBlock_(pMBHead->pMBHeadPrev): NULL,
1259                     pMBHead->pMBHeadNext ? GetMemPtrForMBlock_(pMBHead->pMBHeadNext): NULL
1260                 );
1261 
1262                 freeCnt ++;
1263             }
1264         }
1265 
1266         OSReport("\n");
1267 
1268         {
1269             u32 heapSize  = GetOffsetFromPtr(pHeapHd->heapStart, pHeapHd->heapEnd); // Heap size (data region size)
1270             OSReport("    %d / %d bytes (%6.2f%%) used (U:%d F:%d)\n",
1271                                usedSize, heapSize, 100.0 * usedSize / heapSize, usedCnt, freeCnt);
1272         }
1273 
1274         OSReport("\n");
1275     }
1276 }
1277 
1278 // #if defined(_DEBUG)
1279 #endif
1280 
1281 
1282 
1283 /* ========================================================================
1284     External functions (public)
1285    ======================================================================== */
1286 
1287 /*---------------------------------------------------------------------------*
1288   Name:         MEMCreateExpHeapEx
1289 
1290   Description:  Creates expanded heap
1291 
1292   Arguments:    startAddress: Start address of heap area
1293                 size   :         Size of heap area
1294                 optFlag:      Option flag.
1295 
1296   Returns:      If the function succeeds, a handle for the created expanded heap is returned.
1297                 If the function fails, MEM_HEAP_INVALID_HANDLE is returned.
1298  *---------------------------------------------------------------------------*/
1299 MEMHeapHandle
MEMCreateExpHeapEx(void * startAddress,u32 size,u16 optFlag)1300 MEMCreateExpHeapEx(
1301     void*   startAddress,
1302     u32     size,
1303     u16     optFlag
1304 )
1305 {
1306     void* endAddress;
1307 
1308     ASSERT(startAddress != NULL);
1309 
1310     endAddress   = RoundDownPtr(AddU32ToPtr(startAddress, size), MIN_ALIGNMENT);
1311     startAddress = RoundUpPtr(startAddress, MIN_ALIGNMENT);
1312 
1313     if ( GetUIntPtr(startAddress) > GetUIntPtr(endAddress)
1314          ||  GetOffsetFromPtr(startAddress, endAddress) <
1315                     sizeof(MEMiHeapHead) + sizeof(MEMiExpHeapHead) + sizeof(MEMiExpHeapMBlockHead) + MIN_ALIGNMENT
1316     )
1317     {
1318         return MEM_HEAP_INVALID_HANDLE;
1319     }
1320 
1321     {   // Initialization for the Expanded heap
1322         MEMiHeapHead* pHeapHd = InitExpHeap_( startAddress, endAddress, optFlag );
1323         return pHeapHd;  // The pointer to the heap header is used as-is as the handle value.
1324     }
1325 }
1326 
1327 /*---------------------------------------------------------------------------*
1328   Name:         MEMDestroyExpHeap
1329 
1330   Description:  Destroys the expanded heap
1331 
1332   Arguments:    heap : Handle for expanded heap
1333 
1334   Returns:      Returns a pointer to the region occupied by the destroyed heap.
1335  *---------------------------------------------------------------------------*/
1336 void*
MEMDestroyExpHeap(MEMHeapHandle heap)1337 MEMDestroyExpHeap( MEMHeapHandle heap )
1338 {
1339     ASSERT( IsValidExpHeapHandle_(heap) );
1340 
1341     MEMiFinalizeHeap( heap );
1342     return (void*)heap;
1343 }
1344 
1345 /*---------------------------------------------------------------------------*
1346   Name:         MEMAllocFromExpHeapEx
1347 
1348   Description:  Allocates a memory block from the expanded heap.
1349                 The memory block alignment can be specified.
1350                 If a negative alignment value is specified, an empty region is searched for from the back of the heap.
1351 
1352   Arguments:    heap :      Handle for expanded heap
1353                 size   :      Size of the memory block to be allocated (in bytes)
1354                 alignment: Alignment of the memory block to be allocated.
1355                            The following values can be specified: �}4, �}8, �}16, �}32, �}64, �}128, ...
1356 
1357   Returns:      Returns the pointer
1358                 to the allocated memory block if the allocation is successful.
1359                 If fails, NULL is returned.
1360  *---------------------------------------------------------------------------*/
1361 void*
MEMAllocFromExpHeapEx(MEMHeapHandle heap,u32 size,int alignment)1362 MEMAllocFromExpHeapEx(
1363     MEMHeapHandle   heap,
1364     u32             size,
1365     int             alignment
1366 )
1367 {
1368     void* memory = NULL;
1369 
1370     ASSERT( IsValidExpHeapHandle_(heap) );
1371 
1372     // alignment check
1373     ASSERT(alignment % MIN_ALIGNMENT == 0);
1374     ASSERT((abs(alignment) & (abs(alignment) - 1)) == 0);
1375     ASSERT(MIN_ALIGNMENT <= abs(alignment));
1376 
1377     if ( size == 0 )
1378     {
1379         size = 1;
1380     }
1381 
1382     size = RoundUp( size, MIN_ALIGNMENT );    // The size actually allocated
1383 
1384     LockHeap( heap );
1385 
1386     if ( alignment >= 0 )     // Allocates from the front
1387     {
1388         memory = AllocFromHead_( heap, size, alignment );
1389     }
1390     else                    // Allocates from the back
1391     {
1392         memory = AllocFromTail_( heap, size, -alignment );
1393     }
1394 
1395     UnlockHeap( heap );
1396 
1397     return memory;
1398 }
1399 
1400 /*---------------------------------------------------------------------------*
1401   Name:         MEMResizeForMBlockExpHeap
1402 
1403   Description:  Changes the size of the memory block allocated from the expanded heap.
1404 
1405   Arguments:    heap :     Handle for expanded heap
1406                 memBlock: Pointer to the memory block to be resized.
1407                 size   :     The new size to be allocated (in bytes).
1408 
1409   Returns:      Returns the size of the resized memory block (in bytes) if the function is successful.
1410                 Returns 0 if the function fails.
1411  *---------------------------------------------------------------------------*/
1412 u32
MEMResizeForMBlockExpHeap(MEMHeapHandle heap,void * memBlock,u32 size)1413 MEMResizeForMBlockExpHeap(
1414     MEMHeapHandle   heap,
1415     void*           memBlock,
1416     u32             size
1417 )
1418 {
1419     MEMiExpHeapHead       *pEHHead;
1420     MEMiExpHeapMBlockHead *pMBHead;
1421 
1422     ASSERT(IsValidExpHeapHandle_(heap));
1423     ASSERT(IsValidUsedMBlock_(memBlock, heap));
1424 
1425     pEHHead = GetExpHeapHeadPtrFromHandle_(heap);
1426     pMBHead = GetMBlockHeadPtr_(memBlock);
1427 
1428     size = RoundUp( size, MIN_ALIGNMENT );
1429     if ( size == pMBHead->blockSize )  // If the block size is not changed
1430     {
1431         return size;
1432     }
1433 
1434     LockHeap( heap );
1435 
1436     // For expanding the new area
1437     if ( size > pMBHead->blockSize )
1438     {
1439         void* crUsedEnd = GetMBlockEndAddr_(pMBHead);   // The end address for the block currently being used
1440         MEMiExpHeapMBlockHead* block;
1441 
1442         // Searches for the next free block
1443         for ( block = pEHHead->mbFreeList.head; block; block = block->pMBHeadNext )
1444         {
1445             if ( block == crUsedEnd )
1446             {
1447                 break;
1448             }
1449         }
1450 
1451         // There is no next free block or the size is inadequate
1452         if ( ! block || size > pMBHead->blockSize + sizeof(MEMiExpHeapMBlockHead) + block->blockSize)
1453         {
1454             return 0;
1455         }
1456 
1457         {
1458             MemRegion         rgnNewFree;
1459             void              *oldFreeStart;
1460             MEMiExpHeapMBlockHead *nextBlockPrev;
1461 
1462             // Gets the free block region and temporarily removes the free block
1463             GetRegionOfMBlock_( &rgnNewFree, block );
1464             nextBlockPrev = RemoveMBlock_( &pEHHead->mbFreeList, block );
1465 
1466             oldFreeStart = rgnNewFree.start;
1467             rgnNewFree.start = AddU32ToPtr( memBlock, size ); // The region position to be newly freed
1468 
1469             // If the remainder is smaller than the memory block size
1470             if ( GetOffsetFromPtr(rgnNewFree.start, rgnNewFree.end) < sizeof(MEMiExpHeapMBlockHead) )
1471             {
1472                 rgnNewFree.start = rgnNewFree.end;  // It is absorbed into the block being used
1473             }
1474 
1475             pMBHead->blockSize = GetOffsetFromPtr(memBlock, rgnNewFree.start);  // Changes the target block size
1476 
1477             // If the remainder is equal to or larger than the memory block size
1478             if ( GetOffsetFromPtr(rgnNewFree.start, rgnNewFree.end) >= sizeof(MEMiExpHeapMBlockHead) )
1479             {
1480                 (void)InsertMBlock_(&pEHHead->mbFreeList, InitFreeMBlock_(&rgnNewFree), nextBlockPrev);   // Creates a new free block
1481             }
1482 
1483             FillAllocMemory(  // Extended partial file
1484                 heap,
1485                 oldFreeStart,
1486                 GetOffsetFromPtr(oldFreeStart, rgnNewFree.start));
1487         }
1488     }
1489     // When shrinking the new area
1490     else
1491     {
1492         MemRegion rgnNewFree;
1493         const u32 oldBlockSize = pMBHead->blockSize;
1494 
1495         rgnNewFree.start = AddU32ToPtr(memBlock, size); // The region position to be newly freed
1496         rgnNewFree.end   = GetMBlockEndAddr_(pMBHead);   // The end address for the block currently being used
1497 
1498         pMBHead->blockSize = size;  // Changes the target block size
1499 
1500         if ( ! RecycleRegion_(pEHHead, &rgnNewFree) )    // Tries returning the free list
1501         {
1502             pMBHead->blockSize = oldBlockSize;  // Restores to original form if failed
1503         }
1504     }
1505 
1506     UnlockHeap( heap );
1507 
1508     return pMBHead->blockSize;
1509 }
1510 
1511 /*---------------------------------------------------------------------------*
1512   Name:         MEMFreeToExpHeap
1513 
1514   Description:  Returns the memory block to the expanded heap.
1515 
1516   Arguments:    heap :     Handle for expanded heap
1517                 memBlock: Pointer to the memory block to be returned.
1518 
1519   Returns:      None.
1520  *---------------------------------------------------------------------------*/
1521 void
MEMFreeToExpHeap(MEMHeapHandle heap,void * memBlock)1522 MEMFreeToExpHeap(
1523     MEMHeapHandle   heap,
1524     void*           memBlock
1525 )
1526 {
1527     ASSERT(IsValidExpHeapHandle_(heap));
1528     if ( memBlock == NULL )
1529     {
1530         return;
1531     }
1532 
1533     ASSERT(IsValidUsedMBlock_(memBlock, heap));
1534 
1535     {
1536         MEMiHeapHead          *pHeapHd    = heap;
1537         MEMiExpHeapHead       *pExpHeapHd = GetExpHeapHeadPtrFromHandle_( pHeapHd );
1538         MEMiExpHeapMBlockHead *pMBHead    = GetMBlockHeadPtr_( memBlock );
1539         MemRegion             region;
1540 
1541         // Is it included in this heap?
1542         ASSERT( pHeapHd->heapStart <= memBlock && memBlock < pHeapHd->heapEnd );
1543 
1544         LockHeap( heap );
1545 
1546         GetRegionOfMBlock_( &region, pMBHead );
1547         (void)RemoveMBlock_( &pExpHeapHd->mbUsedList, pMBHead );   // Remove from the list being used
1548         (void)RecycleRegion_( pExpHeapHd, &region );   // Add the specified size from the specified address to the free region
1549 
1550         UnlockHeap( heap );
1551     }
1552 }
1553 
1554 /*---------------------------------------------------------------------------*
1555   Name:         MEMGetTotalFreeSizeForExpHeap
1556 
1557   Description:  Gets the total size of the empty regions of the expanded heap.
1558 
1559   Arguments:    heap :     Handle for expanded heap
1560 
1561   Returns:      Returns the total size of the empty regions in the expanded heap (in bytes).
1562  *---------------------------------------------------------------------------*/
1563 u32
MEMGetTotalFreeSizeForExpHeap(MEMHeapHandle heap)1564 MEMGetTotalFreeSizeForExpHeap( MEMHeapHandle heap )
1565 {
1566     u32     sumSize  = 0;
1567 
1568     ASSERT(IsValidExpHeapHandle_(heap));
1569 
1570     LockHeap( heap );
1571 
1572     {
1573         MEMiExpHeapHead       *pEHHead = GetExpHeapHeadPtrFromHandle_(heap);
1574         MEMiExpHeapMBlockHead *pMBHead;
1575 
1576         for ( pMBHead = pEHHead->mbFreeList.head; pMBHead; pMBHead = pMBHead->pMBHeadNext )
1577         {
1578             sumSize += pMBHead->blockSize;
1579         }
1580     }
1581 
1582     UnlockHeap( heap );
1583     return sumSize;
1584 }
1585 
1586 /*---------------------------------------------------------------------------*
1587   Name:         MEMGetAllocatableSizeForExpHeapEx
1588 
1589   Description:  Gets a memory block of the maximum allocatable size from the expanded heap.
1590                 The memory block alignment can be specified.
1591 
1592   Arguments:    heap :      Handle for expanded heap
1593                 alignment: Alignment of the memory block to be allocated.
1594                            The following values can be specified: �}4, �}8, �}16, �}32, �}64, �}128, ...
1595 
1596   Returns:      Returns the maximum allocatable size from the expanded heap (in bytes).
1597  *---------------------------------------------------------------------------*/
1598 u32
MEMGetAllocatableSizeForExpHeapEx(MEMHeapHandle heap,int alignment)1599 MEMGetAllocatableSizeForExpHeapEx(
1600     MEMHeapHandle   heap,
1601     int             alignment
1602 )
1603 {
1604     ASSERT(IsValidExpHeapHandle_(heap));
1605 
1606     // alignment check
1607     ASSERT(alignment % MIN_ALIGNMENT == 0);
1608     ASSERT((abs(alignment) & (abs(alignment) - 1)) == 0);
1609     ASSERT(MIN_ALIGNMENT <= abs(alignment));
1610 
1611     alignment = abs(alignment); // Convert to a positive value just to be sure
1612 
1613     LockHeap( heap );
1614 
1615     {
1616         MEMiExpHeapHead       *pEHHead  = GetExpHeapHeadPtrFromHandle_(heap);
1617         MEMiExpHeapMBlockHead *pMBlkHd;
1618         u32                   maxSize   = 0;
1619         u32                   offsetMin = 0xFFFFFFFF;
1620 
1621         for ( pMBlkHd = pEHHead->mbFreeList.head; pMBlkHd; pMBlkHd = pMBlkHd->pMBHeadNext )
1622         {
1623             // Memory block position including the alignment
1624             void* baseAddress = RoundUpPtr(GetMemPtrForMBlock_(pMBlkHd), alignment);
1625 
1626             if ( GetUIntPtr(baseAddress) < GetUIntPtr(GetMBlockEndAddr_(pMBlkHd)) )
1627             {
1628                 const u32 blockSize = GetOffsetFromPtr(baseAddress, GetMBlockEndAddr_(pMBlkHd));
1629                 // Empty area due to the alignment
1630                 const u32 offset = GetOffsetFromPtr(GetMemPtrForMBlock_(pMBlkHd), baseAddress);
1631 
1632                 /*
1633                     If the size is large, or the size is the same but wasted space is small,
1634                     the memory block is updated
1635                  */
1636                 if ( maxSize < blockSize
1637                      ||  (maxSize == blockSize && offsetMin > offset)
1638                 )
1639                 {
1640                     maxSize = blockSize;
1641                     offsetMin= offset;
1642                 }
1643             }
1644         }
1645 
1646         UnlockHeap( heap );
1647 
1648         return maxSize;
1649     }
1650 }
1651 
1652 
1653 /*---------------------------------------------------------------------------*
1654   Name:         MEMiIsEmptyExpHeap
1655 
1656   Description:  Checks whether the allocated block exists in the expanded heap.
1657 
1658   Arguments:    heap :  Handle for expanded heap
1659 
1660   Returns:      If it doesn't exist, returns TRUE;
1661                 If it does, returns FALSE.
1662  *---------------------------------------------------------------------------*/
1663 BOOL
MEMiIsEmptyExpHeap(MEMHeapHandle heap)1664 MEMiIsEmptyExpHeap( MEMHeapHandle heap )
1665 {
1666     MEMiExpHeapHead     *pExpHeapHd = GetExpHeapHeadPtrFromHeapHead_( heap );
1667     BOOL                ret;
1668 
1669     LockHeap( heap );
1670 
1671     ret = (pExpHeapHd->mbFreeList.head == NULL);
1672 
1673     UnlockHeap( heap );
1674 
1675     return ret;
1676 }
1677 
1678 /*---------------------------------------------------------------------------*
1679   Name:         MEMSetAllocModeForExpHeap
1680 
1681   Description:  Sets the memory allocation mode for the expanded heap.
1682 
1683   Arguments:    heap :  Handle for expanded heap
1684                 mode:  Memory allocation mode.
1685 
1686   Returns:      Returns the memory allocation mode for the previous expanded heap.
1687  *---------------------------------------------------------------------------*/
1688 u16
MEMSetAllocModeForExpHeap(MEMHeapHandle heap,u16 mode)1689 MEMSetAllocModeForExpHeap(
1690     MEMHeapHandle     heap,
1691     u16               mode
1692 )
1693 {
1694     BOOL enabled;
1695     u16  beforeMode;
1696 
1697     ASSERT(IsValidExpHeapHandle_(heap));
1698 
1699     enabled = OSDisableInterrupts();
1700     {
1701         MEMiExpHeapHead *const pEHHead = GetExpHeapHeadPtrFromHandle_(heap);
1702         beforeMode = GetAllocMode_(pEHHead);
1703         SetAllocMode_(pEHHead, mode);
1704     }
1705     (void)OSRestoreInterrupts( enabled );
1706 
1707     return beforeMode;
1708 }
1709 
1710 /*---------------------------------------------------------------------------*
1711   Name:         MEMGetAllocModeForExpHeap
1712 
1713   Description:  Gets the memory allocation mode for the expanded heap.
1714 
1715   Arguments:    heap :    Handle for expanded heap
1716 
1717   Returns:      Returns the memory allocation mode for the expanded heap.
1718  *---------------------------------------------------------------------------*/
1719 u16
MEMGetAllocModeForExpHeap(MEMHeapHandle heap)1720 MEMGetAllocModeForExpHeap( MEMHeapHandle heap )
1721 {
1722     ASSERT(IsValidExpHeapHandle_(heap));
1723     return GetAllocMode_(GetExpHeapHeadPtrFromHandle_(heap));
1724 }
1725 
1726 /*---------------------------------------------------------------------------*
1727   Name:         MEMSetGroupIDForExpHeap
1728 
1729   Description:  Sets the group ID for the expanded heap.
1730 
1731   Arguments:    heap :    Handle for expanded heap
1732                 groupID: The group ID value to be set.
1733 
1734   Returns:      Returns the previous group ID value.
1735  *---------------------------------------------------------------------------*/
1736 u16
MEMSetGroupIDForExpHeap(MEMHeapHandle heap,u16 groupID)1737 MEMSetGroupIDForExpHeap(
1738     MEMHeapHandle   heap,
1739     u16             groupID
1740 )
1741 {
1742     u16  beforeGroupID;
1743     BOOL enabled;
1744 
1745     ASSERT(IsValidExpHeapHandle_(heap));
1746     ASSERT(groupID <= MAX_GROUPID);
1747 
1748     enabled = OSDisableInterrupts();
1749     {
1750         MEMiExpHeapHead* pEHHead = GetExpHeapHeadPtrFromHandle_(heap);
1751         beforeGroupID = pEHHead->groupID;
1752         pEHHead->groupID = groupID;
1753 
1754     }
1755     (void)OSRestoreInterrupts( enabled );
1756 
1757     return beforeGroupID;
1758 }
1759 
1760 /*---------------------------------------------------------------------------*
1761   Name:         MEMGetGroupIDForExpHeap
1762 
1763   Description:  Gets the group ID for the expanded heap.
1764 
1765   Arguments:    heap :    Handle for expanded heap
1766 
1767   Returns:      Returns the group ID value.
1768  *---------------------------------------------------------------------------*/
1769 u16
MEMGetGroupIDForExpHeap(MEMHeapHandle heap)1770 MEMGetGroupIDForExpHeap( MEMHeapHandle heap )
1771 {
1772     ASSERT(IsValidExpHeapHandle_(heap));
1773 
1774     return GetExpHeapHeadPtrFromHandle_(heap)->groupID;
1775 }
1776 
1777 /*---------------------------------------------------------------------------*
1778   Name:         MEMVisitAllocatedForExpHeap
1779 
1780   Description:  Causes the function specified by the user to be called
1781                 for all the memory blocks allocated from the expanded heap.
1782                 The visitor function is called on these memory blocks in the order they were allocated.
1783 
1784                 The visitor type HeapVisitor is defined as below.
1785 
1786                     typedef void (*HeapVisitor)(
1787                                     void*               memBlock,
1788                                     MEMHeapHandle    heap,
1789                                     u32                 userParam);
1790 
1791                                         memBlock:   Pointer to the memory block.
1792                                         heap :       Heap including the memory block.
1793                                         userParam:  User parameter.
1794 
1795   Arguments:    heap :       Handle for expanded heap
1796                 visitor :    Function called for each memory block.
1797                 userParam:  User-specified parameter to be passed to the visitor function
1798 
1799   Returns:      None.
1800  *---------------------------------------------------------------------------*/
1801 void
MEMVisitAllocatedForExpHeap(MEMHeapHandle heap,MEMHeapVisitor visitor,u32 userParam)1802 MEMVisitAllocatedForExpHeap(
1803     MEMHeapHandle      heap,
1804     MEMHeapVisitor     visitor,
1805     u32                userParam
1806 )
1807 {
1808     ASSERT(IsValidExpHeapHandle_(heap));
1809     ASSERT(visitor != NULL);
1810 
1811     LockHeap( heap );
1812     {
1813         MEMiExpHeapMBlockHead* pMBHead = GetExpHeapHeadPtrFromHandle_(heap)->mbUsedList.head;
1814 
1815         while ( pMBHead )
1816         {
1817             MEMiExpHeapMBlockHead* pMBHeadNext = pMBHead->pMBHeadNext;
1818             (*visitor)(GetMemPtrForMBlock_(pMBHead), heap, userParam);
1819             pMBHead = pMBHeadNext;
1820         }
1821     }
1822     UnlockHeap( heap );
1823 }
1824 
1825 /*---------------------------------------------------------------------------*
1826   Name:         MEMGetSizeForMBlockExpHeap
1827 
1828   Description:  Gets the size of the memory block allocated from the expanded heap.
1829 
1830   Arguments:    memBlock:  Pointer to the memory block for getting the size.
1831 
1832   Returns:      Returns the size of the specified memory block (in bytes).
1833  *---------------------------------------------------------------------------*/
1834 u32
MEMGetSizeForMBlockExpHeap(const void * memBlock)1835 MEMGetSizeForMBlockExpHeap( const void* memBlock )
1836 {
1837     ASSERT(IsValidUsedMBlock_(memBlock, NULL));
1838 
1839     return GetMBlockHeadCPtr_( memBlock )->blockSize;
1840 }
1841 
1842 /*---------------------------------------------------------------------------*
1843   Name:         MEMGetGroupIDForMBlockExpHeap
1844 
1845   Description:  Gets the group ID for the memory block allocated from the expanded heap.
1846 
1847   Arguments:    memBlock:  Pointer to the memory block for getting the group ID.
1848 
1849   Returns:      Returns the group ID for the specified memory block.
1850  *---------------------------------------------------------------------------*/
1851 u16
MEMGetGroupIDForMBlockExpHeap(const void * memBlock)1852 MEMGetGroupIDForMBlockExpHeap( const void* memBlock )
1853 {
1854     ASSERT(IsValidUsedMBlock_(memBlock, NULL));
1855 
1856     return GetGroupIDForMBlock_( GetMBlockHeadCPtr_(memBlock) );
1857 }
1858 
1859 /*---------------------------------------------------------------------------*
1860   Name:         MEMGetAllocDirForMBlockExpHeap
1861 
1862   Description:  Gets the allocation direction for the memory block allocated from the expanded heap.
1863 
1864   Arguments:    memBlock:  Pointer to the memory block.
1865 
1866   Returns:      Returns the allocation direction for the specified memory block.
1867  *---------------------------------------------------------------------------*/
1868 u16
MEMGetAllocDirForMBlockExpHeap(const void * memBlock)1869 MEMGetAllocDirForMBlockExpHeap( const void* memBlock )
1870 {
1871     ASSERT(IsValidUsedMBlock_( memBlock, NULL ));
1872 
1873     return GetAllocDirForMBlock_( GetMBlockHeadCPtr_(memBlock) );
1874 }
1875 
1876 
1877 /*---------------------------------------------------------------------------*
1878   Name:         MEMAdjustExpHeap
1879 
1880   Description:  Releases the expanded heap's empty region, and reduces the memory available for the expanded heap.
1881                 There must not be memory blocks allocated from the back of heap memory.
1882 
1883   Arguments:    heap :      Handle for expanded heap
1884 
1885   Returns:      Returns the overal expanded heap size after reduction if successful.
1886                 (including the header portion)
1887                 Returns 0 if unsuccessful.
1888 
1889  *---------------------------------------------------------------------------*/
1890 u32
MEMAdjustExpHeap(MEMHeapHandle heap)1891 MEMAdjustExpHeap( MEMHeapHandle heap )
1892 {
1893     ASSERT( IsValidExpHeapHandle_(heap) );
1894 
1895     {
1896         MEMiHeapHead            *pHeapHd    = heap;
1897         MEMiExpHeapHead         *pExpHeapHd = GetExpHeapHeadPtrFromHeapHead_( heap );
1898         MEMiExpHeapMBlockHead   *pMBlkHd;
1899         u32                     retVal;
1900 
1901         LockHeap( heap );
1902 
1903         pMBlkHd  = pExpHeapHd->mbFreeList.tail;
1904 
1905         // fails if there are no empty regions
1906         if ( pMBlkHd == NULL )
1907         {
1908             retVal = 0;
1909             goto ret_;
1910         }
1911 
1912         {
1913             void * const pMBlk      = GetMemPtrForMBlock_( pMBlkHd );
1914             void * const pMBlkEnd   = AddU32ToPtr( pMBlk, pMBlkHd->blockSize );
1915             u32 blockSize;
1916 
1917             // fails if there are any memory blocks allocated from the end
1918             if ( pMBlkEnd != MEMGetHeapEndAddress( heap ) )
1919             {
1920                 retVal = 0;
1921                 goto ret_;
1922             }
1923 
1924             // Delete released free block from the free list
1925             (void)RemoveMBlock_( &pExpHeapHd->mbFreeList, pMBlkHd );
1926 
1927             blockSize = pMBlkHd->blockSize + sizeof( MEMiExpHeapMBlockHead );
1928             pHeapHd->heapEnd = SubU32ToPtr( pHeapHd->heapEnd, blockSize );
1929 
1930             retVal = GetOffsetFromPtr( pHeapHd, pHeapHd->heapEnd );
1931         }
1932 ret_:
1933         UnlockHeap( heap );
1934 
1935         return retVal;
1936     }
1937 }
1938 
1939 
1940 #if defined(_DEBUG)
1941 
1942 /*---------------------------------------------------------------------------*
1943   Name:         MEMCheckExpHeap
1944 
1945   Description:  Checks whether the expanded heap has been destroyed.
1946 
1947   Arguments:    heap :     Handle for expanded heap
1948                 optFlag:  Flag.
1949 
1950   Returns:      Returns TRUE if the heap is normal.
1951                 Returns FALSE if the heap has an error.
1952  *---------------------------------------------------------------------------*/
1953 BOOL
MEMCheckExpHeap(MEMHeapHandle heap,u32 optFlag)1954 MEMCheckExpHeap(
1955     MEMHeapHandle     heap,
1956     u32               optFlag
1957 )
1958 {
1959     const BOOL bPrint = 0 != (optFlag & MEM_HEAP_ERROR_PRINT);
1960     u32        totalBytes  = 0;
1961     BOOL       retVal;
1962 
1963     if ( ! IsValidExpHeapHandle_(heap) )
1964     {
1965         HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Invalid heap handle. - %08X\n", heap);
1966         return FALSE;
1967     }
1968 
1969     LockHeap( heap );
1970     {
1971         MEMiHeapHead *const    pHeapHd     = heap;
1972         MEMiExpHeapHead *const pExpHeapHd  = GetExpHeapHeadPtrFromHeapHead_(pHeapHd);
1973         MEMiExpHeapMBlockHead* pMBHead     = NULL;
1974         MEMiExpHeapMBlockHead* pMBHeadPrev = NULL;
1975 
1976         // Block used
1977         for ( pMBHead = pExpHeapHd->mbUsedList.head; pMBHead; pMBHeadPrev = pMBHead, pMBHead = pMBHead->pMBHeadNext )
1978         {
1979             if ( ! CheckUsedMBlock_(pMBHead, pHeapHd, optFlag)
1980               || ! CheckMBlockPrevPtr_(pMBHead, pMBHeadPrev, optFlag)   // Is the pointer to the previous block the same as the pointer to the memory block in the previous loop?
1981             )
1982             {
1983                 retVal = FALSE;
1984                 goto ret_;
1985             }
1986 
1987             // calculates size occupied
1988             totalBytes += sizeof(MEMiExpHeapMBlockHead) + pMBHead->blockSize + GetAlignmentForMBlock_(pMBHead);
1989         }
1990 
1991         if ( ! CheckMBlockLinkTail_(pMBHeadPrev, pExpHeapHd->mbUsedList.tail, "tail", optFlag))  // Is the last block referring to the pointer to the final block?
1992         {
1993             retVal = FALSE;
1994             goto ret_;
1995         }
1996 
1997         // free block
1998         pMBHead = NULL;
1999         pMBHeadPrev = NULL;
2000         for ( pMBHead = pExpHeapHd->mbFreeList.head; pMBHead; pMBHeadPrev = pMBHead, pMBHead = pMBHead->pMBHeadNext )
2001         {
2002             if ( ! CheckFreeMBlock_(pMBHead, pHeapHd, optFlag)
2003                  || ! CheckMBlockPrevPtr_(pMBHead, pMBHeadPrev, optFlag)   // Is the pointer to the previous block the same as the pointer to the memory block in the previous loop?
2004             )
2005             {
2006                 retVal = FALSE;
2007                 goto ret_;
2008             }
2009 
2010             // calculates size occupied
2011             totalBytes += sizeof(MEMiExpHeapMBlockHead) + pMBHead->blockSize;
2012         }
2013 
2014         if ( ! CheckMBlockLinkTail_(pMBHeadPrev, pExpHeapHd->mbFreeList.tail, "tail", optFlag) )  // Is the last block referring to the pointer to the final block?
2015         {
2016             retVal = FALSE;
2017             goto ret_;
2018         }
2019 
2020         // Display all results.
2021         if ( totalBytes != GetOffsetFromPtr(pHeapHd->heapStart, pHeapHd->heapEnd) )
2022         {
2023             HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Incorrect total memory block size. - heap size %08X, sum size %08X\n",
2024                 GetOffsetFromPtr(pHeapHd->heapStart, pHeapHd->heapEnd), totalBytes);
2025             retVal = FALSE;
2026             goto ret_;
2027         }
2028         retVal = TRUE;
2029     }
2030 ret_:
2031     UnlockHeap( heap );
2032     return retVal;
2033 }
2034 
2035 
2036 /*---------------------------------------------------------------------------*
2037   Name:         MEMCheckForMBlockExpHeap
2038 
2039   Description:  This function checks if the memory block of the expanded heap was destroyed.
2040 
2041   Arguments:    memBlock:  Pointer to the memory block checked.
2042                 heap :      Handle for expanded heap
2043                 optFlag:   Flag.
2044 
2045   Returns:      If the memory block is valid, TRUE.
2046                 If the memory block has an error, FALSE.
2047  *---------------------------------------------------------------------------*/
2048 BOOL
MEMCheckForMBlockExpHeap(const void * memBlock,MEMHeapHandle heap,u32 optFlag)2049 MEMCheckForMBlockExpHeap(
2050     const void*     memBlock,
2051     MEMHeapHandle   heap,
2052     u32             optFlag
2053 )
2054 {
2055     const MEMiExpHeapMBlockHead* pMBHead = NULL;
2056     MEMiHeapHead *const          pHeapHd = heap;
2057 
2058     if ( ! memBlock )
2059     {
2060         return FALSE;
2061     }
2062 
2063     pMBHead = GetMBlockHeadCPtr_( memBlock );
2064 
2065     if ( ! CheckUsedMBlock_( pMBHead, pHeapHd, optFlag ) )
2066     {
2067         return FALSE;
2068     }
2069 
2070     if ( pMBHead->pMBHeadPrev )
2071     {
2072         if ( ! CheckUsedMBlock_(pMBHead->pMBHeadPrev, pHeapHd, optFlag)        // Check of signature and size of previous block.
2073              || ! CheckMBlockNextPtr_(pMBHead->pMBHeadPrev, pMBHead, optFlag)  // Is the pointer for the next block of the previous block pointing to itself?
2074         )
2075         {
2076             return FALSE;
2077         }
2078     }
2079     else
2080     {
2081         if ( pHeapHd )
2082         {
2083             // If prev is NULL the head pointer of the list should be pointing to itself.
2084             if ( ! CheckMBlockLinkTail_(pMBHead, GetExpHeapHeadPtrFromHeapHead_(pHeapHd)->mbUsedList.head, "head", optFlag) )
2085             {
2086                 return FALSE;
2087             }
2088         }
2089     }
2090 
2091     if ( pMBHead->pMBHeadNext )
2092     {
2093         if ( ! CheckUsedMBlock_(pMBHead->pMBHeadNext, pHeapHd, optFlag)        // Check of signature and size of next block.
2094              || ! CheckMBlockPrevPtr_(pMBHead->pMBHeadNext, pMBHead, optFlag)  // Is the pointer for the previous block of the next block pointing to itself?
2095         )
2096         {
2097             return FALSE;
2098         }
2099     }
2100     else
2101     {
2102         if ( pHeapHd )
2103         {
2104             // If next is NULL the tail pointer of the list should be pointing to itself.
2105             if ( ! CheckMBlockLinkTail_(pMBHead, GetExpHeapHeadPtrFromHeapHead_(pHeapHd)->mbUsedList.tail, "tail", optFlag) )
2106             {
2107                 return FALSE;
2108             }
2109         }
2110     }
2111 
2112     return TRUE;
2113 }
2114 
2115 // #if defined(_DEBUG)
2116 #endif
2117 
2118 
2119