1 /*---------------------------------------------------------------------------*
2   Project:     MEM library
3   File:        mem_expHeap.c
4   Programmers: Takano Makoto
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 from the pointer to the 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 the pointer to the MEMiExpHeapMBlockHead structure from the pointer to the memory block.
190 
191                 Gets the pointer to the memory block.
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 ending memory address from the pointer to the memory block.
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 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 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 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 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 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:      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 be added to
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 terminal address 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(           // 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 for the time being
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 to the allocated memory block if the memory block was successfully allocated.
691 
692                 If the operation 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 end 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 to the allocated memory block if the memory block was successfully allocated.
756 
757                 If the operation 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 an 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 to be used as a free block, the alignment value of the used block adjacent to the end of the memory space is used.
817 
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 if there are no free blocks at the end
871                         //
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, and FALSE otherwise.
907 
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, and FALSE otherwise.
980 
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, and FALSE otherwise.
1018 
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 previous 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 previous memory block is correct, and FALSE otherwise.
1041 
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, and FALSE otherwise.
1073 
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 pointer to the memory block is at the head or tail of the memory block list, and FALSE otherwise.
1106 
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 the memory block is included in the heap.
1137 
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 used 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                 // ---- Amount Used
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 an 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 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 available 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: + or - 4, + or - 8, + or - 16, + or - 32, + or - 64, + or - 128, ...
1356 
1357   Returns:      Returns the pointer to the allocated memory block if the memory block was successfully allocated.
1358 
1359                 If the operation 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             UnlockHeap( heap );
1455             return 0;
1456         }
1457 
1458         {
1459             MemRegion         rgnNewFree;
1460             void              *oldFreeStart;
1461             MEMiExpHeapMBlockHead *nextBlockPrev;
1462 
1463             // Gets the free block region and temporarily removes the free block
1464             GetRegionOfMBlock_( &rgnNewFree, block );
1465             nextBlockPrev = RemoveMBlock_( &pEHHead->mbFreeList, block );
1466 
1467             oldFreeStart = rgnNewFree.start;
1468             rgnNewFree.start = AddU32ToPtr( memBlock, size ); // The region position to be newly freed
1469 
1470             // If the remainder is smaller than the memory block size
1471             if ( GetOffsetFromPtr(rgnNewFree.start, rgnNewFree.end) < sizeof(MEMiExpHeapMBlockHead) )
1472             {
1473                 rgnNewFree.start = rgnNewFree.end;  // It is absorbed into the block being used
1474             }
1475 
1476             pMBHead->blockSize = GetOffsetFromPtr(memBlock, rgnNewFree.start);  // Changes the target block size
1477 
1478             // If the remainder is equal to or larger than the memory block size
1479             if ( GetOffsetFromPtr(rgnNewFree.start, rgnNewFree.end) >= sizeof(MEMiExpHeapMBlockHead) )
1480             {
1481                 (void)InsertMBlock_(&pEHHead->mbFreeList, InitFreeMBlock_(&rgnNewFree), nextBlockPrev);   // Creates a new free block
1482             }
1483 
1484             FillAllocMemory(  // Extended partial fill
1485                 heap,
1486                 oldFreeStart,
1487                 GetOffsetFromPtr(oldFreeStart, rgnNewFree.start));
1488         }
1489     }
1490     // When shrinking the new area
1491     else
1492     {
1493         MemRegion rgnNewFree;
1494         const u32 oldBlockSize = pMBHead->blockSize;
1495 
1496         rgnNewFree.start = AddU32ToPtr(memBlock, size); // The region position to be newly freed
1497         rgnNewFree.end   = GetMBlockEndAddr_(pMBHead);   // The end address for the block currently being used
1498 
1499         pMBHead->blockSize = size;  // Changes the target block size
1500 
1501         if ( ! RecycleRegion_(pEHHead, &rgnNewFree) )    // Tries returning the free list
1502         {
1503             pMBHead->blockSize = oldBlockSize;  // Restores to original form if failed
1504         }
1505     }
1506 
1507     UnlockHeap( heap );
1508 
1509     return pMBHead->blockSize;
1510 }
1511 
1512 /*---------------------------------------------------------------------------*
1513   Name:         MEMFreeToExpHeap
1514 
1515   Description:  Returns the memory block to the expanded heap.
1516 
1517   Arguments:    heap:     Handle for expanded heap
1518                 memBlock: Pointer to the memory block to be returned.
1519 
1520   Returns:      None.
1521  *---------------------------------------------------------------------------*/
1522 void
MEMFreeToExpHeap(MEMHeapHandle heap,void * memBlock)1523 MEMFreeToExpHeap(
1524     MEMHeapHandle   heap,
1525     void*           memBlock
1526 )
1527 {
1528     ASSERT(IsValidExpHeapHandle_(heap));
1529     if ( memBlock == NULL )
1530     {
1531         return;
1532     }
1533 
1534     ASSERT(IsValidUsedMBlock_(memBlock, heap));
1535 
1536     {
1537         MEMiHeapHead          *pHeapHd    = heap;
1538         MEMiExpHeapHead       *pExpHeapHd = GetExpHeapHeadPtrFromHandle_( pHeapHd );
1539         MEMiExpHeapMBlockHead *pMBHead    = GetMBlockHeadPtr_( memBlock );
1540         MemRegion             region;
1541 
1542         // Is it included in this heap?
1543         ASSERT( pHeapHd->heapStart <= memBlock && memBlock < pHeapHd->heapEnd );
1544 
1545         LockHeap( heap );
1546 
1547         GetRegionOfMBlock_( &region, pMBHead );
1548         (void)RemoveMBlock_( &pExpHeapHd->mbUsedList, pMBHead );   // Remove from the list being used
1549         (void)RecycleRegion_( pExpHeapHd, &region );   // Add the specified size from the specified address to the free region
1550 
1551         UnlockHeap( heap );
1552     }
1553 }
1554 
1555 /*---------------------------------------------------------------------------*
1556   Name:         MEMGetTotalFreeSizeForExpHeap
1557 
1558   Description:  Gets the total size of the available regions of the expanded heap.
1559 
1560   Arguments:    heap:     Handle for expanded heap
1561 
1562   Returns:      Returns the total size of the available regions in the expanded heap (in bytes).
1563  *---------------------------------------------------------------------------*/
1564 u32
MEMGetTotalFreeSizeForExpHeap(MEMHeapHandle heap)1565 MEMGetTotalFreeSizeForExpHeap( MEMHeapHandle heap )
1566 {
1567     u32     sumSize  = 0;
1568 
1569     ASSERT(IsValidExpHeapHandle_(heap));
1570 
1571     LockHeap( heap );
1572 
1573     {
1574         MEMiExpHeapHead       *pEHHead = GetExpHeapHeadPtrFromHandle_(heap);
1575         MEMiExpHeapMBlockHead *pMBHead;
1576 
1577         for ( pMBHead = pEHHead->mbFreeList.head; pMBHead; pMBHead = pMBHead->pMBHeadNext )
1578         {
1579             sumSize += pMBHead->blockSize;
1580         }
1581     }
1582 
1583     UnlockHeap( heap );
1584     return sumSize;
1585 }
1586 
1587 /*---------------------------------------------------------------------------*
1588   Name:         MEMGetAllocatableSizeForExpHeapEx
1589 
1590   Description:  Gets a memory block of the maximum allocatable size from the expanded heap.
1591                 The memory block alignment can be specified.
1592 
1593   Arguments:    heap:      Handle for expanded heap
1594                 alignment: Alignment of the memory block to be allocated
1595                            The following values can be specified: + or - 4, + or - 8, + or - 16, + or - 32, + or - 64, + or - 128, ...
1596 
1597   Returns:      Returns the maximum allocatable size from the expanded heap (in bytes).
1598  *---------------------------------------------------------------------------*/
1599 u32
MEMGetAllocatableSizeForExpHeapEx(MEMHeapHandle heap,int alignment)1600 MEMGetAllocatableSizeForExpHeapEx(
1601     MEMHeapHandle   heap,
1602     int             alignment
1603 )
1604 {
1605     ASSERT(IsValidExpHeapHandle_(heap));
1606 
1607     // alignment check
1608     ASSERT(alignment % MIN_ALIGNMENT == 0);
1609     ASSERT((abs(alignment) & (abs(alignment) - 1)) == 0);
1610     ASSERT(MIN_ALIGNMENT <= abs(alignment));
1611 
1612     alignment = abs(alignment); // Convert to a positive value just to be sure
1613 
1614     LockHeap( heap );
1615 
1616     {
1617         MEMiExpHeapHead       *pEHHead  = GetExpHeapHeadPtrFromHandle_(heap);
1618         MEMiExpHeapMBlockHead *pMBlkHd;
1619         u32                   maxSize   = 0;
1620         u32                   offsetMin = 0xFFFFFFFF;
1621 
1622         for ( pMBlkHd = pEHHead->mbFreeList.head; pMBlkHd; pMBlkHd = pMBlkHd->pMBHeadNext )
1623         {
1624             // Memory block position including the alignment
1625             void* baseAddress = RoundUpPtr(GetMemPtrForMBlock_(pMBlkHd), alignment);
1626 
1627             if ( GetUIntPtr(baseAddress) < GetUIntPtr(GetMBlockEndAddr_(pMBlkHd)) )
1628             {
1629                 const u32 blockSize = GetOffsetFromPtr(baseAddress, GetMBlockEndAddr_(pMBlkHd));
1630                 // Empty area due to the alignment
1631                 const u32 offset = GetOffsetFromPtr(GetMemPtrForMBlock_(pMBlkHd), baseAddress);
1632 
1633                 /*
1634                     If the size is large or the size is the same but wasted space is small, the memory block is updated.
1635 
1636                  */
1637                 if ( maxSize < blockSize
1638                      ||  (maxSize == blockSize && offsetMin > offset)
1639                 )
1640                 {
1641                     maxSize = blockSize;
1642                     offsetMin= offset;
1643                 }
1644             }
1645         }
1646 
1647         UnlockHeap( heap );
1648 
1649         return maxSize;
1650     }
1651 }
1652 
1653 
1654 /*---------------------------------------------------------------------------*
1655   Name:         MEMiIsEmptyExpHeap
1656 
1657   Description:  Checks whether the allocated block exists in the expanded heap.
1658 
1659   Arguments:    heap:  Handle for expanded heap
1660 
1661   Returns:      If it doesn't exist, returns TRUE; otherwise returns FALSE.
1662 
1663  *---------------------------------------------------------------------------*/
1664 BOOL
MEMiIsEmptyExpHeap(MEMHeapHandle heap)1665 MEMiIsEmptyExpHeap( MEMHeapHandle heap )
1666 {
1667     MEMiExpHeapHead     *pExpHeapHd = GetExpHeapHeadPtrFromHeapHead_( heap );
1668     BOOL                ret;
1669 
1670     LockHeap( heap );
1671 
1672     ret = (pExpHeapHd->mbFreeList.head == NULL);
1673 
1674     UnlockHeap( heap );
1675 
1676     return ret;
1677 }
1678 
1679 /*---------------------------------------------------------------------------*
1680   Name:         MEMSetAllocModeForExpHeap
1681 
1682   Description:  Sets the memory allocation mode for the expanded heap.
1683 
1684   Arguments:    heap:  Handle for expanded heap
1685                 mode:  Memory allocation mode.
1686 
1687   Returns:      Returns the memory allocation mode for the previous expanded heap.
1688  *---------------------------------------------------------------------------*/
1689 u16
MEMSetAllocModeForExpHeap(MEMHeapHandle heap,u16 mode)1690 MEMSetAllocModeForExpHeap(
1691     MEMHeapHandle     heap,
1692     u16               mode
1693 )
1694 {
1695     BOOL enabled;
1696     u16  beforeMode;
1697 
1698     ASSERT(IsValidExpHeapHandle_(heap));
1699 
1700     enabled = OSDisableInterrupts();
1701     {
1702         MEMiExpHeapHead *const pEHHead = GetExpHeapHeadPtrFromHandle_(heap);
1703         beforeMode = GetAllocMode_(pEHHead);
1704         SetAllocMode_(pEHHead, mode);
1705     }
1706     (void)OSRestoreInterrupts( enabled );
1707 
1708     return beforeMode;
1709 }
1710 
1711 /*---------------------------------------------------------------------------*
1712   Name:         MEMGetAllocModeForExpHeap
1713 
1714   Description:  Gets the memory allocation mode for the expanded heap.
1715 
1716   Arguments:    heap:    Handle for expanded heap
1717 
1718   Returns:      Returns the memory allocation mode for the expanded heap.
1719  *---------------------------------------------------------------------------*/
1720 u16
MEMGetAllocModeForExpHeap(MEMHeapHandle heap)1721 MEMGetAllocModeForExpHeap( MEMHeapHandle heap )
1722 {
1723     ASSERT(IsValidExpHeapHandle_(heap));
1724     return GetAllocMode_(GetExpHeapHeadPtrFromHandle_(heap));
1725 }
1726 
1727 /*---------------------------------------------------------------------------*
1728   Name:         MEMSetGroupIDForExpHeap
1729 
1730   Description:  Sets the group ID for the expanded heap.
1731 
1732   Arguments:    heap:    Handle for expanded heap
1733                 groupID: The group ID value to be set.
1734 
1735   Returns:      Returns the previous group ID value.
1736  *---------------------------------------------------------------------------*/
1737 u16
MEMSetGroupIDForExpHeap(MEMHeapHandle heap,u16 groupID)1738 MEMSetGroupIDForExpHeap(
1739     MEMHeapHandle   heap,
1740     u16             groupID
1741 )
1742 {
1743     u16  beforeGroupID;
1744     BOOL enabled;
1745 
1746     ASSERT(IsValidExpHeapHandle_(heap));
1747     ASSERT(groupID <= MAX_GROUPID);
1748 
1749     enabled = OSDisableInterrupts();
1750     {
1751         MEMiExpHeapHead* pEHHead = GetExpHeapHeadPtrFromHandle_(heap);
1752         beforeGroupID = pEHHead->groupID;
1753         pEHHead->groupID = groupID;
1754 
1755     }
1756     (void)OSRestoreInterrupts( enabled );
1757 
1758     return beforeGroupID;
1759 }
1760 
1761 /*---------------------------------------------------------------------------*
1762   Name:         MEMGetGroupIDForExpHeap
1763 
1764   Description:  Gets the group ID for the expanded heap.
1765 
1766   Arguments:    heap:    Handle for expanded heap
1767 
1768   Returns:      Returns the group ID value.
1769  *---------------------------------------------------------------------------*/
1770 u16
MEMGetGroupIDForExpHeap(MEMHeapHandle heap)1771 MEMGetGroupIDForExpHeap( MEMHeapHandle heap )
1772 {
1773     ASSERT(IsValidExpHeapHandle_(heap));
1774 
1775     return GetExpHeapHeadPtrFromHandle_(heap)->groupID;
1776 }
1777 
1778 /*---------------------------------------------------------------------------*
1779   Name:         MEMVisitAllocatedForExpHeap
1780 
1781   Description:  Causes the function specified by the user to be called for all the memory blocks allocated from the expanded heap.
1782 
1783                 The visitor function is called on these memory blocks in the order they were allocated.
1784 
1785                 The visitor type HeapVisitor is defined as below.
1786 
1787                     typedef void (*HeapVisitor)(
1788                                     void*               memBlock,
1789                                     MEMHeapHandle    heap,
1790                                     u32                 userParam);
1791 
1792                                         memBlock:   Pointer to the memory block.
1793                                         heap:       Heap including the memory block.
1794                                         userParam:  User parameter.
1795 
1796   Arguments:    heap:       Handle for expanded heap
1797                 visitor:    Function called for each memory block.
1798                 userParam:  User-specified parameter to be passed to the visitor function
1799 
1800   Returns:      None.
1801  *---------------------------------------------------------------------------*/
1802 void
MEMVisitAllocatedForExpHeap(MEMHeapHandle heap,MEMHeapVisitor visitor,u32 userParam)1803 MEMVisitAllocatedForExpHeap(
1804     MEMHeapHandle      heap,
1805     MEMHeapVisitor     visitor,
1806     u32                userParam
1807 )
1808 {
1809     ASSERT(IsValidExpHeapHandle_(heap));
1810     ASSERT(visitor != NULL);
1811 
1812     LockHeap( heap );
1813     {
1814         MEMiExpHeapMBlockHead* pMBHead = GetExpHeapHeadPtrFromHandle_(heap)->mbUsedList.head;
1815 
1816         while ( pMBHead )
1817         {
1818             MEMiExpHeapMBlockHead* pMBHeadNext = pMBHead->pMBHeadNext;
1819             (*visitor)(GetMemPtrForMBlock_(pMBHead), heap, userParam);
1820             pMBHead = pMBHeadNext;
1821         }
1822     }
1823     UnlockHeap( heap );
1824 }
1825 
1826 /*---------------------------------------------------------------------------*
1827   Name:         MEMGetSizeForMBlockExpHeap
1828 
1829   Description:  Gets the size of the memory block that was allocated from the expanded heap.
1830 
1831   Arguments:    memBlock:  Pointer to the memory block for getting the size.
1832 
1833   Returns:      Returns the size of the specified memory block (in bytes).
1834  *---------------------------------------------------------------------------*/
1835 u32
MEMGetSizeForMBlockExpHeap(const void * memBlock)1836 MEMGetSizeForMBlockExpHeap( const void* memBlock )
1837 {
1838     ASSERT(IsValidUsedMBlock_(memBlock, NULL));
1839 
1840     return GetMBlockHeadCPtr_( memBlock )->blockSize;
1841 }
1842 
1843 /*---------------------------------------------------------------------------*
1844   Name:         MEMGetGroupIDForMBlockExpHeap
1845 
1846   Description:  Gets the group ID for the memory block allocated from the expanded heap.
1847 
1848   Arguments:    memBlock:  Pointer to the memory block for getting the group ID.
1849 
1850   Returns:      Returns the group ID for the specified memory block.
1851  *---------------------------------------------------------------------------*/
1852 u16
MEMGetGroupIDForMBlockExpHeap(const void * memBlock)1853 MEMGetGroupIDForMBlockExpHeap( const void* memBlock )
1854 {
1855     ASSERT(IsValidUsedMBlock_(memBlock, NULL));
1856 
1857     return GetGroupIDForMBlock_( GetMBlockHeadCPtr_(memBlock) );
1858 }
1859 
1860 /*---------------------------------------------------------------------------*
1861   Name:         MEMGetAllocDirForMBlockExpHeap
1862 
1863   Description:  Gets the allocation direction for the memory block allocated from the expanded heap.
1864 
1865   Arguments:    memBlock:  Pointer to the memory block.
1866 
1867   Returns:      Returns the allocation direction for the specified memory block.
1868  *---------------------------------------------------------------------------*/
1869 u16
MEMGetAllocDirForMBlockExpHeap(const void * memBlock)1870 MEMGetAllocDirForMBlockExpHeap( const void* memBlock )
1871 {
1872     ASSERT(IsValidUsedMBlock_( memBlock, NULL ));
1873 
1874     return GetAllocDirForMBlock_( GetMBlockHeadCPtr_(memBlock) );
1875 }
1876 
1877 
1878 /*---------------------------------------------------------------------------*
1879   Name:         MEMAdjustExpHeap
1880 
1881   Description:  Deallocates the expanded heap's available region, and reduces the memory available for the expanded heap.
1882                 There must not be memory blocks allocated from the back of heap memory.
1883 
1884   Arguments:    heap:      Handle for expanded heap
1885 
1886   Returns:      Returns the overall expanded heap size after reduction if successful.
1887                 (Including the header portion.)
1888                 Returns 0 if unsuccessful.
1889 
1890  *---------------------------------------------------------------------------*/
1891 u32
MEMAdjustExpHeap(MEMHeapHandle heap)1892 MEMAdjustExpHeap( MEMHeapHandle heap )
1893 {
1894     ASSERT( IsValidExpHeapHandle_(heap) );
1895 
1896     {
1897         MEMiHeapHead            *pHeapHd    = heap;
1898         MEMiExpHeapHead         *pExpHeapHd = GetExpHeapHeadPtrFromHeapHead_( heap );
1899         MEMiExpHeapMBlockHead   *pMBlkHd;
1900         u32                     retVal;
1901 
1902         LockHeap( heap );
1903 
1904         pMBlkHd  = pExpHeapHd->mbFreeList.tail;
1905 
1906         // fails if there are no available regions
1907         if ( pMBlkHd == NULL )
1908         {
1909             retVal = 0;
1910             goto ret_;
1911         }
1912 
1913         {
1914             void * const pMBlk      = GetMemPtrForMBlock_( pMBlkHd );
1915             void * const pMBlkEnd   = AddU32ToPtr( pMBlk, pMBlkHd->blockSize );
1916             u32 blockSize;
1917 
1918             // fails if there are any memory blocks allocated from the end
1919             if ( pMBlkEnd != MEMGetHeapEndAddress( heap ) )
1920             {
1921                 retVal = 0;
1922                 goto ret_;
1923             }
1924 
1925             // Delete deallocated free block from the free list
1926             (void)RemoveMBlock_( &pExpHeapHd->mbFreeList, pMBlkHd );
1927 
1928             blockSize = pMBlkHd->blockSize + sizeof( MEMiExpHeapMBlockHead );
1929             pHeapHd->heapEnd = SubU32ToPtr( pHeapHd->heapEnd, blockSize );
1930 
1931             retVal = GetOffsetFromPtr( pHeapHd, pHeapHd->heapEnd );
1932         }
1933 ret_:
1934         UnlockHeap( heap );
1935 
1936         return retVal;
1937     }
1938 }
1939 
1940 
1941 #if defined(_DEBUG)
1942 
1943 /*---------------------------------------------------------------------------*
1944   Name:         MEMCheckExpHeap
1945 
1946   Description:  Checks whether the expanded heap has been destroyed.
1947 
1948   Arguments:    heap:     Handle for expanded heap
1949                 optFlag:  Flag.
1950 
1951   Returns:      Returns TRUE if the heap is normal.
1952                 Returns FALSE if the heap has an error.
1953  *---------------------------------------------------------------------------*/
1954 BOOL
MEMCheckExpHeap(MEMHeapHandle heap,u32 optFlag)1955 MEMCheckExpHeap(
1956     MEMHeapHandle     heap,
1957     u32               optFlag
1958 )
1959 {
1960     const BOOL bPrint = 0 != (optFlag & MEM_HEAP_ERROR_PRINT);
1961     u32        totalBytes  = 0;
1962     BOOL       retVal;
1963 
1964     if ( ! IsValidExpHeapHandle_(heap) )
1965     {
1966         HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Invalid heap handle. - %08X\n", heap);
1967         return FALSE;
1968     }
1969 
1970     LockHeap( heap );
1971     {
1972         MEMiHeapHead *const    pHeapHd     = heap;
1973         MEMiExpHeapHead *const pExpHeapHd  = GetExpHeapHeadPtrFromHeapHead_(pHeapHd);
1974         MEMiExpHeapMBlockHead* pMBHead     = NULL;
1975         MEMiExpHeapMBlockHead* pMBHeadPrev = NULL;
1976 
1977         // Block used
1978         for ( pMBHead = pExpHeapHd->mbUsedList.head; pMBHead; pMBHeadPrev = pMBHead, pMBHead = pMBHead->pMBHeadNext )
1979         {
1980             if ( ! CheckUsedMBlock_(pMBHead, pHeapHd, optFlag)
1981               || ! CheckMBlockPrevPtr_(pMBHead, pMBHeadPrev, optFlag)   // Is the pointer to the previous block the same as the pointer to the memory block in the previous loop?
1982             )
1983             {
1984                 retVal = FALSE;
1985                 goto ret_;
1986             }
1987 
1988             // calculates size occupied
1989             totalBytes += sizeof(MEMiExpHeapMBlockHead) + pMBHead->blockSize + GetAlignmentForMBlock_(pMBHead);
1990         }
1991 
1992         if ( ! CheckMBlockLinkTail_(pMBHeadPrev, pExpHeapHd->mbUsedList.tail, "tail", optFlag))  // Is the last block referring to the pointer to the final block?
1993         {
1994             retVal = FALSE;
1995             goto ret_;
1996         }
1997 
1998         // free block
1999         pMBHead = NULL;
2000         pMBHeadPrev = NULL;
2001         for ( pMBHead = pExpHeapHd->mbFreeList.head; pMBHead; pMBHeadPrev = pMBHead, pMBHead = pMBHead->pMBHeadNext )
2002         {
2003             if ( ! CheckFreeMBlock_(pMBHead, pHeapHd, optFlag)
2004                  || ! CheckMBlockPrevPtr_(pMBHead, pMBHeadPrev, optFlag)   // Is the pointer to the previous block the same as the pointer to the memory block in the previous loop?
2005             )
2006             {
2007                 retVal = FALSE;
2008                 goto ret_;
2009             }
2010 
2011             // calculates size occupied
2012             totalBytes += sizeof(MEMiExpHeapMBlockHead) + pMBHead->blockSize;
2013         }
2014 
2015         if ( ! CheckMBlockLinkTail_(pMBHeadPrev, pExpHeapHd->mbFreeList.tail, "tail", optFlag) )  // Is the last block referring to the pointer to the final block?
2016         {
2017             retVal = FALSE;
2018             goto ret_;
2019         }
2020 
2021         // Display all results.
2022         if ( totalBytes != GetOffsetFromPtr(pHeapHd->heapStart, pHeapHd->heapEnd) )
2023         {
2024             HEAP_WARNING(bPrint, "[OS Foundation " "Exp" " Heap]" " Incorrect total memory block size. - heap size %08X, sum size %08X\n",
2025                 GetOffsetFromPtr(pHeapHd->heapStart, pHeapHd->heapEnd), totalBytes);
2026             retVal = FALSE;
2027             goto ret_;
2028         }
2029         retVal = TRUE;
2030     }
2031 ret_:
2032     UnlockHeap( heap );
2033     return retVal;
2034 }
2035 
2036 
2037 /*---------------------------------------------------------------------------*
2038   Name:         MEMCheckForMBlockExpHeap
2039 
2040   Description:  This function checks if the memory block of the expanded heap was destroyed.
2041 
2042   Arguments:    memBlock:  Pointer to the memory block checked.
2043                 heap:      Handle for expanded heap
2044                 optFlag:   Flag.
2045 
2046   Returns:      If the memory block is valid, returns TRUE.
2047                 If the memory block has an error, returns FALSE.
2048  *---------------------------------------------------------------------------*/
2049 BOOL
MEMCheckForMBlockExpHeap(const void * memBlock,MEMHeapHandle heap,u32 optFlag)2050 MEMCheckForMBlockExpHeap(
2051     const void*     memBlock,
2052     MEMHeapHandle   heap,
2053     u32             optFlag
2054 )
2055 {
2056     const MEMiExpHeapMBlockHead* pMBHead = NULL;
2057     MEMiHeapHead *const          pHeapHd = heap;
2058 
2059     if ( ! memBlock )
2060     {
2061         return FALSE;
2062     }
2063 
2064     pMBHead = GetMBlockHeadCPtr_( memBlock );
2065 
2066     if ( ! CheckUsedMBlock_( pMBHead, pHeapHd, optFlag ) )
2067     {
2068         return FALSE;
2069     }
2070 
2071     if ( pMBHead->pMBHeadPrev )
2072     {
2073         if ( ! CheckUsedMBlock_(pMBHead->pMBHeadPrev, pHeapHd, optFlag)        // Check of signature and size of previous block.
2074              || ! CheckMBlockNextPtr_(pMBHead->pMBHeadPrev, pMBHead, optFlag)  // Is the previous block's pointer to the next block pointing to the current block?
2075         )
2076         {
2077             return FALSE;
2078         }
2079     }
2080     else
2081     {
2082         if ( pHeapHd )
2083         {
2084             // If prev is NULL the head pointer of the list should be pointing to current (block).
2085             if ( ! CheckMBlockLinkTail_(pMBHead, GetExpHeapHeadPtrFromHeapHead_(pHeapHd)->mbUsedList.head, "head", optFlag) )
2086             {
2087                 return FALSE;
2088             }
2089         }
2090     }
2091 
2092     if ( pMBHead->pMBHeadNext )
2093     {
2094         if ( ! CheckUsedMBlock_(pMBHead->pMBHeadNext, pHeapHd, optFlag)        // Check of signature and size of next block.
2095              || ! CheckMBlockPrevPtr_(pMBHead->pMBHeadNext, pMBHead, optFlag)  // Is the next block's pointer to the previous block pointing to current block?
2096         )
2097         {
2098             return FALSE;
2099         }
2100     }
2101     else
2102     {
2103         if ( pHeapHd )
2104         {
2105             // If next is NULL the tail pointer of the list should be pointing to current (block).
2106             if ( ! CheckMBlockLinkTail_(pMBHead, GetExpHeapHeadPtrFromHeapHead_(pHeapHd)->mbUsedList.tail, "tail", optFlag) )
2107             {
2108                 return FALSE;
2109             }
2110         }
2111     }
2112 
2113     return TRUE;
2114 }
2115 
2116 // #if defined(_DEBUG)
2117 #endif
2118 
2119 
2120