2022-08-23 15:00:33 +00:00
|
|
|
/*! *********************************************************************************
|
|
|
|
* Copyright (c) 2015, Freescale Semiconductor, Inc.
|
2024-03-15 14:23:36 +00:00
|
|
|
* Copyright 2016-2022, 2023 NXP
|
2022-08-23 15:00:33 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* \file
|
|
|
|
*
|
|
|
|
* This is the source file for the Memory Manager.
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
********************************************************************************** */
|
|
|
|
|
|
|
|
/*! *********************************************************************************
|
|
|
|
*************************************************************************************
|
|
|
|
* Include
|
|
|
|
*************************************************************************************
|
|
|
|
********************************************************************************** */
|
|
|
|
|
|
|
|
#include "fsl_common.h"
|
|
|
|
#if defined(MEM_STATISTICS_INTERNAL) || defined(MEM_MANAGER_BENCH)
|
|
|
|
#include "fsl_component_timer_manager.h"
|
|
|
|
#include "fsl_component_mem_manager_internal.h"
|
|
|
|
#endif /* MEM_STATISTICS_INTERNAL MEM_MANAGER_BENCH*/
|
|
|
|
#include "fsl_component_mem_manager.h"
|
|
|
|
#if defined(gDebugConsoleEnable_d) && (gDebugConsoleEnable_d == 1)
|
|
|
|
#include "fsl_debug_console.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(gMemManagerLight) && (gMemManagerLight == 1)
|
|
|
|
|
|
|
|
/* Selects the allocation scheme that will be used by the MemManagerLight
|
|
|
|
0: Allocates the first free block available in the heap, no matter its size
|
|
|
|
1: Allocates the first free block whose size is at most the double of the requested size
|
|
|
|
2: Allocates the first free block whose size is at most the 4/3 of the requested size */
|
|
|
|
#ifndef cMemManagerLightReuseFreeBlocks
|
|
|
|
#define cMemManagerLightReuseFreeBlocks 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(cMemManagerLightReuseFreeBlocks) && (cMemManagerLightReuseFreeBlocks > 0)
|
2024-03-15 14:23:36 +00:00
|
|
|
/* Because a more restrictive on the size of the free blocks when cMemManagerLightReuseFreeBlocks
|
|
|
|
* is set, we need to enable a garbage collector to clean up the free block when possible .
|
|
|
|
* When set gMemManagerLightFreeBlocksCleanUp is used to select between 2 policies:
|
|
|
|
* 1: on each bufffer free, the allocator parses the free list in the forward direction and
|
|
|
|
* attempts to merge the freeed buffer with the top unused remainder of the region.
|
|
|
|
* 2: In addition to behaviour described in 1, allocator parses the list backwards to merge
|
|
|
|
* previous contiguous members of the free list (free blocks) if adjacent to the last block.
|
|
|
|
* In this case they meld in the top of the unused region.
|
|
|
|
*/
|
2022-08-23 15:00:33 +00:00
|
|
|
#ifndef gMemManagerLightFreeBlocksCleanUp
|
2024-03-15 14:23:36 +00:00
|
|
|
#define gMemManagerLightFreeBlocksCleanUp 2
|
2022-08-23 15:00:33 +00:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef gMemManagerLightGuardsCheckEnable
|
|
|
|
#define gMemManagerLightGuardsCheckEnable 0
|
|
|
|
#endif
|
|
|
|
|
2023-08-31 15:30:31 +00:00
|
|
|
/*! Extend Heap usage beyond the size defined by MinimalHeapSize_c up to __HEAP_end__ symbol address
|
|
|
|
* to make full use of the remaining available SRAM for the dynamic allocator. Also, only the data up to the
|
|
|
|
* highest allocated block will be retained by calling the @function MEM_GetHeapUpperLimit() from the power
|
|
|
|
* manager.
|
|
|
|
* When this flag is turned to 1 :
|
|
|
|
* - __HEAP_end__ linker symbol shall be defined in linker script to be the highest allowed address
|
|
|
|
* used by the fsl_component_memory_manager_light
|
|
|
|
* - .heap section shall be defined and placed after bss and zi sections to make sure no data is located
|
|
|
|
* up to __HEAP_end__ symbol.
|
|
|
|
* @Warning, no data shall be placed after memHeap symbol address up to __HEAP_end__ . If an other
|
|
|
|
* memory allocator uses a memory area between __HEAP_start__ and __HEAP_end__, area may overlap
|
|
|
|
* with fsl_component_memory_manager_light, so this flag shall be kept to 0
|
|
|
|
*/
|
|
|
|
#ifndef gMemManagerLightExtendHeapAreaUsage
|
2024-03-15 14:23:36 +00:00
|
|
|
#define gMemManagerLightExtendHeapAreaUsage 0
|
2023-08-31 15:30:31 +00:00
|
|
|
#endif
|
|
|
|
|
2022-08-23 15:00:33 +00:00
|
|
|
/*! *********************************************************************************
|
|
|
|
*************************************************************************************
|
|
|
|
* Private macros
|
|
|
|
*************************************************************************************
|
|
|
|
********************************************************************************** */
|
2024-03-15 14:23:36 +00:00
|
|
|
#ifndef MAX_UINT16
|
|
|
|
#define MAX_UINT16 0x00010000U
|
|
|
|
#endif
|
2022-08-23 15:00:33 +00:00
|
|
|
|
|
|
|
#define MEMMANAGER_BLOCK_INVALID (uint16_t)0x0 /* Used to remove a block in the heap - debug only */
|
|
|
|
#define MEMMANAGER_BLOCK_FREE (uint16_t)0xBA00 /* Mark a previous allocated block as free */
|
|
|
|
#define MEMMANAGER_BLOCK_USED (uint16_t)0xBABE /* Mark the block as allocated */
|
|
|
|
|
|
|
|
#define BLOCK_HDR_SIZE (ROUNDUP_WORD(sizeof(blockHeader_t)))
|
|
|
|
|
|
|
|
#define ROUNDUP_WORD(__x) (((((__x)-1U) & ~0x3U) + 4U) & 0XFFFFFFFFU)
|
|
|
|
|
|
|
|
#define BLOCK_HDR_PREGUARD_SIZE 28U
|
|
|
|
#define BLOCK_HDR_PREGUARD_PATTERN 0x28U
|
|
|
|
#define BLOCK_HDR_POSTGUARD_SIZE 28U
|
|
|
|
#define BLOCK_HDR_POSTGUARD_PATTERN 0x39U
|
|
|
|
|
|
|
|
#if defined(__IAR_SYSTEMS_ICC__)
|
|
|
|
#define __mem_get_LR() __get_LR()
|
|
|
|
#elif defined(__GNUC__)
|
2024-03-15 14:23:36 +00:00
|
|
|
#define __mem_get_LR() __builtin_return_address(0U)
|
2022-08-23 15:00:33 +00:00
|
|
|
#elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
|
|
|
|
#define __mem_get_LR() __return_address()
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(gMemManagerLightGuardsCheckEnable) && (gMemManagerLightGuardsCheckEnable == 1)
|
|
|
|
#define gMemManagerLightAddPreGuard 1
|
|
|
|
#define gMemManagerLightAddPostGuard 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef gMemManagerLightAddPreGuard
|
|
|
|
#define gMemManagerLightAddPreGuard 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef gMemManagerLightAddPostGuard
|
|
|
|
#define gMemManagerLightAddPostGuard 0
|
|
|
|
#endif
|
|
|
|
|
2024-03-15 14:23:36 +00:00
|
|
|
#if defined(__IAR_SYSTEMS_ICC__) && (defined __CORTEX_M) && \
|
|
|
|
((__CORTEX_M == 4U) || (__CORTEX_M == 7U) || (__CORTEX_M == 33U))
|
|
|
|
#define D_BARRIER __asm("DSB"); /* __DSB() could not be used */
|
|
|
|
#else
|
|
|
|
#define D_BARRIER
|
|
|
|
#endif
|
|
|
|
#define ENABLE_GLOBAL_IRQ(reg) \
|
|
|
|
D_BARRIER; \
|
|
|
|
EnableGlobalIRQ(reg)
|
|
|
|
#define KB(x) ((x) << 10u)
|
|
|
|
|
2022-08-23 15:00:33 +00:00
|
|
|
/************************************************************************************
|
|
|
|
*************************************************************************************
|
|
|
|
* Private type definitions
|
|
|
|
*************************************************************************************
|
|
|
|
************************************************************************************/
|
|
|
|
|
|
|
|
typedef struct blockHeader_s
|
|
|
|
{
|
|
|
|
#if defined(gMemManagerLightAddPreGuard) && (gMemManagerLightAddPreGuard == 1)
|
|
|
|
uint8_t preguard[BLOCK_HDR_PREGUARD_SIZE];
|
|
|
|
#endif
|
|
|
|
uint16_t used;
|
2024-03-15 14:23:36 +00:00
|
|
|
uint8_t area_id;
|
|
|
|
uint8_t reserved;
|
2023-08-31 15:30:31 +00:00
|
|
|
#if defined(MEM_STATISTICS_INTERNAL)
|
2022-08-23 15:00:33 +00:00
|
|
|
uint16_t buff_size;
|
|
|
|
#endif
|
|
|
|
struct blockHeader_s *next;
|
|
|
|
struct blockHeader_s *next_free;
|
|
|
|
struct blockHeader_s *prev_free;
|
|
|
|
#ifdef MEM_TRACKING
|
|
|
|
void *first_alloc_caller;
|
|
|
|
void *second_alloc_caller;
|
|
|
|
#endif
|
|
|
|
#if defined(gMemManagerLightAddPostGuard) && (gMemManagerLightAddPostGuard == 1)
|
|
|
|
uint8_t postguard[BLOCK_HDR_POSTGUARD_SIZE];
|
|
|
|
#endif
|
|
|
|
} blockHeader_t;
|
|
|
|
|
|
|
|
typedef struct freeBlockHeaderList_s
|
|
|
|
{
|
|
|
|
struct blockHeader_s *head;
|
|
|
|
struct blockHeader_s *tail;
|
|
|
|
} freeBlockHeaderList_t;
|
|
|
|
|
|
|
|
typedef union void_ptr_tag
|
|
|
|
{
|
|
|
|
uint32_t raw_address;
|
|
|
|
uint32_t *address_ptr;
|
|
|
|
void *void_ptr;
|
|
|
|
blockHeader_t *block_hdr_ptr;
|
|
|
|
} void_ptr_t;
|
2024-03-15 14:23:36 +00:00
|
|
|
typedef struct _memAreaPriv_s
|
|
|
|
{
|
|
|
|
freeBlockHeaderList_t FreeBlockHdrList;
|
|
|
|
#ifdef MEM_STATISTICS_INTERNAL
|
|
|
|
mem_statis_t statistics;
|
|
|
|
#endif
|
|
|
|
} memAreaPriv_t;
|
|
|
|
|
|
|
|
typedef struct _mem_area_priv_desc_s
|
|
|
|
{
|
|
|
|
memAreaCfg_t *next; /*< Next registered RAM area descriptor. */
|
|
|
|
void_ptr_t start_address; /*< Start address of RAM area. */
|
|
|
|
void_ptr_t end_address; /*< End address of registered RAM area. */
|
|
|
|
uint16_t flags; /*< BIT(0) means not member of default pool, other bits RFFU */
|
|
|
|
uint16_t reserved; /*< alignment padding */
|
|
|
|
uint32_t low_watermark;
|
|
|
|
union
|
|
|
|
{
|
|
|
|
uint8_t internal_ctx[MML_INTERNAL_STRUCT_SZ]; /* Placeholder for internal allocator data */
|
|
|
|
memAreaPriv_t ctx;
|
|
|
|
};
|
|
|
|
} memAreaPrivDesc_t;
|
2022-08-23 15:00:33 +00:00
|
|
|
|
|
|
|
/*! *********************************************************************************
|
|
|
|
*************************************************************************************
|
|
|
|
* Private memory declarations
|
|
|
|
*************************************************************************************
|
|
|
|
********************************************************************************** */
|
|
|
|
|
2023-08-31 15:30:31 +00:00
|
|
|
#ifndef MEMORY_POOL_GLOBAL_VARIABLE_ALLOC
|
2022-08-23 15:00:33 +00:00
|
|
|
/* Allocate memHeap array in the .heap section to ensure the size of the .heap section is large enough
|
|
|
|
for the application
|
|
|
|
However, the real heap used at run time will cover all the .heap section so this area can be bigger
|
|
|
|
than the requested MinimalHeapSize_c - see memHeapEnd */
|
|
|
|
#if defined(__IAR_SYSTEMS_ICC__)
|
|
|
|
#pragma location = ".heap"
|
|
|
|
static uint32_t memHeap[MinimalHeapSize_c / sizeof(uint32_t)];
|
2023-08-31 15:30:31 +00:00
|
|
|
#elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
|
2022-08-23 15:00:33 +00:00
|
|
|
static uint32_t memHeap[MinimalHeapSize_c / sizeof(uint32_t)] __attribute__((section(".heap")));
|
2023-08-31 15:30:31 +00:00
|
|
|
#elif defined(__GNUC__)
|
|
|
|
static uint32_t memHeap[MinimalHeapSize_c / sizeof(uint32_t)] __attribute__((section(".heap, \"aw\", %nobits @")));
|
2022-08-23 15:00:33 +00:00
|
|
|
#else
|
|
|
|
#error "Compiler unknown!"
|
|
|
|
#endif
|
|
|
|
|
2023-08-31 15:30:31 +00:00
|
|
|
#if defined(gMemManagerLightExtendHeapAreaUsage) && (gMemManagerLightExtendHeapAreaUsage == 1)
|
|
|
|
#if defined(__ARMCC_VERSION)
|
|
|
|
extern uint32_t Image$$ARM_LIB_STACK$$Base[];
|
|
|
|
static const uint32_t memHeapEnd = (uint32_t)&Image$$ARM_LIB_STACK$$Base;
|
|
|
|
#else
|
2022-08-23 15:00:33 +00:00
|
|
|
extern uint32_t __HEAP_end__[];
|
|
|
|
static const uint32_t memHeapEnd = (uint32_t)&__HEAP_end__;
|
2023-08-31 15:30:31 +00:00
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
static const uint32_t memHeapEnd = (uint32_t)(memHeap + MinimalHeapSize_c / sizeof(uint32_t));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#else
|
|
|
|
extern uint32_t *memHeap;
|
|
|
|
extern uint32_t memHeapEnd;
|
|
|
|
#endif /* MEMORY_POOL_GLOBAL_VARIABLE_ALLOC */
|
2022-08-23 15:00:33 +00:00
|
|
|
|
2024-03-15 14:23:36 +00:00
|
|
|
static memAreaPrivDesc_t heap_area_list;
|
2022-08-23 15:00:33 +00:00
|
|
|
|
|
|
|
#ifdef MEM_STATISTICS_INTERNAL
|
|
|
|
static mem_statis_t s_memStatis;
|
|
|
|
#endif /* MEM_STATISTICS_INTERNAL */
|
|
|
|
|
|
|
|
#if defined(gFSCI_MemAllocTest_Enabled_d) && (gFSCI_MemAllocTest_Enabled_d)
|
|
|
|
extern mem_alloc_test_status_t FSCI_MemAllocTestCanAllocate(void *pCaller);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*! *********************************************************************************
|
|
|
|
*************************************************************************************
|
|
|
|
* Private functions
|
|
|
|
*************************************************************************************
|
|
|
|
********************************************************************************** */
|
|
|
|
|
|
|
|
#ifdef MEM_STATISTICS_INTERNAL
|
|
|
|
static void MEM_Inits_memStatis(mem_statis_t *s_memStatis_)
|
|
|
|
{
|
2024-03-15 14:23:36 +00:00
|
|
|
(void)memset(s_memStatis_, 0U, sizeof(mem_statis_t));
|
2022-08-23 15:00:33 +00:00
|
|
|
SystemCoreClockUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void MEM_BufferAllocates_memStatis(void *buffer, uint32_t time, uint32_t requestedSize)
|
|
|
|
{
|
|
|
|
void_ptr_t buffer_ptr;
|
|
|
|
void_ptr_t blockHdr_ptr;
|
|
|
|
blockHeader_t *BlockHdr;
|
|
|
|
|
|
|
|
/* Using union to fix Misra */
|
|
|
|
buffer_ptr.void_ptr = buffer;
|
|
|
|
blockHdr_ptr.raw_address = buffer_ptr.raw_address - BLOCK_HDR_SIZE;
|
|
|
|
BlockHdr = blockHdr_ptr.block_hdr_ptr;
|
|
|
|
|
|
|
|
/* existing block must have a BlockHdr and a next BlockHdr */
|
|
|
|
assert((BlockHdr != NULL) && (BlockHdr->next != NULL));
|
|
|
|
|
|
|
|
s_memStatis.nb_alloc++;
|
|
|
|
/* Sort the buffers by size, based on defined thresholds */
|
|
|
|
if (requestedSize <= SMALL_BUFFER_SIZE)
|
|
|
|
{
|
|
|
|
s_memStatis.nb_small_buffer++;
|
|
|
|
UPDATE_PEAK(s_memStatis.nb_small_buffer, s_memStatis.peak_small_buffer);
|
|
|
|
}
|
|
|
|
else if (requestedSize <= LARGE_BUFFER_SIZE)
|
|
|
|
{
|
|
|
|
s_memStatis.nb_medium_buffer++;
|
|
|
|
UPDATE_PEAK(s_memStatis.nb_medium_buffer, s_memStatis.peak_medium_buffer);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
s_memStatis.nb_large_buffer++;
|
|
|
|
UPDATE_PEAK(s_memStatis.nb_large_buffer, s_memStatis.peak_large_buffer);
|
|
|
|
}
|
|
|
|
/* the RAM allocated is the buffer size and the block header size*/
|
|
|
|
s_memStatis.ram_allocated += (uint16_t)(requestedSize + BLOCK_HDR_SIZE);
|
|
|
|
UPDATE_PEAK(s_memStatis.ram_allocated, s_memStatis.peak_ram_allocated);
|
|
|
|
|
|
|
|
uint32_t block_size = 0U;
|
|
|
|
block_size = (uint32_t)BlockHdr->next - (uint32_t)BlockHdr - BLOCK_HDR_SIZE;
|
|
|
|
|
|
|
|
assert(block_size >= requestedSize);
|
|
|
|
/* ram lost is the difference between block size and buffer size */
|
|
|
|
s_memStatis.ram_lost += (uint16_t)(block_size - requestedSize);
|
|
|
|
UPDATE_PEAK(s_memStatis.ram_lost, s_memStatis.peak_ram_lost);
|
|
|
|
|
|
|
|
UPDATE_PEAK(((uint32_t)FreeBlockHdrList.tail + BLOCK_HDR_SIZE), s_memStatis.peak_upper_addr);
|
|
|
|
|
|
|
|
#ifdef MEM_MANAGER_BENCH
|
|
|
|
if (time != 0U)
|
|
|
|
{
|
|
|
|
/* update mem stats used for benchmarking */
|
|
|
|
s_memStatis.last_alloc_block_size = (uint16_t)block_size;
|
|
|
|
s_memStatis.last_alloc_buff_size = (uint16_t)requestedSize;
|
|
|
|
s_memStatis.last_alloc_time = (uint16_t)time;
|
|
|
|
s_memStatis.total_alloc_time += time;
|
|
|
|
s_memStatis.average_alloc_time = (uint16_t)(s_memStatis.total_alloc_time / s_memStatis.nb_alloc);
|
|
|
|
UPDATE_PEAK((uint16_t)time, s_memStatis.peak_alloc_time);
|
|
|
|
}
|
|
|
|
else /* alloc time is not correct, we bypass this allocation's data */
|
|
|
|
{
|
|
|
|
s_memStatis.nb_alloc--;
|
|
|
|
}
|
|
|
|
#else
|
2023-08-31 15:30:31 +00:00
|
|
|
(void)time;
|
2022-08-23 15:00:33 +00:00
|
|
|
#endif /* MEM_MANAGER_BENCH */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void MEM_BufferFrees_memStatis(void *buffer)
|
|
|
|
{
|
|
|
|
void_ptr_t buffer_ptr;
|
|
|
|
void_ptr_t blockHdr_ptr;
|
|
|
|
blockHeader_t *BlockHdr;
|
|
|
|
|
|
|
|
/* Use union to fix Misra */
|
|
|
|
buffer_ptr.void_ptr = buffer;
|
|
|
|
blockHdr_ptr.raw_address = buffer_ptr.raw_address - BLOCK_HDR_SIZE;
|
|
|
|
BlockHdr = blockHdr_ptr.block_hdr_ptr;
|
|
|
|
|
|
|
|
/* Existing block must have a next block hdr */
|
|
|
|
assert((BlockHdr != NULL) && (BlockHdr->next != NULL));
|
|
|
|
|
|
|
|
s_memStatis.ram_allocated -= (uint16_t)(BlockHdr->buff_size + BLOCK_HDR_SIZE);
|
|
|
|
/* Sort the buffers by size, based on defined thresholds */
|
|
|
|
if (BlockHdr->buff_size <= SMALL_BUFFER_SIZE)
|
|
|
|
{
|
|
|
|
s_memStatis.nb_small_buffer--;
|
|
|
|
}
|
|
|
|
else if (BlockHdr->buff_size <= LARGE_BUFFER_SIZE)
|
|
|
|
{
|
|
|
|
s_memStatis.nb_medium_buffer--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
s_memStatis.nb_large_buffer--;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t block_size = 0U;
|
|
|
|
block_size = (uint16_t)((uint32_t)BlockHdr->next - (uint32_t)BlockHdr - BLOCK_HDR_SIZE);
|
|
|
|
|
|
|
|
assert(block_size >= BlockHdr->buff_size);
|
|
|
|
assert(s_memStatis.ram_lost >= (block_size - BlockHdr->buff_size));
|
|
|
|
|
|
|
|
/* as the buffer is free, the ram is not "lost" anymore */
|
|
|
|
s_memStatis.ram_lost -= (block_size - BlockHdr->buff_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* MEM_STATISTICS_INTERNAL */
|
|
|
|
|
2024-03-15 14:23:36 +00:00
|
|
|
#if defined(gMemManagerLightFreeBlocksCleanUp) && (gMemManagerLightFreeBlocksCleanUp > 0)
|
|
|
|
static void MEM_BufferFreeBlocksCleanUp(memAreaPrivDesc_t *p_area, blockHeader_t *BlockHdr)
|
2022-08-23 15:00:33 +00:00
|
|
|
{
|
|
|
|
blockHeader_t *NextBlockHdr = BlockHdr->next;
|
|
|
|
blockHeader_t *NextFreeBlockHdr = BlockHdr->next_free;
|
|
|
|
/* This function shouldn't be called on the last free block */
|
2024-03-15 14:23:36 +00:00
|
|
|
assert(BlockHdr < p_area->ctx.FreeBlockHdrList.tail);
|
2022-08-23 15:00:33 +00:00
|
|
|
|
2024-03-15 14:23:36 +00:00
|
|
|
/* Step forward and append contiguous free blocks if they can be merged with the unused top of heap */
|
2022-08-23 15:00:33 +00:00
|
|
|
while (NextBlockHdr == NextFreeBlockHdr)
|
|
|
|
{
|
|
|
|
if (NextBlockHdr == NULL)
|
|
|
|
{
|
2024-03-15 14:23:36 +00:00
|
|
|
#if (gMemManagerLightFreeBlocksCleanUp == 2)
|
|
|
|
/* Step backwards to merge all preceeding contiguous free blocks */
|
|
|
|
blockHeader_t *PrevFreeBlockHdr = BlockHdr->prev_free;
|
|
|
|
while (PrevFreeBlockHdr->next == BlockHdr)
|
|
|
|
{
|
|
|
|
assert(PrevFreeBlockHdr->next_free == BlockHdr);
|
|
|
|
assert(PrevFreeBlockHdr->used == MEMMANAGER_BLOCK_FREE);
|
|
|
|
PrevFreeBlockHdr->next_free = BlockHdr->next_free;
|
|
|
|
PrevFreeBlockHdr->next = BlockHdr->next;
|
|
|
|
BlockHdr = PrevFreeBlockHdr;
|
|
|
|
PrevFreeBlockHdr = BlockHdr->prev_free;
|
|
|
|
}
|
|
|
|
#endif
|
2022-08-23 15:00:33 +00:00
|
|
|
assert(BlockHdr->next == BlockHdr->next_free);
|
|
|
|
assert(BlockHdr->used == MEMMANAGER_BLOCK_FREE);
|
|
|
|
/* pool is reached. All buffers from BlockHdr to the pool are free
|
|
|
|
remove all next buffers */
|
2024-03-15 14:23:36 +00:00
|
|
|
BlockHdr->next = NULL;
|
|
|
|
BlockHdr->next_free = NULL;
|
|
|
|
p_area->ctx.FreeBlockHdrList.tail = BlockHdr;
|
2022-08-23 15:00:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
NextBlockHdr = NextBlockHdr->next;
|
|
|
|
NextFreeBlockHdr = NextFreeBlockHdr->next_free;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* gMemManagerLightFreeBlocksCleanUp */
|
|
|
|
|
|
|
|
#if defined(gMemManagerLightGuardsCheckEnable) && (gMemManagerLightGuardsCheckEnable == 1)
|
|
|
|
static void MEM_BlockHeaderCheck(blockHeader_t *BlockHdr)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
uint8_t guardPrePattern[BLOCK_HDR_PREGUARD_SIZE];
|
|
|
|
uint8_t guardPostPattern[BLOCK_HDR_POSTGUARD_SIZE];
|
|
|
|
|
|
|
|
(void)memset((void *)guardPrePattern, BLOCK_HDR_PREGUARD_PATTERN, BLOCK_HDR_PREGUARD_SIZE);
|
|
|
|
ret = memcmp((const void *)&BlockHdr->preguard, (const void *)guardPrePattern, BLOCK_HDR_PREGUARD_SIZE);
|
|
|
|
if (ret != 0)
|
|
|
|
{
|
|
|
|
MEM_DBG_LOG("Preguard Block Header Corrupted %x", BlockHdr);
|
|
|
|
}
|
|
|
|
assert(ret == 0);
|
|
|
|
|
|
|
|
(void)memset((void *)guardPostPattern, BLOCK_HDR_POSTGUARD_PATTERN, BLOCK_HDR_POSTGUARD_SIZE);
|
|
|
|
ret = memcmp((const void *)&BlockHdr->postguard, (const void *)guardPostPattern, BLOCK_HDR_POSTGUARD_SIZE);
|
|
|
|
if (ret != 0)
|
|
|
|
{
|
|
|
|
MEM_DBG_LOG("Postguard Block Header Corrupted %x", BlockHdr);
|
|
|
|
}
|
|
|
|
assert(ret == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void MEM_BlockHeaderSetGuards(blockHeader_t *BlockHdr)
|
|
|
|
{
|
|
|
|
(void)memset((void *)&BlockHdr->preguard, BLOCK_HDR_PREGUARD_PATTERN, BLOCK_HDR_PREGUARD_SIZE);
|
|
|
|
(void)memset((void *)&BlockHdr->postguard, BLOCK_HDR_POSTGUARD_PATTERN, BLOCK_HDR_POSTGUARD_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2024-03-15 14:23:36 +00:00
|
|
|
static memAreaPrivDesc_t *MEM_GetAreaByAreaId(uint8_t area_id)
|
|
|
|
{
|
|
|
|
memAreaPrivDesc_t *p_area = &heap_area_list;
|
|
|
|
for (uint8_t i = 0u; i < area_id; i++)
|
|
|
|
{
|
|
|
|
p_area = (memAreaPrivDesc_t *)p_area->next;
|
|
|
|
}
|
|
|
|
return p_area;
|
|
|
|
}
|
|
|
|
|
2022-08-23 15:00:33 +00:00
|
|
|
/*! *********************************************************************************
|
|
|
|
*************************************************************************************
|
|
|
|
* Public functions
|
|
|
|
*************************************************************************************
|
|
|
|
********************************************************************************** */
|
|
|
|
|
|
|
|
#if defined(MEM_STATISTICS_INTERNAL)
|
|
|
|
static void MEM_Reports_memStatis(void)
|
|
|
|
{
|
|
|
|
MEM_DBG_LOG("**************** MEM STATS REPORT **************");
|
|
|
|
MEM_DBG_LOG("Nb Alloc: %d\r\n", s_memStatis.nb_alloc);
|
|
|
|
MEM_DBG_LOG("Small buffers: %d\r\n", s_memStatis.nb_small_buffer);
|
|
|
|
MEM_DBG_LOG("Medium buffers: %d\r\n", s_memStatis.nb_medium_buffer);
|
|
|
|
MEM_DBG_LOG("Large buffers: %d\r\n", s_memStatis.nb_large_buffer);
|
|
|
|
MEM_DBG_LOG("Peak small: %d\r\n", s_memStatis.peak_small_buffer);
|
|
|
|
MEM_DBG_LOG("Peak medium: %d\r\n", s_memStatis.peak_medium_buffer);
|
|
|
|
MEM_DBG_LOG("Peak large: %d\r\n", s_memStatis.peak_large_buffer);
|
|
|
|
MEM_DBG_LOG("Current RAM allocated: %d bytes\r\n", s_memStatis.ram_allocated);
|
|
|
|
MEM_DBG_LOG("Peak RAM allocated: %d bytes\r\n", s_memStatis.peak_ram_allocated);
|
|
|
|
MEM_DBG_LOG("Current RAM lost: %d bytes\r\n", s_memStatis.ram_lost);
|
|
|
|
MEM_DBG_LOG("Peak RAM lost: %d bytes\r\n", s_memStatis.peak_ram_lost);
|
|
|
|
MEM_DBG_LOG("Peak Upper Address: %x\r\n", s_memStatis.peak_upper_addr);
|
|
|
|
#ifdef MEM_MANAGER_BENCH
|
|
|
|
MEM_DBG_LOG("************************************************\r\n");
|
|
|
|
MEM_DBG_LOG("********* MEM MANAGER BENCHMARK REPORT *********\r\n");
|
|
|
|
MEM_DBG_LOG("Last Alloc Time: %d us\r\n", s_memStatis.last_alloc_time);
|
|
|
|
MEM_DBG_LOG("Last Alloc Block Size: %d bytes\r\n", s_memStatis.last_alloc_block_size);
|
|
|
|
MEM_DBG_LOG("Last Alloc Buffer Size: %d bytes\r\n", s_memStatis.last_alloc_buff_size);
|
|
|
|
MEM_DBG_LOG("Average Alloc Time: %d us\r\n", s_memStatis.average_alloc_time);
|
|
|
|
MEM_DBG_LOG("Peak Alloc Time: %d us\r\n", s_memStatis.peak_alloc_time);
|
|
|
|
#endif /* MEM_MANAGER_BENCH */
|
|
|
|
MEM_DBG_LOG("************************************************");
|
|
|
|
}
|
|
|
|
#endif /* MEM_STATISTICS_INTERNAL */
|
|
|
|
|
|
|
|
static bool initialized = false;
|
|
|
|
|
2024-03-15 14:23:36 +00:00
|
|
|
mem_status_t MEM_RegisterExtendedArea(memAreaCfg_t *area_desc, uint8_t *p_area_id, uint16_t flags)
|
2022-08-23 15:00:33 +00:00
|
|
|
{
|
2024-03-15 14:23:36 +00:00
|
|
|
mem_status_t st = kStatus_MemSuccess;
|
|
|
|
memAreaPrivDesc_t *p_area;
|
|
|
|
uint32_t regPrimask = DisableGlobalIRQ();
|
|
|
|
assert(offsetof(memAreaCfg_t, internal_ctx) == offsetof(memAreaPrivDesc_t, ctx));
|
|
|
|
assert(sizeof(memAreaCfg_t) >= sizeof(memAreaPrivDesc_t));
|
|
|
|
do
|
2022-08-23 15:00:33 +00:00
|
|
|
{
|
|
|
|
void_ptr_t ptr;
|
|
|
|
blockHeader_t *firstBlockHdr;
|
2024-03-15 14:23:36 +00:00
|
|
|
uint32_t initial_level;
|
|
|
|
|
|
|
|
if (area_desc == NULL)
|
|
|
|
{
|
|
|
|
assert(flags == 0U);
|
|
|
|
p_area = &heap_area_list;
|
|
|
|
/* Area_desc can only be NULL in the case of the implicit default memHeap registration */
|
|
|
|
if ((p_area->start_address.address_ptr != NULL) || (p_area->end_address.address_ptr != NULL))
|
|
|
|
{
|
|
|
|
st = kStatus_MemInitError;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* The head of the area des list is necessarily the main heap */
|
|
|
|
p_area->start_address.address_ptr = &memHeap[0];
|
|
|
|
p_area->end_address.raw_address = memHeapEnd;
|
|
|
|
assert(p_area->end_address.raw_address > p_area->start_address.raw_address);
|
|
|
|
p_area->next = NULL;
|
|
|
|
if (p_area_id != NULL)
|
|
|
|
{
|
|
|
|
*p_area_id = 0u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uint32_t area_sz;
|
|
|
|
|
|
|
|
memAreaPrivDesc_t *new_area_desc = (memAreaPrivDesc_t *)area_desc;
|
|
|
|
assert((flags & AREA_FLAGS_RFFU) == 0U);
|
|
|
|
/* Registering an additional area : memHeap nust have been registered beforehand */
|
|
|
|
uint8_t id = 0;
|
|
|
|
if (area_desc->start_address == NULL)
|
|
|
|
{
|
|
|
|
st = kStatus_MemInitError;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (heap_area_list.start_address.address_ptr == NULL)
|
|
|
|
{
|
|
|
|
/* memHeap must have been registered before */
|
|
|
|
st = kStatus_MemInitError;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
area_sz = new_area_desc->end_address.raw_address - new_area_desc->start_address.raw_address;
|
|
|
|
if (area_sz <= KB(1))
|
|
|
|
{
|
|
|
|
/* doesn't make sense to register an area smaller than 1024 bytes */
|
|
|
|
st = kStatus_MemInitError;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (p_area = &heap_area_list, id = 1; p_area->next != NULL; p_area = (memAreaPrivDesc_t *)p_area->next)
|
|
|
|
{
|
|
|
|
if (p_area == new_area_desc)
|
|
|
|
{
|
|
|
|
st = kStatus_MemInitError;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
id++;
|
|
|
|
}
|
|
|
|
if (st != kStatus_MemSuccess)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (p_area_id != NULL)
|
|
|
|
{
|
|
|
|
/* Determine the rank of the area in the list and return it as area_id */
|
|
|
|
*p_area_id = id;
|
|
|
|
}
|
|
|
|
p_area->next = area_desc; /* p_area still points to previous area desc */
|
|
|
|
p_area = new_area_desc; /* let p_area point to new element */
|
|
|
|
p_area->flags = flags;
|
|
|
|
}
|
|
|
|
/* Here p_area points either to the implicit memHeap when invoked from MEM_Init or to the
|
|
|
|
* newly appended area configuration descriptor
|
|
|
|
*/
|
|
|
|
p_area->next = NULL;
|
|
|
|
ptr.address_ptr = p_area->start_address.address_ptr;
|
|
|
|
firstBlockHdr = ptr.block_hdr_ptr;
|
2022-08-23 15:00:33 +00:00
|
|
|
|
|
|
|
/* MEM_DBG_LOG("%x %d\r\n", memHeap, heapSize_c/sizeof(uint32_t)); */
|
|
|
|
|
|
|
|
/* Init firstBlockHdr as a free block */
|
|
|
|
firstBlockHdr->next = NULL;
|
|
|
|
firstBlockHdr->used = MEMMANAGER_BLOCK_FREE;
|
|
|
|
firstBlockHdr->next_free = NULL;
|
|
|
|
firstBlockHdr->prev_free = NULL;
|
|
|
|
|
2023-08-31 15:30:31 +00:00
|
|
|
#if defined(MEM_STATISTICS_INTERNAL)
|
2022-08-23 15:00:33 +00:00
|
|
|
firstBlockHdr->buff_size = 0U;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Init FreeBlockHdrList with firstBlockHdr */
|
2024-03-15 14:23:36 +00:00
|
|
|
p_area->ctx.FreeBlockHdrList.head = firstBlockHdr;
|
|
|
|
p_area->ctx.FreeBlockHdrList.tail = firstBlockHdr;
|
|
|
|
initial_level = p_area->end_address.raw_address - ((uint32_t)firstBlockHdr + BLOCK_HDR_SIZE - 1U);
|
|
|
|
|
|
|
|
p_area->low_watermark = initial_level;
|
2022-08-23 15:00:33 +00:00
|
|
|
|
|
|
|
#if defined(gMemManagerLightGuardsCheckEnable) && (gMemManagerLightGuardsCheckEnable == 1)
|
|
|
|
MEM_BlockHeaderSetGuards(firstBlockHdr);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(MEM_STATISTICS_INTERNAL)
|
|
|
|
/* Init memory statistics */
|
2024-03-15 14:23:36 +00:00
|
|
|
MEM_Inits_memStatis(&p_area->ctx.statistics);
|
2022-08-23 15:00:33 +00:00
|
|
|
#endif
|
2024-03-15 14:23:36 +00:00
|
|
|
|
|
|
|
st = kStatus_MemSuccess;
|
|
|
|
} while (false);
|
|
|
|
ENABLE_GLOBAL_IRQ(regPrimask);
|
|
|
|
return st;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool MEM_AreaIsEmpty(memAreaPrivDesc_t *p_area)
|
|
|
|
{
|
|
|
|
bool res = false;
|
|
|
|
|
|
|
|
blockHeader_t *FreeBlockHdr = p_area->ctx.FreeBlockHdrList.head;
|
|
|
|
blockHeader_t *NextFreeBlockHdr = FreeBlockHdr->next_free;
|
|
|
|
if ((FreeBlockHdr == (blockHeader_t *)p_area->start_address.raw_address) && (NextFreeBlockHdr == NULL))
|
|
|
|
{
|
|
|
|
res = true;
|
2022-08-23 15:00:33 +00:00
|
|
|
}
|
|
|
|
|
2024-03-15 14:23:36 +00:00
|
|
|
return res;
|
2022-08-23 15:00:33 +00:00
|
|
|
}
|
2024-03-15 14:23:36 +00:00
|
|
|
|
|
|
|
mem_status_t MEM_UnRegisterExtendedArea(uint8_t area_id)
|
2022-08-23 15:00:33 +00:00
|
|
|
{
|
2024-03-15 14:23:36 +00:00
|
|
|
mem_status_t st = kStatus_MemUnknownError;
|
|
|
|
memAreaPrivDesc_t *prev_area;
|
|
|
|
memAreaPrivDesc_t *p_area_to_remove = NULL;
|
|
|
|
uint32_t regPrimask = DisableGlobalIRQ();
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
/* Cannot unregister main heap */
|
|
|
|
if (area_id == 0U)
|
|
|
|
{
|
|
|
|
st = kStatus_MemFreeError;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
prev_area = MEM_GetAreaByAreaId(area_id - 1); /* Get previous area in list */
|
|
|
|
if (prev_area == NULL)
|
|
|
|
{
|
|
|
|
st = kStatus_MemFreeError;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
p_area_to_remove = (memAreaPrivDesc_t *)prev_area->next;
|
|
|
|
if (p_area_to_remove == NULL)
|
|
|
|
{
|
|
|
|
st = kStatus_MemFreeError;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!MEM_AreaIsEmpty(p_area_to_remove))
|
|
|
|
{
|
|
|
|
st = kStatus_MemFreeError;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Only unchain if no remaining allocated buffers */
|
|
|
|
prev_area->next = p_area_to_remove->next;
|
|
|
|
p_area_to_remove->next = NULL;
|
|
|
|
|
|
|
|
st = kStatus_MemSuccess;
|
|
|
|
} while (false);
|
|
|
|
|
|
|
|
ENABLE_GLOBAL_IRQ(regPrimask);
|
|
|
|
|
|
|
|
return st;
|
|
|
|
}
|
|
|
|
|
|
|
|
mem_status_t MEM_Init(void)
|
|
|
|
{
|
|
|
|
mem_status_t st = kStatus_MemSuccess;
|
|
|
|
uint8_t memHeap_id;
|
2022-08-23 15:00:33 +00:00
|
|
|
if (initialized == false)
|
|
|
|
{
|
2024-03-15 14:23:36 +00:00
|
|
|
initialized = true;
|
|
|
|
st = MEM_RegisterExtendedArea(NULL, &memHeap_id, 0U); /* initialized default heap area */
|
2022-08-23 15:00:33 +00:00
|
|
|
}
|
2024-03-15 14:23:36 +00:00
|
|
|
return st;
|
|
|
|
}
|
2022-08-23 15:00:33 +00:00
|
|
|
|
2024-03-15 14:23:36 +00:00
|
|
|
static void *MEM_BufferAllocateFromArea(memAreaPrivDesc_t *p_area, uint8_t area_id, uint32_t numBytes)
|
|
|
|
{
|
2022-08-23 15:00:33 +00:00
|
|
|
uint32_t regPrimask = DisableGlobalIRQ();
|
|
|
|
|
2024-03-15 14:23:36 +00:00
|
|
|
blockHeader_t *FreeBlockHdr = p_area->ctx.FreeBlockHdrList.head;
|
2022-08-23 15:00:33 +00:00
|
|
|
blockHeader_t *NextFreeBlockHdr = FreeBlockHdr->next_free;
|
|
|
|
blockHeader_t *PrevFreeBlockHdr = FreeBlockHdr->prev_free;
|
|
|
|
blockHeader_t *BlockHdrFound = NULL;
|
|
|
|
|
|
|
|
#if defined(cMemManagerLightReuseFreeBlocks) && (cMemManagerLightReuseFreeBlocks > 0)
|
|
|
|
blockHeader_t *UsableBlockHdr = NULL;
|
|
|
|
#endif
|
|
|
|
void *buffer = NULL;
|
|
|
|
|
|
|
|
#ifdef MEM_MANAGER_BENCH
|
|
|
|
uint32_t START_TIME = 0U, STOP_TIME = 0U, ALLOC_TIME = 0U;
|
|
|
|
START_TIME = TM_GetTimestamp();
|
|
|
|
#endif /* MEM_MANAGER_BENCH */
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
assert(FreeBlockHdr->used == MEMMANAGER_BLOCK_FREE);
|
|
|
|
if (FreeBlockHdr->next != NULL)
|
|
|
|
{
|
|
|
|
uint32_t available_size;
|
|
|
|
available_size = (uint32_t)FreeBlockHdr->next - (uint32_t)FreeBlockHdr - BLOCK_HDR_SIZE;
|
|
|
|
/* if a next block hdr exists, it means (by design) that a next free block exists too
|
|
|
|
Because the last block header at the end of the heap will always be free
|
2023-08-31 15:30:31 +00:00
|
|
|
So, the current block header can't be the tail, and the next free can't be NULL */
|
2024-03-15 14:23:36 +00:00
|
|
|
assert(FreeBlockHdr < p_area->ctx.FreeBlockHdrList.tail);
|
2022-08-23 15:00:33 +00:00
|
|
|
assert(FreeBlockHdr->next_free != NULL);
|
|
|
|
|
|
|
|
if (available_size >= numBytes) /* enough space in this free buffer */
|
|
|
|
{
|
|
|
|
#if defined(cMemManagerLightReuseFreeBlocks) && (cMemManagerLightReuseFreeBlocks > 0)
|
|
|
|
/* this block could be used if the memory pool if full, so we memorize it */
|
|
|
|
if (UsableBlockHdr == NULL)
|
|
|
|
{
|
|
|
|
UsableBlockHdr = FreeBlockHdr;
|
|
|
|
}
|
2023-08-31 15:30:31 +00:00
|
|
|
/* To avoid waste of large blocks with small blocks, make sure the required size is big enough for the
|
|
|
|
available block otherwise, try an other block !
|
|
|
|
Do not check if available block size is 4 bytes, take the block anyway ! */
|
2024-03-15 14:23:36 +00:00
|
|
|
if ((available_size <= 4u) ||
|
|
|
|
((available_size - numBytes) < (available_size >> cMemManagerLightReuseFreeBlocks)))
|
2022-08-23 15:00:33 +00:00
|
|
|
#endif
|
|
|
|
{
|
|
|
|
/* Found a matching free block */
|
2024-03-15 14:23:36 +00:00
|
|
|
FreeBlockHdr->used = MEMMANAGER_BLOCK_USED;
|
|
|
|
FreeBlockHdr->area_id = area_id;
|
2022-08-23 15:00:33 +00:00
|
|
|
#if defined(MEM_STATISTICS_INTERNAL)
|
|
|
|
FreeBlockHdr->buff_size = (uint16_t)numBytes;
|
|
|
|
#endif
|
|
|
|
NextFreeBlockHdr = FreeBlockHdr->next_free;
|
|
|
|
PrevFreeBlockHdr = FreeBlockHdr->prev_free;
|
|
|
|
|
|
|
|
/* In the current state, the current block header can be anywhere
|
|
|
|
from list head to previous block of list tail */
|
2024-03-15 14:23:36 +00:00
|
|
|
if (p_area->ctx.FreeBlockHdrList.head == FreeBlockHdr)
|
2022-08-23 15:00:33 +00:00
|
|
|
{
|
2024-03-15 14:23:36 +00:00
|
|
|
p_area->ctx.FreeBlockHdrList.head = NextFreeBlockHdr;
|
|
|
|
NextFreeBlockHdr->prev_free = NULL;
|
2022-08-23 15:00:33 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-03-15 14:23:36 +00:00
|
|
|
assert(p_area->ctx.FreeBlockHdrList.head->next_free <= FreeBlockHdr);
|
2022-08-23 15:00:33 +00:00
|
|
|
|
|
|
|
NextFreeBlockHdr->prev_free = PrevFreeBlockHdr;
|
|
|
|
PrevFreeBlockHdr->next_free = NextFreeBlockHdr;
|
|
|
|
}
|
|
|
|
|
|
|
|
BlockHdrFound = FreeBlockHdr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* last block in the heap, check if available space to allocate the block */
|
2024-03-15 14:23:36 +00:00
|
|
|
int32_t available_size;
|
|
|
|
uint32_t total_size;
|
2023-08-31 15:30:31 +00:00
|
|
|
uint32_t current_footprint = (uint32_t)FreeBlockHdr + BLOCK_HDR_SIZE - 1U;
|
2024-03-15 14:23:36 +00:00
|
|
|
int32_t remaining_bytes;
|
2023-08-31 15:30:31 +00:00
|
|
|
|
|
|
|
/* Current allocation should never be greater than heap end */
|
2024-03-15 14:23:36 +00:00
|
|
|
available_size = p_area->end_address.raw_address - current_footprint;
|
|
|
|
assert(available_size >= 0);
|
2022-08-23 15:00:33 +00:00
|
|
|
|
2024-03-15 14:23:36 +00:00
|
|
|
assert(FreeBlockHdr == p_area->ctx.FreeBlockHdrList.tail);
|
|
|
|
total_size = (numBytes + BLOCK_HDR_SIZE);
|
|
|
|
remaining_bytes = (available_size - total_size);
|
|
|
|
if (remaining_bytes >= 0) /* need to keep the room for the next BlockHeader */
|
2022-08-23 15:00:33 +00:00
|
|
|
{
|
2024-03-15 14:23:36 +00:00
|
|
|
if (p_area->low_watermark > remaining_bytes)
|
|
|
|
{
|
|
|
|
p_area->low_watermark = remaining_bytes;
|
|
|
|
}
|
2023-08-31 15:30:31 +00:00
|
|
|
/* Depending on the platform, some RAM banks could need some reinitialization after a low power
|
|
|
|
* period, such as ECC RAM banks */
|
2024-03-15 14:23:36 +00:00
|
|
|
MEM_ReinitRamBank((uint32_t)FreeBlockHdr + BLOCK_HDR_SIZE,
|
|
|
|
ROUNDUP_WORD(((uint32_t)FreeBlockHdr + total_size + BLOCK_HDR_SIZE)));
|
2023-08-31 15:30:31 +00:00
|
|
|
|
2024-03-15 14:23:36 +00:00
|
|
|
FreeBlockHdr->used = MEMMANAGER_BLOCK_USED;
|
|
|
|
FreeBlockHdr->area_id = area_id;
|
2022-08-23 15:00:33 +00:00
|
|
|
#if defined(MEM_STATISTICS_INTERNAL)
|
|
|
|
FreeBlockHdr->buff_size = (uint16_t)numBytes;
|
|
|
|
#endif
|
2024-03-15 14:23:36 +00:00
|
|
|
FreeBlockHdr->next = (blockHeader_t *)ROUNDUP_WORD(((uint32_t)FreeBlockHdr + total_size));
|
2022-08-23 15:00:33 +00:00
|
|
|
FreeBlockHdr->next_free = FreeBlockHdr->next;
|
|
|
|
|
|
|
|
PrevFreeBlockHdr = FreeBlockHdr->prev_free;
|
|
|
|
|
|
|
|
NextFreeBlockHdr = FreeBlockHdr->next_free;
|
|
|
|
NextFreeBlockHdr->used = MEMMANAGER_BLOCK_FREE;
|
|
|
|
#if defined(MEM_STATISTICS_INTERNAL)
|
|
|
|
NextFreeBlockHdr->buff_size = 0U;
|
|
|
|
#endif
|
|
|
|
NextFreeBlockHdr->next = NULL;
|
|
|
|
NextFreeBlockHdr->next_free = NULL;
|
|
|
|
NextFreeBlockHdr->prev_free = PrevFreeBlockHdr;
|
|
|
|
|
2024-03-15 14:23:36 +00:00
|
|
|
if (p_area->ctx.FreeBlockHdrList.head == FreeBlockHdr)
|
2022-08-23 15:00:33 +00:00
|
|
|
{
|
2024-03-15 14:23:36 +00:00
|
|
|
assert(p_area->ctx.FreeBlockHdrList.head == p_area->ctx.FreeBlockHdrList.tail);
|
2022-08-23 15:00:33 +00:00
|
|
|
assert(PrevFreeBlockHdr == NULL);
|
|
|
|
/* last free block in heap was the only free block available
|
|
|
|
so now the first free block in the heap is the next one */
|
2024-03-15 14:23:36 +00:00
|
|
|
p_area->ctx.FreeBlockHdrList.head = FreeBlockHdr->next_free;
|
2022-08-23 15:00:33 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* update previous free block header to point its next
|
|
|
|
to the new free block */
|
|
|
|
PrevFreeBlockHdr->next_free = NextFreeBlockHdr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* new free block is now the tail of the free block list */
|
2024-03-15 14:23:36 +00:00
|
|
|
p_area->ctx.FreeBlockHdrList.tail = NextFreeBlockHdr;
|
2022-08-23 15:00:33 +00:00
|
|
|
|
|
|
|
#if defined(gMemManagerLightGuardsCheckEnable) && (gMemManagerLightGuardsCheckEnable == 1)
|
|
|
|
MEM_BlockHeaderSetGuards(NextFreeBlockHdr);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
BlockHdrFound = FreeBlockHdr;
|
|
|
|
}
|
|
|
|
#if defined(cMemManagerLightReuseFreeBlocks) && (cMemManagerLightReuseFreeBlocks > 0)
|
|
|
|
else if (UsableBlockHdr != NULL)
|
|
|
|
{
|
|
|
|
/* we found a free block that can be used */
|
2024-03-15 14:23:36 +00:00
|
|
|
UsableBlockHdr->used = MEMMANAGER_BLOCK_USED;
|
|
|
|
UsableBlockHdr->area_id = area_id;
|
2022-08-23 15:00:33 +00:00
|
|
|
#if defined(MEM_STATISTICS_INTERNAL)
|
|
|
|
UsableBlockHdr->buff_size = (uint16_t)numBytes;
|
|
|
|
#endif
|
|
|
|
NextFreeBlockHdr = UsableBlockHdr->next_free;
|
|
|
|
PrevFreeBlockHdr = UsableBlockHdr->prev_free;
|
|
|
|
|
|
|
|
/* In the current state, the current block header can be anywhere
|
|
|
|
from list head to previous block of list tail */
|
2024-03-15 14:23:36 +00:00
|
|
|
if (p_area->ctx.FreeBlockHdrList.head == UsableBlockHdr)
|
2022-08-23 15:00:33 +00:00
|
|
|
{
|
2024-03-15 14:23:36 +00:00
|
|
|
p_area->ctx.FreeBlockHdrList.head = NextFreeBlockHdr;
|
|
|
|
NextFreeBlockHdr->prev_free = NULL;
|
2022-08-23 15:00:33 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-03-15 14:23:36 +00:00
|
|
|
assert(p_area->ctx.FreeBlockHdrList.head->next_free <= UsableBlockHdr);
|
2022-08-23 15:00:33 +00:00
|
|
|
|
|
|
|
NextFreeBlockHdr->prev_free = PrevFreeBlockHdr;
|
|
|
|
PrevFreeBlockHdr->next_free = NextFreeBlockHdr;
|
|
|
|
}
|
|
|
|
BlockHdrFound = UsableBlockHdr;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BlockHdrFound = NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#if defined(gMemManagerLightGuardsCheckEnable) && (gMemManagerLightGuardsCheckEnable == 1)
|
|
|
|
MEM_BlockHeaderCheck(FreeBlockHdr->next_free);
|
|
|
|
#endif
|
|
|
|
FreeBlockHdr = FreeBlockHdr->next_free;
|
|
|
|
/* avoid looping */
|
|
|
|
assert(FreeBlockHdr != FreeBlockHdr->next_free);
|
|
|
|
} while (true);
|
|
|
|
/* MEM_DBG_LOG("BlockHdrFound: %x", BlockHdrFound); */
|
|
|
|
|
|
|
|
#ifdef MEM_DEBUG_OUT_OF_MEMORY
|
|
|
|
assert(BlockHdrFound);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MEM_MANAGER_BENCH
|
|
|
|
STOP_TIME = TM_GetTimestamp();
|
|
|
|
ALLOC_TIME = STOP_TIME - START_TIME;
|
|
|
|
#endif /* MEM_MANAGER_BENCH */
|
|
|
|
|
|
|
|
if (BlockHdrFound != NULL)
|
|
|
|
{
|
|
|
|
void_ptr_t buffer_ptr;
|
|
|
|
#ifdef MEM_TRACKING
|
|
|
|
void_ptr_t lr;
|
2023-08-31 15:30:31 +00:00
|
|
|
lr.raw_address = (uint32_t)__mem_get_LR();
|
2022-08-23 15:00:33 +00:00
|
|
|
BlockHdrFound->first_alloc_caller = lr.void_ptr;
|
|
|
|
#endif
|
|
|
|
buffer_ptr.raw_address = (uint32_t)BlockHdrFound + BLOCK_HDR_SIZE;
|
|
|
|
buffer = buffer_ptr.void_ptr;
|
|
|
|
#ifdef MEM_STATISTICS_INTERNAL
|
|
|
|
#ifdef MEM_MANAGER_BENCH
|
2024-03-15 14:23:36 +00:00
|
|
|
MEM_BufferAllocates_memStatis(buffer, ALLOC_TIME, numBytes);
|
2022-08-23 15:00:33 +00:00
|
|
|
#else
|
2024-03-15 14:23:36 +00:00
|
|
|
MEM_BufferAllocates_memStatis(buffer, 0, numBytes);
|
2022-08-23 15:00:33 +00:00
|
|
|
#endif
|
2024-03-15 14:23:36 +00:00
|
|
|
if ((p_area->ctx.statistics.nb_alloc % NB_ALLOC_REPORT_THRESHOLD) == 0U)
|
|
|
|
{
|
|
|
|
MEM_Reports_memStatis();
|
|
|
|
}
|
|
|
|
#endif /* MEM_STATISTICS_INTERNAL */
|
|
|
|
}
|
|
|
|
else
|
2022-08-23 15:00:33 +00:00
|
|
|
{
|
2024-03-15 14:23:36 +00:00
|
|
|
/* TODO: Allocation failure try to merge free blocks together */
|
2022-08-23 15:00:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
EnableGlobalIRQ(regPrimask);
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2024-03-15 14:23:36 +00:00
|
|
|
static void *MEM_BufferAllocate(uint32_t numBytes, uint8_t poolId)
|
|
|
|
{
|
|
|
|
memAreaPrivDesc_t *p_area;
|
|
|
|
void *buffer = NULL;
|
|
|
|
uint8_t area_id = 0U;
|
|
|
|
|
|
|
|
if (initialized == false)
|
|
|
|
{
|
|
|
|
(void)MEM_Init();
|
|
|
|
}
|
|
|
|
if (poolId == 0U)
|
|
|
|
{
|
|
|
|
area_id = 0U;
|
|
|
|
for (p_area = &heap_area_list; p_area != NULL; p_area = (memAreaPrivDesc_t *)p_area->next)
|
|
|
|
{
|
|
|
|
if ((p_area->flags & AREA_FLAGS_POOL_NOT_SHARED) == 0U)
|
|
|
|
{
|
|
|
|
buffer = MEM_BufferAllocateFromArea(p_area, area_id, numBytes);
|
|
|
|
if (buffer != NULL)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
area_id++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
p_area = MEM_GetAreaByAreaId(poolId); /* Exclusively allocate from targeted pool */
|
|
|
|
if (p_area != NULL)
|
|
|
|
{
|
|
|
|
buffer = MEM_BufferAllocateFromArea(p_area, poolId, numBytes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2022-08-23 15:00:33 +00:00
|
|
|
void *MEM_BufferAllocWithId(uint32_t numBytes, uint8_t poolId)
|
|
|
|
{
|
|
|
|
#ifdef MEM_TRACKING
|
|
|
|
void_ptr_t BlockHdr_ptr;
|
|
|
|
#endif
|
|
|
|
void_ptr_t buffer_ptr;
|
|
|
|
|
|
|
|
#if defined(gFSCI_MemAllocTest_Enabled_d) && (gFSCI_MemAllocTest_Enabled_d)
|
|
|
|
void *pCaller = (void *)((uint32_t *)__mem_get_LR());
|
|
|
|
/* Verify if the caller is part of any FSCI memory allocation test. If so, return NULL. */
|
|
|
|
if (FSCI_MemAllocTestCanAllocate(pCaller) == kStatus_AllocBlock)
|
|
|
|
{
|
|
|
|
buffer_ptr.void_ptr = NULL;
|
|
|
|
return buffer_ptr.void_ptr;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Alloc a buffer */
|
|
|
|
buffer_ptr.void_ptr = MEM_BufferAllocate(numBytes, poolId);
|
|
|
|
|
|
|
|
#ifdef MEM_TRACKING
|
|
|
|
if (buffer_ptr.void_ptr != NULL)
|
|
|
|
{
|
|
|
|
BlockHdr_ptr.raw_address = buffer_ptr.raw_address - BLOCK_HDR_SIZE;
|
|
|
|
/* store caller */
|
|
|
|
BlockHdr_ptr.block_hdr_ptr->second_alloc_caller = (void *)((uint32_t *)__mem_get_LR());
|
|
|
|
;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return buffer_ptr.void_ptr;
|
|
|
|
}
|
|
|
|
|
2024-03-15 14:23:36 +00:00
|
|
|
static mem_status_t MEM_BufferFreeBackToArea(memAreaPrivDesc_t *p_area, void *buffer)
|
|
|
|
{
|
|
|
|
void_ptr_t buffer_ptr;
|
|
|
|
buffer_ptr.void_ptr = buffer;
|
|
|
|
blockHeader_t *BlockHdr;
|
|
|
|
BlockHdr = (blockHeader_t *)(buffer_ptr.raw_address - BLOCK_HDR_SIZE);
|
|
|
|
|
|
|
|
mem_status_t ret = kStatus_MemSuccess;
|
|
|
|
/* when allocating a buffer, we always create a FreeBlockHdr at
|
|
|
|
the end of the buffer, so the FreeBlockHdrList.tail should always
|
|
|
|
be at a higher address than current BlockHdr */
|
|
|
|
assert(BlockHdr < p_area->ctx.FreeBlockHdrList.tail);
|
|
|
|
|
|
|
|
#if defined(gMemManagerLightGuardsCheckEnable) && (gMemManagerLightGuardsCheckEnable == 1)
|
|
|
|
MEM_BlockHeaderCheck(BlockHdr->next);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* MEM_DBG_LOG("%x %d", BlockHdr, BlockHdr->buff_size); */
|
|
|
|
|
|
|
|
#if defined(MEM_STATISTICS_INTERNAL)
|
|
|
|
MEM_BufferFrees_memStatis(buffer);
|
|
|
|
#endif /* MEM_STATISTICS_INTERNAL */
|
|
|
|
|
|
|
|
if (BlockHdr < p_area->ctx.FreeBlockHdrList.head)
|
|
|
|
{
|
|
|
|
/* BlockHdr is placed before FreeBlockHdrList.head so we can set it as
|
|
|
|
the new head of the list */
|
|
|
|
BlockHdr->next_free = p_area->ctx.FreeBlockHdrList.head;
|
|
|
|
BlockHdr->prev_free = NULL;
|
|
|
|
p_area->ctx.FreeBlockHdrList.head->prev_free = BlockHdr;
|
|
|
|
p_area->ctx.FreeBlockHdrList.head = BlockHdr;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* we want to find the previous free block header
|
|
|
|
here, we cannot use prev_free as this information could be outdated
|
|
|
|
so we need to run through the whole list to be sure to catch the
|
|
|
|
correct previous free block header */
|
|
|
|
blockHeader_t *PrevFreeBlockHdr = p_area->ctx.FreeBlockHdrList.head;
|
|
|
|
while ((uint32_t)PrevFreeBlockHdr->next_free < (uint32_t)BlockHdr)
|
|
|
|
{
|
|
|
|
PrevFreeBlockHdr = PrevFreeBlockHdr->next_free;
|
|
|
|
}
|
|
|
|
/* insert the new free block in the list */
|
|
|
|
BlockHdr->next_free = PrevFreeBlockHdr->next_free;
|
|
|
|
BlockHdr->prev_free = PrevFreeBlockHdr;
|
|
|
|
BlockHdr->next_free->prev_free = BlockHdr;
|
|
|
|
PrevFreeBlockHdr->next_free = BlockHdr;
|
|
|
|
}
|
|
|
|
|
|
|
|
BlockHdr->used = MEMMANAGER_BLOCK_FREE;
|
|
|
|
#if defined(MEM_STATISTICS_INTERNAL)
|
|
|
|
BlockHdr->buff_size = 0U;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(gMemManagerLightFreeBlocksCleanUp) && (gMemManagerLightFreeBlocksCleanUp != 0)
|
|
|
|
MEM_BufferFreeBlocksCleanUp(p_area, BlockHdr);
|
|
|
|
#endif
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-08-23 15:00:33 +00:00
|
|
|
mem_status_t MEM_BufferFree(void *buffer /* IN: Block of memory to free*/)
|
|
|
|
{
|
|
|
|
mem_status_t ret = kStatus_MemSuccess;
|
|
|
|
void_ptr_t buffer_ptr;
|
|
|
|
buffer_ptr.void_ptr = buffer;
|
|
|
|
|
|
|
|
if (buffer == NULL)
|
|
|
|
{
|
|
|
|
ret = kStatus_MemFreeError;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uint32_t regPrimask = DisableGlobalIRQ();
|
|
|
|
|
|
|
|
blockHeader_t *BlockHdr;
|
|
|
|
BlockHdr = (blockHeader_t *)(buffer_ptr.raw_address - BLOCK_HDR_SIZE);
|
|
|
|
|
|
|
|
/* assert checks */
|
|
|
|
assert(BlockHdr->used == MEMMANAGER_BLOCK_USED);
|
|
|
|
assert(BlockHdr->next != NULL);
|
2024-03-15 14:23:36 +00:00
|
|
|
memAreaPrivDesc_t *p_area = MEM_GetAreaByAreaId(BlockHdr->area_id);
|
2022-08-23 15:00:33 +00:00
|
|
|
|
2024-03-15 14:23:36 +00:00
|
|
|
if (p_area != NULL)
|
2022-08-23 15:00:33 +00:00
|
|
|
{
|
2024-03-15 14:23:36 +00:00
|
|
|
ret = MEM_BufferFreeBackToArea(p_area, buffer);
|
2022-08-23 15:00:33 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-03-15 14:23:36 +00:00
|
|
|
assert(p_area != NULL);
|
|
|
|
ret = kStatus_MemFreeError;
|
2022-08-23 15:00:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
EnableGlobalIRQ(regPrimask);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
mem_status_t MEM_BufferFreeAllWithId(uint8_t poolId)
|
|
|
|
{
|
|
|
|
mem_status_t status = kStatus_MemSuccess;
|
|
|
|
#if (defined(MEM_TRACK_ALLOC_SOURCE) && (MEM_TRACK_ALLOC_SOURCE == 1))
|
|
|
|
#ifdef MEMMANAGER_NOT_IMPLEMENTED_YET
|
|
|
|
|
|
|
|
#endif /* MEMMANAGER_NOT_IMPLEMENTED_YET */
|
|
|
|
#else /* (defined(MEM_TRACK_ALLOC_SOURCE) && (MEM_TRACK_ALLOC_SOURCE == 1)) */
|
|
|
|
status = kStatus_MemFreeError;
|
|
|
|
#endif /* (defined(MEM_TRACK_ALLOC_SOURCE) && (MEM_TRACK_ALLOC_SOURCE == 1)) */
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2024-03-15 14:23:36 +00:00
|
|
|
uint32_t MEM_GetHeapUpperLimitByAreaId(uint8_t area_id)
|
2022-08-23 15:00:33 +00:00
|
|
|
{
|
|
|
|
/* There is always a free block at the end of the heap
|
2024-03-15 14:23:36 +00:00
|
|
|
and this free block is the tail of the list */
|
|
|
|
uint32_t upper_limit = 0U;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
memAreaPrivDesc_t *p_area;
|
|
|
|
p_area = MEM_GetAreaByAreaId(area_id);
|
|
|
|
if (p_area == NULL)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
upper_limit = ((uint32_t)p_area->ctx.FreeBlockHdrList.tail + BLOCK_HDR_SIZE);
|
|
|
|
|
|
|
|
} while (false);
|
|
|
|
|
|
|
|
return upper_limit;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t MEM_GetHeapUpperLimit(void)
|
|
|
|
{
|
|
|
|
return MEM_GetHeapUpperLimitByAreaId(0u);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t MEM_GetFreeHeapSizeLowWaterMarkByAreaId(uint8_t area_id)
|
|
|
|
{
|
|
|
|
uint32_t low_watermark = 0U;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
memAreaPrivDesc_t *p_area;
|
|
|
|
p_area = MEM_GetAreaByAreaId(area_id);
|
|
|
|
if (p_area == NULL)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
low_watermark = p_area->low_watermark;
|
|
|
|
|
|
|
|
} while (false);
|
|
|
|
return low_watermark;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t MEM_GetFreeHeapSizeLowWaterMark(void)
|
|
|
|
{
|
|
|
|
return MEM_GetFreeHeapSizeLowWaterMarkByAreaId(0u);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t MEM_ResetFreeHeapSizeLowWaterMarkByAreaId(uint8_t area_id)
|
|
|
|
{
|
|
|
|
uint32_t current_level = 0U;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
memAreaPrivDesc_t *p_area;
|
|
|
|
blockHeader_t *FreeBlockHdr;
|
|
|
|
uint32_t current_footprint;
|
|
|
|
p_area = MEM_GetAreaByAreaId(area_id);
|
|
|
|
if (p_area == NULL)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
FreeBlockHdr = p_area->ctx.FreeBlockHdrList.head;
|
|
|
|
current_footprint = (uint32_t)FreeBlockHdr + BLOCK_HDR_SIZE - 1U;
|
|
|
|
|
|
|
|
/* Current allocation should never be greater than heap end */
|
|
|
|
current_level = p_area->end_address.raw_address - current_footprint;
|
|
|
|
p_area->low_watermark = current_level;
|
|
|
|
|
|
|
|
} while (false);
|
|
|
|
return current_level;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t MEM_ResetFreeHeapSizeLowWaterMark(void)
|
|
|
|
{
|
|
|
|
return MEM_ResetFreeHeapSizeLowWaterMarkByAreaId(0u);
|
2022-08-23 15:00:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t MEM_BufferGetSize(void *buffer)
|
|
|
|
{
|
|
|
|
blockHeader_t *BlockHdr = NULL;
|
|
|
|
uint16_t size;
|
|
|
|
/* union used to fix Misra */
|
|
|
|
void_ptr_t buffer_ptr;
|
|
|
|
buffer_ptr.void_ptr = buffer;
|
|
|
|
|
|
|
|
if (buffer != NULL)
|
|
|
|
{
|
|
|
|
BlockHdr = (blockHeader_t *)(buffer_ptr.raw_address - BLOCK_HDR_SIZE);
|
|
|
|
/* block size is the space between current BlockHdr and next BlockHdr */
|
|
|
|
size = (uint16_t)((uint32_t)BlockHdr->next - (uint32_t)BlockHdr - BLOCK_HDR_SIZE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* is case of a NULL buffer, we return 0U */
|
|
|
|
size = 0U;
|
|
|
|
}
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *MEM_BufferRealloc(void *buffer, uint32_t new_size)
|
|
|
|
{
|
|
|
|
void *realloc_buffer = NULL;
|
|
|
|
uint16_t block_size = 0U;
|
2024-03-15 14:23:36 +00:00
|
|
|
do
|
2022-08-23 15:00:33 +00:00
|
|
|
{
|
2024-03-15 14:23:36 +00:00
|
|
|
if (new_size >= MAX_UINT16)
|
|
|
|
{
|
|
|
|
realloc_buffer = NULL;
|
|
|
|
/* Bypass he whole procedure so keep original buffer that cannot be reallocated */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (new_size == 0U)
|
|
|
|
{
|
|
|
|
/* new requested size is 0, free old buffer */
|
|
|
|
(void)MEM_BufferFree(buffer);
|
|
|
|
realloc_buffer = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (buffer == NULL)
|
|
|
|
{
|
|
|
|
/* input buffer is NULL simply allocate a new buffer and return it */
|
|
|
|
realloc_buffer = MEM_BufferAllocate(new_size, 0U);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* Current buffer needs to be reallocated */
|
2022-08-23 15:00:33 +00:00
|
|
|
block_size = MEM_BufferGetSize(buffer);
|
|
|
|
|
|
|
|
if ((uint16_t)new_size <= block_size)
|
|
|
|
{
|
|
|
|
/* current buffer is large enough for the new requested size
|
|
|
|
we can still use it */
|
|
|
|
realloc_buffer = buffer;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* not enough space in the current block, creating a new one */
|
2024-03-15 14:23:36 +00:00
|
|
|
realloc_buffer = MEM_BufferAllocate(new_size, 0U);
|
2022-08-23 15:00:33 +00:00
|
|
|
|
|
|
|
if (realloc_buffer != NULL)
|
|
|
|
{
|
|
|
|
/* copy input buffer data to new buffer */
|
|
|
|
(void)memcpy(realloc_buffer, buffer, (uint32_t)block_size);
|
|
|
|
|
|
|
|
/* free old buffer */
|
|
|
|
(void)MEM_BufferFree(buffer);
|
|
|
|
}
|
|
|
|
}
|
2024-03-15 14:23:36 +00:00
|
|
|
} while (false);
|
2022-08-23 15:00:33 +00:00
|
|
|
return realloc_buffer;
|
|
|
|
}
|
2024-03-15 14:23:36 +00:00
|
|
|
static uint32_t MEM_GetFreeHeapSpaceInArea(memAreaPrivDesc_t *p_area)
|
2022-08-23 15:00:33 +00:00
|
|
|
{
|
2024-03-15 14:23:36 +00:00
|
|
|
uint32_t free_sz = 0U;
|
|
|
|
/* skip unshared areas */
|
|
|
|
blockHeader_t *freeBlockHdr = p_area->ctx.FreeBlockHdrList.head;
|
2022-08-23 15:00:33 +00:00
|
|
|
|
|
|
|
/* Count every free block in the free space */
|
2024-03-15 14:23:36 +00:00
|
|
|
while (freeBlockHdr != p_area->ctx.FreeBlockHdrList.tail)
|
2022-08-23 15:00:33 +00:00
|
|
|
{
|
2024-03-15 14:23:36 +00:00
|
|
|
free_sz += ((uint32_t)freeBlockHdr->next - (uint32_t)freeBlockHdr - BLOCK_HDR_SIZE);
|
2022-08-23 15:00:33 +00:00
|
|
|
freeBlockHdr = freeBlockHdr->next_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add remaining free space in the heap */
|
2024-03-15 14:23:36 +00:00
|
|
|
free_sz += p_area->end_address.raw_address - (uint32_t)p_area->ctx.FreeBlockHdrList.tail - BLOCK_HDR_SIZE + 1;
|
|
|
|
return free_sz;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t MEM_GetFreeHeapSizeByAreaId(uint8_t area_id)
|
|
|
|
{
|
|
|
|
memAreaPrivDesc_t *p_area;
|
|
|
|
uint32_t free_size = 0U;
|
2022-08-23 15:00:33 +00:00
|
|
|
|
2024-03-15 14:23:36 +00:00
|
|
|
if (area_id == 0U)
|
|
|
|
{
|
|
|
|
/* Iterate through all registered areas */
|
|
|
|
for (p_area = &heap_area_list; p_area != NULL; p_area = (memAreaPrivDesc_t *)p_area->next)
|
|
|
|
{
|
|
|
|
if ((p_area->flags & AREA_FLAGS_POOL_NOT_SHARED) == 0U)
|
|
|
|
{
|
|
|
|
free_size += MEM_GetFreeHeapSpaceInArea(p_area);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
p_area = MEM_GetAreaByAreaId(area_id);
|
|
|
|
if (p_area != NULL)
|
|
|
|
{
|
|
|
|
free_size = MEM_GetFreeHeapSpaceInArea(p_area);
|
|
|
|
}
|
|
|
|
}
|
2022-08-23 15:00:33 +00:00
|
|
|
return free_size;
|
|
|
|
}
|
|
|
|
|
2024-03-15 14:23:36 +00:00
|
|
|
uint32_t MEM_GetFreeHeapSize(void)
|
|
|
|
{
|
|
|
|
return MEM_GetFreeHeapSizeByAreaId(0U);
|
|
|
|
}
|
|
|
|
|
2023-08-31 15:30:31 +00:00
|
|
|
__attribute__((weak)) void MEM_ReinitRamBank(uint32_t startAddress, uint32_t endAddress)
|
|
|
|
{
|
|
|
|
/* To be implemented by the platform */
|
|
|
|
(void)startAddress;
|
|
|
|
(void)endAddress;
|
|
|
|
}
|
|
|
|
|
2022-08-23 15:00:33 +00:00
|
|
|
#if 0 /* MISRA C-2012 Rule 8.4 */
|
|
|
|
uint32_t MEM_GetAvailableBlocks(uint32_t size)
|
|
|
|
{
|
|
|
|
/* Function not implemented yet */
|
|
|
|
assert(0);
|
|
|
|
|
|
|
|
return 0U;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void *MEM_CallocAlt(size_t len, size_t val)
|
|
|
|
{
|
|
|
|
size_t blk_size;
|
|
|
|
|
|
|
|
blk_size = len * val;
|
|
|
|
|
2024-03-15 14:23:36 +00:00
|
|
|
void *pData = MEM_BufferAllocate(blk_size, 0U);
|
2022-08-23 15:00:33 +00:00
|
|
|
if (NULL != pData)
|
|
|
|
{
|
2024-03-15 14:23:36 +00:00
|
|
|
(void)memset(pData, 0U, blk_size);
|
2022-08-23 15:00:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return pData;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0 /* MISRA C-2012 Rule 8.4 */
|
|
|
|
void MEM_FreeAlt(void *pData)
|
|
|
|
{
|
|
|
|
/* Function not implemented yet */
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|