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