334 lines
8.1 KiB
C
334 lines
8.1 KiB
C
|
/*
|
||
|
* INCLUDE FILES
|
||
|
****************************************************************************************
|
||
|
*/
|
||
|
#include <common/bk_include.h>
|
||
|
#include <os/mem.h>
|
||
|
#include "FreeRTOS.h"
|
||
|
#include "task.h"
|
||
|
#include "mmgmt.h"
|
||
|
|
||
|
/*
|
||
|
* GLOBAL VARIABLES
|
||
|
****************************************************************************************
|
||
|
*/
|
||
|
static uint8_t mmgmt_heap[KE_HEAP_SIZE];
|
||
|
static struct mblock_free *mblock_first;
|
||
|
|
||
|
#define MEM_FILL 0xCC
|
||
|
|
||
|
#define CO_ALIGN4_HI(val) (((val)+3)&~3)
|
||
|
|
||
|
/*
|
||
|
* FUNCTION DEFINITIONS
|
||
|
****************************************************************************************
|
||
|
*/
|
||
|
void sys_mem_init(void)
|
||
|
{
|
||
|
#ifdef MMGMT_DEBUG
|
||
|
os_memset(mmgmt_heap, MEM_FILL, sizeof(mmgmt_heap));
|
||
|
#endif
|
||
|
mblock_first = mmgmt_init();
|
||
|
}
|
||
|
|
||
|
struct mblock_free *mmgmt_init(void)
|
||
|
{
|
||
|
struct mblock_free *first;
|
||
|
|
||
|
// align first free descriptor to word boundary
|
||
|
first = (struct mblock_free *)CO_ALIGN4_HI((uint32_t)mmgmt_heap);
|
||
|
|
||
|
// protect accesses to descriptors
|
||
|
vTaskSuspendAll();
|
||
|
|
||
|
// initialize the first block
|
||
|
// + compute the size from the last aligned word before heap_end
|
||
|
first->size = ((uint32_t)&mmgmt_heap[KE_HEAP_SIZE] & (~3)) - (uint32_t)first;
|
||
|
first->next = NULL;
|
||
|
|
||
|
// end of protection
|
||
|
( void ) xTaskResumeAll();
|
||
|
|
||
|
// save the pointer to the first free block
|
||
|
return first;
|
||
|
}
|
||
|
|
||
|
uint32_t mmgmt_alloc_space(void)
|
||
|
{
|
||
|
struct mblock_free *node;
|
||
|
uint32_t valid_size = 0;
|
||
|
|
||
|
node = mblock_first;
|
||
|
|
||
|
while (node != NULL) {
|
||
|
BK_ASSERT(node->size);
|
||
|
valid_size += node->size;
|
||
|
|
||
|
node = node->next;
|
||
|
}
|
||
|
|
||
|
return valid_size;
|
||
|
}
|
||
|
|
||
|
#if CONFIG_MALLOC_STATIS || CONFIG_MEM_DEBUG
|
||
|
void *mmgmt_malloc(const char *call_func_name, int line, uint32_t size)
|
||
|
#else
|
||
|
void *mmgmt_malloc(uint32_t size)
|
||
|
#endif
|
||
|
{
|
||
|
struct mblock_free *node, *found;
|
||
|
struct mblock_used *alloc = 0;
|
||
|
uint32_t totalsize;
|
||
|
|
||
|
if (0 == size)
|
||
|
goto alloc_exit;
|
||
|
|
||
|
// initialize the pointers
|
||
|
found = NULL;
|
||
|
|
||
|
// compute overall block size (including requested size PLUS descriptor size)
|
||
|
totalsize = CO_ALIGN4_HI(size) + sizeof(struct mblock_used);
|
||
|
|
||
|
// sanity check: the totalsize should be large enough to hold free block descriptor
|
||
|
BK_ASSERT(totalsize >= sizeof(struct mblock_free)); /* ASSERT VERIFIED */
|
||
|
|
||
|
node = mblock_first;
|
||
|
|
||
|
// protect accesses to descriptors
|
||
|
vTaskSuspendAll();
|
||
|
|
||
|
// go through free memory blocks list
|
||
|
while (node != NULL) {
|
||
|
// check if there is enough room in this free block
|
||
|
BK_ASSERT(node->size); /* ASSERT VERIFIED */
|
||
|
if (node->size >= (totalsize + sizeof(struct mblock_free))) {
|
||
|
// if a match was already found, check if this one is smaller
|
||
|
if ((found == NULL) || (found->size > node->size))
|
||
|
found = node;
|
||
|
}
|
||
|
// move to next block
|
||
|
node = node->next;
|
||
|
}
|
||
|
|
||
|
if (0 == found) {
|
||
|
( void ) xTaskResumeAll();
|
||
|
goto alloc_exit;
|
||
|
}
|
||
|
|
||
|
// found a free block that matches, subtract the allocation size from the
|
||
|
// free block size. If equal, the free block will be kept with 0 size... but
|
||
|
// moving it out of the linked list is too much work.
|
||
|
found->size -= totalsize;
|
||
|
|
||
|
// compute the pointer to the beginning of the free space
|
||
|
alloc = (struct mblock_used *)((uint32_t)found + found->size);
|
||
|
|
||
|
// sanity check: allocation should always succeed
|
||
|
BK_ASSERT(found != NULL); /* ASSERT VERIFIED */
|
||
|
|
||
|
// save the size of the allocated block (use low bit to indicate mem type)
|
||
|
alloc->size = totalsize;
|
||
|
alloc->magic = MM_MAGIC;
|
||
|
|
||
|
// move to the user memory space
|
||
|
alloc++;
|
||
|
|
||
|
// end of protection (as early as possible)
|
||
|
( void ) xTaskResumeAll();
|
||
|
|
||
|
#if CONFIG_MALLOC_STATIS || CONFIG_MEM_DEBUG
|
||
|
bk_printf("\r\nm:%p,%ld|%s,%d\r\n", alloc - 1, totalsize, call_func_name, line);
|
||
|
#endif
|
||
|
|
||
|
|
||
|
alloc_exit:
|
||
|
BK_ASSERT(0 == ((UINT32)alloc & 3)); /* ASSERT VERIFIED */
|
||
|
//BK_ASSERT(alloc);
|
||
|
return (void *)alloc;
|
||
|
}
|
||
|
|
||
|
void *mmgmt_realloc(void *ptr, size_t size)
|
||
|
{
|
||
|
struct mblock_used *a;
|
||
|
size_t copy_len;
|
||
|
void *n;
|
||
|
|
||
|
if (ptr == NULL)
|
||
|
return mmgmt_malloc(size);
|
||
|
|
||
|
#if CONFIG_MALLOC_STATIS || CONFIG_MEM_DEBUG
|
||
|
n = mmgmt_malloc(size, __func__, __LINE__);
|
||
|
#else
|
||
|
n = mmgmt_malloc(size);
|
||
|
#endif
|
||
|
if (n == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
a = ((struct mblock_used *)ptr) - 1;
|
||
|
copy_len = a->size;
|
||
|
if (copy_len > size)
|
||
|
copy_len = size;
|
||
|
|
||
|
os_memcpy(n, a + 1, copy_len);
|
||
|
|
||
|
#if CONFIG_MALLOC_STATIS || CONFIG_MEM_DEBUG
|
||
|
mmgmt_free(ptr, __func__, __LINE__);
|
||
|
#else
|
||
|
mmgmt_free(ptr);
|
||
|
#endif
|
||
|
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
#if CONFIG_MALLOC_STATIS || CONFIG_MEM_DEBUG
|
||
|
void mmgmt_free(const char *call_func_name, int line, void *mem_ptr)
|
||
|
#else
|
||
|
void mmgmt_free(void *mem_ptr)
|
||
|
#endif
|
||
|
{
|
||
|
struct mblock_used *freed;
|
||
|
struct mblock_free *node, *prev_node, *next_node;
|
||
|
uint32_t size;
|
||
|
|
||
|
// point to the block descriptor (before user memory so decrement)
|
||
|
freed = ((struct mblock_used *)mem_ptr) - 1;
|
||
|
|
||
|
// point to the first node of the free elements linked list
|
||
|
size = freed->size;
|
||
|
node = mblock_first;
|
||
|
prev_node = NULL;
|
||
|
|
||
|
// sanity checks
|
||
|
BK_ASSERT(freed->magic == MM_MAGIC); /* ASSERT VERIFIED */
|
||
|
BK_ASSERT(size); /* ASSERT VERIFIED */
|
||
|
BK_ASSERT(mem_ptr != NULL); /* ASSERT VERIFIED */
|
||
|
BK_ASSERT((uint32_t)mem_ptr > (uint32_t)node); /* ASSERT VERIFIED */
|
||
|
|
||
|
#if CONFIG_MALLOC_STATIS || CONFIG_MEM_DEBUG
|
||
|
bk_printf("\r\nf:%p,%ld|%s,%d\r\n", freed, freed->size, call_func_name, line);
|
||
|
#endif
|
||
|
|
||
|
// protect accesses to descriptors
|
||
|
vTaskSuspendAll();
|
||
|
|
||
|
while (node != NULL) {
|
||
|
// check if the freed block is right after the current block
|
||
|
if ((uint32_t)freed == ((uint32_t)node + node->size)) {
|
||
|
// append the freed block to the current one
|
||
|
node->size += size;
|
||
|
#ifdef MMGMT_DEBUG
|
||
|
os_memset(freed, MEM_FILL, sizeof(struct mblock_used));
|
||
|
#endif
|
||
|
// check if this merge made the link between free blocks
|
||
|
if ((uint32_t)node->next == ((uint32_t)node + node->size)) {
|
||
|
next_node = node->next;
|
||
|
// add the size of the next node to the current node
|
||
|
node->size += next_node->size;
|
||
|
// update the next of the current node
|
||
|
node->next = next_node->next;
|
||
|
|
||
|
#ifdef MMGMT_DEBUG
|
||
|
os_memset(next_node, MEM_FILL, sizeof(struct mblock_free));
|
||
|
#endif
|
||
|
}
|
||
|
goto free_end;
|
||
|
} else if ((uint32_t)freed < (uint32_t)node) {
|
||
|
// sanity check: can not happen before first node
|
||
|
BK_ASSERT(prev_node != NULL); /* ASSERT VERIFIED */
|
||
|
|
||
|
// update the next pointer of the previous node
|
||
|
prev_node->next = (struct mblock_free *)freed;
|
||
|
|
||
|
// check if the released node is right before the free block
|
||
|
if (((uint32_t)freed + size) == (uint32_t)node) {
|
||
|
// merge the two nodes
|
||
|
((struct mblock_free *)freed)->next = node->next;
|
||
|
((struct mblock_free *)freed)->size = node->size + (uint32_t)node - (uint32_t)freed;
|
||
|
#ifdef MMGMT_DEBUG
|
||
|
os_memset(node, MEM_FILL, sizeof(struct mblock_free));
|
||
|
#endif
|
||
|
} else {
|
||
|
// insert the new node
|
||
|
((struct mblock_free *)freed)->next = node;
|
||
|
((struct mblock_free *)freed)->size = size;
|
||
|
}
|
||
|
goto free_end;
|
||
|
}
|
||
|
|
||
|
// move to the next free block node
|
||
|
prev_node = node;
|
||
|
node = node->next;
|
||
|
}
|
||
|
|
||
|
// if reached here, freed block is after last free block and not contiguous
|
||
|
prev_node->next = (struct mblock_free *)freed;
|
||
|
((struct mblock_free *)freed)->next = NULL;
|
||
|
((struct mblock_free *)freed)->size = size;
|
||
|
|
||
|
free_end:
|
||
|
#ifdef MMGMT_DEBUG
|
||
|
os_memset(mem_ptr, MEM_FILL, size - sizeof(struct mblock_used));
|
||
|
#endif
|
||
|
|
||
|
// end of protection
|
||
|
( void ) xTaskResumeAll();
|
||
|
}
|
||
|
|
||
|
int mm_magic_match(void *mem_ptr)
|
||
|
{
|
||
|
struct mblock_used *freed;
|
||
|
|
||
|
// point to the block descriptor (before user memory so decrement)
|
||
|
freed = ((struct mblock_used *)mem_ptr) - 1;
|
||
|
|
||
|
BK_ASSERT(freed->magic == MM_MAGIC); /* ASSERT VERIFIED */
|
||
|
|
||
|
// sanity checks
|
||
|
return freed->magic == MM_MAGIC;
|
||
|
}
|
||
|
|
||
|
#if CONFIG_MALLOC_STATIS || CONFIG_MEM_DEBUG
|
||
|
void *pvPortMalloc_cm(const char *call_func_name, int line, size_t xWantedSize, int need_zero)
|
||
|
{
|
||
|
return mmgmt_malloc(call_func_name, line, xWantedSize);
|
||
|
}
|
||
|
|
||
|
void *vPortFree_cm(const char *call_func_name, int line, void *pv)
|
||
|
{
|
||
|
mmgmt_free(call_func_name, line, pv);
|
||
|
return NULL;
|
||
|
}
|
||
|
#else
|
||
|
|
||
|
void *pvPortMalloc(size_t xWantedSize)
|
||
|
{
|
||
|
return mmgmt_malloc(xWantedSize);
|
||
|
}
|
||
|
|
||
|
void vPortFree(void *pv)
|
||
|
{
|
||
|
mmgmt_free(pv);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
void *pvPortRealloc(void *pv, size_t xWantedSize)
|
||
|
{
|
||
|
return mmgmt_realloc(pv, xWantedSize);
|
||
|
}
|
||
|
|
||
|
size_t xPortGetFreeHeapSize( void )
|
||
|
{
|
||
|
return mmgmt_alloc_space();
|
||
|
}
|
||
|
|
||
|
// void* os_malloc_wifi_buffer(size_t size)
|
||
|
// {
|
||
|
// #if (CONFIG_SOC_BK7251)
|
||
|
// return (void*)pvPortMalloc(size);
|
||
|
// #else
|
||
|
// return (void*)os_malloc(size);
|
||
|
// #endif
|
||
|
// }
|
||
|
|
||
|
/// @}
|