1 /*
2  * Copyright 2018, 2020 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 /*!
44  * @brief Configures the memory manager light enable.
45  */
46 #ifndef gMemManagerLight
47 #define gMemManagerLight (1)
48 #endif
49 
50 /*!
51  * @brief Configures the memory manager trace debug enable.
52  */
53 #ifndef MEM_MANAGER_ENABLE_TRACE
54 #define MEM_MANAGER_ENABLE_TRACE (0)
55 #endif
56 
57 /*
58  * @brief Configures the memory manager remove memory buffer.
59  */
60 #ifndef MEM_MANAGER_BUFFER_REMOVE
61 #define MEM_MANAGER_BUFFER_REMOVE (0)
62 #endif
63 
64 /*!
65  * @brief Configures the memory manager pre configure.
66  */
67 #ifndef MEM_MANAGER_PRE_CONFIGURE
68 #define MEM_MANAGER_PRE_CONFIGURE (1)
69 #endif
70 
71 #if (defined(MEM_MANAGER_ENABLE_TRACE) && (MEM_MANAGER_ENABLE_TRACE > 0U))
72 #ifndef MEM_POOL_SIZE
73 #define MEM_POOL_SIZE (32U)
74 #endif
75 #ifndef MEM_BLOCK_SIZE
76 #define MEM_BLOCK_SIZE (12U)
77 #endif
78 #else
79 #ifndef MEM_POOL_SIZE
80 #define MEM_POOL_SIZE (20U)
81 #endif
82 #ifndef MEM_BLOCK_SIZE
83 #define MEM_BLOCK_SIZE (4U)
84 #endif
85 #endif
86 
87 #define MAX_POOL_ID 3U
88 
89 /* Debug Macros - stub if not defined */
90 #ifndef MEM_DBG_LOG
91 #define MEM_DBG_LOG(...)
92 #endif
93 
94 /* Default memory allocator */
95 #ifndef MEM_BufferAlloc
96 #define MEM_BufferAlloc(numBytes) MEM_BufferAllocWithId(numBytes, 0)
97 #endif
98 
99 #if (defined(MEM_MANAGER_PRE_CONFIGURE) && (MEM_MANAGER_PRE_CONFIGURE > 0U))
100 /*
101  * Defines pools by block size and number of blocks. Must be aligned to 4 bytes.
102  * Defines block as  (blockSize ,numberOfBlocks,  id), id must be keep here,
103  * even id is 0, will be _block_set_(64, 8, 0) _eol_
104  * and _block_set_(64, 8) _eol_\ could not supported
105  */
106 #ifndef PoolsDetails_c
107 #define PoolsDetails_c _block_set_(64, 8, 0) _eol_ _block_set_(128, 2, 1) _eol_ _block_set_(256, 6, 1) _eol_
108 #endif /* PoolsDetails_c */
109 
110 #define MEM_BLOCK_DATA_BUFFER_NONAME_DEFINE(blockSize, numberOfBlocks, id)                                        \
111     uint32_t g_poolBuffer##blockSize##_##numberOfBlocks##_##id[(MEM_POOL_SIZE + (numberOfBlocks)*MEM_BLOCK_SIZE + \
112                                                                 ((numberOfBlocks) * (blockSize)) + 3U) >>         \
113                                                                2U];
114 
115 #define MEM_BLOCK_BUFFER_NONAME_DEFINE(blockSize, numberOfBlocks, id)                   \
116     MEM_BLOCK_DATA_BUFFER_NONAME_DEFINE(blockSize, numberOfBlocks, id)                  \
117     const static mem_config_t g_poolHeadBuffer##blockSize##_##numberOfBlocks##_##id = { \
118         (blockSize), (numberOfBlocks), (id), (0), (uint8_t *)&g_poolBuffer##blockSize##_##numberOfBlocks##_##id[0]}
119 #define MEM_BLOCK_NONAME_BUFFER(blockSize, numberOfBlocks, id) \
120     (uint8_t *)&g_poolHeadBuffer##blockSize##_##numberOfBlocks##_##id
121 #endif /* MEM_MANAGER_PRE_CONFIGURE */
122 
123 /*!
124  * @brief Defines the memory buffer
125  *
126  * This macro is used to define the shell memory buffer for memory manager.
127  * And then uses the macro MEM_BLOCK_BUFFER to get the memory buffer pointer.
128  * The macro should not be used in any function.
129  *
130  * This is a example,
131  * @code
132  * MEM_BLOCK_BUFFER_DEFINE(app64, 5, 64,0);
133  * MEM_BLOCK_BUFFER_DEFINE(app128, 6, 128,0);
134  * MEM_BLOCK_BUFFER_DEFINE(app256, 7, 256,0);
135  * @endcode
136  *
137  * @param name The name string of the memory buffer.
138  * @param numberOfBlocks The number Of Blocks.
139  * @param blockSize The memory block size.
140  * @param id The id Of memory buffer.
141  */
142 #define MEM_BLOCK_DATA_BUFFER_DEFINE(name, numberOfBlocks, blockSize, id) \
143     uint32_t                                                              \
144         g_poolBuffer##name[(MEM_POOL_SIZE + numberOfBlocks * MEM_BLOCK_SIZE + numberOfBlocks * blockSize + 3U) >> 2U];
145 
146 #define MEM_BLOCK_BUFFER_DEFINE(name, numberOfBlocks, blockSize, id)  \
147     MEM_BLOCK_DATA_BUFFER_DEFINE(name, numberOfBlocks, blockSize, id) \
148     mem_config_t g_poolHeadBuffer##name = {(blockSize), (numberOfBlocks), (id), (0), (uint8_t *)&g_poolBuffer##name[0]}
149 
150 /*!                                                                     \
151  * @brief Gets the memory buffer pointer                                 \
152  *                                                                       \
153  * This macro is used to get the memory buffer pointer. The macro should \
154  * not be used before the macro MEM_BLOCK_BUFFER_DEFINE is used.         \
155  *                                                                       \
156  * @param name The memory name string of the buffer.                     \
157  */
158 #define MEM_BLOCK_BUFFER(name) (uint8_t *)&g_poolHeadBuffer##name
159 
160 /*****************************************************************************
161 ******************************************************************************
162 * Public type definitions
163 ******************************************************************************
164 *****************************************************************************/
165 
166 /**@brief Memory status. */
167 #if (defined(SDK_COMPONENT_DEPENDENCY_FSL_COMMON) && (SDK_COMPONENT_DEPENDENCY_FSL_COMMON > 0U))
168 typedef enum _mem_status
169 {
170     kStatus_MemSuccess      = kStatus_Success,                          /* No error occurred */
171     kStatus_MemInitError    = MAKE_STATUS(kStatusGroup_MEM_MANAGER, 1), /* Memory initialization error */
172     kStatus_MemAllocError   = MAKE_STATUS(kStatusGroup_MEM_MANAGER, 2), /* Memory allocation error */
173     kStatus_MemFreeError    = MAKE_STATUS(kStatusGroup_MEM_MANAGER, 3), /* Memory free error */
174     kStatus_MemUnknownError = MAKE_STATUS(kStatusGroup_MEM_MANAGER, 4), /* something bad has happened... */
175 } mem_status_t;
176 #else
177 typedef enum _mem_status
178 {
179     kStatus_MemSuccess      = 0, /* No error occurred */
180     kStatus_MemInitError    = 1, /* Memory initialization error */
181     kStatus_MemAllocError   = 2, /* Memory allocation error */
182     kStatus_MemFreeError    = 3, /* Memory free error */
183     kStatus_MemUnknownError = 4, /* something bad has happened... */
184 } mem_status_t;
185 
186 #endif
187 
188 /**@brief Memory user config. */
189 typedef struct _mem_config
190 {
191     uint16_t blockSize;      /*< The memory block size. */
192     uint16_t numberOfBlocks; /*< The number Of Blocks. */
193     uint16_t poolId;         /*< The pool id Of Blocks. */
194     uint16_t reserved;       /*< reserved. */
195     uint8_t *pbuffer;        /*< buffer. */
196 } mem_config_t;
197 
198 #if defined(gFSCI_MemAllocTest_Enabled_d) && (gFSCI_MemAllocTest_Enabled_d)
199 /**@brief Memory status. */
200 typedef enum mem_alloc_test_status
201 {
202     kStatus_AllocSuccess = kStatus_Success, /* Allow buffer to be allocated */
203     kStatus_AllocBlock   = kStatus_Busy,    /* Block buffer to be allocated */
204 } mem_alloc_test_status_t;
205 #endif
206 
207 /*****************************************************************************
208 ******************************************************************************
209 * Public memory declarations
210 ******************************************************************************
211 *****************************************************************************/
212 /*****************************************************************************
213 ******************************************************************************
214 * Public prototypes
215 ******************************************************************************
216 *****************************************************************************/
217 
218 #if defined(__cplusplus)
219 extern "C" {
220 #endif /* _cplusplus */
221 #if (defined(MEM_MANAGER_PRE_CONFIGURE) && (MEM_MANAGER_PRE_CONFIGURE > 0U))
222 /*!
223  * @brief  Initialises the Memory Manager.
224  *
225  */
226 mem_status_t MEM_Init(void);
227 
228 #endif
229 
230 #if !defined(gMemManagerLight) || (gMemManagerLight == 0)
231 /*!
232  * @brief Add memory buffer to memory manager buffer list.
233  *
234  * @note This API should be called when need add memory buffer to memory manager buffer list. First use
235  * MEM_BLOCK_BUFFER_DEFINE to
236  *        define memory buffer, then call MEM_AddBuffer function with MEM_BLOCK_BUFFER Macro as the input parameter.
237  *  @code
238  * MEM_BLOCK_BUFFER_DEFINE(app64, 5, 64,0);
239  * MEM_BLOCK_BUFFER_DEFINE(app128, 6, 128,0);
240  * MEM_BLOCK_BUFFER_DEFINE(app256, 7, 256,0);
241  *
242  * MEM_AddBuffer(MEM_BLOCK_BUFFER(app64));
243  * MEM_AddBuffer(MEM_BLOCK_BUFFER(app128));
244  * MEM_AddBuffer(MEM_BLOCK_BUFFER(app256));
245  * @endcode
246  *
247  * @param buffer                     Pointer the memory pool buffer, use MEM_BLOCK_BUFFER Macro as the input parameter.
248  *
249  * @retval kStatus_MemSuccess        Memory manager add buffer succeed.
250  * @retval kStatus_MemUnknownError   Memory manager add buffer error occurred.
251  */
252 mem_status_t MEM_AddBuffer(const uint8_t *buffer);
253 #endif /* gMemManagerLight */
254 
255 #if !defined(gMemManagerLight) || (gMemManagerLight == 0)
256 #if (defined(MEM_MANAGER_BUFFER_REMOVE) && (MEM_MANAGER_BUFFER_REMOVE > 0U))
257 /*!
258  * @brief Remove memory buffer from memory manager buffer list.
259  *
260  * @note This API should be called when need remove memory buffer from memory manager buffer list. Use MEM_BLOCK_BUFFER
261  * Macro as the input parameter.
262  *
263  * @param buffer                     Pointer the memory pool buffer, use MEM_BLOCK_BUFFER Macro as the input parameter.
264  *
265  * @retval kStatus_MemSuccess        Memory manager remove buffer succeed.
266  * @retval kStatus_MemUnknownError    Memory manager remove buffer error occurred.
267  */
268 mem_status_t MEM_RemoveBuffer(uint8_t *buffer);
269 #endif /* MEM_MANAGER_BUFFER_REMOVE */
270 #endif /* gMemManagerLight */
271 /*!
272  * @brief Allocate a block from the memory pools. The function uses the
273  *        numBytes argument to look up a pool with adequate block sizes.
274  *
275  * @param numBytes           The number of bytes will be allocated.
276  * @param poolId             The ID of the pool where to search for a free buffer.
277  * @retval Memory buffer address when allocate success, NULL when allocate fail.
278  */
279 void *MEM_BufferAllocWithId(uint32_t numBytes, uint8_t poolId);
280 
281 /*!
282  * @brief Memory buffer free .
283  *
284  * @param buffer                     The memory buffer address will be free.
285  * @retval kStatus_MemSuccess        Memory free succeed.
286  * @retval kStatus_MemFreeError      Memory free error occurred.
287  */
288 mem_status_t MEM_BufferFree(void *buffer);
289 
290 /*!
291  * @brief Returns the size of a given buffer.
292  *
293  * @param buffer  The memory buffer address will be get size.
294  * @retval The size of a given buffer.
295  */
296 uint16_t MEM_BufferGetSize(void *buffer);
297 
298 /*!
299  * @brief Frees all allocated blocks by selected source and in selected pool.
300  *
301  * @param poolId                     Selected pool Id (4 LSBs of poolId parameter) and selected
302  *                                   source Id (4 MSBs of poolId parameter).
303  * @retval kStatus_MemSuccess        Memory free succeed.
304  * @retval kStatus_MemFreeError      Memory free error occurred.
305  */
306 mem_status_t MEM_BufferFreeAllWithId(uint8_t poolId);
307 
308 /*!
309  * @brief Memory buffer realloc.
310  *
311  * @param buffer                     The memory buffer address will be reallocated.
312  * @param new_size                   The number of bytes will be reallocated
313  * @retval kStatus_MemSuccess        Memory free succeed.
314  * @retval kStatus_MemFreeError      Memory free error occurred.
315  */
316 void *MEM_BufferRealloc(void *buffer, uint32_t new_size);
317 
318 /*!
319  * @brief Get the address after the last allocated block if MemManagerLight is used.
320  *
321  * @retval UpperLimit  Return the address after the last allocated block if MemManagerLight is used.
322  * @retval 0           Return 0 in case of the legacy MemManager.
323  */
324 uint32_t MEM_GetHeapUpperLimit(void);
325 
326 /*!
327  * @brief Get the free space in the heap.
328  *
329  * @retval FreeHeapSize  Return the free space in the heap if MemManagerLight is used.
330  * @retval 0             Return 0 in case of the legacy MemManager.
331  */
332 uint32_t MEM_GetFreeHeapSize(void);
333 
334 #if defined(gMemManagerLight) && (gMemManagerLight > 0)
335 /*!
336  * @brief Selective RAM bank reinit after low power, based on a requested address range
337  *        Useful for ECC RAM banks
338  *        Defined as weak and empty in fsl_component_mem_manager_light.c to be overloaded by user
339  *
340  * @param[in] startAddress Start address of the requested range
341  * @param[in] endAddress End address of the requested range
342  */
343 void MEM_ReinitRamBank(uint32_t startAddress, uint32_t endAddress);
344 #endif /* gMemManagerLight */
345 
346 #if !defined(gMemManagerLight) || (gMemManagerLight == 0)
347 #if (defined(MEM_MANAGER_ENABLE_TRACE) && (MEM_MANAGER_ENABLE_TRACE > 0U))
348 /*!
349  * @brief Function to print statistics related to memory blocks managed by memory manager. Like bellow:
350  * allocationFailures: 241  freeFailures:0
351  * POOL: ID 0  status:
352  * numBlocks allocatedBlocks    allocatedBlocksPeak  poolFragmentWaste poolFragmentWastePeak poolFragmentMinWaste
353  * poolTotalFragmentWaste
354  *     5            5                 5                  59                  63                       59 305
355  * Currently pool meory block allocate status:
356  * Block 0 Allocated    bytes: 1
357  * Block 1 Allocated    bytes: 2
358  * Block 2 Allocated    bytes: 3
359  * Block 3 Allocated    bytes: 4
360  * Block 4 Allocated    bytes: 5
361  *
362  * @details This API prints information with respects to each pool and block, including Allocated size,
363  *          total block count, number of blocks in use at the time of printing, The API is intended to
364  *          help developers tune the block sizes to make optimal use of memory for the application.
365  *
366  * @note This API should be disable by configure MEM_MANAGER_ENABLE_TRACE to 0
367  *
368  */
369 void MEM_Trace(void);
370 
371 #endif /* MEM_MANAGER_ENABLE_TRACE */
372 #endif /* gMemManagerLight */
373 
374 #if defined(gMemManagerLight) && (gMemManagerLight == 1)
375 void *MEM_CallocAlt(size_t len, size_t val);
376 #endif /*gMemManagerLight == 1*/
377 
378 #if defined(__cplusplus)
379 }
380 #endif
381 /*! @}*/
382 #endif /* #ifndef __MEM_MANAGER_H__ */
383