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