1 /*! *********************************************************************************
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2016-2022 NXP
4  * All rights reserved.
5  *
6  * \file
7  *
8  * This is the source file for the Memory Manager.
9  *
10  * SPDX-License-Identifier: BSD-3-Clause
11  ********************************************************************************** */
12 
13 /*! *********************************************************************************
14 *************************************************************************************
15 * Include
16 *************************************************************************************
17 ********************************************************************************** */
18 
19 #include "fsl_common.h"
20 #if defined(MEM_STATISTICS_INTERNAL) || defined(MEM_MANAGER_BENCH)
21 #include "fsl_component_timer_manager.h"
22 #include "fsl_component_mem_manager_internal.h"
23 #endif /* MEM_STATISTICS_INTERNAL MEM_MANAGER_BENCH*/
24 #include "fsl_component_mem_manager.h"
25 #if defined(gDebugConsoleEnable_d) && (gDebugConsoleEnable_d == 1)
26 #include "fsl_debug_console.h"
27 #endif
28 
29 #if defined(gMemManagerLight) && (gMemManagerLight == 1)
30 
31 /*  Selects the allocation scheme that will be used by the MemManagerLight
32     0: Allocates the first free block available in the heap, no matter its size
33     1: Allocates the first free block whose size is at most the double of the requested size
34     2: Allocates the first free block whose size is at most the 4/3 of the requested size     */
35 #ifndef cMemManagerLightReuseFreeBlocks
36 #define cMemManagerLightReuseFreeBlocks 1
37 #endif
38 
39 #if defined(cMemManagerLightReuseFreeBlocks) && (cMemManagerLightReuseFreeBlocks > 0)
40 /* because a more restrictive on the size of the free blocks when cMemManagerLightReuseFreeBlocks
41    is set, we need to enable a garbage collector to clean up the free block when possible  */
42 #ifndef gMemManagerLightFreeBlocksCleanUp
43 #define gMemManagerLightFreeBlocksCleanUp 1
44 #endif
45 #endif
46 
47 #ifndef gMemManagerLightGuardsCheckEnable
48 #define gMemManagerLightGuardsCheckEnable 0
49 #endif
50 
51 /*! Extend Heap usage beyond the size defined by MinimalHeapSize_c up to __HEAP_end__ symbol address
52  *   to make full use of the remaining available SRAM for the dynamic allocator. Also, only the data up to the
53  *   highest allocated block will be retained by calling the @function MEM_GetHeapUpperLimit() from the power
54  *   manager.
55  *   When this flag is turned to 1 :
56  *     -  __HEAP_end__ linker symbol shall be defined in linker script to be the highest allowed address
57  *   used by the fsl_component_memory_manager_light
58  *     - .heap section shall be defined and placed after bss and zi sections to make sure no data is located
59  *   up to __HEAP_end__ symbol.
60  *   @Warning, no data shall be placed after memHeap symbol address up to __HEAP_end__ . If an other
61  *   memory allocator uses a memory area between __HEAP_start__ and __HEAP_end__, area may overlap
62  *   with fsl_component_memory_manager_light, so this flag shall be kept to 0
63  */
64 #ifndef gMemManagerLightExtendHeapAreaUsage
65 #define gMemManagerLightExtendHeapAreaUsage   0
66 #endif
67 
68 /*! *********************************************************************************
69 *************************************************************************************
70 * Private macros
71 *************************************************************************************
72 ********************************************************************************** */
73 
74 #define MEMMANAGER_BLOCK_INVALID (uint16_t)0x0    /* Used to remove a block in the heap - debug only */
75 #define MEMMANAGER_BLOCK_FREE    (uint16_t)0xBA00 /* Mark a previous allocated block as free         */
76 #define MEMMANAGER_BLOCK_USED    (uint16_t)0xBABE /* Mark the block as allocated                     */
77 
78 #define BLOCK_HDR_SIZE (ROUNDUP_WORD(sizeof(blockHeader_t)))
79 
80 #define ROUNDUP_WORD(__x) (((((__x)-1U) & ~0x3U) + 4U) & 0XFFFFFFFFU)
81 
82 #define BLOCK_HDR_PREGUARD_SIZE     28U
83 #define BLOCK_HDR_PREGUARD_PATTERN  0x28U
84 #define BLOCK_HDR_POSTGUARD_SIZE    28U
85 #define BLOCK_HDR_POSTGUARD_PATTERN 0x39U
86 
87 #if defined(__IAR_SYSTEMS_ICC__)
88 #define __mem_get_LR() __get_LR()
89 #elif defined(__GNUC__)
90 #define __mem_get_LR() __builtin_return_address(0)
91 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
92 #define __mem_get_LR() __return_address()
93 #endif
94 
95 #if defined(gMemManagerLightGuardsCheckEnable) && (gMemManagerLightGuardsCheckEnable == 1)
96 #define gMemManagerLightAddPreGuard  1
97 #define gMemManagerLightAddPostGuard 1
98 #endif
99 
100 #ifndef gMemManagerLightAddPreGuard
101 #define gMemManagerLightAddPreGuard 0
102 #endif
103 
104 #ifndef gMemManagerLightAddPostGuard
105 #define gMemManagerLightAddPostGuard 0
106 #endif
107 
108 /************************************************************************************
109 *************************************************************************************
110 * Private type definitions
111 *************************************************************************************
112 ************************************************************************************/
113 
114 typedef struct blockHeader_s
115 {
116 #if defined(gMemManagerLightAddPreGuard) && (gMemManagerLightAddPreGuard == 1)
117     uint8_t preguard[BLOCK_HDR_PREGUARD_SIZE];
118 #endif
119     uint16_t used;
120 #if defined(MEM_STATISTICS_INTERNAL)
121     uint16_t buff_size;
122 #endif
123     struct blockHeader_s *next;
124     struct blockHeader_s *next_free;
125     struct blockHeader_s *prev_free;
126 #ifdef MEM_TRACKING
127     void *first_alloc_caller;
128     void *second_alloc_caller;
129 #endif
130 #if defined(gMemManagerLightAddPostGuard) && (gMemManagerLightAddPostGuard == 1)
131     uint8_t postguard[BLOCK_HDR_POSTGUARD_SIZE];
132 #endif
133 } blockHeader_t;
134 
135 typedef struct freeBlockHeaderList_s
136 {
137     struct blockHeader_s *head;
138     struct blockHeader_s *tail;
139 } freeBlockHeaderList_t;
140 
141 typedef union void_ptr_tag
142 {
143     uint32_t raw_address;
144     uint32_t *address_ptr;
145     void *void_ptr;
146     blockHeader_t *block_hdr_ptr;
147 } void_ptr_t;
148 
149 /*! *********************************************************************************
150 *************************************************************************************
151 * Private memory declarations
152 *************************************************************************************
153 ********************************************************************************** */
154 
155 #ifndef MEMORY_POOL_GLOBAL_VARIABLE_ALLOC
156 /* Allocate memHeap array in the .heap section to ensure the size of the .heap section is large enough
157    for the application
158    However, the real heap used at run time will cover all the .heap section so this area can be bigger
159    than the requested MinimalHeapSize_c - see memHeapEnd */
160 #if defined(__IAR_SYSTEMS_ICC__)
161 #pragma location = ".heap"
162 static uint32_t memHeap[MinimalHeapSize_c / sizeof(uint32_t)];
163 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
164 static uint32_t memHeap[MinimalHeapSize_c / sizeof(uint32_t)] __attribute__((section(".heap")));
165 #elif defined(__GNUC__)
166 static uint32_t memHeap[MinimalHeapSize_c / sizeof(uint32_t)] __attribute__((section(".heap, \"aw\", %nobits @")));
167 #else
168 #error "Compiler unknown!"
169 #endif
170 
171 #if defined(gMemManagerLightExtendHeapAreaUsage) && (gMemManagerLightExtendHeapAreaUsage == 1)
172 #if defined(__ARMCC_VERSION)
173 extern uint32_t Image$$ARM_LIB_STACK$$Base[];
174 static const uint32_t memHeapEnd = (uint32_t)&Image$$ARM_LIB_STACK$$Base;
175 #else
176 extern uint32_t __HEAP_end__[];
177 static const uint32_t memHeapEnd = (uint32_t)&__HEAP_end__;
178 #endif
179 #else
180 static const uint32_t memHeapEnd = (uint32_t)(memHeap + MinimalHeapSize_c / sizeof(uint32_t));
181 #endif
182 
183 #else
184 extern uint32_t *memHeap;
185 extern uint32_t memHeapEnd;
186 #endif /* MEMORY_POOL_GLOBAL_VARIABLE_ALLOC */
187 
188 static freeBlockHeaderList_t FreeBlockHdrList;
189 
190 #ifdef MEM_STATISTICS_INTERNAL
191 static mem_statis_t s_memStatis;
192 #endif /* MEM_STATISTICS_INTERNAL */
193 
194 #if defined(gFSCI_MemAllocTest_Enabled_d) && (gFSCI_MemAllocTest_Enabled_d)
195 extern mem_alloc_test_status_t FSCI_MemAllocTestCanAllocate(void *pCaller);
196 #endif
197 
198 /*! *********************************************************************************
199 *************************************************************************************
200 * Private functions
201 *************************************************************************************
202 ********************************************************************************** */
203 
204 #ifdef MEM_STATISTICS_INTERNAL
MEM_Inits_memStatis(mem_statis_t * s_memStatis_)205 static void MEM_Inits_memStatis(mem_statis_t *s_memStatis_)
206 {
207     (void)memset(s_memStatis_, 0, sizeof(mem_statis_t));
208     SystemCoreClockUpdate();
209 }
210 
MEM_BufferAllocates_memStatis(void * buffer,uint32_t time,uint32_t requestedSize)211 static void MEM_BufferAllocates_memStatis(void *buffer, uint32_t time, uint32_t requestedSize)
212 {
213     void_ptr_t buffer_ptr;
214     void_ptr_t blockHdr_ptr;
215     blockHeader_t *BlockHdr;
216 
217     /* Using union to fix Misra */
218     buffer_ptr.void_ptr      = buffer;
219     blockHdr_ptr.raw_address = buffer_ptr.raw_address - BLOCK_HDR_SIZE;
220     BlockHdr                 = blockHdr_ptr.block_hdr_ptr;
221 
222     /* existing block must have a BlockHdr and a next BlockHdr */
223     assert((BlockHdr != NULL) && (BlockHdr->next != NULL));
224 
225     s_memStatis.nb_alloc++;
226     /* Sort the buffers by size, based on defined thresholds */
227     if (requestedSize <= SMALL_BUFFER_SIZE)
228     {
229         s_memStatis.nb_small_buffer++;
230         UPDATE_PEAK(s_memStatis.nb_small_buffer, s_memStatis.peak_small_buffer);
231     }
232     else if (requestedSize <= LARGE_BUFFER_SIZE)
233     {
234         s_memStatis.nb_medium_buffer++;
235         UPDATE_PEAK(s_memStatis.nb_medium_buffer, s_memStatis.peak_medium_buffer);
236     }
237     else
238     {
239         s_memStatis.nb_large_buffer++;
240         UPDATE_PEAK(s_memStatis.nb_large_buffer, s_memStatis.peak_large_buffer);
241     }
242     /* the RAM allocated is the buffer size and the block header size*/
243     s_memStatis.ram_allocated += (uint16_t)(requestedSize + BLOCK_HDR_SIZE);
244     UPDATE_PEAK(s_memStatis.ram_allocated, s_memStatis.peak_ram_allocated);
245 
246     uint32_t block_size = 0U;
247     block_size          = (uint32_t)BlockHdr->next - (uint32_t)BlockHdr - BLOCK_HDR_SIZE;
248 
249     assert(block_size >= requestedSize);
250     /* ram lost is the difference between block size and buffer size */
251     s_memStatis.ram_lost += (uint16_t)(block_size - requestedSize);
252     UPDATE_PEAK(s_memStatis.ram_lost, s_memStatis.peak_ram_lost);
253 
254     UPDATE_PEAK(((uint32_t)FreeBlockHdrList.tail + BLOCK_HDR_SIZE), s_memStatis.peak_upper_addr);
255 
256 #ifdef MEM_MANAGER_BENCH
257     if (time != 0U)
258     {
259         /* update mem stats used for benchmarking */
260         s_memStatis.last_alloc_block_size = (uint16_t)block_size;
261         s_memStatis.last_alloc_buff_size  = (uint16_t)requestedSize;
262         s_memStatis.last_alloc_time       = (uint16_t)time;
263         s_memStatis.total_alloc_time += time;
264         s_memStatis.average_alloc_time = (uint16_t)(s_memStatis.total_alloc_time / s_memStatis.nb_alloc);
265         UPDATE_PEAK((uint16_t)time, s_memStatis.peak_alloc_time);
266     }
267     else /* alloc time is not correct, we bypass this allocation's data */
268     {
269         s_memStatis.nb_alloc--;
270     }
271 #else
272     (void)time;
273 #endif /* MEM_MANAGER_BENCH */
274 }
275 
MEM_BufferFrees_memStatis(void * buffer)276 static void MEM_BufferFrees_memStatis(void *buffer)
277 {
278     void_ptr_t buffer_ptr;
279     void_ptr_t blockHdr_ptr;
280     blockHeader_t *BlockHdr;
281 
282     /* Use union to fix Misra */
283     buffer_ptr.void_ptr      = buffer;
284     blockHdr_ptr.raw_address = buffer_ptr.raw_address - BLOCK_HDR_SIZE;
285     BlockHdr                 = blockHdr_ptr.block_hdr_ptr;
286 
287     /* Existing block must have a next block hdr */
288     assert((BlockHdr != NULL) && (BlockHdr->next != NULL));
289 
290     s_memStatis.ram_allocated -= (uint16_t)(BlockHdr->buff_size + BLOCK_HDR_SIZE);
291     /* Sort the buffers by size, based on defined thresholds */
292     if (BlockHdr->buff_size <= SMALL_BUFFER_SIZE)
293     {
294         s_memStatis.nb_small_buffer--;
295     }
296     else if (BlockHdr->buff_size <= LARGE_BUFFER_SIZE)
297     {
298         s_memStatis.nb_medium_buffer--;
299     }
300     else
301     {
302         s_memStatis.nb_large_buffer--;
303     }
304 
305     uint16_t block_size = 0U;
306     block_size          = (uint16_t)((uint32_t)BlockHdr->next - (uint32_t)BlockHdr - BLOCK_HDR_SIZE);
307 
308     assert(block_size >= BlockHdr->buff_size);
309     assert(s_memStatis.ram_lost >= (block_size - BlockHdr->buff_size));
310 
311     /* as the buffer is free, the ram is not "lost" anymore */
312     s_memStatis.ram_lost -= (block_size - BlockHdr->buff_size);
313 }
314 
315 #endif /* MEM_STATISTICS_INTERNAL */
316 
317 #if defined(gMemManagerLightFreeBlocksCleanUp) && (gMemManagerLightFreeBlocksCleanUp == 1)
MEM_BufferFreeBlocksCleanUp(blockHeader_t * BlockHdr)318 static void MEM_BufferFreeBlocksCleanUp(blockHeader_t *BlockHdr)
319 {
320     blockHeader_t *NextBlockHdr     = BlockHdr->next;
321     blockHeader_t *NextFreeBlockHdr = BlockHdr->next_free;
322 
323     /* This function shouldn't be called on the last free block */
324     assert(BlockHdr < FreeBlockHdrList.tail);
325 
326     while (NextBlockHdr == NextFreeBlockHdr)
327     {
328         if (NextBlockHdr == NULL)
329         {
330             assert(BlockHdr->next == BlockHdr->next_free);
331             assert(BlockHdr->used == MEMMANAGER_BLOCK_FREE);
332             /* pool is reached.  All buffers from BlockHdr to the pool are free
333                remove all next buffers */
334             BlockHdr->next        = NULL;
335             BlockHdr->next_free   = NULL;
336             FreeBlockHdrList.tail = BlockHdr;
337             break;
338         }
339         NextBlockHdr     = NextBlockHdr->next;
340         NextFreeBlockHdr = NextFreeBlockHdr->next_free;
341     }
342 }
343 #endif /* gMemManagerLightFreeBlocksCleanUp */
344 
345 #if defined(gMemManagerLightGuardsCheckEnable) && (gMemManagerLightGuardsCheckEnable == 1)
MEM_BlockHeaderCheck(blockHeader_t * BlockHdr)346 static void MEM_BlockHeaderCheck(blockHeader_t *BlockHdr)
347 {
348     int ret;
349     uint8_t guardPrePattern[BLOCK_HDR_PREGUARD_SIZE];
350     uint8_t guardPostPattern[BLOCK_HDR_POSTGUARD_SIZE];
351 
352     (void)memset((void *)guardPrePattern, BLOCK_HDR_PREGUARD_PATTERN, BLOCK_HDR_PREGUARD_SIZE);
353     ret = memcmp((const void *)&BlockHdr->preguard, (const void *)guardPrePattern, BLOCK_HDR_PREGUARD_SIZE);
354     if (ret != 0)
355     {
356         MEM_DBG_LOG("Preguard Block Header Corrupted %x", BlockHdr);
357     }
358     assert(ret == 0);
359 
360     (void)memset((void *)guardPostPattern, BLOCK_HDR_POSTGUARD_PATTERN, BLOCK_HDR_POSTGUARD_SIZE);
361     ret = memcmp((const void *)&BlockHdr->postguard, (const void *)guardPostPattern, BLOCK_HDR_POSTGUARD_SIZE);
362     if (ret != 0)
363     {
364         MEM_DBG_LOG("Postguard Block Header Corrupted %x", BlockHdr);
365     }
366     assert(ret == 0);
367 }
368 
MEM_BlockHeaderSetGuards(blockHeader_t * BlockHdr)369 static void MEM_BlockHeaderSetGuards(blockHeader_t *BlockHdr)
370 {
371     (void)memset((void *)&BlockHdr->preguard, BLOCK_HDR_PREGUARD_PATTERN, BLOCK_HDR_PREGUARD_SIZE);
372     (void)memset((void *)&BlockHdr->postguard, BLOCK_HDR_POSTGUARD_PATTERN, BLOCK_HDR_POSTGUARD_SIZE);
373 }
374 
375 #endif
376 
377 /*! *********************************************************************************
378 *************************************************************************************
379 * Public functions
380 *************************************************************************************
381 ********************************************************************************** */
382 
383 #if defined(MEM_STATISTICS_INTERNAL)
MEM_Reports_memStatis(void)384 static void MEM_Reports_memStatis(void)
385 {
386     MEM_DBG_LOG("**************** MEM STATS REPORT **************");
387     MEM_DBG_LOG("Nb Alloc:                  %d\r\n", s_memStatis.nb_alloc);
388     MEM_DBG_LOG("Small buffers:             %d\r\n", s_memStatis.nb_small_buffer);
389     MEM_DBG_LOG("Medium buffers:            %d\r\n", s_memStatis.nb_medium_buffer);
390     MEM_DBG_LOG("Large buffers:             %d\r\n", s_memStatis.nb_large_buffer);
391     MEM_DBG_LOG("Peak small:                %d\r\n", s_memStatis.peak_small_buffer);
392     MEM_DBG_LOG("Peak medium:               %d\r\n", s_memStatis.peak_medium_buffer);
393     MEM_DBG_LOG("Peak large:                %d\r\n", s_memStatis.peak_large_buffer);
394     MEM_DBG_LOG("Current RAM allocated:     %d bytes\r\n", s_memStatis.ram_allocated);
395     MEM_DBG_LOG("Peak RAM allocated:        %d bytes\r\n", s_memStatis.peak_ram_allocated);
396     MEM_DBG_LOG("Current RAM lost:          %d bytes\r\n", s_memStatis.ram_lost);
397     MEM_DBG_LOG("Peak RAM lost:             %d bytes\r\n", s_memStatis.peak_ram_lost);
398     MEM_DBG_LOG("Peak Upper Address:        %x\r\n", s_memStatis.peak_upper_addr);
399 #ifdef MEM_MANAGER_BENCH
400     MEM_DBG_LOG("************************************************\r\n");
401     MEM_DBG_LOG("********* MEM MANAGER BENCHMARK REPORT *********\r\n");
402     MEM_DBG_LOG("Last Alloc Time:           %d us\r\n", s_memStatis.last_alloc_time);
403     MEM_DBG_LOG("Last Alloc Block Size:     %d bytes\r\n", s_memStatis.last_alloc_block_size);
404     MEM_DBG_LOG("Last Alloc Buffer Size:    %d bytes\r\n", s_memStatis.last_alloc_buff_size);
405     MEM_DBG_LOG("Average Alloc Time:        %d us\r\n", s_memStatis.average_alloc_time);
406     MEM_DBG_LOG("Peak Alloc Time:           %d us\r\n", s_memStatis.peak_alloc_time);
407 #endif /* MEM_MANAGER_BENCH */
408     MEM_DBG_LOG("************************************************");
409 }
410 #endif /* MEM_STATISTICS_INTERNAL */
411 
412 static bool initialized = false;
413 
MEM_Init(void)414 mem_status_t MEM_Init(void)
415 {
416     if (initialized == false)
417     {
418         initialized = true;
419         /* union to solve Misra 11.3 */
420         void_ptr_t ptr;
421         ptr.address_ptr = memHeap;
422         blockHeader_t *firstBlockHdr;
423         firstBlockHdr = ptr.block_hdr_ptr;
424 
425         /* MEM_DBG_LOG("%x %d\r\n", memHeap, heapSize_c/sizeof(uint32_t)); */
426 
427         /* Init firstBlockHdr as a free block */
428         firstBlockHdr->next      = NULL;
429         firstBlockHdr->used      = MEMMANAGER_BLOCK_FREE;
430         firstBlockHdr->next_free = NULL;
431         firstBlockHdr->prev_free = NULL;
432 
433 #if defined(MEM_STATISTICS_INTERNAL)
434         firstBlockHdr->buff_size = 0U;
435 #endif
436 
437         /* Init FreeBlockHdrList with firstBlockHdr */
438         FreeBlockHdrList.head = firstBlockHdr;
439         FreeBlockHdrList.tail = firstBlockHdr;
440 
441 #if defined(gMemManagerLightGuardsCheckEnable) && (gMemManagerLightGuardsCheckEnable == 1)
442         MEM_BlockHeaderSetGuards(firstBlockHdr);
443 #endif
444 
445 #if defined(MEM_STATISTICS_INTERNAL)
446         /* Init memory statistics */
447         MEM_Inits_memStatis(&s_memStatis);
448 #endif
449     }
450 
451     return kStatus_MemSuccess;
452 }
MEM_BufferAllocate(uint32_t numBytes,uint8_t poolId)453 static void *MEM_BufferAllocate(uint32_t numBytes, uint8_t poolId)
454 {
455     if (initialized == false)
456     {
457         (void)MEM_Init();
458     }
459 
460     uint32_t regPrimask = DisableGlobalIRQ();
461 
462     blockHeader_t *FreeBlockHdr     = FreeBlockHdrList.head;
463     blockHeader_t *NextFreeBlockHdr = FreeBlockHdr->next_free;
464     blockHeader_t *PrevFreeBlockHdr = FreeBlockHdr->prev_free;
465     blockHeader_t *BlockHdrFound    = NULL;
466 
467 #if defined(cMemManagerLightReuseFreeBlocks) && (cMemManagerLightReuseFreeBlocks > 0)
468     blockHeader_t *UsableBlockHdr = NULL;
469 #endif
470     void *buffer = NULL;
471 
472 #ifdef MEM_MANAGER_BENCH
473     uint32_t START_TIME = 0U, STOP_TIME = 0U, ALLOC_TIME = 0U;
474     START_TIME = TM_GetTimestamp();
475 #endif /* MEM_MANAGER_BENCH */
476 
477     do
478     {
479         assert(FreeBlockHdr->used == MEMMANAGER_BLOCK_FREE);
480         if (FreeBlockHdr->next != NULL)
481         {
482             uint32_t available_size;
483             available_size = (uint32_t)FreeBlockHdr->next - (uint32_t)FreeBlockHdr - BLOCK_HDR_SIZE;
484             /* if a next block hdr exists, it means (by design) that a next free block exists too
485                Because the last block header at the end of the heap will always be free
486                So, the current block header can't be the tail, and the next free can't be NULL */
487             assert(FreeBlockHdr < FreeBlockHdrList.tail);
488             assert(FreeBlockHdr->next_free != NULL);
489 
490             if (available_size >= numBytes) /* enough space in this free buffer */
491             {
492 #if defined(cMemManagerLightReuseFreeBlocks) && (cMemManagerLightReuseFreeBlocks > 0)
493                 /* this block could be used if the memory pool if full, so we memorize it */
494                 if (UsableBlockHdr == NULL)
495                 {
496                     UsableBlockHdr = FreeBlockHdr;
497                 }
498                 /* To avoid waste of large blocks with small blocks, make sure the required size is big enough for the
499                   available block otherwise, try an other block !
500                   Do not check if available block size is 4 bytes, take the block anyway ! */
501                 if ( (available_size <= 4u) || ((available_size - numBytes) < (available_size >> cMemManagerLightReuseFreeBlocks)))
502 #endif
503                 {
504                     /* Found a matching free block */
505                     FreeBlockHdr->used = MEMMANAGER_BLOCK_USED;
506 #if defined(MEM_STATISTICS_INTERNAL)
507                     FreeBlockHdr->buff_size = (uint16_t)numBytes;
508 #endif
509                     NextFreeBlockHdr = FreeBlockHdr->next_free;
510                     PrevFreeBlockHdr = FreeBlockHdr->prev_free;
511 
512                     /* In the current state, the current block header can be anywhere
513                        from list head to previous block of list tail */
514                     if (FreeBlockHdrList.head == FreeBlockHdr)
515                     {
516                         FreeBlockHdrList.head       = NextFreeBlockHdr;
517                         NextFreeBlockHdr->prev_free = NULL;
518                     }
519                     else
520                     {
521                         assert(FreeBlockHdrList.head->next_free <= FreeBlockHdr);
522 
523                         NextFreeBlockHdr->prev_free = PrevFreeBlockHdr;
524                         PrevFreeBlockHdr->next_free = NextFreeBlockHdr;
525                     }
526 
527                     BlockHdrFound = FreeBlockHdr;
528                     break;
529                 }
530             }
531         }
532         else
533         {
534             /* last block in the heap, check if available space to allocate the block */
535             uint32_t available_size;
536             uint32_t current_footprint = (uint32_t)FreeBlockHdr + BLOCK_HDR_SIZE - 1U;
537 
538             /* Current allocation should never be greater than heap end */
539             assert(current_footprint <= memHeapEnd);
540 
541             available_size = memHeapEnd - current_footprint;
542 
543             assert(FreeBlockHdr == FreeBlockHdrList.tail);
544 
545             if (available_size >= (numBytes + BLOCK_HDR_SIZE)) /* need to keep the room for the next BlockHeader */
546             {
547                 /* Depending on the platform, some RAM banks could need some reinitialization after a low power
548                  * period, such as ECC RAM banks */
549                 MEM_ReinitRamBank((uint32_t)FreeBlockHdr + BLOCK_HDR_SIZE, ROUNDUP_WORD(((uint32_t)FreeBlockHdr + BLOCK_HDR_SIZE + numBytes)));
550 
551                 FreeBlockHdr->used = MEMMANAGER_BLOCK_USED;
552 #if defined(MEM_STATISTICS_INTERNAL)
553                 FreeBlockHdr->buff_size = (uint16_t)numBytes;
554 #endif
555                 FreeBlockHdr->next =
556                     (blockHeader_t *)ROUNDUP_WORD(((uint32_t)FreeBlockHdr + BLOCK_HDR_SIZE + numBytes));
557                 FreeBlockHdr->next_free = FreeBlockHdr->next;
558 
559                 PrevFreeBlockHdr = FreeBlockHdr->prev_free;
560 
561                 NextFreeBlockHdr       = FreeBlockHdr->next_free;
562                 NextFreeBlockHdr->used = MEMMANAGER_BLOCK_FREE;
563 #if defined(MEM_STATISTICS_INTERNAL)
564                 NextFreeBlockHdr->buff_size = 0U;
565 #endif
566                 NextFreeBlockHdr->next      = NULL;
567                 NextFreeBlockHdr->next_free = NULL;
568                 NextFreeBlockHdr->prev_free = PrevFreeBlockHdr;
569 
570                 if (FreeBlockHdrList.head == FreeBlockHdr)
571                 {
572                     assert(FreeBlockHdrList.head == FreeBlockHdrList.tail);
573                     assert(PrevFreeBlockHdr == NULL);
574                     /* last free block in heap was the only free block available
575                        so now the first free block in the heap is the next one */
576                     FreeBlockHdrList.head = FreeBlockHdr->next_free;
577                 }
578                 else
579                 {
580                     /* update previous free block header to point its next
581                        to the new free block */
582                     PrevFreeBlockHdr->next_free = NextFreeBlockHdr;
583                 }
584 
585                 /* new free block is now the tail of the free block list */
586                 FreeBlockHdrList.tail = NextFreeBlockHdr;
587 
588 #if defined(gMemManagerLightGuardsCheckEnable) && (gMemManagerLightGuardsCheckEnable == 1)
589                 MEM_BlockHeaderSetGuards(NextFreeBlockHdr);
590 #endif
591 
592                 BlockHdrFound = FreeBlockHdr;
593             }
594 #if defined(cMemManagerLightReuseFreeBlocks) && (cMemManagerLightReuseFreeBlocks > 0)
595             else if (UsableBlockHdr != NULL)
596             {
597                 /* we found a free block that can be used */
598                 UsableBlockHdr->used = MEMMANAGER_BLOCK_USED;
599 #if defined(MEM_STATISTICS_INTERNAL)
600                 UsableBlockHdr->buff_size = (uint16_t)numBytes;
601 #endif
602                 NextFreeBlockHdr = UsableBlockHdr->next_free;
603                 PrevFreeBlockHdr = UsableBlockHdr->prev_free;
604 
605                 /* In the current state, the current block header can be anywhere
606                    from list head to previous block of list tail */
607                 if (FreeBlockHdrList.head == UsableBlockHdr)
608                 {
609                     FreeBlockHdrList.head       = NextFreeBlockHdr;
610                     NextFreeBlockHdr->prev_free = NULL;
611                 }
612                 else
613                 {
614                     assert(FreeBlockHdrList.head->next_free <= UsableBlockHdr);
615 
616                     NextFreeBlockHdr->prev_free = PrevFreeBlockHdr;
617                     PrevFreeBlockHdr->next_free = NextFreeBlockHdr;
618                 }
619                 BlockHdrFound = UsableBlockHdr;
620             }
621 #endif
622             else
623             {
624                 BlockHdrFound = NULL;
625             }
626             break;
627         }
628 #if defined(gMemManagerLightGuardsCheckEnable) && (gMemManagerLightGuardsCheckEnable == 1)
629         MEM_BlockHeaderCheck(FreeBlockHdr->next_free);
630 #endif
631         FreeBlockHdr = FreeBlockHdr->next_free;
632         /* avoid looping */
633         assert(FreeBlockHdr != FreeBlockHdr->next_free);
634     } while (true);
635     /* MEM_DBG_LOG("BlockHdrFound: %x", BlockHdrFound); */
636 
637 #ifdef MEM_DEBUG_OUT_OF_MEMORY
638     assert(BlockHdrFound);
639 #endif
640 
641 #ifdef MEM_MANAGER_BENCH
642     STOP_TIME  = TM_GetTimestamp();
643     ALLOC_TIME = STOP_TIME - START_TIME;
644 #endif /* MEM_MANAGER_BENCH */
645 
646     if (BlockHdrFound != NULL)
647     {
648         void_ptr_t buffer_ptr;
649 #ifdef MEM_TRACKING
650         void_ptr_t lr;
651         lr.raw_address                    = (uint32_t)__mem_get_LR();
652         BlockHdrFound->first_alloc_caller = lr.void_ptr;
653 #endif
654         buffer_ptr.raw_address = (uint32_t)BlockHdrFound + BLOCK_HDR_SIZE;
655         buffer                 = buffer_ptr.void_ptr;
656         (void)memset(buffer, 0x0, numBytes);
657     }
658 
659 #ifdef MEM_STATISTICS_INTERNAL
660 #ifdef MEM_MANAGER_BENCH
661     MEM_BufferAllocates_memStatis(buffer, ALLOC_TIME, numBytes);
662 #else
663     MEM_BufferAllocates_memStatis(buffer, 0, numBytes);
664 #endif
665 
666     if ((s_memStatis.nb_alloc % NB_ALLOC_REPORT_THRESHOLD) == 0U)
667     {
668         MEM_Reports_memStatis();
669     }
670 #endif /* MEM_STATISTICS_INTERNAL */
671 
672     EnableGlobalIRQ(regPrimask);
673 
674     return buffer;
675 }
676 
MEM_BufferAllocWithId(uint32_t numBytes,uint8_t poolId)677 void *MEM_BufferAllocWithId(uint32_t numBytes, uint8_t poolId)
678 {
679 #ifdef MEM_TRACKING
680     void_ptr_t BlockHdr_ptr;
681 #endif
682     void_ptr_t buffer_ptr;
683 
684 #if defined(gFSCI_MemAllocTest_Enabled_d) && (gFSCI_MemAllocTest_Enabled_d)
685     void *pCaller = (void *)((uint32_t *)__mem_get_LR());
686     /* Verify if the caller is part of any FSCI memory allocation test. If so, return NULL. */
687     if (FSCI_MemAllocTestCanAllocate(pCaller) == kStatus_AllocBlock)
688     {
689         buffer_ptr.void_ptr = NULL;
690         return buffer_ptr.void_ptr;
691     }
692 #endif
693 
694     /* Alloc a buffer */
695     buffer_ptr.void_ptr = MEM_BufferAllocate(numBytes, poolId);
696 
697 #ifdef MEM_TRACKING
698     if (buffer_ptr.void_ptr != NULL)
699     {
700         BlockHdr_ptr.raw_address = buffer_ptr.raw_address - BLOCK_HDR_SIZE;
701         /* store caller */
702         BlockHdr_ptr.block_hdr_ptr->second_alloc_caller = (void *)((uint32_t *)__mem_get_LR());
703         ;
704     }
705 #endif
706 
707     return buffer_ptr.void_ptr;
708 }
709 
MEM_BufferFree(void * buffer)710 mem_status_t MEM_BufferFree(void *buffer /* IN: Block of memory to free*/)
711 {
712     mem_status_t ret = kStatus_MemSuccess;
713     void_ptr_t buffer_ptr;
714     buffer_ptr.void_ptr = buffer;
715 
716     if (buffer == NULL)
717     {
718         ret = kStatus_MemFreeError;
719     }
720     else
721     {
722         uint32_t regPrimask = DisableGlobalIRQ();
723 
724         blockHeader_t *BlockHdr;
725         BlockHdr = (blockHeader_t *)(buffer_ptr.raw_address - BLOCK_HDR_SIZE);
726 
727         /* assert checks */
728         assert(BlockHdr->used == MEMMANAGER_BLOCK_USED);
729         assert(BlockHdr->next != NULL);
730         /* when allocating a buffer, we always create a FreeBlockHdr at
731            the end of the buffer, so the FreeBlockHdrList.tail should always
732            be at a higher address than current BlockHdr */
733         assert(BlockHdr < FreeBlockHdrList.tail);
734 
735 #if defined(gMemManagerLightGuardsCheckEnable) && (gMemManagerLightGuardsCheckEnable == 1)
736         MEM_BlockHeaderCheck(BlockHdr->next);
737 #endif
738 
739         /* MEM_DBG_LOG("%x %d", BlockHdr, BlockHdr->buff_size); */
740 
741 #if defined(MEM_STATISTICS_INTERNAL)
742         MEM_BufferFrees_memStatis(buffer);
743 #endif /* MEM_STATISTICS_INTERNAL */
744 
745         if (BlockHdr < FreeBlockHdrList.head)
746         {
747             /* BlockHdr is placed before FreeBlockHdrList.head so we can set it as
748                the new head of the list */
749             BlockHdr->next_free              = FreeBlockHdrList.head;
750             BlockHdr->prev_free              = NULL;
751             FreeBlockHdrList.head->prev_free = BlockHdr;
752             FreeBlockHdrList.head            = BlockHdr;
753         }
754         else
755         {
756             /* we want to find the previous free block header
757                here, we cannot use prev_free as this information could be outdated
758                so we need to run through the whole list to be sure to catch the
759                correct previous free block header */
760             blockHeader_t *PrevFreeBlockHdr = FreeBlockHdrList.head;
761             while ((uint32_t)PrevFreeBlockHdr->next_free < (uint32_t)BlockHdr)
762             {
763                 PrevFreeBlockHdr = PrevFreeBlockHdr->next_free;
764             }
765             /* insert the new free block in the list */
766             BlockHdr->next_free            = PrevFreeBlockHdr->next_free;
767             BlockHdr->prev_free            = PrevFreeBlockHdr;
768             BlockHdr->next_free->prev_free = BlockHdr;
769             PrevFreeBlockHdr->next_free    = BlockHdr;
770         }
771 
772         BlockHdr->used = MEMMANAGER_BLOCK_FREE;
773 #if defined(MEM_STATISTICS_INTERNAL)
774         BlockHdr->buff_size = 0U;
775 #endif
776 
777 #if defined(gMemManagerLightFreeBlocksCleanUp) && (gMemManagerLightFreeBlocksCleanUp == 1)
778         MEM_BufferFreeBlocksCleanUp(BlockHdr);
779 #endif
780 
781         EnableGlobalIRQ(regPrimask);
782     }
783 
784     return ret;
785 }
786 
MEM_BufferFreeAllWithId(uint8_t poolId)787 mem_status_t MEM_BufferFreeAllWithId(uint8_t poolId)
788 {
789     mem_status_t status = kStatus_MemSuccess;
790 #if (defined(MEM_TRACK_ALLOC_SOURCE) && (MEM_TRACK_ALLOC_SOURCE == 1))
791 #ifdef MEMMANAGER_NOT_IMPLEMENTED_YET
792 
793 #endif /* MEMMANAGER_NOT_IMPLEMENTED_YET */
794 #else  /* (defined(MEM_TRACK_ALLOC_SOURCE) && (MEM_TRACK_ALLOC_SOURCE == 1)) */
795     status = kStatus_MemFreeError;
796 #endif /* (defined(MEM_TRACK_ALLOC_SOURCE) && (MEM_TRACK_ALLOC_SOURCE == 1)) */
797     return status;
798 }
799 
MEM_GetHeapUpperLimit(void)800 uint32_t MEM_GetHeapUpperLimit(void)
801 {
802     /* There is always a free block at the end of the heap
803        and this free block is the tail of the list */
804     return ((uint32_t)FreeBlockHdrList.tail + BLOCK_HDR_SIZE);
805 }
806 
MEM_BufferGetSize(void * buffer)807 uint16_t MEM_BufferGetSize(void *buffer)
808 {
809     blockHeader_t *BlockHdr = NULL;
810     uint16_t size;
811     /* union used to fix Misra */
812     void_ptr_t buffer_ptr;
813     buffer_ptr.void_ptr = buffer;
814 
815     if (buffer != NULL)
816     {
817         BlockHdr = (blockHeader_t *)(buffer_ptr.raw_address - BLOCK_HDR_SIZE);
818         /* block size is the space between current BlockHdr and next BlockHdr */
819         size = (uint16_t)((uint32_t)BlockHdr->next - (uint32_t)BlockHdr - BLOCK_HDR_SIZE);
820     }
821     else
822     {
823         /* is case of a NULL buffer, we return 0U */
824         size = 0U;
825     }
826 
827     return size;
828 }
829 
MEM_BufferRealloc(void * buffer,uint32_t new_size)830 void *MEM_BufferRealloc(void *buffer, uint32_t new_size)
831 {
832     void *realloc_buffer = NULL;
833     uint16_t block_size  = 0U;
834 
835     assert(new_size <= 0x0000FFFFU); /* size will be casted to 16 bits */
836 
837     if (new_size == 0U)
838     {
839         /* new requested size is 0, free old buffer */
840         (void)MEM_BufferFree(buffer);
841         realloc_buffer = NULL;
842     }
843     else if (buffer == NULL)
844     {
845         /* input buffer is NULL simply allocate a new buffer and return it */
846         realloc_buffer = MEM_BufferAllocate(new_size, 0U);
847     }
848     else
849     {
850         block_size = MEM_BufferGetSize(buffer);
851 
852         if ((uint16_t)new_size <= block_size)
853         {
854             /* current buffer is large enough for the new requested size
855                we can still use it */
856             realloc_buffer = buffer;
857         }
858         else
859         {
860             /* not enough space in the current block, creating a new one */
861             realloc_buffer = MEM_BufferAllocate(new_size, 0);
862 
863             if (realloc_buffer != NULL)
864             {
865                 /* copy input buffer data to new buffer */
866                 (void)memcpy(realloc_buffer, buffer, (uint32_t)block_size);
867 
868                 /* free old buffer */
869                 (void)MEM_BufferFree(buffer);
870             }
871         }
872     }
873 
874     return realloc_buffer;
875 }
876 
MEM_GetFreeHeapSize(void)877 uint32_t MEM_GetFreeHeapSize(void)
878 {
879     uint32_t free_size          = 0U;
880     blockHeader_t *freeBlockHdr = FreeBlockHdrList.head;
881 
882     /* Count every free block in the free space */
883     while (freeBlockHdr != FreeBlockHdrList.tail)
884     {
885         free_size += ((uint32_t)freeBlockHdr->next - (uint32_t)freeBlockHdr - BLOCK_HDR_SIZE);
886         freeBlockHdr = freeBlockHdr->next_free;
887     }
888 
889     /* Add remaining free space in the heap */
890     free_size += memHeapEnd - (uint32_t)FreeBlockHdrList.tail - BLOCK_HDR_SIZE;
891 
892     return free_size;
893 }
894 
MEM_ReinitRamBank(uint32_t startAddress,uint32_t endAddress)895 __attribute__((weak)) void MEM_ReinitRamBank(uint32_t startAddress, uint32_t endAddress)
896 {
897     /* To be implemented by the platform */
898     (void)startAddress;
899     (void)endAddress;
900 }
901 
902 #if 0 /* MISRA C-2012 Rule 8.4 */
903 uint32_t MEM_GetAvailableBlocks(uint32_t size)
904 {
905     /* Function not implemented yet */
906     assert(0);
907 
908     return 0U;
909 }
910 #endif
911 
MEM_CallocAlt(size_t len,size_t val)912 void *MEM_CallocAlt(size_t len, size_t val)
913 {
914     size_t blk_size;
915 
916     blk_size = len * val;
917 
918     void *pData = MEM_BufferAllocate(blk_size, 0);
919     if (NULL != pData)
920     {
921         (void)memset(pData, 0, blk_size);
922     }
923 
924     return pData;
925 }
926 
927 #if 0 /* MISRA C-2012 Rule 8.4 */
928 void MEM_FreeAlt(void *pData)
929 {
930     /* Function not implemented yet */
931     assert(0);
932 }
933 #endif
934 
935 #endif
936