1 /*
2  * Copyright 2018, 2020, 2023 NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #ifndef __MEM_MANAGER_H__
10 #define __MEM_MANAGER_H__
11 
12 #ifndef SDK_COMPONENT_DEPENDENCY_FSL_COMMON
13 #define SDK_COMPONENT_DEPENDENCY_FSL_COMMON (1U)
14 #endif
15 #if (defined(SDK_COMPONENT_DEPENDENCY_FSL_COMMON) && (SDK_COMPONENT_DEPENDENCY_FSL_COMMON > 0U))
16 #include "fsl_common.h"
17 #else
18 #endif
19 
20 /*!
21  * @addtogroup MemManager
22  * @{
23  */
24 
25 /*****************************************************************************
26 ******************************************************************************
27 * Public macros
28 ******************************************************************************
29 *****************************************************************************/
30 
31 /*!
32  * @brief Provide Minimal heap size for application to execute correctly.
33  *
34  * The application can define a minimal heap size for proper code exection at run time,
35  * This will issue a link error if the minimal heap size requirement is not fullfilled (not enough space in RAM)
36  * By Default, Minimal heap size is set to 4 bytes (unlikely enough to have application work correctly)
37  */
38 #if !defined(MinimalHeapSize_c)
39 #define MinimalHeapSize_c (uint32_t)4
40 #endif
41 
42 /*!
43  * @brief Configures the memory manager light enable.
44  */
45 #ifndef gMemManagerLight
46 #define gMemManagerLight (1)
47 #endif
48 
49 /*!
50  * @brief Configures the memory manager trace debug enable.
51  */
52 #ifndef MEM_MANAGER_ENABLE_TRACE
53 #define MEM_MANAGER_ENABLE_TRACE (0)
54 #endif
55 
56 /*
57  * @brief Configures the memory manager remove memory buffer.
58  */
59 #ifndef MEM_MANAGER_BUFFER_REMOVE
60 #define MEM_MANAGER_BUFFER_REMOVE (0)
61 #endif
62 
63 /*!
64  * @brief Configures the memory manager pre configure.
65  */
66 #ifndef MEM_MANAGER_PRE_CONFIGURE
67 #define MEM_MANAGER_PRE_CONFIGURE (1)
68 #endif
69 
70 #if (defined(MEM_MANAGER_ENABLE_TRACE) && (MEM_MANAGER_ENABLE_TRACE > 0U))
71 #ifndef MEM_POOL_SIZE
72 #define MEM_POOL_SIZE (32U)
73 #endif
74 #ifndef MEM_BLOCK_SIZE
75 #define MEM_BLOCK_SIZE (12U)
76 #endif
77 #else
78 #ifndef MEM_POOL_SIZE
79 #define MEM_POOL_SIZE (20U)
80 #endif
81 #ifndef MEM_BLOCK_SIZE
82 #define MEM_BLOCK_SIZE (4U)
83 #endif
84 #endif
85 
86 #define MAX_POOL_ID 3U
87 
88 /* Debug Macros - stub if not defined */
89 #ifndef MEM_DBG_LOG
90 #define MEM_DBG_LOG(...)
91 #endif
92 
93 /* Default memory allocator */
94 #ifndef MEM_BufferAlloc
95 #define MEM_BufferAlloc(numBytes) MEM_BufferAllocWithId(numBytes, 0)
96 #endif
97 
98 #if (defined(MEM_MANAGER_PRE_CONFIGURE) && (MEM_MANAGER_PRE_CONFIGURE > 0U))
99 /*
100  * Defines pools by block size and number of blocks. Must be aligned to 4 bytes.
101  * Defines block as  (blockSize ,numberOfBlocks,  id), id must be keep here,
102  * even id is 0, will be _block_set_(64, 8, 0) _eol_
103  * and _block_set_(64, 8) _eol_\ could not supported
104  */
105 #ifndef PoolsDetails_c
106 #define PoolsDetails_c _block_set_(64, 8, 0) _eol_ _block_set_(128, 2, 1) _eol_ _block_set_(256, 6, 1) _eol_
107 #endif /* PoolsDetails_c */
108 
109 #define MEM_BLOCK_DATA_BUFFER_NONAME_DEFINE(blockSize, numberOfBlocks, id)                                        \
110     uint32_t g_poolBuffer##blockSize##_##numberOfBlocks##_##id[(MEM_POOL_SIZE + (numberOfBlocks)*MEM_BLOCK_SIZE + \
111                                                                 ((numberOfBlocks) * (blockSize)) + 3U) >>         \
112                                                                2U];
113 
114 #define MEM_BLOCK_BUFFER_NONAME_DEFINE(blockSize, numberOfBlocks, id)                   \
115     MEM_BLOCK_DATA_BUFFER_NONAME_DEFINE(blockSize, numberOfBlocks, id)                  \
116     const static mem_config_t g_poolHeadBuffer##blockSize##_##numberOfBlocks##_##id = { \
117         (blockSize), (numberOfBlocks), (id), (0), (uint8_t *)&g_poolBuffer##blockSize##_##numberOfBlocks##_##id[0]}
118 #define MEM_BLOCK_NONAME_BUFFER(blockSize, numberOfBlocks, id) \
119     (uint8_t *)&g_poolHeadBuffer##blockSize##_##numberOfBlocks##_##id
120 #endif /* MEM_MANAGER_PRE_CONFIGURE */
121 
122 /*!
123  * @brief Defines the memory buffer
124  *
125  * This macro is used to define the shell memory buffer for memory manager.
126  * And then uses the macro MEM_BLOCK_BUFFER to get the memory buffer pointer.
127  * The macro should not be used in any function.
128  *
129  * This is a example,
130  * @code
131  * MEM_BLOCK_BUFFER_DEFINE(app64, 5, 64,0);
132  * MEM_BLOCK_BUFFER_DEFINE(app128, 6, 128,0);
133  * MEM_BLOCK_BUFFER_DEFINE(app256, 7, 256,0);
134  * @endcode
135  *
136  * @param name The name string of the memory buffer.
137  * @param numberOfBlocks The number Of Blocks.
138  * @param blockSize The memory block size.
139  * @param id The id Of memory buffer.
140  */
141 #define MEM_BLOCK_DATA_BUFFER_DEFINE(name, numberOfBlocks, blockSize, id) \
142     uint32_t                                                              \
143         g_poolBuffer##name[(MEM_POOL_SIZE + numberOfBlocks * MEM_BLOCK_SIZE + numberOfBlocks * blockSize + 3U) >> 2U];
144 
145 #define MEM_BLOCK_BUFFER_DEFINE(name, numberOfBlocks, blockSize, id)  \
146     MEM_BLOCK_DATA_BUFFER_DEFINE(name, numberOfBlocks, blockSize, id) \
147     mem_config_t g_poolHeadBuffer##name = {(blockSize), (numberOfBlocks), (id), (0), (uint8_t *)&g_poolBuffer##name[0]}
148 
149 /*!                                                                     \
150  * @brief Gets the memory buffer pointer                                 \
151  *                                                                       \
152  * This macro is used to get the memory buffer pointer. The macro should \
153  * not be used before the macro MEM_BLOCK_BUFFER_DEFINE is used.         \
154  *                                                                       \
155  * @param name The memory name string of the buffer.                     \
156  */
157 #define MEM_BLOCK_BUFFER(name) (uint8_t *)&g_poolHeadBuffer##name
158 
159 /*****************************************************************************
160 ******************************************************************************
161 * Public type definitions
162 ******************************************************************************
163 *****************************************************************************/
164 
165 /**@brief Memory status. */
166 #if (defined(SDK_COMPONENT_DEPENDENCY_FSL_COMMON) && (SDK_COMPONENT_DEPENDENCY_FSL_COMMON > 0U))
167 typedef enum _mem_status
168 {
169     kStatus_MemSuccess      = kStatus_Success,                          /* No error occurred */
170     kStatus_MemInitError    = MAKE_STATUS(kStatusGroup_MEM_MANAGER, 1), /* Memory initialization error */
171     kStatus_MemAllocError   = MAKE_STATUS(kStatusGroup_MEM_MANAGER, 2), /* Memory allocation error */
172     kStatus_MemFreeError    = MAKE_STATUS(kStatusGroup_MEM_MANAGER, 3), /* Memory free error */
173     kStatus_MemUnknownError = MAKE_STATUS(kStatusGroup_MEM_MANAGER, 4), /* something bad has happened... */
174 } mem_status_t;
175 #else
176 typedef enum _mem_status
177 {
178     kStatus_MemSuccess      = 0, /* No error occurred */
179     kStatus_MemInitError    = 1, /* Memory initialization error */
180     kStatus_MemAllocError   = 2, /* Memory allocation error */
181     kStatus_MemFreeError    = 3, /* Memory free error */
182     kStatus_MemUnknownError = 4, /* something bad has happened... */
183 } mem_status_t;
184 
185 #endif
186 
187 /**@brief Memory user config. */
188 typedef struct _mem_config
189 {
190     uint16_t blockSize;      /*< The memory block size. */
191     uint16_t numberOfBlocks; /*< The number Of Blocks. */
192     uint16_t poolId;         /*< The pool id Of Blocks. */
193     uint16_t reserved;       /*< reserved. */
194     uint8_t *pbuffer;        /*< buffer. */
195 } mem_config_t;
196 
197 #if defined(gFSCI_MemAllocTest_Enabled_d) && (gFSCI_MemAllocTest_Enabled_d)
198 /**@brief Memory status. */
199 typedef enum mem_alloc_test_status
200 {
201     kStatus_AllocSuccess = kStatus_Success, /* Allow buffer to be allocated */
202     kStatus_AllocBlock   = kStatus_Busy,    /* Block buffer to be allocated */
203 } mem_alloc_test_status_t;
204 #endif
205 
206 #ifdef MEM_STATISTICS
207 #define MML_INTERNAL_STRUCT_SZ (2 * sizeof(uint32_t) + 48)
208 #else
209 #define MML_INTERNAL_STRUCT_SZ (2 * sizeof(uint32_t))
210 #endif
211 
212 #define AREA_FLAGS_POOL_NOT_SHARED (1u << 0)
213 #define AREA_FLAGS_VALID_MASK      (AREA_FLAGS_POOL_NOT_SHARED)
214 #define AREA_FLAGS_RFFU            ~(AREA_FLAGS_VALID_MASK)
215 
216 /**@brief Memory user config. */
217 typedef struct _mem_area_cfg_s memAreaCfg_t;
218 struct _mem_area_cfg_s
219 {
220     memAreaCfg_t *next;     /*< Next registered RAM area descriptor. */
221     void *start_address;    /*< Start address of RAM area. */
222     void *end_address;      /*< Size of registered RAM area. */
223     uint16_t flags;         /*< BIT(0) AREA_FLAGS_POOL_NOT_SHARED means not member of default pool, other bits RFFU */
224     uint16_t reserved;      /*< 16 bit padding */
225     uint32_t low_watermark; /*< lowest level of number of free bytes */
226     uint8_t internal_ctx[MML_INTERNAL_STRUCT_SZ]; /* Placeholder for internal allocator data */
227 };
228 
229 /*****************************************************************************
230 ******************************************************************************
231 * Public memory declarations
232 ******************************************************************************
233 *****************************************************************************/
234 /*****************************************************************************
235 ******************************************************************************
236 * Public prototypes
237 ******************************************************************************
238 *****************************************************************************/
239 
240 #if defined(__cplusplus)
241 extern "C" {
242 #endif /* _cplusplus */
243 #if (defined(MEM_MANAGER_PRE_CONFIGURE) && (MEM_MANAGER_PRE_CONFIGURE > 0U))
244 /*!
245  * @brief  Initialises the Memory Manager.
246  *
247  */
248 mem_status_t MEM_Init(void);
249 
250 #endif
251 
252 #if !defined(gMemManagerLight) || (gMemManagerLight == 0)
253 /*!
254  * @brief Add memory buffer to memory manager buffer list.
255  *
256  * @note This API should be called when need add memory buffer to memory manager buffer list. First use
257  * MEM_BLOCK_BUFFER_DEFINE to
258  *        define memory buffer, then call MEM_AddBuffer function with MEM_BLOCK_BUFFER Macro as the input parameter.
259  *  @code
260  * MEM_BLOCK_BUFFER_DEFINE(app64, 5, 64,0);
261  * MEM_BLOCK_BUFFER_DEFINE(app128, 6, 128,0);
262  * MEM_BLOCK_BUFFER_DEFINE(app256, 7, 256,0);
263  *
264  * MEM_AddBuffer(MEM_BLOCK_BUFFER(app64));
265  * MEM_AddBuffer(MEM_BLOCK_BUFFER(app128));
266  * MEM_AddBuffer(MEM_BLOCK_BUFFER(app256));
267  * @endcode
268  *
269  * @param buffer                     Pointer the memory pool buffer, use MEM_BLOCK_BUFFER Macro as the input parameter.
270  *
271  * @retval kStatus_MemSuccess        Memory manager add buffer succeed.
272  * @retval kStatus_MemUnknownError   Memory manager add buffer error occurred.
273  */
274 mem_status_t MEM_AddBuffer(const uint8_t *buffer);
275 #endif /* gMemManagerLight */
276 
277 #if !defined(gMemManagerLight) || (gMemManagerLight == 0)
278 #if (defined(MEM_MANAGER_BUFFER_REMOVE) && (MEM_MANAGER_BUFFER_REMOVE > 0U))
279 /*!
280  * @brief Remove memory buffer from memory manager buffer list.
281  *
282  * @note This API should be called when need remove memory buffer from memory manager buffer list. Use MEM_BLOCK_BUFFER
283  * Macro as the input parameter.
284  *
285  * @param buffer                     Pointer the memory pool buffer, use MEM_BLOCK_BUFFER Macro as the input parameter.
286  *
287  * @retval kStatus_MemSuccess        Memory manager remove buffer succeed.
288  * @retval kStatus_MemUnknownError    Memory manager remove buffer error occurred.
289  */
290 mem_status_t MEM_RemoveBuffer(uint8_t *buffer);
291 #endif /* MEM_MANAGER_BUFFER_REMOVE */
292 #endif /* gMemManagerLight */
293 /*!
294  * @brief Allocate a block from the memory pools. The function uses the
295  *        numBytes argument to look up a pool with adequate block sizes.
296  *
297  * @param numBytes           The number of bytes will be allocated.
298  * @param poolId             The ID of the pool where to search for a free buffer.
299  * @retval Memory buffer address when allocate success, NULL when allocate fail.
300  */
301 void *MEM_BufferAllocWithId(uint32_t numBytes, uint8_t poolId);
302 
303 /*!
304  * @brief Memory buffer free .
305  *
306  * @param buffer                     The memory buffer address will be free.
307  * @retval kStatus_MemSuccess        Memory free succeed.
308  * @retval kStatus_MemFreeError      Memory free error occurred.
309  */
310 mem_status_t MEM_BufferFree(void *buffer);
311 
312 /*!
313  * @brief Returns the size of a given buffer.
314  *
315  * @param buffer  The memory buffer address will be get size.
316  * @retval The size of a given buffer.
317  */
318 uint16_t MEM_BufferGetSize(void *buffer);
319 
320 /*!
321  * @brief Frees all allocated blocks by selected source and in selected pool.
322  *
323  * @param poolId                     Selected pool Id (4 LSBs of poolId parameter) and selected
324  *                                   source Id (4 MSBs of poolId parameter).
325  * @retval kStatus_MemSuccess        Memory free succeed.
326  * @retval kStatus_MemFreeError      Memory free error occurred.
327  */
328 mem_status_t MEM_BufferFreeAllWithId(uint8_t poolId);
329 
330 /*!
331  * @brief Memory buffer realloc.
332  *
333  * @param buffer                     The memory buffer address will be reallocated.
334  * @param new_size                   The number of bytes will be reallocated
335  * @retval kStatus_MemSuccess        Memory free succeed.
336  * @retval kStatus_MemFreeError      Memory free error occurred.
337  */
338 void *MEM_BufferRealloc(void *buffer, uint32_t new_size);
339 
340 /*!
341  * @brief Get the address after the last allocated block if MemManagerLight is used.
342  *
343  * @retval UpperLimit  Return the address after the last allocated block if MemManagerLight is used.
344  * @retval 0           Return 0 in case of the legacy MemManager.
345  */
346 uint32_t MEM_GetHeapUpperLimit(void);
347 
348 #if defined(gMemManagerLight) && (gMemManagerLight > 0)
349 /*!
350  * @brief Get the address after the last allocated block in area defined by id.
351  *
352  * @param[in] id       0 means memHeap, other values depend on number of registered areas
353  *
354  * @retval UpperLimit  Return the address after the last allocated block if MemManagerLight is used.
355  * @retval 0           Return 0 in case of the legacy MemManager.
356  */
357 uint32_t MEM_GetHeapUpperLimitByAreaId(uint8_t area_id);
358 #endif
359 
360 /*!
361  * @brief Get the free space low watermark.
362  *
363  * @retval FreeHeapSize  Return the heap space low water mark free if MemManagerLight is used.
364  * @retval 0             Return 0 in case of the legacy MemManager.
365  */
366 uint32_t MEM_GetFreeHeapSizeLowWaterMark(void);
367 
368 /*!
369  * @brief Get the free space low watermark.
370  *
371  * @param area_id       Selected area Id
372  *
373  * @retval             Return the heap space low water mark free if MemManagerLight is used.
374  * @retval 0           Return 0 in case of the legacy MemManager.
375  */
376 uint32_t MEM_GetFreeHeapSizeLowWaterMarkByAreaId(uint8_t area_id);
377 
378 /*!
379  * @brief Reset the free space low watermark.
380  *
381  * @retval FreeHeapSize  Return the heap space low water mark free at the time it was reset
382  *                       if MemManagerLight is used.
383  * @retval 0             Return 0 in case of the legacy MemManager.
384  */
385 uint32_t MEM_ResetFreeHeapSizeLowWaterMark(void);
386 
387 /*!
388  * @brief Reset the free space low watermark.
389  *
390  * @param area_id       Selected area Id
391  *
392  * @retval FreeHeapSize  Return the heap space low water mark free at the time it was reset
393  *                       if MemManagerLight is used.
394  * @retval 0             Return 0 in case of the legacy MemManager.
395  */
396 uint32_t MEM_ResetFreeHeapSizeLowWaterMarkByAreaId(uint8_t area_id);
397 
398 /*!
399  * @brief Get the free space in the heap for a area id.
400  *
401  * @param area_id        area_id whose available size is requested (0 means generic pool)
402  *
403  * @retval FreeHeapSize  Return the free space in the heap if MemManagerLight is used.
404  * @retval 0             Return 0 in case of the legacy MemManager.
405  */
406 uint32_t MEM_GetFreeHeapSizeByAreaId(uint8_t area_id);
407 
408 /*!
409  * @brief Get the free space in the heap.
410  *
411  * @retval FreeHeapSize  Return the free space in the heap if MemManagerLight is used.
412  * @retval 0             Return 0 in case of the legacy MemManager.
413  */
414 uint32_t MEM_GetFreeHeapSize(void);
415 
416 #if defined(gMemManagerLight) && (gMemManagerLight > 0)
417 /*!
418  * @brief Selective RAM bank reinit after low power, based on a requested address range
419  *        Useful for ECC RAM banks
420  *        Defined as weak and empty in fsl_component_mem_manager_light.c to be overloaded by user
421  *
422  * @param[in] startAddress Start address of the requested range
423  * @param[in] endAddress End address of the requested range
424  */
425 void MEM_ReinitRamBank(uint32_t startAddress, uint32_t endAddress);
426 #endif /* gMemManagerLight */
427 
428 #if !defined(gMemManagerLight) || (gMemManagerLight == 0)
429 #if (defined(MEM_MANAGER_ENABLE_TRACE) && (MEM_MANAGER_ENABLE_TRACE > 0U))
430 /*!
431  * @brief Function to print statistics related to memory blocks managed by memory manager. Like bellow:
432  * allocationFailures: 241  freeFailures:0
433  * POOL: ID 0  status:
434  * numBlocks allocatedBlocks    allocatedBlocksPeak  poolFragmentWaste poolFragmentWastePeak poolFragmentMinWaste
435  * poolTotalFragmentWaste
436  *     5            5                 5                  59                  63                       59 305
437  * Currently pool meory block allocate status:
438  * Block 0 Allocated    bytes: 1
439  * Block 1 Allocated    bytes: 2
440  * Block 2 Allocated    bytes: 3
441  * Block 3 Allocated    bytes: 4
442  * Block 4 Allocated    bytes: 5
443  *
444  * @details This API prints information with respects to each pool and block, including Allocated size,
445  *          total block count, number of blocks in use at the time of printing, The API is intended to
446  *          help developers tune the block sizes to make optimal use of memory for the application.
447  *
448  * @note This API should be disable by configure MEM_MANAGER_ENABLE_TRACE to 0
449  *
450  */
451 void MEM_Trace(void);
452 
453 #endif /* MEM_MANAGER_ENABLE_TRACE */
454 #endif /* gMemManagerLight */
455 
456 #if defined(gMemManagerLight) && (gMemManagerLight == 1)
457 void *MEM_CallocAlt(size_t len, size_t val);
458 #endif /*gMemManagerLight == 1*/
459 
460 #if defined(gMemManagerLight) && (gMemManagerLight > 0)
461 /*!
462  * @brief Function to register additional areas to allocate memory from.
463  *
464  * @param[in]  area_desc memAreaCfg_t structure defining start address and end address of area.
465  *             This atructure may not be in rodata becasue the next field and internal private
466  *             context are reserved in this structure. If NULL defines the default memHeap area.
467  * @param[out] area_id pointer to return id of area. Required if allocation from specific pool
468  *             is required.
469  * @param[in]  flags BIT(0) means that allocations can be performed in pool only explicitly and
470  *             it is not a member of the default pool (id 0). Invalid for initial registration call.
471  * @return   kStatus_MemSuccess if success,  kStatus_MemInitError otherwise.
472  *
473  */
474 mem_status_t MEM_RegisterExtendedArea(memAreaCfg_t *area_desc, uint8_t *p_area_id, uint16_t flags);
475 
476 /*!
477  * @brief Function to unregister an extended area
478  *
479  * @param[in]  area_id must be different from 0 (main heap).
480  *
481  * @return   kStatus_MemSuccess if success,
482  *           kStatus_MemFreeError if area_id is 0 or area not found or still has buffers in use.
483  *
484  */
485 mem_status_t MEM_UnRegisterExtendedArea(uint8_t area_id);
486 
487 #endif
488 
489 #if defined(__cplusplus)
490 }
491 #endif
492 /*! @}*/
493 #endif /* #ifndef __MEM_MANAGER_H__ */
494