1 /*
2  * Copyright 2018-2020 NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_common.h"
10 #if defined(MEM_STATISTICS_INTERNAL) || defined(MEM_MANAGER_BENCH)
11 #include "fsl_component_timer_manager.h"
12 #include "fsl_component_mem_manager_internal.h"
13 #endif /* MEM_STATISTICS_INTERNAL MEM_MANAGER_BENCH*/
14 #include "fsl_component_mem_manager.h"
15 #if (defined(MEM_MANAGER_ENABLE_TRACE) && (MEM_MANAGER_ENABLE_TRACE > 0U))
16 #include "fsl_debug_console.h"
17 #endif
18 
19 #if defined(OSA_USED)
20 #include "fsl_os_abstraction.h"
21 #if (defined(USE_RTOS) && (USE_RTOS > 0U))
22 #define MEM_ENTER_CRITICAL() \
23     OSA_SR_ALLOC();          \
24     OSA_ENTER_CRITICAL()
25 #define MEM_EXIT_CRITICAL() OSA_EXIT_CRITICAL()
26 #else
27 #define MEM_ENTER_CRITICAL() uint32_t regPrimask = DisableGlobalIRQ();
28 #define MEM_EXIT_CRITICAL()  EnableGlobalIRQ(regPrimask);
29 #endif
30 #else
31 #define MEM_ENTER_CRITICAL() uint32_t regPrimask = DisableGlobalIRQ();
32 #define MEM_EXIT_CRITICAL()  EnableGlobalIRQ(regPrimask);
33 #endif
34 #if !defined(gMemManagerLight) || (gMemManagerLight == 0)
35 /*****************************************************************************
36 ******************************************************************************
37 * Private macros
38 ******************************************************************************
39 *****************************************************************************/
40 #if defined(__IAR_SYSTEMS_ICC__)
41 #define __mem_get_LR() __get_LR()
42 #elif defined(__GNUC__)
43 #define __mem_get_LR() __builtin_return_address(0)
44 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
45 #define __mem_get_LR() __return_address()
46 #endif
47 
48 #if (defined(MEM_MANAGER_PRE_CONFIGURE) && (MEM_MANAGER_PRE_CONFIGURE > 0U))
49 #undef _block_set_
50 #undef _eol_
51 
52 #define _eol_       ;
53 #define _block_set_ MEM_BLOCK_BUFFER_NONAME_DEFINE
54 
55 PoolsDetails_c
56 
57 #undef _block_set_
58 #undef _number_of_blocks_
59 #undef _eol_
60 #undef _pool_id_
61 
62 #define _eol_       ,
63 #define _block_set_ MEM_BLOCK_NONAME_BUFFER
64 
65     static uint8_t const *s_PoolList[] = {PoolsDetails_c};
66 #endif /*MEM_MANAGER_PRE_CONFIGURE*/
67 
68 /*****************************************************************************
69 ******************************************************************************
70 * Private type definitions
71 ******************************************************************************
72 *****************************************************************************/
73 /*! @brief Buffer pools structure*/
74 typedef struct _mem_pool_structure
75 {
76     struct _mem_pool_structure *nextPool;
77     uint8_t *pHeap;
78     uint32_t heapSize;
79 #if (defined(MEM_MANAGER_ENABLE_TRACE) && (MEM_MANAGER_ENABLE_TRACE > 0U))
80     uint16_t allocatedBlocksPeak;
81     uint16_t poolFragmentWaste;
82     uint16_t poolTotalFragmentWaste;
83     uint16_t poolFragmentWastePeak;
84     uint16_t poolFragmentMinWaste;
85 #endif /*MEM_MANAGER_ENABLE_TRACE*/
86     uint16_t poolId;
87     uint16_t blockSize;
88     uint16_t numBlocks;
89     uint16_t allocatedBlocks;
90 } mem_pool_structure_t;
91 
92 /*! @brief Header description for buffers.*/
93 typedef struct _block_list_header
94 {
95     uint16_t allocated;
96     uint16_t blockSize;
97 #if (defined(MEM_MANAGER_ENABLE_TRACE) && (MEM_MANAGER_ENABLE_TRACE > 0U))
98     uint32_t caller;
99     uint16_t allocatedBytes;
100 #endif /*MEM_MANAGER_ENABLE_TRACE*/
101 } block_list_header_t;
102 
103 /*! @brief State structure for memory manager. */
104 typedef struct _mem_manager_info
105 {
106     mem_pool_structure_t *pHeadPool;
107     uint16_t poolNum;
108 #if (defined(MEM_MANAGER_ENABLE_TRACE) && (MEM_MANAGER_ENABLE_TRACE > 0U))
109     uint16_t allocationFailures;
110     uint16_t freeFailures;
111 #endif /*MEM_MANAGER_ENABLE_TRACE*/
112 } mem_manager_info_t;
113 
114 /*****************************************************************************
115 ******************************************************************************
116 * Public memory declarations
117 ******************************************************************************
118 *****************************************************************************/
119 /*****************************************************************************
120  *****************************************************************************
121  * Private prototypes
122  *****************************************************************************
123  *****************************************************************************/
124 /*****************************************************************************
125  *****************************************************************************
126  * Private memory definitions
127  *****************************************************************************
128  *****************************************************************************/
129 static mem_manager_info_t s_memmanager = {0};
130 #ifdef MEM_STATISTICS_INTERNAL
131 static mem_statis_t s_memStatis;
132 #endif /* MEM_STATISTICS_INTERNAL */
133 
134 /*****************************************************************************
135 ******************************************************************************
136 * Private API macro define
137 ******************************************************************************
138 *****************************************************************************/
139 #define BLOCK_HDR_SIZE sizeof(block_list_header_t)
140 /*****************************************************************************
141 ******************************************************************************
142 * Private functions
143 ******************************************************************************
144 *****************************************************************************/
145 #ifdef MEM_STATISTICS_INTERNAL
MEM_BufferAllocates_memStatis(void * buffer,uint32_t time,uint32_t requestedSize)146 static void MEM_BufferAllocates_memStatis(void *buffer, uint32_t time, uint32_t requestedSize)
147 {
148     block_list_header_t *pBlock = (block_list_header_t *)buffer - 1;
149     /* existing block must have a BlockHdr and a next BlockHdr */
150     assert((pBlock != NULL));
151 
152     s_memStatis.nb_alloc++;
153     /* Sort the buffers by size, based on defined thresholds */
154     if (requestedSize <= SMALL_BUFFER_SIZE)
155     {
156         s_memStatis.nb_small_buffer++;
157         UPDATE_PEAK(s_memStatis.nb_small_buffer, s_memStatis.peak_small_buffer);
158     }
159     else if (requestedSize <= LARGE_BUFFER_SIZE)
160     {
161         s_memStatis.nb_medium_buffer++;
162         UPDATE_PEAK(s_memStatis.nb_medium_buffer, s_memStatis.peak_medium_buffer);
163     }
164     else
165     {
166         s_memStatis.nb_large_buffer++;
167         UPDATE_PEAK(s_memStatis.nb_large_buffer, s_memStatis.peak_large_buffer);
168     }
169     /* the RAM allocated is the buffer size and the block header size*/
170     s_memStatis.ram_allocated += (uint16_t)(requestedSize + BLOCK_HDR_SIZE);
171     UPDATE_PEAK(s_memStatis.ram_allocated, s_memStatis.peak_ram_allocated);
172 
173     uint32_t block_size = 0U;
174 
175     block_size = pBlock->blockSize;
176 
177     assert(block_size >= requestedSize);
178     /* ram lost is the difference between block size and buffer size */
179     s_memStatis.ram_lost += (uint16_t)(block_size - requestedSize);
180     UPDATE_PEAK(s_memStatis.ram_lost, s_memStatis.peak_ram_lost);
181 
182     /* UPDATE_PEAK(((uint32_t)FreeBlockHdrList.tail + BLOCK_HDR_SIZE), s_memStatis.peak_upper_addr); */
183 
184 #ifdef MEM_MANAGER_BENCH
185     if (time != 0U)
186     {
187         /* update mem stats used for benchmarking */
188         s_memStatis.last_alloc_block_size = (uint16_t)block_size;
189         s_memStatis.last_alloc_buff_size  = (uint16_t)requestedSize;
190         s_memStatis.last_alloc_time       = (uint16_t)time;
191         s_memStatis.total_alloc_time += time;
192         s_memStatis.average_alloc_time = (uint16_t)(s_memStatis.total_alloc_time / s_memStatis.nb_alloc);
193         UPDATE_PEAK((uint16_t)time, s_memStatis.peak_alloc_time);
194     }
195     else /* alloc time is not correct, we bypass this allocation's data */
196     {
197         s_memStatis.nb_alloc--;
198     }
199 #else
200     NOT_USED(time);
201 #endif /* MEM_MANAGER_BENCH */
202 }
203 
MEM_BufferFrees_memStatis(void * buffer)204 static void MEM_BufferFrees_memStatis(void *buffer)
205 {
206     block_list_header_t *pBlock = (block_list_header_t *)buffer - 1;
207     s_memStatis.ram_allocated -= (uint16_t)(pBlock->allocatedBytes + BLOCK_HDR_SIZE);
208     /* Sort the buffers by size, based on defined thresholds */
209     if (pBlock->allocatedBytes <= SMALL_BUFFER_SIZE)
210     {
211         s_memStatis.nb_small_buffer--;
212     }
213     else if (pBlock->allocatedBytes <= LARGE_BUFFER_SIZE)
214     {
215         s_memStatis.nb_medium_buffer--;
216     }
217     else
218     {
219         s_memStatis.nb_large_buffer--;
220     }
221 
222     uint16_t block_size = 0U;
223     block_size          = pBlock->blockSize;
224 
225     assert(block_size >= pBlock->allocatedBytes);
226     assert(s_memStatis.ram_lost >= (block_size - pBlock->allocatedBytes));
227 
228     /* as the buffer is free, the ram is not "lost" anymore */
229     s_memStatis.ram_lost -= (block_size - pBlock->allocatedBytes);
230 }
231 #endif
232 #if defined(MEM_STATISTICS_INTERNAL)
MEM_Reports_memStatis(void)233 static void MEM_Reports_memStatis(void)
234 {
235     MEM_DBG_LOG("**************** MEM STATS REPORT **************");
236     MEM_DBG_LOG("Nb Alloc:                  %d\r\n", s_memStatis.nb_alloc);
237     MEM_DBG_LOG("Small buffers:             %d\r\n", s_memStatis.nb_small_buffer);
238     MEM_DBG_LOG("Medium buffers:            %d\r\n", s_memStatis.nb_medium_buffer);
239     MEM_DBG_LOG("Large buffers:             %d\r\n", s_memStatis.nb_large_buffer);
240     MEM_DBG_LOG("Peak small:                %d\r\n", s_memStatis.peak_small_buffer);
241     MEM_DBG_LOG("Peak medium:               %d\r\n", s_memStatis.peak_medium_buffer);
242     MEM_DBG_LOG("Peak large:                %d\r\n", s_memStatis.peak_large_buffer);
243     MEM_DBG_LOG("Current RAM allocated:     %d bytes\r\n", s_memStatis.ram_allocated);
244     MEM_DBG_LOG("Peak RAM allocated:        %d bytes\r\n", s_memStatis.peak_ram_allocated);
245     MEM_DBG_LOG("Current RAM lost:          %d bytes\r\n", s_memStatis.ram_lost);
246     MEM_DBG_LOG("Peak RAM lost:             %d bytes\r\n", s_memStatis.peak_ram_lost);
247     MEM_DBG_LOG("Peak Upper Address:        %x\r\n", s_memStatis.peak_upper_addr);
248 #ifdef MEM_MANAGER_BENCH
249     MEM_DBG_LOG("************************************************\r\n");
250     MEM_DBG_LOG("********* MEM MANAGER BENCHMARK REPORT *********\r\n");
251     MEM_DBG_LOG("Last Alloc Time:           %d us\r\n", s_memStatis.last_alloc_time);
252     MEM_DBG_LOG("Last Alloc Block Size:     %d bytes\r\n", s_memStatis.last_alloc_block_size);
253     MEM_DBG_LOG("Last Alloc Buffer Size:    %d bytes\r\n", s_memStatis.last_alloc_buff_size);
254     MEM_DBG_LOG("Average Alloc Time:        %d us\r\n", s_memStatis.average_alloc_time);
255     MEM_DBG_LOG("Peak Alloc Time:           %d us\r\n", s_memStatis.peak_alloc_time);
256 #endif /* MEM_MANAGER_BENCH */
257     MEM_DBG_LOG("************************************************");
258 }
259 #endif /* MEM_STATISTICS_INTERNAL */
260 
261 /*****************************************************************************
262 ******************************************************************************
263 * Public functions
264 ******************************************************************************
265 *****************************************************************************/
266 /*!
267  * @brief  Initialises the Memory Manager.
268  *
269  */
MEM_Init(void)270 mem_status_t MEM_Init(void)
271 {
272     static bool initialized = false;
273     assert(sizeof(mem_pool_structure_t) == MEM_POOL_SIZE);
274     assert(sizeof(block_list_header_t) == MEM_BLOCK_SIZE);
275     if (!initialized)
276     {
277         s_memmanager.pHeadPool = NULL;
278         s_memmanager.poolNum   = 0;
279 #if (defined(MEM_MANAGER_ENABLE_TRACE) && (MEM_MANAGER_ENABLE_TRACE > 0U))
280         s_memmanager.allocationFailures = 0;
281         s_memmanager.freeFailures       = 0;
282 #endif /*MEM_MANAGER_ENABLE_TRACE*/
283 #if (defined(MEM_MANAGER_PRE_CONFIGURE) && (MEM_MANAGER_PRE_CONFIGURE > 0U))
284         for (uint8_t i = 0; i < (sizeof(s_PoolList) / sizeof(s_PoolList[0])); i++)
285         {
286             (void)MEM_AddBuffer(s_PoolList[i]);
287         }
288 #endif /*MEM_MANAGER_PRE_CONFIGURE*/
289         initialized = true;
290     }
291     return kStatus_MemSuccess;
292 }
293 
294 /*!
295  * @brief Add memory buffer to memory manager buffer list.
296  *
297  * @note This API should be called when need add memory buffer to memory manager buffer list. First use
298  * MEM_BLOCK_BUFFER_DEFINE to
299  *        define memory buffer, then call MEM_AddBuffer function with MEM_BLOCK_BUFFER Macro.
300  *  @code
301  * MEM_BLOCK_BUFFER_DEFINE(app64, 5, 64,0);
302  * MEM_BLOCK_BUFFER_DEFINE(app128, 6, 128,0);
303  * MEM_BLOCK_BUFFER_DEFINE(app256, 7, 256,0);
304  *
305  * MEM_AddBuffer(MEM_BLOCK_BUFFER(app64));
306  * MEM_AddBuffer(MEM_BLOCK_BUFFER(app128));
307  * MEM_AddBuffer(MEM_BLOCK_BUFFER(app256));
308  *  @endcode
309  *
310  * @param buffer                     Pointer the memory pool buffer, use MEM_BLOCK_BUFFER Macro as the input parameter.
311  *
312  * @retval kStatus_MemSuccess        Memory manager add Buffer succeed.
313  * @retval kStatus_MemInitError      Memory manager add Buffer error occurred.
314  */
MEM_AddBuffer(const uint8_t * buffer)315 mem_status_t MEM_AddBuffer(const uint8_t *buffer)
316 {
317     mem_config_t *memConfig     = (mem_config_t *)(void *)buffer;
318     mem_pool_structure_t *pPool = (mem_pool_structure_t *)(void *)memConfig->pbuffer;
319     uint8_t *pHeap              = &memConfig->pbuffer[sizeof(mem_pool_structure_t)];
320     mem_pool_structure_t *pPrevPool, *pTempPool;
321 
322     assert(buffer);
323     assert(memConfig->numberOfBlocks);
324     assert(memConfig->blockSize);
325 
326     MEM_ENTER_CRITICAL();
327 #if (defined(MEM_MANAGER_PRE_CONFIGURE) && (MEM_MANAGER_PRE_CONFIGURE == 0U))
328     (void)MEM_Init();
329 #endif
330     pPool->pHeap     = pHeap;
331     pPool->numBlocks = memConfig->numberOfBlocks;
332     pPool->blockSize = memConfig->blockSize;
333     pPool->poolId    = *(uint16_t *)(void *)(&buffer[4]);
334     pPool->heapSize =
335         (MEM_POOL_SIZE + (uint32_t)memConfig->numberOfBlocks * (MEM_BLOCK_SIZE + (uint32_t)memConfig->blockSize));
336 #if (defined(MEM_MANAGER_ENABLE_TRACE) && (MEM_MANAGER_ENABLE_TRACE > 0U))
337     pPool->allocatedBlocksPeak    = 0;
338     pPool->poolTotalFragmentWaste = 0;
339     pPool->poolFragmentWaste      = 0;
340     pPool->poolFragmentWastePeak  = 0;
341     pPool->poolFragmentMinWaste   = 0xffff;
342 #endif /*MEM_MANAGER_ENABLE_TRACE*/
343     if (s_memmanager.pHeadPool == NULL)
344     {
345         s_memmanager.pHeadPool = pPool;
346     }
347     else
348     {
349         pTempPool = s_memmanager.pHeadPool;
350         pPrevPool = pTempPool;
351         while (NULL != pTempPool)
352         {
353             if (((pPool->blockSize >= pPrevPool->blockSize) && (pPool->blockSize <= pTempPool->blockSize)) ||
354                 (pPool->blockSize <= pPrevPool->blockSize))
355             {
356                 if (pTempPool == s_memmanager.pHeadPool)
357                 {
358                     s_memmanager.pHeadPool = pPool;
359                 }
360                 else
361                 {
362                     pPrevPool->nextPool = pPool;
363                 }
364                 pPool->nextPool = pTempPool;
365                 break;
366             }
367             pPrevPool = pTempPool;
368             pTempPool = pTempPool->nextPool;
369         }
370         if (pPool->blockSize > pPrevPool->blockSize)
371         {
372             pPrevPool->nextPool = pPool;
373         }
374     }
375 
376     s_memmanager.poolNum++;
377     MEM_EXIT_CRITICAL();
378     return kStatus_MemSuccess;
379 }
380 
381 /*!
382  * @brief Remove memory buffer from memory manager buffer list.
383  *
384  * @note This API should be called when need remove memory buffer to memory manager buffer list. Use with
385  * MEM_BLOCK_BUFFER Macro as input parameter.
386  *
387  * @param buffer                     Pointer the memory pool buffer, use MEM_BLOCK_BUFFER Macro as the input parameter.
388  *
389  * @retval kStatus_MemSuccess        Memory manager remove buffer succeed.
390  * @retval kStatus_MemUnknownError      Memory manager remove buffer error occurred.
391  */
392 #if (defined(MEM_MANAGER_BUFFER_REMOVE) && (MEM_MANAGER_BUFFER_REMOVE > 0U))
MEM_RemoveBuffer(uint8_t * buffer)393 mem_status_t MEM_RemoveBuffer(uint8_t *buffer)
394 {
395     mem_config_t *memConfig     = (mem_config_t *)(void *)buffer;
396     mem_pool_structure_t *pPool = (mem_pool_structure_t *)(void *)memConfig->pbuffer;
397     uint8_t *pHeap              = &memConfig->pbuffer[sizeof(mem_pool_structure_t)];
398     mem_pool_structure_t *pPrevPool, *pTempPool;
399 
400     assert(buffer);
401     assert(memConfig->numberOfBlocks > 0U);
402     assert(memConfig->blockSize > 0U);
403 
404     MEM_ENTER_CRITICAL();
405     pTempPool = s_memmanager.pHeadPool;
406     pPrevPool = pTempPool;
407     while (NULL != pTempPool)
408     {
409         if (0U != pPool->allocatedBlocks)
410         {
411             break;
412         }
413         if (pTempPool->pHeap == pHeap)
414         {
415             if (pPool == s_memmanager.pHeadPool)
416             {
417                 s_memmanager.pHeadPool = pPool->nextPool;
418             }
419             else
420             {
421                 pPrevPool->nextPool = pPool->nextPool;
422             }
423             s_memmanager.poolNum--;
424             MEM_EXIT_CRITICAL();
425             return kStatus_MemSuccess;
426         }
427         pPrevPool = pTempPool;
428         pTempPool = pTempPool->nextPool;
429     }
430     MEM_EXIT_CRITICAL();
431     return kStatus_MemUnknownError;
432 }
433 #endif /* MEM_MANAGER_BUFFER_REMOVE */
434 
435 /*!
436  * @brief Allocate a block from the memory pools. The function uses the
437  *        numBytes argument to look up a pool with adequate block sizes.
438  *
439  * @param numBytes           The number of bytes will be allocated.
440  * @param poolId             The ID of the pool where to search for a free buffer.
441  * @retval Memory buffer address when allocate success, NULL when allocate fail.
442  */
MEM_BufferAllocWithId(uint32_t numBytes,uint8_t poolId)443 void *MEM_BufferAllocWithId(uint32_t numBytes, uint8_t poolId)
444 {
445 #if (defined(MEM_MANAGER_ENABLE_TRACE) && (MEM_MANAGER_ENABLE_TRACE > 0U))
446     uint32_t fragmentWaste = 0;
447 #endif /*MEM_MANAGER_ENABLE_TRACE*/
448     mem_pool_structure_t *pPool = s_memmanager.pHeadPool;
449     block_list_header_t *pBlock;
450     void *buffer = NULL;
451 
452     MEM_ENTER_CRITICAL();
453 #ifdef MEM_MANAGER_BENCH
454     uint32_t START_TIME = 0U, STOP_TIME = 0U, ALLOC_TIME = 0U;
455     START_TIME = TM_GetTimestamp();
456 #endif /* MEM_MANAGER_BENCH */
457 
458     while (0U != numBytes)
459     {
460         if ((numBytes <= pPool->blockSize) && (pPool->poolId == poolId))
461         {
462             for (uint32_t i = 0; i < pPool->numBlocks; i++)
463             {
464                 pBlock = (block_list_header_t *)(void *)(pPool->pHeap + i * ((uint32_t)pPool->blockSize +
465                                                                              (uint32_t)sizeof(block_list_header_t)));
466                 if (0U == pBlock->allocated)
467                 {
468                     pBlock->allocated = 1;
469                     pBlock->blockSize = pPool->blockSize;
470 #if (defined(MEM_MANAGER_ENABLE_TRACE) && (MEM_MANAGER_ENABLE_TRACE > 0U))
471                     pBlock->allocatedBytes = (uint16_t)numBytes;
472                     pBlock->caller         = (uint32_t)((uint32_t *)__mem_get_LR());
473 #endif /*MEM_MANAGER_ENABLE_TRACE*/
474                     pBlock++;
475                     pPool->allocatedBlocks++;
476                     buffer = pBlock;
477                     (void)memset(buffer, 0x0, pBlock->blockSize);
478                     break;
479                 }
480             }
481         }
482         if (NULL != buffer)
483         {
484             break;
485         }
486         /* Try next pool*/
487         pPool = pPool->nextPool;
488         if (NULL == pPool)
489         {
490             break;
491         }
492     }
493 #ifdef MEM_MANAGER_BENCH
494     STOP_TIME  = TM_GetTimestamp();
495     ALLOC_TIME = STOP_TIME - START_TIME;
496 #endif /* MEM_MANAGER_BENCH */
497 #if (defined(MEM_MANAGER_ENABLE_TRACE) && (MEM_MANAGER_ENABLE_TRACE > 0U))
498     if (NULL == buffer)
499     {
500         s_memmanager.allocationFailures++;
501     }
502 #endif /*MEM_MANAGER_ENABLE_TRACE*/
503 
504 #ifdef MEM_STATISTICS_INTERNAL
505 #ifdef MEM_MANAGER_BENCH
506     MEM_BufferAllocates_memStatis(buffer, ALLOC_TIME, numBytes);
507 #else
508     MEM_BufferAllocates_memStatis(buffer, 0, numBytes);
509 #endif
510 
511     if ((s_memStatis.nb_alloc % NB_ALLOC_REPORT_THRESHOLD) == 0U)
512     {
513         MEM_Reports_memStatis();
514     }
515 #endif /* MEM_STATISTICS_INTERNAL */
516 #if (defined(MEM_MANAGER_ENABLE_TRACE) && (MEM_MANAGER_ENABLE_TRACE > 0U))
517     if (pPool->allocatedBlocks > pPool->allocatedBlocksPeak)
518     {
519         pPool->allocatedBlocksPeak = pPool->allocatedBlocks;
520     }
521     fragmentWaste = pPool->blockSize - numBytes;
522     if (fragmentWaste > pPool->poolFragmentWastePeak)
523     {
524         pPool->poolFragmentWastePeak = (uint16_t)fragmentWaste;
525     }
526     pPool->poolFragmentWaste = (uint16_t)fragmentWaste;
527     pPool->poolTotalFragmentWaste += (uint16_t)fragmentWaste;
528     if (fragmentWaste < pPool->poolFragmentMinWaste)
529     {
530         pPool->poolFragmentMinWaste = (uint16_t)fragmentWaste;
531     }
532 #endif /*MEM_MANAGER_ENABLE_TRACE*/
533     MEM_EXIT_CRITICAL();
534     return buffer;
535 }
536 
537 /*!
538  * @brief Memory buffer free.
539  *
540  * @param buffer                     The memory buffer address will be free.
541  * @retval kStatus_MemSuccess        Memory free succeed.
542  * @retval kStatus_MemFreeError      Memory free error occurred.
543  */
MEM_BufferFree(void * buffer)544 mem_status_t MEM_BufferFree(void *buffer /* IN: Block of memory to free*/
545 )
546 {
547     block_list_header_t *pBlock;
548     mem_pool_structure_t *pPool = s_memmanager.pHeadPool;
549     MEM_ENTER_CRITICAL();
550 
551     do
552     {
553         if (NULL == buffer)
554         {
555             break;
556         }
557 #if defined(MEM_STATISTICS_INTERNAL)
558         MEM_BufferFrees_memStatis(buffer);
559 #endif /* MEM_STATISTICS_INTERNAL */
560         pBlock = (block_list_header_t *)buffer - 1;
561         assert(pBlock);
562         if (1U == pBlock->allocated)
563         {
564             (void)memset(pBlock, 0x0, (sizeof(block_list_header_t) + (uint32_t)pBlock->blockSize));
565             MEM_EXIT_CRITICAL();
566             while (true)
567             {
568                 if (((uint32_t)pPool->pHeap <= (uint32_t)pBlock) &&
569                     ((uint32_t)pBlock <
570                      (uint32_t)pPool->pHeap +
571                          pPool->numBlocks * ((uint32_t)pPool->blockSize + (uint32_t)sizeof(block_list_header_t))))
572                 {
573                     pPool->allocatedBlocks--;
574                     return kStatus_MemSuccess;
575                 }
576                 pPool = pPool->nextPool;
577                 if (NULL == pPool)
578                 {
579                     return kStatus_MemFreeError;
580                 }
581             }
582         }
583 
584 #if (defined(MEM_MANAGER_ENABLE_TRACE) && (MEM_MANAGER_ENABLE_TRACE > 0U))
585         s_memmanager.freeFailures++;
586 #endif /*MEM_MANAGER_ENABLE_TRACE*/
587 
588     } while (false);
589 
590     MEM_EXIT_CRITICAL();
591     return kStatus_MemFreeError;
592 }
593 
594 /*!
595  * @brief Returns the size of a given buffer.
596  *
597  * @param buffer                     The memory buffer address will be free.
598  * @retval The size of a given buffer.
599  */
MEM_BufferGetSize(void * buffer)600 uint16_t MEM_BufferGetSize(void *buffer) /* IN: Block of memory to get size*/
601 {
602     block_list_header_t *pBlock;
603     assert(buffer);
604 
605     pBlock = (block_list_header_t *)buffer - 1;
606     assert(pBlock);
607 
608     return pBlock->blockSize;
609 }
610 
611 /*!
612  * @brief Frees all allocated blocks by selected source and in selected pool.
613  *
614  * @param poolId                     Selected pool Id (4 LSBs of poolId parameter) and selected
615  *                                   source Id (4 MSBs of poolId parameter).
616  * @retval kStatus_MemSuccess        Memory free succeed.
617  * @retval kStatus_MemFreeError      Memory free error occurred.
618  */
MEM_BufferFreeAllWithId(uint8_t poolId)619 mem_status_t MEM_BufferFreeAllWithId(uint8_t poolId)
620 {
621     mem_pool_structure_t *pPool = s_memmanager.pHeadPool;
622 
623     MEM_ENTER_CRITICAL();
624 
625     while (pPool != NULL)
626     {
627         if (pPool->poolId == poolId)
628         {
629             (void)memset(pPool->pHeap, 0x0,
630                          ((sizeof(block_list_header_t) + (uint32_t)pPool->blockSize) * pPool->numBlocks));
631 #if (defined(MEM_MANAGER_ENABLE_TRACE) && (MEM_MANAGER_ENABLE_TRACE > 0U))
632             pPool->allocatedBlocksPeak    = 0;
633             pPool->poolTotalFragmentWaste = 0;
634             pPool->poolFragmentWaste      = 0;
635             pPool->poolFragmentWastePeak  = 0;
636             pPool->poolFragmentMinWaste   = 0xffff;
637 #endif /*MEM_MANAGER_ENABLE_TRACE*/
638             pPool->allocatedBlocks = 0;
639         }
640         pPool = pPool->nextPool;
641     }
642 
643     MEM_EXIT_CRITICAL();
644     return kStatus_MemSuccess;
645 }
646 
647 /*!
648  * @brief Memory buffer realloc.
649  *
650  * @param buffer                     The memory buffer address will be reallocated.
651  * @param new_size                   The number of bytes will be reallocated
652  * @retval kStatus_MemSuccess        Memory free succeed.
653  * @retval kStatus_MemFreeError      Memory free error occurred.
654  */
MEM_BufferRealloc(void * buffer,uint32_t new_size)655 void *MEM_BufferRealloc(void *buffer, uint32_t new_size)
656 {
657     void *realloc_buffer = NULL;
658     uint16_t block_size  = 0U;
659 
660     if (new_size == 0U)
661     {
662         /* new requested size is 0, free old buffer */
663         (void)MEM_BufferFree(buffer);
664         realloc_buffer = NULL;
665     }
666     else if (buffer == NULL)
667     {
668         /* input buffer is NULL simply allocate a new buffer and return it */
669         realloc_buffer = MEM_BufferAllocWithId(new_size, 0U);
670     }
671     else
672     {
673         block_size = MEM_BufferGetSize(buffer);
674 
675         if ((uint16_t)new_size <= block_size)
676         {
677             /* current buffer is large enough for the new requested size
678                we can still use it */
679             realloc_buffer = buffer;
680         }
681         else
682         {
683             /* not enough space in the current block, creating a new one */
684             realloc_buffer = MEM_BufferAllocWithId(new_size, 0U);
685 
686             if (realloc_buffer != NULL)
687             {
688                 /* copy input buffer data to new buffer */
689                 (void)memcpy(realloc_buffer, buffer, (uint32_t)block_size);
690 
691                 /* free old buffer */
692                 (void)MEM_BufferFree(buffer);
693             }
694         }
695     }
696 
697     return realloc_buffer;
698 }
699 
700 /*!
701  * @brief Get the address after the last allocated block if MemManagerLight is used.
702  *
703  * @retval 0      Return 0 in case of the legacy MemManager.
704  */
MEM_GetHeapUpperLimit(void)705 uint32_t MEM_GetHeapUpperLimit(void)
706 {
707     return 0U;
708 }
709 
710 /*!
711  * @brief Get the free space in the heap.
712  *
713  * @retval 0      Return 0 in case of the legacy MemManager.
714  */
MEM_GetFreeHeapSize(void)715 uint32_t MEM_GetFreeHeapSize(void)
716 {
717     return 0U;
718 }
719 
720 /*!
721  * @brief Trace memory manager all information to use debug.
722  *
723  */
724 #if (defined(MEM_MANAGER_ENABLE_TRACE) && (MEM_MANAGER_ENABLE_TRACE > 0U))
MEM_Trace(void)725 void MEM_Trace(void)
726 {
727     mem_pool_structure_t *pPool = s_memmanager.pHeadPool;
728     block_list_header_t *pBlock;
729     (void)PRINTF("MEM_Trace debug information, Pools Number:%d   allocationFailures: %d  freeFailures:%d\r\n",
730                  s_memmanager.poolNum, s_memmanager.allocationFailures, s_memmanager.allocationFailures,
731                  s_memmanager.freeFailures);
732     while (NULL != pPool)
733     {
734         (void)PRINTF("POOL: ID %d  blockSize:%d   status:\r\n", pPool->poolId, pPool->blockSize);
735         (void)PRINTF(
736             "numBlocks allocatedBlocks  allocatedBlocksPeak  poolFragmentWaste poolFragmentWastePeak "
737             "poolFragmentMinWaste poolTotalFragmentWaste\r\n");
738         (void)PRINTF(
739             "    %d          %d                %d                %d                  %d                       %d       "
740             "              %d\r\n",
741             pPool->numBlocks, pPool->allocatedBlocks, pPool->allocatedBlocksPeak, pPool->poolFragmentWaste,
742             pPool->poolFragmentWastePeak, pPool->poolFragmentMinWaste, pPool->poolTotalFragmentWaste);
743         (void)PRINTF("Currently pool meory block allocate status:\r\n");
744         for (uint32_t i = 0; i < pPool->numBlocks; i++)
745         {
746             pBlock = (block_list_header_t *)(void *)(pPool->pHeap +
747                                                      i * ((uint32_t)pPool->blockSize + sizeof(block_list_header_t)));
748 
749             (void)PRINTF("Block %d caller : 0x%x Allocated %d bytes: %d\r\n", i, pBlock->caller, pBlock->allocated,
750                          pBlock->allocatedBytes);
751         }
752         /* Try next pool*/
753         pPool = pPool->nextPool;
754     }
755 }
756 #endif /*MEM_MANAGER_ENABLE_TRACE*/
757 #endif /*gMemManagerLight*/
758