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