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 // signature for free memory block
24 #define MBLOCK_FREE_SIGNATURE   ('FR')
25 
26 // signature for the memory block being used
27 #define MBLOCK_USED_SIGNATURE   ('UD')
28 
29 // maximum value for the group ID
30 #define MAX_GROUPID             0xff
31 
32 // default value for the group ID
33 #define DEFAULT_GROUPID         0
34 
35 // minimum value for alignment
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 to register as a free block (size not including 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 warning output 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:  Get the larger address for two pointers
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 a pointer to a memory block from a pointer to a MEMiExpHeapMBlockHead structure.
168 
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 a pointer to a MEMiExpHeapMBlockHead structure from a pointer to a memory block.
190 
191                 Gets the pointer to the memory block.
192 
193   Arguments:    memBlock:  pointer to the memory block
194 
195   Returns:      Returns a pointer to a 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 terminal memory address from a memory block pointer.
213 
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 Functions
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 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 Functions
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 information 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 operations
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:      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 a 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 where the memory block will be inserted
449 
450   Returns:      Pointer to 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:   list to be added to
494                 block:  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 a 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;   /* Embed the signature */
526     block->attribute.val = 0;       /* Clear the attribute parameters */
527 
528     // Set 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:    terminal address for the memory for the expanded heap 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(           // common heap initializations
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     // create 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 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 start 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 );  // delete the free block for the time being
635 
636     // when there is no space for creating a free block
637     if ( ( GetOffsetFromPtr(freeRgnT.start, freeRgnT.end) < sizeof(MEMiExpHeapMBlockHead) + MIN_FREE_BLOCK_SIZE ) ||
638          ( direction == MEM_EXPHEAP_ALLOC_DIR_FRONT && !pEHHead->feature.fields.useMarginOfAlign                ) )
639     {
640         freeRgnT.end = freeRgnT.start;  // include the alignment value for the block being used
641     }
642     else
643     {
644         pMBHeadFreePrev = InsertMBlock_( &pEHHead->mbFreeList, InitFreeMBlock_(&freeRgnT), pMBHeadFreePrev );
645     }
646 
647     // when there is no space for creating a free block
648     if ( ( GetOffsetFromPtr(freeRgnB.start, freeRgnB.end) < sizeof(MEMiExpHeapMBlockHead) + MIN_FREE_BLOCK_SIZE ) ||
649          ( direction == MEM_EXPHEAP_ALLOC_DIR_REAR && !pEHHead->feature.fields.useMarginOfAlign                 ) )
650     {
651         freeRgnB.start= freeRgnB.end;   // include the block being used
652     }
653     else
654     {
655         (void)InsertMBlock_( &pEHHead->mbFreeList, InitFreeMBlock_(&freeRgnB), pMBHeadFreePrev );
656     }
657 
658     // fill the memory for debugging
659     FillAllocMemory(
660             GetHeapHeadPtrFromExpHeapHead_(pEHHead),
661             freeRgnT.end,
662             GetOffsetFromPtr(freeRgnT.end, freeRgnB.start)
663     );
664 
665     // create a new block
666     {
667         MEMiExpHeapMBlockHead* pMBHeadNewUsed;
668         MemRegion region;
669 
670         region.start = SubU32ToPtr( mblock, sizeof(MEMiExpHeapMBlockHead) );
671         region.end   = freeRgnB.start;
672 
673         pMBHeadNewUsed = InitMBlock_(&region, MBLOCK_USED_SIGNATURE );
674         SetAllocDirForMBlock_( pMBHeadNewUsed, direction );
675         SetAlignmentForMBlock_( pMBHeadNewUsed, (u16)GetOffsetFromPtr(freeRgnT.end, pMBHeadNewUsed) );
676         SetGroupIDForMBlock_( pMBHeadNewUsed, pEHHead->groupID );
677         AppendMBlock_( &pEHHead->mbUsedList, pMBHeadNewUsed );
678     }
679 
680     return mblock;
681 }
682 
683 /*---------------------------------------------------------------------------*
684   Name:         AllocFromHead_
685 
686   Description:  Allocates the memory block from the start of the heap.
687 
688   Arguments:    pHeapHd:    pointer to the heap header
689                 size:       size of the memory block to be allocated
690                 alignment:  alignment value
691 
692   Returns:      Returns a pointer to the allocated memory block if it was successfully allocated.
693 
694                 If the operation fails, NULL is returned.
695  *---------------------------------------------------------------------------*/
696 static void*
AllocFromHead_(MEMiHeapHead * pHeapHd,u32 size,int alignment)697 AllocFromHead_(
698     MEMiHeapHead*   pHeapHd,
699     u32             size,
700     int             alignment
701 )
702 {
703     MEMiExpHeapHead* pExpHeapHd = GetExpHeapHeadPtrFromHeapHead_(pHeapHd);
704 
705     // Allocate the first one found?
706     const BOOL bAllocFirst = GetAllocMode_(pExpHeapHd) == MEM_EXPHEAP_ALLOC_MODE_FIRST;
707 
708     MEMiExpHeapMBlockHead* pMBlkHd      = NULL;
709     MEMiExpHeapMBlockHead* pMBlkHdFound = NULL;
710     u32 foundSize = 0xffffffff;
711     void* foundMBlock = NULL;
712 
713     // search for free block
714     for ( pMBlkHd = pExpHeapHd->mbFreeList.head; pMBlkHd; pMBlkHd = pMBlkHd->pMBHeadNext )
715     {
716         void *const mblock    = GetMemPtrForMBlock_(pMBlkHd);
717         void *const reqMBlock = RoundUpPtr( mblock, alignment );
718         const u32 offset      = GetOffsetFromPtr( mblock, reqMBlock );    // generated offset
719 
720         if ( pMBlkHd->blockSize >= size + offset &&
721              foundSize > pMBlkHd->blockSize      )
722         {
723             pMBlkHdFound  = pMBlkHd;
724             foundSize     = pMBlkHd->blockSize;
725             foundMBlock   = reqMBlock;
726 
727             if ( bAllocFirst || foundSize == size )
728             {
729                 break;
730             }
731         }
732     }
733 
734     if ( ! pMBlkHdFound ) // no blocks matching the conditions were found
735     {
736         return NULL;
737     }
738 
739     return AllocUsedBlockFromFreeBlock_( // allocate a region from the free block that was found
740                     pExpHeapHd,
741                     pMBlkHdFound,
742                     foundMBlock,
743                     size,
744                     MEM_EXPHEAP_ALLOC_DIR_FRONT
745            );
746 }
747 
748 /*---------------------------------------------------------------------------*
749   Name:         AllocFromTail_
750 
751   Description:  Allocates a memory block from the end of the heap.
752 
753   Arguments:    pHeapHd:    pointer to the heap header
754                 size:       size of the memory block to be allocated
755                 alignment:  alignment value
756 
757   Returns:      Returns a pointer to the allocated memory block if it was successfully allocated.
758 
759                 If the operation fails, NULL is returned.
760  *---------------------------------------------------------------------------*/
761 static void*
AllocFromTail_(MEMiHeapHead * pHeapHd,u32 size,int alignment)762 AllocFromTail_(
763     MEMiHeapHead*   pHeapHd,
764     u32             size,
765     int             alignment
766 )
767 {
768     MEMiExpHeapHead* pExpHeapHd = GetExpHeapHeadPtrFromHeapHead_(pHeapHd);
769 
770     // Allocate the first one found?
771     const BOOL bAllocFirst = GetAllocMode_(pExpHeapHd) == MEM_EXPHEAP_ALLOC_MODE_FIRST;
772 
773     MEMiExpHeapMBlockHead* pMBlkHd      = NULL;
774     MEMiExpHeapMBlockHead* pMBlkHdFound = NULL;
775     u32 foundSize = 0xffffffff;
776     void* foundMBlock = NULL;
777 
778     // search for free block
779     for ( pMBlkHd = pExpHeapHd->mbFreeList.tail; pMBlkHd; pMBlkHd = pMBlkHd->pMBHeadPrev )
780     {
781         void *const mblock    = GetMemPtrForMBlock_(pMBlkHd);
782         void *const mblockEnd = AddU32ToPtr( mblock, pMBlkHd->blockSize );
783         void *const reqMBlock = RoundDownPtr( SubU32ToPtr(mblockEnd, size), alignment );  // aligned address
784 
785         if ( ComparePtr( reqMBlock, mblock ) >= 0
786              &&  foundSize > pMBlkHd->blockSize )
787         {
788             pMBlkHdFound = pMBlkHd;
789             foundSize    = pMBlkHd->blockSize;
790             foundMBlock  = reqMBlock;
791 
792             if ( bAllocFirst || foundSize == size )
793             {
794                 break;
795             }
796         }
797     }
798 
799     if ( ! pMBlkHdFound ) // no blocks matching the conditions were found
800     {
801         return NULL;
802     }
803 
804     return AllocUsedBlockFromFreeBlock_( // allocate a region from the free block that was found
805                     pExpHeapHd,
806                     pMBlkHdFound,
807                     foundMBlock,
808                     size,
809                     MEM_EXPHEAP_ALLOC_DIR_REAR
810            );
811 }
812 
813 /*---------------------------------------------------------------------------*
814   Name:         RecycleRegion_
815 
816   Description:  Incorporates an empty region into a free memory block.
817                 If it is adjacent to a free block, the free block is expanded.
818                 If it is not adjacent to a free block nor large enough to be used as a free block, the size of this empty region will be set as the alignment value for the used block adjacent to the end of it.
819 
820 
821                 If there is no used block adjacent to the end of the empty region, the function fails.
822 
823 
824   Arguments:    pEHHead:  pointer to the expanded heap header
825                 pRegion:  pointer to the empty region
826 
827   Returns:      Returns TRUE if the function is successful.
828                 Returns FALSE if it fails.
829  *---------------------------------------------------------------------------*/
830 static BOOL
RecycleRegion_(MEMiExpHeapHead * pEHHead,const MemRegion * pRegion)831 RecycleRegion_(
832     MEMiExpHeapHead*    pEHHead,
833     const MemRegion*    pRegion
834 )
835 {
836     MEMiExpHeapMBlockHead* pBlkPrFree  = NULL;   // immediately preceding free block
837     MemRegion freeRgn = *pRegion;
838 
839     // search for free area next to the specified one
840     {
841         MEMiExpHeapMBlockHead* pBlk;
842 
843         for ( pBlk = pEHHead->mbFreeList.head; pBlk; pBlk = pBlk->pMBHeadNext )
844         {
845             if ( pBlk < pRegion->start )
846             {
847                 pBlkPrFree = pBlk;
848                 continue;
849             }
850 
851             if ( pBlk == pRegion->end )   // Is the block adjacent to the end?
852             {
853                 // combine the available regions
854                 freeRgn.end = GetMBlockEndAddr_(pBlk);
855                 (void)RemoveMBlock_( &pEHHead->mbFreeList, pBlk );
856 
857                 // pad the header with NoUse
858                 FillNoUseMemory( GetHeapHeadPtrFromExpHeapHead_(pEHHead), pBlk, sizeof(MEMiExpHeapMBlockHead) );
859             }
860             break;
861         }
862     }
863 
864     // Is the immediately preceding free block adjacent to the front?
865     if ( pBlkPrFree && GetMBlockEndAddr_(pBlkPrFree) == pRegion->start )
866     {
867         // combine the available regions
868         freeRgn.start = pBlkPrFree;
869         pBlkPrFree = RemoveMBlock_(&pEHHead->mbFreeList, pBlkPrFree);
870     }
871 
872     if ( GetOffsetFromPtr(freeRgn.start, freeRgn.end) < sizeof(MEMiExpHeapMBlockHead) ) // size is not suitable for use as a block
873     {
874         return FALSE;   // Control reaches this point if an attempt is made to shrink a small block using ResizeForMBlockExpHeap() and if there are no free blocks behind it.
875                         //
876     }
877 
878     // fill the memory for debugging
879     FillFreeMemory( GetHeapHeadPtrFromExpHeapHead_(pEHHead), pRegion->start, GetOffsetFromPtr(pRegion->start, pRegion->end) );
880 
881     (void)InsertMBlock_(
882                 &pEHHead->mbFreeList,
883                 InitFreeMBlock_(&freeRgn),   // create the free block
884                 pBlkPrFree
885           );
886 
887     return TRUE;
888 }
889 
890 
891 
892 
893 
894 /* ========================================================================
895     Functions to Check Operations
896    ======================================================================== */
897 #if defined(_DEBUG)
898 
899 /*---------------------------------------------------------------------------*
900   Name:         CheckMBlock_
901 
902   Description:  Checks whether the header contents for the memory block are valid.
903 
904   Arguments:    pMBHead:    pointer to the header for the memory block to be checked
905                 pHeapHd:    pointer to the expanded heap header
906                 signature:  memory block signature
907                 heapType:   memory block type (used or free)
908                 flag:       flag
909 
910   Returns:      Returns TRUE if the contents of the memory block header are valid, and FALSE otherwise.
911 
912  *---------------------------------------------------------------------------*/
913 static BOOL
CheckMBlock_(const MEMiExpHeapMBlockHead * pMBHead,MEMiHeapHead * pHeapHd,u16 signature,const char * heapType,u32 flag)914 CheckMBlock_(
915     const MEMiExpHeapMBlockHead*    pMBHead,
916     MEMiHeapHead*                   pHeapHd,
917     u16                             signature,
918     const char*                     heapType,
919     u32                             flag
920 )
921 {
922     const BOOL bPrint = ( 0 != (flag & MEM_HEAP_ERROR_PRINT) );
923     const void *const memBlock = GetMemCPtrForMBlock_(pMBHead);
924 
925     if ( pHeapHd )
926     {
927         if ( GetUIntPtr(pMBHead) < GetUIntPtr(pHeapHd->heapStart)
928              || GetUIntPtr(memBlock) > GetUIntPtr(pHeapHd->heapEnd)
929         )
930         {
931             HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Bad %s memory block address. - address %08X, heap area [%08X - %08X)\n",
932                          heapType, memBlock, pHeapHd->heapStart, pHeapHd->heapEnd);
933             return FALSE;
934         }
935     }
936     else
937     {
938         if ( GetUIntPtr(pMBHead) < 0x80000000 )
939         {
940             HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Bad %s memory block address. - address %08X\n",
941                          heapType, memBlock);
942             return FALSE;
943         }
944     }
945 
946     if ( pMBHead->signature != signature )    // Is the signature different?
947     {
948         HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Bad %s memory block signature. - address %08X, signature %04X\n",
949                      heapType, memBlock, pMBHead->signature);
950         return FALSE;
951     }
952 
953     if ( pMBHead->blockSize >= 0x08000000 )   // Too large? (128 MB or greater)
954     {
955         HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Too large %s memory block. - address %08X, block size %08X\n",
956                      heapType, memBlock, pMBHead->blockSize);
957         return FALSE;
958     }
959 
960     if ( pHeapHd )
961     {
962         if ( GetUIntPtr(memBlock) + pMBHead->blockSize > GetUIntPtr(pHeapHd->heapEnd) )
963         {
964             HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " wrong size %s memory block. - address %08X, block size %08X\n",
965                          heapType, memBlock, pMBHead->blockSize);
966             return FALSE;
967         }
968     }
969 
970     return TRUE;
971 }
972 
973 
974 /*---------------------------------------------------------------------------*
975   Name:         CheckUsedMBlock_
976 
977   Description:  Checks whether the header contents for the memory block being used are valid.
978 
979   Arguments:    pMBHead:  pointer to the header for the memory block to be checked
980                 pHeapHd:  pointer to the expanded heap header
981                 flag:     flag
982 
983   Returns:      Returns TRUE if the contents of the memory block header are valid, and FALSE otherwise.
984 
985  *---------------------------------------------------------------------------*/
986 static inline BOOL
CheckUsedMBlock_(const MEMiExpHeapMBlockHead * pMBHead,MEMiHeapHead * pHeapHd,u32 flag)987 CheckUsedMBlock_(
988     const MEMiExpHeapMBlockHead*    pMBHead,
989     MEMiHeapHead*                   pHeapHd,
990     u32                             flag
991 )
992 {
993     if ( pHeapHd )
994     {
995         MEMiExpHeapHead* pExpHeapHd = GetExpHeapHeadPtrFromHeapHead_(pHeapHd);
996         MEMiExpHeapMBlockHead* pMBlkHd      = NULL;
997         for ( pMBlkHd = pExpHeapHd->mbUsedList.head; pMBlkHd; pMBlkHd = pMBlkHd->pMBHeadNext )
998         {
999             if ( pMBHead == pMBlkHd )
1000             {
1001                 break;
1002             }
1003         }
1004         if ( pMBlkHd == NULL )
1005         {
1006             return FALSE;
1007         }
1008     }
1009     return CheckMBlock_( pMBHead, pHeapHd, MBLOCK_USED_SIGNATURE, "used", flag );
1010 }
1011 
1012 /*---------------------------------------------------------------------------*
1013   Name:         CheckFreeMBlock_
1014 
1015   Description:  Checks whether the header contents for the free memory block are valid.
1016 
1017   Arguments:    pMBHead:  pointer to the header for the memory block to be checked
1018                 pHeapHd:  pointer to the expanded heap header
1019                 flag:     flag
1020 
1021   Returns:      Returns TRUE if the contents of the memory block header are valid, and FALSE otherwise.
1022 
1023  *---------------------------------------------------------------------------*/
1024 static inline BOOL
CheckFreeMBlock_(const MEMiExpHeapMBlockHead * pMBHead,MEMiHeapHead * pHeapHd,u32 flag)1025 CheckFreeMBlock_(
1026     const MEMiExpHeapMBlockHead*    pMBHead,
1027     MEMiHeapHead*                   pHeapHd,
1028     u32                             flag
1029 )
1030 {
1031     return CheckMBlock_( pMBHead, pHeapHd, MBLOCK_FREE_SIGNATURE, "free", flag );
1032 }
1033 
1034 
1035 /*---------------------------------------------------------------------------*
1036   Name:         CheckMBlockPrevPtr_
1037 
1038   Description:  Checks whether the link to the previous memory block is correct.
1039 
1040   Arguments:    pMBHead:      pointer to the header for the memory block to be checked
1041                 pMBHeadPrev:  pointer to the header for the memory block prior to the one being checked
1042                 flag:         flag
1043 
1044   Returns:      Returns TRUE if the link to the previous memory block is correct and FALSE otherwise.
1045 
1046  *---------------------------------------------------------------------------*/
1047 static BOOL
CheckMBlockPrevPtr_(const MEMiExpHeapMBlockHead * pMBHead,const MEMiExpHeapMBlockHead * pMBHeadPrev,u32 flag)1048 CheckMBlockPrevPtr_(
1049     const MEMiExpHeapMBlockHead*    pMBHead,
1050     const MEMiExpHeapMBlockHead*    pMBHeadPrev,
1051     u32                             flag
1052 )
1053 {
1054     const BOOL bPrint = ( 0 != (flag & MEM_HEAP_ERROR_PRINT) );
1055 
1056     if ( pMBHead->pMBHeadPrev != pMBHeadPrev )
1057     {
1058         HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Wrong link memory block. - address %08X, previous address %08X != %08X\n",
1059                      GetMemCPtrForMBlock_(pMBHead), pMBHead->pMBHeadPrev, pMBHeadPrev);
1060         return FALSE;
1061     }
1062 
1063     return TRUE;
1064 }
1065 
1066 
1067 /*---------------------------------------------------------------------------*
1068   Name:         CheckMBlockNextPtr_
1069 
1070   Description:  Checks whether the link to the next memory block is correct.
1071 
1072   Arguments:    pMBHead:      pointer to the header for the memory block to be checked
1073                 pMBHeadNext:  pointer to the header for the memory block after the one being checked
1074                 flag:         flag
1075 
1076   Returns:      Returns TRUE if the link to the next memory block is correct and FALSE otherwise.
1077 
1078  *---------------------------------------------------------------------------*/
1079 static BOOL
CheckMBlockNextPtr_(const MEMiExpHeapMBlockHead * pMBHead,const MEMiExpHeapMBlockHead * pMBHeadNext,u32 flag)1080 CheckMBlockNextPtr_(
1081     const MEMiExpHeapMBlockHead*   pMBHead,
1082     const MEMiExpHeapMBlockHead*   pMBHeadNext,
1083     u32                            flag
1084 )
1085 {
1086     const BOOL bPrint = ( 0 != (flag & MEM_HEAP_ERROR_PRINT) );
1087 
1088     if (pMBHead->pMBHeadNext != pMBHeadNext)
1089     {
1090         HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Wrong link memory block. - address %08X, next address %08X != %08X\n",
1091                      GetMemCPtrForMBlock_(pMBHead), pMBHead->pMBHeadNext, pMBHeadNext);
1092         return FALSE;
1093     }
1094 
1095     return TRUE;
1096 }
1097 
1098 
1099 /*---------------------------------------------------------------------------*
1100   Name:         CheckMBlockLinkTail_
1101 
1102   Description:  Checks whether the memory block pointer is at the start or end of the memory block list.
1103 
1104   Arguments:    pMBHead:      pointer to the header for the memory block to be checked
1105                 pMBHeadTail:  pointer to the memory block at the start or end of the memory block list
1106                 headType:     string indicating the start or end
1107                 flag:         flag
1108 
1109   Returns:      Returns TRUE if the memory block pointer is at the start or end of the memory block list, and FALSE otherwise.
1110 
1111  *---------------------------------------------------------------------------*/
1112 static BOOL
CheckMBlockLinkTail_(const MEMiExpHeapMBlockHead * pMBHead,const MEMiExpHeapMBlockHead * pMBHeadTail,const char * heapType,u32 flag)1113 CheckMBlockLinkTail_(
1114     const MEMiExpHeapMBlockHead*    pMBHead,
1115     const MEMiExpHeapMBlockHead*    pMBHeadTail,
1116     const char*                     heapType,
1117     u32                             flag
1118 )
1119 {
1120     const BOOL bPrint = 0 != (flag & MEM_HEAP_ERROR_PRINT);
1121 
1122     if ( pMBHead != pMBHeadTail )
1123     {
1124         HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Wrong memory brock list %s pointer. - address %08X, %s address %08X != %08X\n",
1125                      heapType, GetMemCPtrForMBlock_(pMBHead), heapType, pMBHead, pMBHeadTail);
1126         return FALSE;
1127     }
1128 
1129     return TRUE;
1130 }
1131 
1132 
1133 /*---------------------------------------------------------------------------*
1134   Name:         IsValidUsedMBlock_
1135 
1136   Description:  Checks whether the memory block being used is appropriate.
1137 
1138   Arguments:    memBlock:  memory block to be checked
1139                 heap:      handle for the expanded heap containing the memory block
1140                            If NULL is specified, no check is run to see if the memory block is included in the heap.
1141 
1142 
1143   Returns:      Returns TRUE if there is no problem with the specified memory block.
1144                 Returns FALSE if there is a problem.
1145  *---------------------------------------------------------------------------*/
1146 static BOOL
IsValidUsedMBlock_(const void * memBlock,MEMHeapHandle heap)1147 IsValidUsedMBlock_(
1148     const void*       memBlock,
1149     MEMHeapHandle     heap
1150 )
1151 {
1152     MEMiHeapHead* pHeapHd = heap;
1153     BOOL ret;
1154 
1155     if ( ! memBlock)
1156     {
1157         return FALSE;
1158     }
1159 
1160     if ( heap ) { LockHeap( heap );   }
1161 
1162     ret = CheckUsedMBlock_(GetMBlockHeadCPtr_(memBlock), pHeapHd, 0);
1163 
1164     if ( heap ) { UnlockHeap( heap ); }
1165 
1166     return ret;
1167 }
1168 
1169 // #if defined(_DEBUG)
1170 #endif
1171 
1172 
1173 
1174 /* ========================================================================
1175     external functions (non-public)
1176    ======================================================================== */
1177 
1178 /*---------------------------------------------------------------------------*
1179   Name:         MEMiDumpExpHeap
1180 
1181   Description:  Shows internal expanded heap information.
1182                 This function is used for debugging.
1183 
1184   Arguments:    heap:    Handle for the expanded heap.
1185 
1186   Returns:      None.
1187  *---------------------------------------------------------------------------*/
1188 #if defined(_DEBUG)
1189 
1190 void
MEMiDumpExpHeap(MEMHeapHandle heap)1191 MEMiDumpExpHeap( MEMHeapHandle heap )
1192 {
1193     ASSERT(IsValidExpHeapHandle_(heap));
1194 
1195     {
1196         u32  usedSize = 0;
1197         u32  usedCnt = 0;
1198         u32  freeSize = 0;
1199         u32  freeCnt = 0;
1200 
1201         MEMiHeapHead* pHeapHd = heap;
1202         MEMiExpHeapHead* pExpHeapHd = GetExpHeapHeadPtrFromHandle_(pHeapHd);
1203 
1204         MEMiDumpHeapHead(pHeapHd);
1205 
1206         OSReport("     attr  address:   size    gid aln   prev_ptr next_ptr\n");   // header line
1207 
1208         // ---------------- UsedBlock dump ----------------
1209         OSReport("    (Used Blocks)\n" );
1210 
1211         if ( pExpHeapHd->mbUsedList.head == NULL )
1212         {
1213             OSReport("     NONE\n");
1214         }
1215         else
1216         {
1217             MEMiExpHeapMBlockHead* pMBHead;
1218 
1219             for ( pMBHead = pExpHeapHd->mbUsedList.head; pMBHead; pMBHead = pMBHead->pMBHeadNext )
1220             {
1221                 if ( pMBHead->signature != MBLOCK_USED_SIGNATURE )
1222                 {
1223                     OSReport("    xxxxx %08x: --------  --- ---  (-------- --------)\nabort\n", pMBHead);
1224                     break;
1225                 }
1226 
1227                 OSReport("    %s %08x: %8d  %3d %3d  (%08x %08x)\n",
1228                     GetAllocDirForMBlock_(pMBHead) == MEM_EXPHEAP_ALLOC_DIR_REAR ? " rear" : "front",
1229                     GetMemPtrForMBlock_(pMBHead),
1230                     pMBHead->blockSize,
1231                     GetGroupIDForMBlock_( pMBHead ),
1232                     GetAlignmentForMBlock_( pMBHead ),
1233                     pMBHead->pMBHeadPrev ? GetMemPtrForMBlock_(pMBHead->pMBHeadPrev): NULL,
1234                     pMBHead->pMBHeadNext ? GetMemPtrForMBlock_(pMBHead->pMBHeadNext): NULL
1235                 );
1236 
1237                 // ---- amount used
1238                 usedSize += sizeof(MEMiExpHeapMBlockHead) + pMBHead->blockSize + GetAlignmentForMBlock_(pMBHead);
1239 
1240                 usedCnt ++;
1241             }
1242         }
1243 
1244         // ---------------- FreeBlock dump ----------------
1245         OSReport("    (Free Blocks)\n" );
1246 
1247         if ( pExpHeapHd->mbFreeList.head == NULL )
1248         {
1249             OSReport("     NONE\n" );
1250         }
1251         else
1252         {
1253             MEMiExpHeapMBlockHead* pMBHead;
1254 
1255             for ( pMBHead = pExpHeapHd->mbFreeList.head; pMBHead; pMBHead = pMBHead->pMBHeadNext )
1256             {
1257                 if ( pMBHead->signature != MBLOCK_FREE_SIGNATURE )
1258                 {
1259                     OSReport("    xxxxx %08x: --------  --- ---  (-------- --------)\nabort\n", pMBHead);
1260                     break;
1261                 }
1262 
1263                 OSReport("    %s %08x: %8d  %3d %3d  (%08x %08x)\n",
1264                     " free",
1265                     GetMemPtrForMBlock_(pMBHead),
1266                     pMBHead->blockSize,
1267                     GetGroupIDForMBlock_( pMBHead ),
1268                     GetAlignmentForMBlock_( pMBHead ),
1269                     pMBHead->pMBHeadPrev ? GetMemPtrForMBlock_(pMBHead->pMBHeadPrev): NULL,
1270                     pMBHead->pMBHeadNext ? GetMemPtrForMBlock_(pMBHead->pMBHeadNext): NULL
1271                 );
1272 
1273                 freeCnt ++;
1274             }
1275         }
1276 
1277         OSReport("\n");
1278 
1279         {
1280             u32 heapSize  = GetOffsetFromPtr(pHeapHd->heapStart, pHeapHd->heapEnd); // heap size (data region size)
1281             OSReport("    %d / %d bytes (%6.2f%%) used (U:%d F:%d)\n",
1282                                usedSize, heapSize, 100.0 * usedSize / heapSize, usedCnt, freeCnt);
1283         }
1284 
1285         OSReport("\n");
1286     }
1287 }
1288 
1289 // #if defined(_DEBUG)
1290 #endif
1291 
1292 
1293 
1294 /* ========================================================================
1295     external functions (public)
1296    ======================================================================== */
1297 
1298 /*---------------------------------------------------------------------------*
1299   Name:         MEMCreateExpHeapEx
1300 
1301   Description:  Creates an expanded heap.
1302 
1303   Arguments:    startAddress: Start address of heap area
1304                 size:         Size of heap area
1305                 optFlag:      Option flag
1306 
1307   Returns:      If the function succeeds, a handle for the created expanded heap is returned.
1308                 If the function fails, MEM_HEAP_INVALID_HANDLE is returned.
1309  *---------------------------------------------------------------------------*/
1310 MEMHeapHandle
MEMCreateExpHeapEx(void * startAddress,u32 size,u16 optFlag)1311 MEMCreateExpHeapEx(
1312     void*   startAddress,
1313     u32     size,
1314     u16     optFlag
1315 )
1316 {
1317     void* endAddress;
1318 
1319     ASSERT(startAddress != NULL);
1320 
1321     endAddress   = RoundDownPtr(AddU32ToPtr(startAddress, size), MIN_ALIGNMENT);
1322     startAddress = RoundUpPtr(startAddress, MIN_ALIGNMENT);
1323 
1324     if ( GetUIntPtr(startAddress) > GetUIntPtr(endAddress)
1325          ||  GetOffsetFromPtr(startAddress, endAddress) <
1326                     sizeof(MEMiHeapHead) + sizeof(MEMiExpHeapHead) + sizeof(MEMiExpHeapMBlockHead) + MIN_ALIGNMENT
1327     )
1328     {
1329         return MEM_HEAP_INVALID_HANDLE;
1330     }
1331 
1332     {   // initialization of the expanded heap
1333         MEMiHeapHead* pHeapHd = InitExpHeap_( startAddress, endAddress, optFlag );
1334         return pHeapHd;  // the pointer to the heap header is used as the handle value
1335     }
1336 }
1337 
1338 /*---------------------------------------------------------------------------*
1339   Name:         MEMDestroyExpHeap
1340 
1341   Description:  Destroys the expanded heap.
1342 
1343   Arguments:    heap: Handle for the expanded heap.
1344 
1345   Returns:      Returns a pointer to the region occupied by the destroyed heap.
1346  *---------------------------------------------------------------------------*/
1347 void*
MEMDestroyExpHeap(MEMHeapHandle heap)1348 MEMDestroyExpHeap( MEMHeapHandle heap )
1349 {
1350     ASSERT( IsValidExpHeapHandle_(heap) );
1351 
1352     MEMiFinalizeHeap( heap );
1353     return (void*)heap;
1354 }
1355 
1356 /*---------------------------------------------------------------------------*
1357   Name:         MEMAllocFromExpHeapEx
1358 
1359   Description:  Allocates a memory block from the expanded heap.
1360                 The memory block alignment can be specified.
1361                 If a negative alignment value is specified, an available region is searched for from the back of the heap.
1362 
1363   Arguments:    heap:      Handle for the expanded heap.
1364                 size:      Size of the memory block to be allocated (in bytes)
1365                 alignment: Alignment of the memory block to be allocated
1366                            The following values can be specified: + or - 4, + or - 8, + or - 16, + or - 32, + or - 64, + or - 128, ...
1367 
1368   Returns:      Returns a pointer to the allocated memory block if it was successfully allocated.
1369 
1370                 If the operation fails, NULL is returned.
1371  *---------------------------------------------------------------------------*/
1372 void*
MEMAllocFromExpHeapEx(MEMHeapHandle heap,u32 size,int alignment)1373 MEMAllocFromExpHeapEx(
1374     MEMHeapHandle   heap,
1375     u32             size,
1376     int             alignment
1377 )
1378 {
1379     void* memory = NULL;
1380 
1381     ASSERT( IsValidExpHeapHandle_(heap) );
1382 
1383     // check alignment
1384     ASSERT(alignment % MIN_ALIGNMENT == 0);
1385     ASSERT((abs(alignment) & (abs(alignment) - 1)) == 0);
1386     ASSERT(MIN_ALIGNMENT <= abs(alignment));
1387     ASSERT( (-128 <= alignment) && (alignment <= 128 ) );
1388 
1389     if ( size == 0 )
1390     {
1391         size = 1;
1392     }
1393 
1394     size = RoundUp( size, MIN_ALIGNMENT );    // size actually allocated
1395 
1396     LockHeap( heap );
1397 
1398     if ( alignment >= 0 )     // allocate from the front
1399     {
1400         memory = AllocFromHead_( heap, size, alignment );
1401     }
1402     else                    // allocate from the back
1403     {
1404         memory = AllocFromTail_( heap, size, -alignment );
1405     }
1406 
1407     UnlockHeap( heap );
1408 
1409     return memory;
1410 }
1411 
1412 /*---------------------------------------------------------------------------*
1413   Name:         MEMResizeForMBlockExpHeap
1414 
1415   Description:  Changes the size of the memory block allocated from the expanded heap.
1416 
1417   Arguments:    heap:     Handle for the expanded heap.
1418                 memBlock: Pointer to the memory block to be resized
1419                 size:     New size to be allocated (in bytes)
1420 
1421   Returns:      Returns the size of the resized memory block (in bytes), if the function is successful.
1422                 Returns 0 if the function fails.
1423  *---------------------------------------------------------------------------*/
1424 u32
MEMResizeForMBlockExpHeap(MEMHeapHandle heap,void * memBlock,u32 size)1425 MEMResizeForMBlockExpHeap(
1426     MEMHeapHandle   heap,
1427     void*           memBlock,
1428     u32             size
1429 )
1430 {
1431     MEMiExpHeapHead       *pEHHead;
1432     MEMiExpHeapMBlockHead *pMBHead;
1433 
1434     ASSERT(IsValidExpHeapHandle_(heap));
1435     ASSERT(memBlock != NULL);
1436 
1437     pEHHead = GetExpHeapHeadPtrFromHandle_(heap);
1438     pMBHead = GetMBlockHeadPtr_(memBlock);
1439 
1440     size = RoundUp( size, MIN_ALIGNMENT );
1441     if ( size == pMBHead->blockSize )  // when the block size is not changed
1442     {
1443         return size;
1444     }
1445 
1446     LockHeap( heap );
1447 
1448     ASSERT(IsValidUsedMBlock_(memBlock, heap));
1449 
1450     // for expanding the new area
1451     if ( size > pMBHead->blockSize )
1452     {
1453         void* crUsedEnd = GetMBlockEndAddr_(pMBHead);   // end address for the used block
1454         MEMiExpHeapMBlockHead* block;
1455 
1456         // search for the next free block
1457         for ( block = pEHHead->mbFreeList.head; block; block = block->pMBHeadNext )
1458         {
1459             if ( block == crUsedEnd )
1460             {
1461                 break;
1462             }
1463         }
1464 
1465         // there is no next free block or the size is inadequate
1466         if ( ! block || size > pMBHead->blockSize + sizeof(MEMiExpHeapMBlockHead) + block->blockSize)
1467         {
1468             UnlockHeap( heap );
1469             return 0;
1470         }
1471 
1472         {
1473             MemRegion         rgnNewFree;
1474             void              *oldFreeStart;
1475             MEMiExpHeapMBlockHead *nextBlockPrev;
1476 
1477             // get the free block region, and temporarily remove the free block
1478             GetRegionOfMBlock_( &rgnNewFree, block );
1479             nextBlockPrev = RemoveMBlock_( &pEHHead->mbFreeList, block );
1480 
1481             oldFreeStart = rgnNewFree.start;
1482             rgnNewFree.start = AddU32ToPtr( memBlock, size ); // region position to be newly freed
1483 
1484             // when the remainder is smaller than the memory block size
1485             if ( GetOffsetFromPtr(rgnNewFree.start, rgnNewFree.end) < sizeof(MEMiExpHeapMBlockHead) )
1486             {
1487                 rgnNewFree.start = rgnNewFree.end;  // absorbed into the used block
1488             }
1489 
1490             pMBHead->blockSize = GetOffsetFromPtr(memBlock, rgnNewFree.start);  // change the target block size
1491 
1492             // when the remainder is equal to or larger than the memory block size
1493             if ( GetOffsetFromPtr(rgnNewFree.start, rgnNewFree.end) >= sizeof(MEMiExpHeapMBlockHead) )
1494             {
1495                 (void)InsertMBlock_(&pEHHead->mbFreeList, InitFreeMBlock_(&rgnNewFree), nextBlockPrev);   // create a new free block
1496             }
1497 
1498             FillAllocMemory(  // expanded portion fill
1499                 heap,
1500                 oldFreeStart,
1501                 GetOffsetFromPtr(oldFreeStart, rgnNewFree.start));
1502         }
1503     }
1504     // when the new area is reduced
1505     else
1506     {
1507         MemRegion rgnNewFree;
1508         const u32 oldBlockSize = pMBHead->blockSize;
1509 
1510         rgnNewFree.start = AddU32ToPtr(memBlock, size); // region position to be newly freed
1511         rgnNewFree.end   = GetMBlockEndAddr_(pMBHead);   // end address for the used block
1512 
1513         pMBHead->blockSize = size;  // change the target block size
1514 
1515         if ( ! RecycleRegion_(pEHHead, &rgnNewFree) )    // try to return to the free list
1516         {
1517             pMBHead->blockSize = oldBlockSize;  // restore to original form if failed
1518         }
1519     }
1520 
1521     UnlockHeap( heap );
1522 
1523     return pMBHead->blockSize;
1524 }
1525 
1526 /*---------------------------------------------------------------------------*
1527   Name:         MEMFreeToExpHeap
1528 
1529   Description:  Returns the memory block to the expanded heap.
1530 
1531   Arguments:    heap:     Handle for the expanded heap.
1532                 memBlock: Pointer to the memory block to be returned
1533 
1534   Returns:      None.
1535  *---------------------------------------------------------------------------*/
1536 void
MEMFreeToExpHeap(MEMHeapHandle heap,void * memBlock)1537 MEMFreeToExpHeap(
1538     MEMHeapHandle   heap,
1539     void*           memBlock
1540 )
1541 {
1542     ASSERT(IsValidExpHeapHandle_(heap));
1543     if ( memBlock == NULL )
1544     {
1545         return;
1546     }
1547 
1548     LockHeap( heap );
1549     {
1550         MEMiHeapHead          *pHeapHd    = heap;
1551         MEMiExpHeapHead       *pExpHeapHd = GetExpHeapHeadPtrFromHandle_( pHeapHd );
1552         MEMiExpHeapMBlockHead *pMBHead    = GetMBlockHeadPtr_( memBlock );
1553         MemRegion             region;
1554 
1555         ASSERT(IsValidUsedMBlock_(memBlock, heap));
1556 
1557         // Is it included in this heap?
1558         ASSERT( pHeapHd->heapStart <= memBlock && memBlock < pHeapHd->heapEnd );
1559 
1560         GetRegionOfMBlock_( &region, pMBHead );
1561         (void)RemoveMBlock_( &pExpHeapHd->mbUsedList, pMBHead );   // remove from the list being used
1562         (void)RecycleRegion_( pExpHeapHd, &region );   // add the specified size from the specified address to the free region
1563     }
1564     UnlockHeap( heap );
1565 }
1566 
1567 /*---------------------------------------------------------------------------*
1568   Name:         MEMGetTotalFreeSizeForExpHeap
1569 
1570   Description:  Gets the total size of the available regions of the expanded heap.
1571 
1572   Arguments:    heap:     Handle for the expanded heap.
1573 
1574   Returns:      Returns the total size of the available regions in the expanded heap (in bytes).
1575  *---------------------------------------------------------------------------*/
1576 u32
MEMGetTotalFreeSizeForExpHeap(MEMHeapHandle heap)1577 MEMGetTotalFreeSizeForExpHeap( MEMHeapHandle heap )
1578 {
1579     u32     sumSize  = 0;
1580 
1581     ASSERT(IsValidExpHeapHandle_(heap));
1582 
1583     LockHeap( heap );
1584 
1585     {
1586         MEMiExpHeapHead       *pEHHead = GetExpHeapHeadPtrFromHandle_(heap);
1587         MEMiExpHeapMBlockHead *pMBHead;
1588 
1589         for ( pMBHead = pEHHead->mbFreeList.head; pMBHead; pMBHead = pMBHead->pMBHeadNext )
1590         {
1591             sumSize += pMBHead->blockSize;
1592         }
1593     }
1594 
1595     UnlockHeap( heap );
1596     return sumSize;
1597 }
1598 
1599 /*---------------------------------------------------------------------------*
1600   Name:         MEMGetAllocatableSizeForExpHeapEx
1601 
1602   Description:  Gets a memory block of the maximum allocatable size from the expanded heap.
1603                 The memory block alignment can be specified.
1604 
1605   Arguments:    heap:      Handle for the expanded heap.
1606                 alignment: Alignment of the memory block to be allocated
1607                            The following values can be specified: + or - 4, + or - 8, + or - 16, + or - 32, + or - 64, + or - 128, ...
1608 
1609   Returns:      Returns the maximum allocatable size from the expanded heap (in bytes).
1610  *---------------------------------------------------------------------------*/
1611 u32
MEMGetAllocatableSizeForExpHeapEx(MEMHeapHandle heap,int alignment)1612 MEMGetAllocatableSizeForExpHeapEx(
1613     MEMHeapHandle   heap,
1614     int             alignment
1615 )
1616 {
1617     ASSERT(IsValidExpHeapHandle_(heap));
1618 
1619     // check alignment
1620     ASSERT(alignment % MIN_ALIGNMENT == 0);
1621     ASSERT((abs(alignment) & (abs(alignment) - 1)) == 0);
1622     ASSERT(MIN_ALIGNMENT <= abs(alignment));
1623 
1624     alignment = abs(alignment); // convert to a positive value just to be sure
1625 
1626     LockHeap( heap );
1627 
1628     {
1629         MEMiExpHeapHead       *pEHHead  = GetExpHeapHeadPtrFromHandle_(heap);
1630         MEMiExpHeapMBlockHead *pMBlkHd;
1631         u32                   maxSize   = 0;
1632         u32                   offsetMin = 0xFFFFFFFF;
1633 
1634         for ( pMBlkHd = pEHHead->mbFreeList.head; pMBlkHd; pMBlkHd = pMBlkHd->pMBHeadNext )
1635         {
1636             // memory block position giving consideration to the alignment
1637             void* baseAddress = RoundUpPtr(GetMemPtrForMBlock_(pMBlkHd), alignment);
1638 
1639             if ( GetUIntPtr(baseAddress) < GetUIntPtr(GetMBlockEndAddr_(pMBlkHd)) )
1640             {
1641                 const u32 blockSize = GetOffsetFromPtr(baseAddress, GetMBlockEndAddr_(pMBlkHd));
1642                 // empty area due to the alignment
1643                 const u32 offset = GetOffsetFromPtr(GetMemPtrForMBlock_(pMBlkHd), baseAddress);
1644 
1645                 /*
1646                     when the size is large, or if the size is the same but the wasted space is smaller, the memory block is updated
1647 
1648                  */
1649                 if ( maxSize < blockSize
1650                      ||  (maxSize == blockSize && offsetMin > offset)
1651                 )
1652                 {
1653                     maxSize = blockSize;
1654                     offsetMin= offset;
1655                 }
1656             }
1657         }
1658 
1659         UnlockHeap( heap );
1660 
1661         return maxSize;
1662     }
1663 }
1664 
1665 
1666 /*---------------------------------------------------------------------------*
1667   Name:         MEMiIsEmptyExpHeap
1668 
1669   Description:  Checks whether the allocated block exists in the expanded heap.
1670 
1671   Arguments:    heap:  Handle for the expanded heap.
1672 
1673   Returns:      TRUE if it does not exist and FALSE otherwise.
1674 
1675  *---------------------------------------------------------------------------*/
1676 BOOL
MEMiIsEmptyExpHeap(MEMHeapHandle heap)1677 MEMiIsEmptyExpHeap( MEMHeapHandle heap )
1678 {
1679     MEMiExpHeapHead     *pExpHeapHd = GetExpHeapHeadPtrFromHeapHead_( heap );
1680     BOOL                ret;
1681 
1682     LockHeap( heap );
1683 
1684     ret = (pExpHeapHd->mbFreeList.head == NULL);
1685 
1686     UnlockHeap( heap );
1687 
1688     return ret;
1689 }
1690 
1691 /*---------------------------------------------------------------------------*
1692   Name:         MEMSetAllocModeForExpHeap
1693 
1694   Description:  Sets the memory allocation mode for the expanded heap.
1695 
1696   Arguments:    heap:  Handle for the expanded heap.
1697                 mode:  Memory allocation mode.
1698 
1699   Returns:      Returns the memory allocation mode for the previous expanded heap.
1700  *---------------------------------------------------------------------------*/
1701 u16
MEMSetAllocModeForExpHeap(MEMHeapHandle heap,u16 mode)1702 MEMSetAllocModeForExpHeap(
1703     MEMHeapHandle     heap,
1704     u16               mode
1705 )
1706 {
1707     BOOL enabled;
1708     u16  beforeMode;
1709 
1710     ASSERT(IsValidExpHeapHandle_(heap));
1711 
1712     enabled = OSDisableInterrupts();
1713     {
1714         MEMiExpHeapHead *const pEHHead = GetExpHeapHeadPtrFromHandle_(heap);
1715         beforeMode = GetAllocMode_(pEHHead);
1716         SetAllocMode_(pEHHead, mode);
1717     }
1718     (void)OSRestoreInterrupts( enabled );
1719 
1720     return beforeMode;
1721 }
1722 
1723 /*---------------------------------------------------------------------------*
1724   Name:         MEMGetAllocModeForExpHeap
1725 
1726   Description:  Gets the memory allocation mode for the expanded heap.
1727 
1728   Arguments:    heap:    Handle for the expanded heap.
1729 
1730   Returns:      Returns the memory allocation mode for the expanded heap.
1731  *---------------------------------------------------------------------------*/
1732 u16
MEMGetAllocModeForExpHeap(MEMHeapHandle heap)1733 MEMGetAllocModeForExpHeap( MEMHeapHandle heap )
1734 {
1735     ASSERT(IsValidExpHeapHandle_(heap));
1736     return GetAllocMode_(GetExpHeapHeadPtrFromHandle_(heap));
1737 }
1738 
1739 
1740 /*---------------------------------------------------------------------------*
1741   Name:         MEMUseMarginOfAlignmentForExpHeap
1742 
1743   Description:  Configures whether regions should be reused in the gaps that occur during alignment.
1744 
1745                 Set to FALSE by default.
1746 
1747                 If this is set to TRUE, it is possible to use small memory regions effectively. However, there is a risk that a large number of free blocks will be created and performance could degrade when memory is allocated.
1748 
1749 
1750 
1751 
1752   Arguments:    heap:    Expanded heap handle
1753                 reuse:   If TRUE, reuse regions that are generated during alignment.
1754                          If FALSE, do not reuse.
1755 
1756   Returns:      Returns the value of the previous setting.
1757  *---------------------------------------------------------------------------*/
1758 BOOL
MEMUseMarginOfAlignmentForExpHeap(MEMHeapHandle heap,BOOL reuse)1759 MEMUseMarginOfAlignmentForExpHeap( MEMHeapHandle heap, BOOL reuse )
1760 {
1761     MEMiExpHeapHead *const pEHHead = GetExpHeapHeadPtrFromHandle_(heap);
1762     BOOL before;
1763 
1764     ASSERT( IsValidExpHeapHandle_(heap) );
1765 
1766     before = pEHHead->feature.fields.useMarginOfAlign;
1767     pEHHead->feature.fields.useMarginOfAlign = reuse;
1768 
1769     return before;
1770 }
1771 
1772 
1773 /*---------------------------------------------------------------------------*
1774   Name:         MEMSetGroupIDForExpHeap
1775 
1776   Description:  Sets the group ID for the expanded heap.
1777 
1778   Arguments:    heap:    Handle for the expanded heap.
1779                 groupID: Group ID value to be set.
1780 
1781   Returns:      Returns the previous group ID value.
1782  *---------------------------------------------------------------------------*/
1783 u16
MEMSetGroupIDForExpHeap(MEMHeapHandle heap,u16 groupID)1784 MEMSetGroupIDForExpHeap(
1785     MEMHeapHandle   heap,
1786     u16             groupID
1787 )
1788 {
1789     u16  beforeGroupID;
1790     BOOL enabled;
1791 
1792     ASSERT( IsValidExpHeapHandle_(heap) );
1793     ASSERT( groupID <= MAX_GROUPID      );
1794 
1795     enabled = OSDisableInterrupts();
1796     {
1797         MEMiExpHeapHead* pEHHead = GetExpHeapHeadPtrFromHandle_(heap);
1798         beforeGroupID = pEHHead->groupID;
1799         pEHHead->groupID = groupID;
1800 
1801     }
1802     (void)OSRestoreInterrupts( enabled );
1803 
1804     return beforeGroupID;
1805 }
1806 
1807 /*---------------------------------------------------------------------------*
1808   Name:         MEMGetGroupIDForExpHeap
1809 
1810   Description:  Gets the group ID for the expanded heap.
1811 
1812   Arguments:    heap:    Handle for the expanded heap.
1813 
1814   Returns:      Returns the group ID value.
1815  *---------------------------------------------------------------------------*/
1816 u16
MEMGetGroupIDForExpHeap(MEMHeapHandle heap)1817 MEMGetGroupIDForExpHeap( MEMHeapHandle heap )
1818 {
1819     ASSERT(IsValidExpHeapHandle_(heap));
1820 
1821     return GetExpHeapHeadPtrFromHandle_(heap)->groupID;
1822 }
1823 
1824 /*---------------------------------------------------------------------------*
1825   Name:         MEMVisitAllocatedForExpHeap
1826 
1827   Description:  Causes the function specified by the user to be called for all the memory blocks allocated from the expanded heap.
1828 
1829                 The order of the memory blocks called by the visitor function is the order in which they were allocated.
1830 
1831                 The visitor type HeapVisitor is defined as below.
1832 
1833                     typedef void (*HeapVisitor)(
1834                                     void*               memBlock,
1835                                     MEMHeapHandle    heap,
1836                                     u32                 userParam);
1837 
1838                                         memBlock:   pointer to the memory block
1839                                         heap:       heap that includes the memory block
1840                                         userParam:  user parameter
1841 
1842   Arguments:    heap:       Handle for the expanded heap.
1843                 visitor:    Function called for each memory block
1844                 userParam:  User-specified parameter passed to the visitor function
1845 
1846   Returns:      None.
1847  *---------------------------------------------------------------------------*/
1848 void
MEMVisitAllocatedForExpHeap(MEMHeapHandle heap,MEMHeapVisitor visitor,u32 userParam)1849 MEMVisitAllocatedForExpHeap(
1850     MEMHeapHandle      heap,
1851     MEMHeapVisitor     visitor,
1852     u32                userParam
1853 )
1854 {
1855     ASSERT(IsValidExpHeapHandle_(heap));
1856     ASSERT(visitor != NULL);
1857 
1858     LockHeap( heap );
1859     {
1860         MEMiExpHeapMBlockHead* pMBHead = GetExpHeapHeadPtrFromHandle_(heap)->mbUsedList.head;
1861 
1862         while ( pMBHead )
1863         {
1864             MEMiExpHeapMBlockHead* pMBHeadNext = pMBHead->pMBHeadNext;
1865             (*visitor)(GetMemPtrForMBlock_(pMBHead), heap, userParam);
1866             pMBHead = pMBHeadNext;
1867         }
1868     }
1869     UnlockHeap( heap );
1870 }
1871 
1872 /*---------------------------------------------------------------------------*
1873   Name:         MEMGetSizeForMBlockExpHeap
1874 
1875   Description:  Gets the size of the memory block that was allocated from the expanded heap.
1876 
1877   Arguments:    memBlock:  pointer to the memory block for getting the size
1878 
1879   Returns:      Returns the size of the specified memory block (in bytes).
1880  *---------------------------------------------------------------------------*/
1881 u32
MEMGetSizeForMBlockExpHeap(const void * memBlock)1882 MEMGetSizeForMBlockExpHeap( const void* memBlock )
1883 {
1884     ASSERT(IsValidUsedMBlock_(memBlock, NULL));
1885 
1886     return GetMBlockHeadCPtr_( memBlock )->blockSize;
1887 }
1888 
1889 /*---------------------------------------------------------------------------*
1890   Name:         MEMGetGroupIDForMBlockExpHeap
1891 
1892   Description:  Gets the group ID for the memory block allocated from the expanded heap.
1893 
1894   Arguments:    memBlock:  pointer to the memory block for getting the group ID
1895 
1896   Returns:      Returns the group ID for the specified memory block.
1897  *---------------------------------------------------------------------------*/
1898 u16
MEMGetGroupIDForMBlockExpHeap(const void * memBlock)1899 MEMGetGroupIDForMBlockExpHeap( const void* memBlock )
1900 {
1901     ASSERT(IsValidUsedMBlock_(memBlock, NULL));
1902 
1903     return GetGroupIDForMBlock_( GetMBlockHeadCPtr_(memBlock) );
1904 }
1905 
1906 /*---------------------------------------------------------------------------*
1907   Name:         MEMGetAllocDirForMBlockExpHeap
1908 
1909   Description:  Gets the allocation direction for the memory block allocated from the expanded heap.
1910 
1911   Arguments:    memBlock:  pointer to the memory block
1912 
1913   Returns:      Returns the allocation direction for the specified memory block.
1914  *---------------------------------------------------------------------------*/
1915 u16
MEMGetAllocDirForMBlockExpHeap(const void * memBlock)1916 MEMGetAllocDirForMBlockExpHeap( const void* memBlock )
1917 {
1918     ASSERT(IsValidUsedMBlock_( memBlock, NULL ));
1919 
1920     return GetAllocDirForMBlock_( GetMBlockHeadCPtr_(memBlock) );
1921 }
1922 
1923 
1924 /*---------------------------------------------------------------------------*
1925   Name:         MEMAdjustExpHeap
1926 
1927   Description:  Deallocates the expanded heap's available region and reduces the memory region that is available for use by the expanded heap.
1928                 There must not be memory blocks allocated from the back of heap memory.
1929 
1930   Arguments:    heap:      Handle for the expanded heap.
1931 
1932   Returns:      Returns the overall expanded heap size after reduction if successful.
1933                 (Including the header portion.)
1934                 Returns 0 if unsuccessful.
1935 
1936  *---------------------------------------------------------------------------*/
1937 u32
MEMAdjustExpHeap(MEMHeapHandle heap)1938 MEMAdjustExpHeap( MEMHeapHandle heap )
1939 {
1940     ASSERT( IsValidExpHeapHandle_(heap) );
1941 
1942     {
1943         MEMiHeapHead            *pHeapHd    = heap;
1944         MEMiExpHeapHead         *pExpHeapHd = GetExpHeapHeadPtrFromHeapHead_( heap );
1945         MEMiExpHeapMBlockHead   *pMBlkHd;
1946         u32                     retVal;
1947 
1948         LockHeap( heap );
1949 
1950         pMBlkHd  = pExpHeapHd->mbFreeList.tail;
1951 
1952         // Fail if there are no available regions
1953         if ( pMBlkHd == NULL )
1954         {
1955             retVal = 0;
1956             goto ret_;
1957         }
1958 
1959         {
1960             void * const pMBlk      = GetMemPtrForMBlock_( pMBlkHd );
1961             void * const pMBlkEnd   = AddU32ToPtr( pMBlk, pMBlkHd->blockSize );
1962             u32 blockSize;
1963 
1964             // Fail if there exist any memory blocks allocated from the end
1965             if ( pMBlkEnd != MEMGetHeapEndAddress( heap ) )
1966             {
1967                 retVal = 0;
1968                 goto ret_;
1969             }
1970 
1971             // Delete deallocated free block from the free list
1972             (void)RemoveMBlock_( &pExpHeapHd->mbFreeList, pMBlkHd );
1973 
1974             blockSize = pMBlkHd->blockSize + sizeof( MEMiExpHeapMBlockHead );
1975             pHeapHd->heapEnd = SubU32ToPtr( pHeapHd->heapEnd, blockSize );
1976 
1977             retVal = GetOffsetFromPtr( pHeapHd, pHeapHd->heapEnd );
1978         }
1979 ret_:
1980         UnlockHeap( heap );
1981 
1982         return retVal;
1983     }
1984 }
1985 
1986 
1987 #if defined(_DEBUG)
1988 
1989 /*---------------------------------------------------------------------------*
1990   Name:         MEMCheckExpHeap
1991 
1992   Description:  Checks whether the expanded heap has been destroyed.
1993 
1994   Arguments:    heap:     Handle for the expanded heap.
1995                 optFlag:  Flag.
1996 
1997   Returns:      Returns TRUE if the heap is normal.
1998                 Returns FALSE if the heap has an error.
1999  *---------------------------------------------------------------------------*/
2000 BOOL
MEMCheckExpHeap(MEMHeapHandle heap,u32 optFlag)2001 MEMCheckExpHeap(
2002     MEMHeapHandle     heap,
2003     u32               optFlag
2004 )
2005 {
2006     const BOOL bPrint = 0 != (optFlag & MEM_HEAP_ERROR_PRINT);
2007     u32        totalBytes  = 0;
2008     BOOL       retVal;
2009 
2010     if ( ! IsValidExpHeapHandle_(heap) )
2011     {
2012         HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Invalid heap handle. - %08X\n", heap);
2013         return FALSE;
2014     }
2015 
2016     LockHeap( heap );
2017     {
2018         MEMiHeapHead *const    pHeapHd     = heap;
2019         MEMiExpHeapHead *const pExpHeapHd  = GetExpHeapHeadPtrFromHeapHead_(pHeapHd);
2020         MEMiExpHeapMBlockHead* pMBHead     = NULL;
2021         MEMiExpHeapMBlockHead* pMBHeadPrev = NULL;
2022 
2023         // used block
2024         for ( pMBHead = pExpHeapHd->mbUsedList.head; pMBHead; pMBHeadPrev = pMBHead, pMBHead = pMBHead->pMBHeadNext )
2025         {
2026             if ( ! CheckUsedMBlock_(pMBHead, pHeapHd, optFlag)
2027               || ! CheckMBlockPrevPtr_(pMBHead, pMBHeadPrev, optFlag)   // Is the pointer to the previous block the same as the pointer to the memory block in the previous loop?
2028             )
2029             {
2030                 retVal = FALSE;
2031                 goto ret_;
2032             }
2033 
2034             // calculate size occupied
2035             totalBytes += sizeof(MEMiExpHeapMBlockHead) + pMBHead->blockSize + GetAlignmentForMBlock_(pMBHead);
2036         }
2037 
2038         if ( ! CheckMBlockLinkTail_(pMBHeadPrev, pExpHeapHd->mbUsedList.tail, "tail", optFlag))  // Is the last block indicating the pointer to the final block?
2039         {
2040             retVal = FALSE;
2041             goto ret_;
2042         }
2043 
2044         // free block
2045         pMBHead = NULL;
2046         pMBHeadPrev = NULL;
2047         for ( pMBHead = pExpHeapHd->mbFreeList.head; pMBHead; pMBHeadPrev = pMBHead, pMBHead = pMBHead->pMBHeadNext )
2048         {
2049             if ( ! CheckFreeMBlock_(pMBHead, pHeapHd, optFlag)
2050                  || ! CheckMBlockPrevPtr_(pMBHead, pMBHeadPrev, optFlag)   // Is the pointer to the previous block the same as the pointer to the memory block in the previous loop?
2051             )
2052             {
2053                 retVal = FALSE;
2054                 goto ret_;
2055             }
2056 
2057             // calculate size occupied
2058             totalBytes += sizeof(MEMiExpHeapMBlockHead) + pMBHead->blockSize;
2059         }
2060 
2061         if ( ! CheckMBlockLinkTail_(pMBHeadPrev, pExpHeapHd->mbFreeList.tail, "tail", optFlag) )  // Is the last block indicating the pointer to the final block?
2062         {
2063             retVal = FALSE;
2064             goto ret_;
2065         }
2066 
2067         // Display all results.
2068         if ( totalBytes != GetOffsetFromPtr(pHeapHd->heapStart, pHeapHd->heapEnd) )
2069         {
2070             HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Incorrect total memory block size. - heap size %08X, sum size %08X\n",
2071                 GetOffsetFromPtr(pHeapHd->heapStart, pHeapHd->heapEnd), totalBytes);
2072             retVal = FALSE;
2073             goto ret_;
2074         }
2075         retVal = TRUE;
2076     }
2077 ret_:
2078     UnlockHeap( heap );
2079     return retVal;
2080 }
2081 
2082 
2083 /*---------------------------------------------------------------------------*
2084   Name:         MEMCheckForMBlockExpHeap
2085 
2086   Description:  This function checks if the memory block of the expanded heap was destroyed.
2087 
2088   Arguments:    memBlock:  Pointer to the memory block to be checked.
2089                 heap:      Handle for the expanded heap.
2090                 optFlag:   Flag.
2091 
2092   Returns:      Returns TRUE if the memory block is valid.
2093                 Returns FALSE if the memory block has an error.
2094  *---------------------------------------------------------------------------*/
2095 BOOL
MEMCheckForMBlockExpHeap(const void * memBlock,MEMHeapHandle heap,u32 optFlag)2096 MEMCheckForMBlockExpHeap(
2097     const void*     memBlock,
2098     MEMHeapHandle   heap,
2099     u32             optFlag
2100 )
2101 {
2102     const MEMiExpHeapMBlockHead* pMBHead = NULL;
2103     MEMiHeapHead *const          pHeapHd = heap;
2104 
2105     if ( ! memBlock )
2106     {
2107         return FALSE;
2108     }
2109 
2110     pMBHead = GetMBlockHeadCPtr_( memBlock );
2111 
2112     if ( ! CheckUsedMBlock_( pMBHead, pHeapHd, optFlag ) )
2113     {
2114         return FALSE;
2115     }
2116 
2117     if ( pMBHead->pMBHeadPrev )
2118     {
2119         if ( ! CheckUsedMBlock_(pMBHead->pMBHeadPrev, pHeapHd, optFlag)        // check of signature and size of previous block
2120              || ! CheckMBlockNextPtr_(pMBHead->pMBHeadPrev, pMBHead, optFlag)  // Is the previous block's pointer to the next block indicating the current block?
2121         )
2122         {
2123             return FALSE;
2124         }
2125     }
2126     else
2127     {
2128         if ( pHeapHd )
2129         {
2130             // When prev is NULL, the head pointer of the list should indicate the current (block).
2131             if ( ! CheckMBlockLinkTail_(pMBHead, GetExpHeapHeadPtrFromHeapHead_(pHeapHd)->mbUsedList.head, "head", optFlag) )
2132             {
2133                 return FALSE;
2134             }
2135         }
2136     }
2137 
2138     if ( pMBHead->pMBHeadNext )
2139     {
2140         if ( ! CheckUsedMBlock_(pMBHead->pMBHeadNext, pHeapHd, optFlag)        // check of signature and size of next block
2141              || ! CheckMBlockPrevPtr_(pMBHead->pMBHeadNext, pMBHead, optFlag)  // Is the next block's pointer to the previous block indicating the current block?
2142         )
2143         {
2144             return FALSE;
2145         }
2146     }
2147     else
2148     {
2149         if ( pHeapHd )
2150         {
2151             // When next is NULL, the tail pointer of the list should indicate the current (block).
2152             if ( ! CheckMBlockLinkTail_(pMBHead, GetExpHeapHeadPtrFromHeapHead_(pHeapHd)->mbUsedList.tail, "tail", optFlag) )
2153             {
2154                 return FALSE;
2155             }
2156         }
2157     }
2158 
2159     return TRUE;
2160 }
2161 
2162 // #if defined(_DEBUG)
2163 #endif
2164 
2165 
2166