forked from xuos/xiuos
1266 lines
42 KiB
C
1266 lines
42 KiB
C
/*
|
|
* Copyright (c) 2020 AIIT XUOS Lab
|
|
* XiUOS is licensed under Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
* http://license.coscl.org.cn/MulanPSL2
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PSL v2 for more details.
|
|
*/
|
|
|
|
/**
|
|
* @file: byte_manage.c
|
|
* @brief: memory management file
|
|
* @version: 1.0
|
|
* @author: AIIT XUOS Lab
|
|
* @date: 2020/3/8
|
|
*
|
|
*/
|
|
|
|
#include <xizi.h>
|
|
#include <string.h>
|
|
|
|
#define MEM_STATS
|
|
|
|
/* Covert pointer to other structure */
|
|
#define PTR2ALLOCNODE(pointer) (struct DynamicAllocNode *)(pointer)
|
|
#define PTR2FREENODE(pointer) (struct DynamicFreeNode *)(pointer)
|
|
|
|
/* Calculate the size of AllocNode and FreeNode */
|
|
#define SIZEOF_DYNAMICALLOCNODE_MEM (sizeof(struct DynamicAllocNode))
|
|
#define SIZEOF_PTR_MEM (sizeof(struct DynamicFreeNode *))
|
|
#define SIZEOF_XSFREENODE_MEM (SIZEOF_DYNAMICALLOCNODE_MEM + 2* SIZEOF_PTR_MEM)
|
|
|
|
/* Set the limits of buddy memory */
|
|
#define MEM_LOW_SHIFT (6)
|
|
#define MEM_HIGH_SHIFT (20)
|
|
#define MEM_LOW_RANGE (1 << MEM_LOW_SHIFT)
|
|
#define MEM_HIGH_RANGE (1 << MEM_HIGH_SHIFT)
|
|
#define MEM_LINKNRS (MEM_HIGH_SHIFT-MEM_LOW_SHIFT +1)
|
|
|
|
/* These masks are used to get the flags and data field of memory blocks */
|
|
#define STATIC_BLOCK_MASK 0x80000000
|
|
#define DYNAMIC_BLOCK_MASK 0x40000000
|
|
#define DYNAMIC_BLOCK_NO_EXTMEM_MASK DYNAMIC_BLOCK_MASK
|
|
// #define DYNAMIC_BLOCK_EXTMEM1_MASK 0x40010000 ///< dynamic memory block external SRAM 1
|
|
// #define DYNAMIC_BLOCK_EXTMEM2_MASK 0x40020000 ///< dynamic memory block external SRAM 2
|
|
// #define DYNAMIC_BLOCK_EXTMEM3_MASK 0x40030000 ///< dynamic memory block external SRAM 3
|
|
// #define DYNAMIC_BLOCK_EXTMEM4_MASK 0x40040000 ///< dynamic memory block external SRAM 4
|
|
#define DYNAMIC_BLOCK_EXTMEMn_MASK(n) (DYNAMIC_BLOCK_MASK | (0xFF & n) << 16)
|
|
|
|
#define ALLOC_BLOCK_MASK 0xc0000000
|
|
#define DYNAMIC_REMAINING_MASK 0x3fffffff
|
|
|
|
enum SmallSizeAllocSize {
|
|
SIZEOF_32B = 32,
|
|
SIZEOF_64B = 64,
|
|
};
|
|
|
|
#define SMALL_SIZE_32B(ITEMSIZE) ((ITEMSIZE + SIZEOF_DYNAMICALLOCNODE_MEM) * SMALL_NUMBER_32B) /* Calculate the total size for SIZEOF_32B blocks*/
|
|
#define SMALL_SIZE_64B(ITEMSIZE) ((ITEMSIZE + SIZEOF_DYNAMICALLOCNODE_MEM) * SMALL_NUMBER_64B) /* Calculate the total size for SIZEOF_64B blocks*/
|
|
|
|
#define FREE_LIST_LOCK() DISABLE_INTERRUPT()
|
|
#define FREE_LIST_UNLOCK(lock) ENABLE_INTERRUPT(lock)
|
|
|
|
/**
|
|
* The structure describes an allocated memory block from dynamic buddy memory.
|
|
*/
|
|
struct DynamicAllocNode
|
|
{
|
|
x_size_t size; /* the size of dynamicAllocNode */
|
|
uint32 prev_adj_size; /* the size of the previous adjacent node, (dynamic alloc node or dynamic free node */
|
|
uint32 flag; /* |static_dynamic[32-24]|ext_sram[23-16]|res[15-8]|res[7-0]| */
|
|
};
|
|
|
|
/**
|
|
* The structure describes a released memory block in dynamic buddy memory.
|
|
*/
|
|
struct DynamicFreeNode
|
|
{
|
|
x_size_t size; /* the size of dynamicAllocNode */
|
|
uint32 prev_adj_size; /* the size of the previous adjacent node, (dynamic alloc node or dynamic free node */
|
|
uint32 flag; /* |static_dynamic_region_flag[32-24]|ext_sram_idx[23-16]|res[15-8]|res[7-0]| */
|
|
|
|
struct DynamicFreeNode *next;
|
|
struct DynamicFreeNode *prev;
|
|
};
|
|
|
|
/**
|
|
* The structure is the heart of Dynamic memory.
|
|
*/
|
|
struct DynamicBuddyMemory
|
|
{
|
|
|
|
x_ubase dynamic_buddy_start;
|
|
x_ubase dynamic_buddy_end;
|
|
x_ubase active_memory;
|
|
x_ubase max_ever_usedmem;
|
|
x_ubase static_memory;
|
|
uint64 mm_total_size; /* record the total size of dynamic buddy memory */
|
|
|
|
struct DynamicAllocNode *mm_dynamic_start[1]; /* record the start boundary of dynamic buddy memory */
|
|
struct DynamicAllocNode *mm_dynamic_end[1]; /* record the end boundary of dynamic buddy memory */
|
|
struct DynamicFreeNode mm_freenode_list[MEM_LINKNRS]; /* multiple lists */
|
|
struct DynamicBuddyMemoryDone *done;
|
|
};
|
|
|
|
/**
|
|
* The structure is for static memory mangement, such as SIZEOF_32B and SIZEOF_64B
|
|
*/
|
|
struct segment
|
|
{
|
|
x_size_t block_size; /* record the size of static memory block */
|
|
uint8 * freelist; /* list for all free static memory blocks */
|
|
int block_total_count; /* total static memory blocks */
|
|
int block_free_count; /* the remaining count of static memory blocks */
|
|
struct StaticMemoryDone *done;
|
|
};
|
|
/**
|
|
* The index of static memory blocks
|
|
*/
|
|
enum {
|
|
MM_SEGMENT_32B=0,
|
|
MM_SEGMENT_64B,
|
|
MM_SMALL_SEGMENTS
|
|
};
|
|
|
|
/**
|
|
* The structure is the operation of dynamic alloc node.
|
|
*/
|
|
struct DynamicAllocNodeDone
|
|
{
|
|
int (*JudgeStaticOrDynamic)(struct DynamicAllocNode *address);
|
|
int (*JudgeAllocated)(struct DynamicAllocNode *memory_ptr);
|
|
};
|
|
|
|
struct ByteMemory
|
|
{
|
|
struct DynamicBuddyMemory dynamic_buddy_manager; /* the manager of dynamic buddy memory */
|
|
struct segment static_manager[MM_SMALL_SEGMENTS]; /* the manager of static memory */
|
|
struct DynamicAllocNodeDone *done;
|
|
};
|
|
|
|
/**
|
|
* The structure is the operation of static memory.
|
|
*/
|
|
struct StaticMemoryDone
|
|
{
|
|
void (*init)(struct ByteMemory *byte_memory);
|
|
void* (*malloc)(struct ByteMemory *byte_memory, enum SmallSizeAllocSize size);
|
|
void (*release)(void *pointer);
|
|
};
|
|
|
|
/**
|
|
* The structure is the operation of dynamic memory.
|
|
*/
|
|
struct DynamicBuddyMemoryDone
|
|
{
|
|
void (*init)(struct DynamicBuddyMemory *dynamic_buddy, x_ubase dynamic_buddy_start,x_ubase dynamic_buddy_size);
|
|
void* (*malloc)(struct DynamicBuddyMemory *dynamic_buddy, x_size_t size, uint32 extsram_mask);
|
|
void (*release)(struct ByteMemory *byte_memory, void *pointer);
|
|
int (*JudgeLegal)(struct DynamicBuddyMemory *dynamic_buddy, void *pointer);
|
|
};
|
|
|
|
|
|
static struct ByteMemory ByteManager;
|
|
|
|
#ifdef SEPARATE_COMPILE
|
|
static struct ByteMemory UserByteManager;
|
|
#endif
|
|
|
|
#ifdef MEM_EXTERN_SRAM
|
|
static struct ByteMemory ExtByteManager[EXTSRAM_MAX_NUM] = {0};
|
|
#endif
|
|
/**
|
|
* This function determines whether the address is valid.
|
|
*
|
|
* @param dynamic_buddy
|
|
* @param pointer the memory address
|
|
*
|
|
* @return valid return RET_TRUE; or invalid, return 0.
|
|
*/
|
|
static int JudgeValidAddressRange(struct DynamicBuddyMemory *dynamic_buddy, void *pointer)
|
|
{
|
|
NULL_PARAM_CHECK(dynamic_buddy);
|
|
NULL_PARAM_CHECK(pointer);
|
|
|
|
/* the given address is between the physical start address and physical end address */
|
|
if (((struct DynamicAllocNode *)pointer > dynamic_buddy->mm_dynamic_start[0]) && ((struct DynamicAllocNode *)pointer < dynamic_buddy->mm_dynamic_end[0])) {
|
|
return RET_TRUE;
|
|
}
|
|
/* invalid address */
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* This function judges whether the memory address is in static or dynamic memory.
|
|
*
|
|
* @param address the given memory address
|
|
*
|
|
* @return the memory type, 1 on static memory area; 0 on dynamic memory area
|
|
*/
|
|
static int SmallMemTypeAlloc(struct DynamicAllocNode *address)
|
|
{
|
|
NULL_PARAM_CHECK(address);
|
|
|
|
if(address->flag & STATIC_BLOCK_MASK) {
|
|
return RET_TRUE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* This function judges whether the memory block is allocated.
|
|
*
|
|
* @param memory_ptr the memory block to be judged
|
|
*
|
|
* @return the result, 1 on allocated node; 0 on release node
|
|
*/
|
|
static int MmAllocNode(struct DynamicAllocNode *memory_ptr)
|
|
{
|
|
NULL_PARAM_CHECK(memory_ptr);
|
|
|
|
if(memory_ptr->flag & ALLOC_BLOCK_MASK) {
|
|
return RET_TRUE;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static struct DynamicAllocNodeDone NodeDone = {
|
|
SmallMemTypeAlloc,
|
|
MmAllocNode,
|
|
};
|
|
|
|
/**
|
|
* This function calculates the dynamic buddy mm_freenode_list according the give memory size.
|
|
*
|
|
* @param size the memory size
|
|
*
|
|
* @return the mm_freenode_list index
|
|
*/
|
|
static int CaculateBuddyIndex(x_size_t size)
|
|
{
|
|
int ndx = 0;
|
|
|
|
if (size < MEM_HIGH_RANGE) {
|
|
size >>= MEM_LOW_SHIFT;
|
|
for (; size > 1; ndx++, size /= 2);
|
|
} else {
|
|
ndx = MEM_LINKNRS - 1;
|
|
}
|
|
return ndx;
|
|
}
|
|
|
|
/**
|
|
* This function inserts freenode into dynamic buddy memory.
|
|
*
|
|
* @param dynamic_buddy the heart dynamic memory structure
|
|
* @param release_node the node to be released to dynamic_buddy
|
|
*/
|
|
static void AddNewNodeIntoBuddy(struct DynamicBuddyMemory *dynamic_buddy, struct DynamicFreeNode *release_node)
|
|
{
|
|
int ndx = 0;
|
|
struct DynamicFreeNode *nextFreeNode = NONE;
|
|
struct DynamicFreeNode *prevFreeNode = NONE;
|
|
|
|
NULL_PARAM_CHECK(dynamic_buddy);
|
|
NULL_PARAM_CHECK(release_node);
|
|
|
|
/* calculate the index value */
|
|
ndx = CaculateBuddyIndex(release_node->size);
|
|
|
|
/* find the most suitable location, which is sorted by size */
|
|
for (prevFreeNode = &dynamic_buddy->mm_freenode_list[ndx], nextFreeNode = dynamic_buddy->mm_freenode_list[ndx].next;
|
|
nextFreeNode && nextFreeNode->size && nextFreeNode->size < release_node->size;
|
|
prevFreeNode = nextFreeNode, nextFreeNode = nextFreeNode->next);
|
|
|
|
/* insert the release_node into the linklist */
|
|
prevFreeNode->next = release_node;
|
|
release_node->prev = prevFreeNode;
|
|
release_node->next = nextFreeNode;
|
|
|
|
if (nextFreeNode) {
|
|
nextFreeNode->prev = release_node;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function initializes the structure of dynamic buddy memory.
|
|
*
|
|
* @param dynamic_buddy the heart buddy structure
|
|
* @param dynamic_buddy_start the physical start address of dynamic memory
|
|
* @param dynamic_buddy_size the size of dynamic memory
|
|
*/
|
|
static void InitBuddy(struct DynamicBuddyMemory *dynamic_buddy, x_ubase dynamic_buddy_start,x_ubase dynamic_buddy_size)
|
|
{
|
|
struct DynamicFreeNode *node = NONE;
|
|
|
|
NULL_PARAM_CHECK(dynamic_buddy);
|
|
|
|
/* record the dynamic memory size */
|
|
dynamic_buddy->mm_total_size += (uint64)dynamic_buddy_size;
|
|
|
|
/* record the start boundary of dynamic buddy memory */
|
|
dynamic_buddy->mm_dynamic_start[0] = PTR2ALLOCNODE(dynamic_buddy_start);
|
|
dynamic_buddy->mm_dynamic_start[0]->size = SIZEOF_DYNAMICALLOCNODE_MEM;
|
|
dynamic_buddy->mm_dynamic_start[0]->prev_adj_size = 0;
|
|
dynamic_buddy->mm_dynamic_start[0]->flag = DYNAMIC_BLOCK_MASK;
|
|
|
|
/* the initialized free node */
|
|
node =(struct DynamicFreeNode *) ((x_ubase)dynamic_buddy_start + SIZEOF_DYNAMICALLOCNODE_MEM);
|
|
node->size=(dynamic_buddy_size - 2* SIZEOF_DYNAMICALLOCNODE_MEM);
|
|
node->prev_adj_size= SIZEOF_DYNAMICALLOCNODE_MEM;
|
|
node->flag= 0;
|
|
|
|
/* record the end boundary of dynamic buddy memory */
|
|
dynamic_buddy->mm_dynamic_end[0] = PTR2ALLOCNODE((x_ubase)dynamic_buddy_start + (x_ubase)dynamic_buddy_size - SIZEOF_DYNAMICALLOCNODE_MEM);
|
|
dynamic_buddy->mm_dynamic_end[0]->size = SIZEOF_DYNAMICALLOCNODE_MEM;
|
|
dynamic_buddy->mm_dynamic_end[0]->prev_adj_size = node->size;
|
|
dynamic_buddy->mm_dynamic_end[0]->flag = DYNAMIC_BLOCK_MASK;
|
|
|
|
/* insert node into dynamic buddy memory */
|
|
AddNewNodeIntoBuddy(dynamic_buddy,node);
|
|
}
|
|
|
|
/**
|
|
* This function allocates dynamic memory from dynamic buddy memory.
|
|
*
|
|
* @param dynamic_buddy the heart dynamic buddy structure
|
|
* @param size the memory size to be allocated
|
|
* @param extsram_mask mask the memory region comes from ext sram
|
|
*
|
|
* @return pointer address on success; NULL on failure
|
|
*/
|
|
static void* BigMemMalloc(struct DynamicBuddyMemory *dynamic_buddy, x_size_t size, uint32 extsram_mask)
|
|
{
|
|
int ndx = 0;
|
|
uint32 allocsize = 0;
|
|
void *result = NONE;
|
|
struct DynamicFreeNode *node = NONE;
|
|
|
|
NULL_PARAM_CHECK(dynamic_buddy);
|
|
|
|
/* calculate the real size */
|
|
allocsize = size + SIZEOF_DYNAMICALLOCNODE_MEM;
|
|
/* if the size exceeds the upper limit, return MEM_LINKNRS - 1 */
|
|
if (allocsize >= MEM_HIGH_RANGE) {
|
|
ndx = MEM_LINKNRS - 1;
|
|
} else {
|
|
/* convert the request size into a linklist index */
|
|
ndx = CaculateBuddyIndex(allocsize);
|
|
}
|
|
|
|
/* best-fit method */
|
|
node = dynamic_buddy->mm_freenode_list[ndx].next;
|
|
while(ndx < MEM_LINKNRS && (NONE == node || node->size < allocsize)) {
|
|
if (NONE == node) {
|
|
ndx++;
|
|
if (ndx == MEM_LINKNRS) { // no space to allocate
|
|
return NONE;
|
|
}
|
|
node = dynamic_buddy->mm_freenode_list[ndx].next;
|
|
} else {
|
|
node = node->next;
|
|
}
|
|
}
|
|
/* get the best-fit freeNode */
|
|
if (node && (node->size >= allocsize)) {
|
|
struct DynamicFreeNode *remainder;
|
|
struct DynamicFreeNode *next;
|
|
uint32 remaining;
|
|
|
|
node->prev->next = node->next;
|
|
if (node->next) {
|
|
node->next->prev = node->prev;
|
|
}
|
|
|
|
remaining = node->size - allocsize;
|
|
if (remaining >= MEM_LOW_RANGE){
|
|
next = PTR2FREENODE(((char *)node) + node->size);
|
|
|
|
/* create the remainder node */
|
|
remainder = PTR2FREENODE(((char *)node) + allocsize);
|
|
remainder->size = remaining;
|
|
|
|
remainder->prev_adj_size = allocsize;
|
|
remainder->flag = 0;
|
|
|
|
/* adjust the size of the node */
|
|
node->size = allocsize;
|
|
next->prev_adj_size = remaining;
|
|
|
|
/* insert the remainder freeNode back into the dynamic buddy memory */
|
|
AddNewNodeIntoBuddy(dynamic_buddy, remainder);
|
|
}
|
|
|
|
/* handle the case of an exact size match */
|
|
node->flag = extsram_mask;
|
|
result = (void *)((char *)node + SIZEOF_DYNAMICALLOCNODE_MEM);
|
|
}
|
|
|
|
/* failure allocation */
|
|
if (result == NONE) {
|
|
#ifndef MEM_EXTERN_SRAM
|
|
KPrintf("%s: allocation failed, size %d.\n", __func__, size);
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
#ifdef MEM_STATS
|
|
/* statistic memory usage */
|
|
dynamic_buddy->active_memory += node->size;
|
|
if(dynamic_buddy->active_memory > dynamic_buddy->max_ever_usedmem)
|
|
dynamic_buddy->max_ever_usedmem = dynamic_buddy->active_memory;
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* This function will release dynamic memory. It is called by x_free function.
|
|
*
|
|
* @param pointer
|
|
*/
|
|
static void BigMemFree( struct ByteMemory *byte_memory, void *pointer)
|
|
{
|
|
struct DynamicFreeNode *node = NONE;
|
|
struct DynamicFreeNode *prev = NONE;
|
|
struct DynamicFreeNode *next = NONE;
|
|
|
|
NULL_PARAM_CHECK(byte_memory);
|
|
NULL_PARAM_CHECK(pointer);
|
|
|
|
/* get the freeNode according the pointer address */
|
|
node = PTR2FREENODE((char*)pointer - SIZEOF_DYNAMICALLOCNODE_MEM);
|
|
|
|
#ifdef MEM_STATS
|
|
/* statistic memory information */
|
|
byte_memory->dynamic_buddy_manager.active_memory -= node->size;
|
|
#endif
|
|
/* get the next sibling freeNode */
|
|
next = PTR2FREENODE((char*)node + node->size);
|
|
|
|
if (((next->flag & DYNAMIC_BLOCK_MASK) == 0)) {
|
|
struct DynamicAllocNode *andbeyond;
|
|
|
|
andbeyond = PTR2ALLOCNODE((char*)next + next->size);
|
|
next->prev->next = next->next;
|
|
if(next->next) {
|
|
next->next->prev = next->prev;
|
|
}
|
|
|
|
node->size += next->size;
|
|
andbeyond->prev_adj_size = node->size;
|
|
next = (struct DynamicFreeNode*)andbeyond;
|
|
}
|
|
/* get the prev sibling freeNode */
|
|
prev = (struct DynamicFreeNode*)((char*)node - node->prev_adj_size );
|
|
if ((prev->flag & DYNAMIC_BLOCK_MASK) == 0) {
|
|
|
|
prev->prev->next=prev->next;
|
|
if(prev->next){
|
|
prev->next->prev = prev->prev;
|
|
}
|
|
prev->size += node->size;
|
|
next->prev_adj_size = prev->size;
|
|
node = prev;
|
|
}
|
|
node->flag = 0;
|
|
|
|
/* insert freeNode into dynamic buddy memory */
|
|
AddNewNodeIntoBuddy(&byte_memory->dynamic_buddy_manager, node);
|
|
}
|
|
|
|
static struct DynamicBuddyMemoryDone DynamicDone = {
|
|
InitBuddy,
|
|
BigMemMalloc,
|
|
BigMemFree,
|
|
JudgeValidAddressRange,
|
|
};
|
|
|
|
/**
|
|
* This function initializes the static segment struction.
|
|
*
|
|
* @param static_segment the static_segment to be initialized
|
|
*/
|
|
static void SmallMemInit(struct ByteMemory *byte_memory)
|
|
{
|
|
register x_size_t offset = 0;
|
|
struct segment *item = NONE;
|
|
struct DynamicAllocNode *node = NONE;
|
|
|
|
NULL_PARAM_CHECK(byte_memory);
|
|
|
|
item = &byte_memory->static_manager[MM_SEGMENT_32B];
|
|
|
|
/* allocate memory zone for [32b] */
|
|
item->freelist = byte_memory->dynamic_buddy_manager.done->malloc(&byte_memory->dynamic_buddy_manager, SMALL_SIZE_32B(SIZEOF_32B), DYNAMIC_BLOCK_NO_EXTMEM_MASK);
|
|
if(!item->freelist) {
|
|
KPrintf("%s: no memory for small memory[32B].\n",__func__);
|
|
item->block_free_count = 0;
|
|
return;
|
|
}
|
|
|
|
/* initialize the attributes of static_segment_32B */
|
|
item->block_size = SIZEOF_32B;
|
|
item->block_total_count = SMALL_NUMBER_32B;
|
|
item->block_free_count = SMALL_NUMBER_32B;
|
|
|
|
for(offset = 0; offset < item->block_total_count; offset++) {
|
|
node = PTR2ALLOCNODE((char*)item->freelist + offset * (SIZEOF_32B + SIZEOF_DYNAMICALLOCNODE_MEM));
|
|
node->size =(x_size_t) ((char*)item->freelist + (offset + 1) * (SIZEOF_32B + SIZEOF_DYNAMICALLOCNODE_MEM));
|
|
node->flag = STATIC_BLOCK_MASK;
|
|
}
|
|
node->size = NONE;
|
|
|
|
item = &byte_memory->static_manager[MM_SEGMENT_64B];
|
|
|
|
/* allocate memory zone for [64B] */
|
|
item->freelist = byte_memory->dynamic_buddy_manager.done->malloc(&byte_memory->dynamic_buddy_manager, SMALL_SIZE_64B(SIZEOF_64B),DYNAMIC_BLOCK_NO_EXTMEM_MASK);
|
|
if(!item->freelist) {
|
|
KPrintf("%s: no memory for small memory[64B].\n",__func__);
|
|
return;
|
|
}
|
|
|
|
/* initialize the attributes of static_segment_64B */
|
|
item->block_size = SIZEOF_64B;
|
|
item->block_total_count = SMALL_NUMBER_64B;
|
|
item->block_free_count = SMALL_NUMBER_64B;
|
|
|
|
for(offset = 0; offset < item->block_total_count; offset++) {
|
|
node = PTR2ALLOCNODE((char*)item->freelist + offset * (SIZEOF_64B + SIZEOF_DYNAMICALLOCNODE_MEM));
|
|
node->size =(x_size_t) ((char*)item->freelist + (offset + 1) * (SIZEOF_64B + SIZEOF_DYNAMICALLOCNODE_MEM));
|
|
node->flag = STATIC_BLOCK_MASK;
|
|
}
|
|
node->size = NONE;
|
|
|
|
#ifdef MEM_STATS
|
|
/* statistic static memory information */
|
|
byte_memory->dynamic_buddy_manager.static_memory = SMALL_NUMBER_64B * SIZEOF_64B + SMALL_NUMBER_32B * SIZEOF_32B;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
*
|
|
* This function will release the static memory block to static segment.
|
|
*
|
|
* @param pointer the memory to be released
|
|
*/
|
|
static void SmallMemFree(void *pointer)
|
|
{
|
|
struct segment *static_segment = NONE;
|
|
struct DynamicAllocNode *node = NONE;
|
|
|
|
NULL_PARAM_CHECK(pointer);
|
|
|
|
/* get the allocNode */
|
|
node = PTR2ALLOCNODE((char*)pointer - SIZEOF_DYNAMICALLOCNODE_MEM);
|
|
static_segment = (struct segment*)(x_size_t)node->size;
|
|
|
|
/* update the statistic information of static_segment */
|
|
node->size = (x_size_t)static_segment->freelist;
|
|
static_segment->freelist = (uint8 *)node;
|
|
node->flag = 0; // it's unnecessary, actually
|
|
|
|
static_segment->block_free_count++;
|
|
|
|
/* parameter detection */
|
|
CHECK(static_segment->block_free_count <= static_segment->block_total_count);
|
|
}
|
|
|
|
/**
|
|
* This funcation allocates a static memory block from static segment.
|
|
*
|
|
* @param static_segment the heart static segment structure to allocate static memory
|
|
* @param size the size to be allocated
|
|
*
|
|
* @return pointer address on success; NULL on failure
|
|
*/
|
|
static void *SmallMemMalloc(struct ByteMemory *byte_memory, enum SmallSizeAllocSize size)
|
|
{
|
|
uint8 i = 0;
|
|
void *result = NONE;
|
|
struct DynamicAllocNode *node = NONE;
|
|
struct segment *static_segment = NONE;
|
|
|
|
NULL_PARAM_CHECK(byte_memory);
|
|
|
|
if (size == SIZEOF_32B)
|
|
static_segment = &byte_memory->static_manager[0];
|
|
else
|
|
static_segment = &byte_memory->static_manager[1];
|
|
|
|
/* current static segment has free static memory block */
|
|
if(static_segment->block_free_count > 0) {
|
|
/* get the head static memory block */
|
|
result = static_segment->freelist;
|
|
node = PTR2ALLOCNODE(static_segment->freelist);
|
|
node->flag = STATIC_BLOCK_MASK;
|
|
|
|
/* update the statistic information of static segment */
|
|
static_segment->freelist = (uint8 *)(long)(node->size);
|
|
static_segment->block_free_count--;
|
|
node->size = (long)static_segment;
|
|
}
|
|
|
|
if (NONE != result) {
|
|
/* return static memory block */
|
|
return (char*)result + SIZEOF_DYNAMICALLOCNODE_MEM;
|
|
}
|
|
|
|
/* the static memory block is exhausted, now turn to dynamic buddy memory for allocation. */
|
|
// fall to dynamic allocation
|
|
return NONE;
|
|
}
|
|
|
|
static struct StaticMemoryDone StaticDone = {
|
|
SmallMemInit,
|
|
SmallMemMalloc,
|
|
SmallMemFree,
|
|
};
|
|
|
|
/**
|
|
* This function is provided to allocate memory block.
|
|
*
|
|
* @param size the memory size to be allocated
|
|
*
|
|
* @return pointer on success; NULL on failure
|
|
*/
|
|
void *x_malloc(x_size_t size)
|
|
{
|
|
uint8 i = 0;
|
|
void *ret = NONE;
|
|
register x_base lock = 0;
|
|
|
|
/* hold lock before allocation */
|
|
lock = FREE_LIST_LOCK();
|
|
|
|
/* alignment */
|
|
size = ALIGN_MEN_UP(size, MEM_ALIGN_SIZE);
|
|
|
|
/* parameter detection */
|
|
#ifdef MEM_EXTERN_SRAM
|
|
/* parameter detection */
|
|
if (size == 0) {
|
|
FREE_LIST_UNLOCK(lock);
|
|
return NONE;
|
|
}
|
|
if ((size > ByteManager.dynamic_buddy_manager.dynamic_buddy_end - ByteManager.dynamic_buddy_manager.dynamic_buddy_start - ByteManager.dynamic_buddy_manager.active_memory)) {
|
|
/* alignment */
|
|
size = ALIGN_MEN_UP(size, MEM_ALIGN_SIZE);
|
|
goto try_extmem;
|
|
}
|
|
#else
|
|
/* parameter detection */
|
|
if ((size == 0) || (size > ByteManager.dynamic_buddy_manager.dynamic_buddy_end - ByteManager.dynamic_buddy_manager.dynamic_buddy_start - ByteManager.dynamic_buddy_manager.active_memory)) {
|
|
FREE_LIST_UNLOCK(lock);
|
|
return NONE;
|
|
}
|
|
#endif
|
|
|
|
/* determine allocation operation from static segments or dynamic buddy memory */
|
|
#ifdef KERNEL_SMALL_MEM_ALLOC
|
|
if (size <= SIZEOF_32B) {
|
|
ret = ByteManager.static_manager[0].done->malloc(&ByteManager, SIZEOF_32B);
|
|
} else if (size <= SIZEOF_64B) {
|
|
ret = ByteManager.static_manager[1].done->malloc(&ByteManager, SIZEOF_64B);
|
|
}
|
|
#endif
|
|
|
|
if (ret == NONE) {
|
|
ret = ByteManager.dynamic_buddy_manager.done->malloc(&ByteManager.dynamic_buddy_manager, size, DYNAMIC_BLOCK_NO_EXTMEM_MASK);
|
|
if (ret != NONE) {
|
|
CHECK(ByteManager.dynamic_buddy_manager.done->JudgeLegal(&ByteManager.dynamic_buddy_manager, ret - SIZEOF_DYNAMICALLOCNODE_MEM));
|
|
}
|
|
|
|
#ifdef MEM_EXTERN_SRAM
|
|
try_extmem:
|
|
if (NONE == ret) {
|
|
for (i = 0; i < EXTSRAM_MAX_NUM; i++) {
|
|
if (NONE != ExtByteManager[i].done) {
|
|
ret = ExtByteManager[i].dynamic_buddy_manager.done->malloc(&ExtByteManager[i].dynamic_buddy_manager, size, DYNAMIC_BLOCK_EXTMEMn_MASK(i + 1));
|
|
if (ret) {
|
|
CHECK(ExtByteManager[i].dynamic_buddy_manager.done->JudgeLegal(&ExtByteManager[i].dynamic_buddy_manager, ret - SIZEOF_DYNAMICALLOCNODE_MEM));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* release lock */
|
|
FREE_LIST_UNLOCK(lock);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* This function is provided to re-allocate memory block.
|
|
*
|
|
* @param pointer the old memory pointer
|
|
* @param size the memory size to be re-allocated
|
|
*
|
|
* @return pointer on success; NULL on failure
|
|
*/
|
|
void* x_realloc(void* pointer, x_size_t size)
|
|
{
|
|
x_size_t newsize = 0;
|
|
x_size_t oldsize = 0;
|
|
void* newmem = NONE;
|
|
struct DynamicAllocNode* oldnode = NONE;
|
|
|
|
/* the given pointer is NULL */
|
|
if (pointer == NONE)
|
|
return x_malloc(size);
|
|
|
|
/* parameter detection */
|
|
if (size == 0) {
|
|
x_free(pointer);
|
|
return NONE;
|
|
}
|
|
CHECK(ByteManager.dynamic_buddy_manager.done->JudgeLegal(&ByteManager.dynamic_buddy_manager, pointer));
|
|
|
|
/* alignment and calculate the real size */
|
|
newsize = ALIGN_MEN_UP(size, MEM_ALIGN_SIZE);
|
|
newsize += SIZEOF_DYNAMICALLOCNODE_MEM;
|
|
|
|
oldnode = PTR2ALLOCNODE((char*)pointer - SIZEOF_DYNAMICALLOCNODE_MEM);
|
|
CHECK(ByteManager.done->JudgeAllocated(oldnode));
|
|
|
|
/* achieve the old memory size */
|
|
if (ByteManager.done->JudgeStaticOrDynamic(oldnode)) {
|
|
oldsize = ((struct segment*)(long)(oldnode->size))->block_size;
|
|
} else {
|
|
oldsize = oldnode->size - SIZEOF_DYNAMICALLOCNODE_MEM;
|
|
}
|
|
|
|
/* allocate new memory */
|
|
newmem = x_malloc(size);
|
|
if (newmem == NONE) {
|
|
return NONE;
|
|
}
|
|
|
|
/* copy the old memory and then release old memory pointer */
|
|
memcpy((char*)newmem, (char*)pointer, size > oldsize ? oldsize : size);
|
|
x_free(pointer);
|
|
|
|
return newmem;
|
|
}
|
|
|
|
/**
|
|
* This function will allocate memory blocks and then clear the memory.
|
|
*
|
|
* @param count the number of memory blocks
|
|
* @param size the size of a memory block
|
|
*
|
|
* @return pointer on success; NULL on failure
|
|
*/
|
|
void* x_calloc(x_size_t count, x_size_t size)
|
|
{
|
|
void* p = NONE;
|
|
|
|
/* parameter detection */
|
|
if (count * size > ByteManager.dynamic_buddy_manager.dynamic_buddy_end - ByteManager.dynamic_buddy_manager.dynamic_buddy_start - ByteManager.dynamic_buddy_manager.active_memory)
|
|
return NONE;
|
|
|
|
/* calls x_malloc to allocate count * size memory */
|
|
p = x_malloc(count * size);
|
|
|
|
/* zero the memory */
|
|
if (p)
|
|
memset((char*)p, 0, count * size);
|
|
|
|
return p;
|
|
}
|
|
|
|
/**
|
|
* This function is provided to release memory block.
|
|
*
|
|
* @param pointer the memory to be released
|
|
*/
|
|
void x_free(void* pointer)
|
|
{
|
|
x_base lock = 0;
|
|
struct DynamicAllocNode* node = NONE;
|
|
|
|
/* parameter detection */
|
|
if (pointer == NONE) {
|
|
return;
|
|
}
|
|
|
|
/* hold lock before release */
|
|
lock = FREE_LIST_LOCK();
|
|
|
|
if (!ByteManager.dynamic_buddy_manager.done->JudgeLegal(&ByteManager.dynamic_buddy_manager, pointer)) {
|
|
FREE_LIST_UNLOCK(lock);
|
|
SYS_ERR("[%s] Freeing a unallocated address.\n", __func__);
|
|
return;
|
|
}
|
|
|
|
node = PTR2ALLOCNODE((char*)pointer - SIZEOF_DYNAMICALLOCNODE_MEM);
|
|
CHECK(ByteManager.done->JudgeAllocated(node));
|
|
|
|
/* judge release the memory block ro static_segment or dynamic buddy memory */
|
|
#ifdef KERNEL_SMALL_MEM_ALLOC
|
|
if (node->flag & STATIC_BLOCK_MASK) {
|
|
ByteManager.static_manager->done->release(pointer);
|
|
} else
|
|
#endif
|
|
{
|
|
#ifdef MEM_EXTERN_SRAM
|
|
/* judge the pointer is not malloced from extern memory*/
|
|
if (0 == (node->flag & 0xFF0000)) {
|
|
ByteManager.dynamic_buddy_manager.done->release(&ByteManager, pointer);
|
|
}
|
|
|
|
/* judge the pointer is malloced from extern memory*/
|
|
if (0 != (node->flag & 0xFF0000)) {
|
|
ExtByteManager[((node->flag & 0xFF0000) >> 16) - 1].dynamic_buddy_manager.done->release(&ExtByteManager[((node->flag & 0xFF0000) >> 16) - 1], pointer);
|
|
}
|
|
#else
|
|
ByteManager.dynamic_buddy_manager.done->release(&ByteManager, pointer);
|
|
#endif
|
|
}
|
|
|
|
/* release the lock */
|
|
FREE_LIST_UNLOCK(lock);
|
|
}
|
|
|
|
#ifdef MEM_EXTERN_SRAM
|
|
/**
|
|
* This function initializes the dynamic buddy memory of extern sram.
|
|
*
|
|
* @param start_phy_address the start physical address for static and dynamic memory
|
|
* @param end_phy_address the end physical address for static and dynamic memory
|
|
* @param extsram_idx the idx of extsram chip
|
|
*/
|
|
void ExtSramInitBoardMemory(void* start_phy_address, void* end_phy_address, uint8 extsram_idx)
|
|
{
|
|
register x_size_t offset = 0;
|
|
|
|
NULL_PARAM_CHECK(start_phy_address);
|
|
NULL_PARAM_CHECK(end_phy_address);
|
|
|
|
KDEBUG_NOT_IN_INTERRUPT;
|
|
struct DynamicBuddyMemory* uheap = &ExtByteManager[extsram_idx].dynamic_buddy_manager;
|
|
|
|
/* align begin and end addr to page */
|
|
ExtByteManager[extsram_idx].dynamic_buddy_manager.dynamic_buddy_start = ALIGN_MEN_UP((x_ubase)start_phy_address, MM_PAGE_SIZE);
|
|
ExtByteManager[extsram_idx].dynamic_buddy_manager.dynamic_buddy_end = ALIGN_MEN_DOWN((x_ubase)end_phy_address, MM_PAGE_SIZE);
|
|
KPrintf("%s: 0x%x-0x%x extsram_idx = %d\n", __func__, ExtByteManager[extsram_idx].dynamic_buddy_manager.dynamic_buddy_start, ExtByteManager[extsram_idx].dynamic_buddy_manager.dynamic_buddy_end, extsram_idx);
|
|
|
|
/* parameter detection */
|
|
if (ExtByteManager[extsram_idx].dynamic_buddy_manager.dynamic_buddy_start >= ExtByteManager[extsram_idx].dynamic_buddy_manager.dynamic_buddy_end) {
|
|
KPrintf("ExtSramInitBoardMemory, wrong address[0x%x - 0x%x]\n",
|
|
(x_ubase)start_phy_address, (x_ubase)end_phy_address);
|
|
return;
|
|
}
|
|
|
|
uheap->mm_total_size = 0;
|
|
memset(uheap->mm_freenode_list, 0, SIZEOF_XSFREENODE_MEM * MEM_LINKNRS);
|
|
|
|
/* initialize the freeNodeList */
|
|
for (offset = 1; offset < MEM_LINKNRS; offset++) {
|
|
uheap->mm_freenode_list[offset - 1].next = &uheap->mm_freenode_list[offset];
|
|
uheap->mm_freenode_list[offset].prev = &uheap->mm_freenode_list[offset - 1];
|
|
}
|
|
|
|
ExtByteManager[extsram_idx].dynamic_buddy_manager.done = &DynamicDone;
|
|
ExtByteManager[extsram_idx].done = &NodeDone;
|
|
|
|
/* dynamic buddy memory initialization */
|
|
ExtByteManager[extsram_idx].dynamic_buddy_manager.done->init(&ExtByteManager[extsram_idx].dynamic_buddy_manager, ExtByteManager[extsram_idx].dynamic_buddy_manager.dynamic_buddy_start, ExtByteManager[extsram_idx].dynamic_buddy_manager.dynamic_buddy_end - ExtByteManager[extsram_idx].dynamic_buddy_manager.dynamic_buddy_start);
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* This function initializes the static segments and dynamic buddy memory structures.
|
|
*
|
|
* @param start_phy_address the start physical address for static and dynamic memory
|
|
* @param end_phy_address the end physical address for static and dynamic memory
|
|
*/
|
|
void InitBoardMemory(void* start_phy_address, void* end_phy_address)
|
|
{
|
|
register x_size_t offset = 0;
|
|
|
|
NULL_PARAM_CHECK(start_phy_address);
|
|
NULL_PARAM_CHECK(end_phy_address);
|
|
|
|
KDEBUG_NOT_IN_INTERRUPT;
|
|
struct DynamicBuddyMemory* mheap = &ByteManager.dynamic_buddy_manager;
|
|
|
|
/* align begin and end addr to page */
|
|
ByteManager.dynamic_buddy_manager.dynamic_buddy_start = ALIGN_MEN_UP((x_ubase)start_phy_address, MM_PAGE_SIZE);
|
|
ByteManager.dynamic_buddy_manager.dynamic_buddy_end = ALIGN_MEN_DOWN((x_ubase)end_phy_address, MM_PAGE_SIZE);
|
|
// KPrintf("%s: 0x%x-0x%x \n",__func__,ByteManager.dynamic_buddy_manager.dynamic_buddy_start,ByteManager.dynamic_buddy_manager.dynamic_buddy_end);
|
|
|
|
/* parameter detection */
|
|
if (ByteManager.dynamic_buddy_manager.dynamic_buddy_start >= ByteManager.dynamic_buddy_manager.dynamic_buddy_end) {
|
|
// KPrintf("InitBoardMemory, wrong address[0x%x - 0x%x]\n", (x_ubase)start_phy_address, (x_ubase)end_phy_address);
|
|
SYS_KDEBUG_LOG(KDBG_MEM, ("InitBoardMemory, wrong address[0x%x - 0x%x]\n", (x_ubase)start_phy_address, (x_ubase)end_phy_address));
|
|
return;
|
|
}
|
|
|
|
mheap->mm_total_size = 0;
|
|
memset(mheap->mm_freenode_list, 0, SIZEOF_XSFREENODE_MEM * MEM_LINKNRS);
|
|
|
|
/* initialize the freeNodeList */
|
|
for (offset = 1; offset < MEM_LINKNRS; offset++) {
|
|
mheap->mm_freenode_list[offset - 1].next = &mheap->mm_freenode_list[offset];
|
|
mheap->mm_freenode_list[offset].prev = &mheap->mm_freenode_list[offset - 1];
|
|
}
|
|
|
|
ByteManager.dynamic_buddy_manager.done = &DynamicDone;
|
|
ByteManager.static_manager[MM_SEGMENT_32B].done = &StaticDone;
|
|
ByteManager.static_manager[MM_SEGMENT_64B].done = &StaticDone;
|
|
ByteManager.done = &NodeDone;
|
|
|
|
/* dynamic buddy memory initialization */
|
|
ByteManager.dynamic_buddy_manager.done->init(&ByteManager.dynamic_buddy_manager, ByteManager.dynamic_buddy_manager.dynamic_buddy_start, ByteManager.dynamic_buddy_manager.dynamic_buddy_end - ByteManager.dynamic_buddy_manager.dynamic_buddy_start);
|
|
|
|
/* dynamic static segments initialization */
|
|
#ifdef KERNEL_SMALL_MEM_ALLOC
|
|
ByteManager.static_manager->done->init(&ByteManager);
|
|
#endif
|
|
}
|
|
|
|
#ifdef SEPARATE_COMPILE
|
|
|
|
/**
|
|
* This function is provided to allocate user memory block.
|
|
*
|
|
* @param size the memory size to be allocated
|
|
*
|
|
* @return pointer on success; NULL on failure
|
|
*/
|
|
void* x_umalloc(x_size_t size)
|
|
{
|
|
uint8 i = 0;
|
|
void* ret = NONE;
|
|
register x_base lock = 0;
|
|
|
|
#ifdef MEM_EXTERN_SRAM
|
|
/* parameter detection */
|
|
if (size == 0) {
|
|
return NONE;
|
|
}
|
|
if ((size > ByteManager.dynamic_buddy_manager.dynamic_buddy_end - ByteManager.dynamic_buddy_manager.dynamic_buddy_start - ByteManager.dynamic_buddy_manager.active_memory)) {
|
|
lock = FREE_LIST_LOCK();
|
|
/* alignment */
|
|
size = ALIGN_MEN_UP(size, MEM_ALIGN_SIZE);
|
|
goto try_extmem;
|
|
}
|
|
|
|
#else
|
|
/* parameter detection */
|
|
if ((size == 0) || (size > UserByteManager.dynamic_buddy_manager.dynamic_buddy_end - UserByteManager.dynamic_buddy_manager.dynamic_buddy_start - UserByteManager.dynamic_buddy_manager.active_memory))
|
|
return NONE;
|
|
#endif
|
|
|
|
/* hold lock before allocation */
|
|
lock = FREE_LIST_LOCK();
|
|
/* alignment */
|
|
size = ALIGN_MEN_UP(size, MEM_ALIGN_SIZE);
|
|
ret = UserByteManager.dynamic_buddy_manager.done->malloc(&UserByteManager.dynamic_buddy_manager, size, DYNAMIC_BLOCK_NO_EXTMEM_MASK);
|
|
if (ret != NONE)
|
|
CHECK(UserByteManager.dynamic_buddy_manager.done->JudgeLegal(&UserByteManager.dynamic_buddy_manager, ret - SIZEOF_DYNAMICALLOCNODE_MEM));
|
|
|
|
#ifdef MEM_EXTERN_SRAM
|
|
try_extmem:
|
|
if (NONE == ret) {
|
|
for (i = 0; i < EXTSRAM_MAX_NUM; i++) {
|
|
if (NONE != ExtByteManager[i].done) {
|
|
ret = ExtByteManager[i].dynamic_buddy_manager.done->malloc(&ExtByteManager[i].dynamic_buddy_manager, size, DYNAMIC_BLOCK_EXTMEMn_MASK(i + 1));
|
|
if (ret) {
|
|
CHECK(ExtByteManager[i].dynamic_buddy_manager.done->JudgeLegal(&ExtByteManager[i].dynamic_buddy_manager, ret - SIZEOF_DYNAMICALLOCNODE_MEM));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
/* release lock */
|
|
FREE_LIST_UNLOCK(lock);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* This function is provided to re-allocate memory block.
|
|
*
|
|
* @param pointer the old memory pointer
|
|
* @param size the memory size to be re-allocated
|
|
*
|
|
* @return pointer on success; NULL on failure
|
|
*/
|
|
void* x_urealloc(void* pointer, x_size_t size)
|
|
{
|
|
x_size_t newsize = 0;
|
|
x_size_t oldsize = 0;
|
|
void* newmem = NONE;
|
|
struct DynamicAllocNode* oldnode = NONE;
|
|
|
|
/* the given pointer is NULL */
|
|
if (pointer == NONE)
|
|
return x_umalloc(size);
|
|
|
|
/* parameter detection */
|
|
if (size == 0) {
|
|
x_ufree(pointer);
|
|
return NONE;
|
|
}
|
|
CHECK(UserByteManager.dynamic_buddy_manager.done->JudgeLegal(&UserByteManager.dynamic_buddy_manager, pointer));
|
|
|
|
/* alignment and calculate the real size */
|
|
newsize = ALIGN_MEN_UP(size, MEM_ALIGN_SIZE);
|
|
newsize += SIZEOF_DYNAMICALLOCNODE_MEM;
|
|
|
|
oldnode = PTR2ALLOCNODE((char*)pointer - SIZEOF_DYNAMICALLOCNODE_MEM);
|
|
CHECK(UserByteManager.done->JudgeAllocated(oldnode));
|
|
|
|
/* achieve the old memory size */
|
|
if (UserByteManager.done->JudgeStaticOrDynamic(oldnode)) {
|
|
oldsize = ((struct segment*)(oldnode->size))->block_size;
|
|
} else {
|
|
oldsize = oldnode->size - SIZEOF_DYNAMICALLOCNODE_MEM;
|
|
}
|
|
|
|
/* allocate new memory */
|
|
newmem = x_umalloc(size);
|
|
if (newmem == NONE) {
|
|
return NONE;
|
|
}
|
|
|
|
/* copy the old memory and then release old memory pointer */
|
|
memcpy((char*)newmem, (char*)pointer, size > oldsize ? oldsize : size);
|
|
x_ufree(pointer);
|
|
|
|
return newmem;
|
|
}
|
|
|
|
/**
|
|
* This function will allocate memory blocks and then clear the memory.
|
|
*
|
|
* @param count the number of memory blocks
|
|
* @param size the size of a memory block
|
|
*
|
|
* @return pointer on success; NULL on failure
|
|
*/
|
|
void* x_ucalloc(x_size_t count, x_size_t size)
|
|
{
|
|
void* p = NONE;
|
|
|
|
/* parameter detection */
|
|
if (count * size > UserByteManager.dynamic_buddy_manager.dynamic_buddy_end - UserByteManager.dynamic_buddy_manager.dynamic_buddy_start - UserByteManager.dynamic_buddy_manager.active_memory)
|
|
return NONE;
|
|
|
|
/* calls x_malloc to allocate count * size memory */
|
|
p = x_umalloc(count * size);
|
|
|
|
/* zero the memory */
|
|
if (p)
|
|
memset((char*)p, 0, count * size);
|
|
|
|
return p;
|
|
}
|
|
|
|
/**
|
|
* This function is provided to release memory block.
|
|
*
|
|
* @param pointer the memory to be released
|
|
*/
|
|
void x_ufree(void* pointer)
|
|
{
|
|
x_base lock = 0;
|
|
struct DynamicAllocNode* node = NONE;
|
|
|
|
/* parameter detection */
|
|
if (pointer == NONE)
|
|
return;
|
|
CHECK(UserByteManager.dynamic_buddy_manager.done->JudgeLegal(&UserByteManager.dynamic_buddy_manager, pointer));
|
|
|
|
/* hold lock before release */
|
|
lock = FREE_LIST_LOCK();
|
|
node = PTR2ALLOCNODE((char*)pointer - SIZEOF_DYNAMICALLOCNODE_MEM);
|
|
CHECK(UserByteManager.done->JudgeAllocated(node));
|
|
|
|
#ifdef MEM_EXTERN_SRAM
|
|
/* judge the pointer is not malloced from extern memory*/
|
|
if (0 == (node->flag & 0xFF0000)) {
|
|
UserByteManager.dynamic_buddy_manager.done->release(&ByteManager, pointer);
|
|
}
|
|
|
|
/* judge the pointer is malloced from extern memory*/
|
|
if (0 != (node->flag & 0xFF0000)) {
|
|
ExtByteManager[((node->flag & 0xFF0000) >> 16) - 1].dynamic_buddy_manager.done->release(&ExtByteManager[((node->flag & 0xFF0000) >> 16) - 1], pointer);
|
|
}
|
|
|
|
#else
|
|
UserByteManager.dynamic_buddy_manager.done->release(&UserByteManager, pointer);
|
|
#endif
|
|
/* release the lock */
|
|
FREE_LIST_UNLOCK(lock);
|
|
}
|
|
|
|
/**
|
|
* This function initializes the static segments and dynamic buddy memory structures.
|
|
*
|
|
* @param start_phy_address the start physical address for static and dynamic memory
|
|
* @param end_phy_address the end physical address for static and dynamic memory
|
|
*/
|
|
void UserInitBoardMemory(void *start_phy_address, void *end_phy_address)
|
|
{
|
|
register x_size_t offset = 0;
|
|
|
|
NULL_PARAM_CHECK(start_phy_address);
|
|
NULL_PARAM_CHECK(end_phy_address);
|
|
|
|
KDEBUG_NOT_IN_INTERRUPT;
|
|
struct DynamicBuddyMemory *uheap = &UserByteManager.dynamic_buddy_manager;
|
|
|
|
/* align begin and end addr to page */
|
|
UserByteManager.dynamic_buddy_manager.dynamic_buddy_start = ALIGN_MEN_UP((x_ubase)start_phy_address, MM_PAGE_SIZE);
|
|
UserByteManager.dynamic_buddy_manager.dynamic_buddy_end = ALIGN_MEN_DOWN((x_ubase)end_phy_address, MM_PAGE_SIZE);
|
|
KPrintf("%s: 0x%x-0x%x \n",__func__,UserByteManager.dynamic_buddy_manager.dynamic_buddy_start,UserByteManager.dynamic_buddy_manager.dynamic_buddy_end);
|
|
|
|
/* parameter detection */
|
|
if (UserByteManager.dynamic_buddy_manager.dynamic_buddy_start >= UserByteManager.dynamic_buddy_manager.dynamic_buddy_end) {
|
|
KPrintf("InitBoardMemory, wrong address[0x%x - 0x%x]\n",
|
|
(x_ubase)start_phy_address, (x_ubase)end_phy_address);
|
|
return;
|
|
}
|
|
|
|
uheap->mm_total_size = 0;
|
|
memset(uheap->mm_freenode_list, 0, SIZEOF_XSFREENODE_MEM * MEM_LINKNRS);
|
|
|
|
/* initialize the freeNodeList */
|
|
for (offset = 1; offset < MEM_LINKNRS; offset++) {
|
|
uheap->mm_freenode_list[offset - 1].next = &uheap->mm_freenode_list[offset];
|
|
uheap->mm_freenode_list[offset].prev = &uheap->mm_freenode_list[offset - 1];
|
|
}
|
|
|
|
UserByteManager.dynamic_buddy_manager.done = &DynamicDone;
|
|
UserByteManager.done = &NodeDone;
|
|
|
|
|
|
/* dynamic buddy memory initialization */
|
|
UserByteManager.dynamic_buddy_manager.done->init(&UserByteManager.dynamic_buddy_manager, UserByteManager.dynamic_buddy_manager.dynamic_buddy_start, UserByteManager.dynamic_buddy_manager.dynamic_buddy_end - UserByteManager.dynamic_buddy_manager.dynamic_buddy_start);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef MEM_STATS
|
|
|
|
/**
|
|
* This function obtains the statistic information about memory
|
|
*
|
|
* @param total_memory the total memory
|
|
* @param used_memory the meory being used
|
|
* @param max_used_memory the max allocated memory
|
|
*/
|
|
void MemoryInfo(uint32 *total_memory, uint32 *used_memory, uint32 *max_used_memory)
|
|
{
|
|
if (NONE != total_memory)
|
|
*total_memory = ByteManager.dynamic_buddy_manager.dynamic_buddy_end - ByteManager.dynamic_buddy_manager.dynamic_buddy_start;
|
|
|
|
if (NONE != used_memory)
|
|
*used_memory = ByteManager.dynamic_buddy_manager.active_memory;
|
|
|
|
if (NONE != max_used_memory)
|
|
*max_used_memory = ByteManager.dynamic_buddy_manager.max_ever_usedmem;
|
|
}
|
|
|
|
#ifdef TOOL_SHELL
|
|
#include <shell.h>
|
|
|
|
void ShowBuddy();
|
|
void ShowMemory(void);
|
|
/**
|
|
* This function will list the statistic information about memory.
|
|
*/
|
|
void ShowMemory(void)
|
|
{
|
|
int i = 0;
|
|
KPrintf("total memory: %d\n", ByteManager.dynamic_buddy_manager.dynamic_buddy_end - ByteManager.dynamic_buddy_manager.dynamic_buddy_start - SIZEOF_32B);
|
|
KPrintf("used memory : %d\n", ByteManager.dynamic_buddy_manager.active_memory);
|
|
KPrintf("maximum allocated memory: %d\n", ByteManager.dynamic_buddy_manager.max_ever_usedmem);
|
|
KPrintf("total cache size: %d, %d/%d[32B],%d/%d[64B]\n", ByteManager.dynamic_buddy_manager.static_memory,ByteManager.static_manager[0].block_free_count,SMALL_NUMBER_32B,ByteManager.static_manager[1].block_free_count,SMALL_NUMBER_64B);
|
|
#ifdef MEM_EXTERN_SRAM
|
|
for(i = 0; i < EXTSRAM_MAX_NUM; i++) {
|
|
if(NONE != ExtByteManager[i].done){
|
|
KPrintf("\nlist extern sram[%d] memory information\n\n",i);
|
|
KPrintf("extern sram total memory: %d\n", ExtByteManager[i].dynamic_buddy_manager.dynamic_buddy_end - ExtByteManager[i].dynamic_buddy_manager.dynamic_buddy_start);
|
|
KPrintf("extern sram used memory : %d\n", ExtByteManager[i].dynamic_buddy_manager.active_memory);
|
|
KPrintf("extern sram maximum allocated memory: %d\n", ExtByteManager[i].dynamic_buddy_manager.max_ever_usedmem);
|
|
}
|
|
}
|
|
#endif
|
|
ShowBuddy();
|
|
}
|
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0),
|
|
ShowMemory,ShowMemory,list memory usage information);
|
|
/**
|
|
* This function will list the freeNodeList information on dynamic buddy memory.
|
|
*/
|
|
void ShowBuddy(void)
|
|
{
|
|
|
|
int i = 0;
|
|
int lock = 0;
|
|
struct DynamicFreeNode *debug = NONE;
|
|
|
|
lock = FREE_LIST_LOCK();
|
|
KPrintf("\n\033[41;1mlist memory information\033[0m\n", __func__);
|
|
for(int level = 0; level < MEM_LINKNRS; level++) {
|
|
KPrintf("%s level [%d],memory size[2^%d] \n",__func__, level,level +6);
|
|
for (debug = &ByteManager.dynamic_buddy_manager.mm_freenode_list[level]; ; ) {
|
|
if(debug->next)
|
|
{
|
|
debug = debug->next;
|
|
|
|
if(debug->size > 0)
|
|
KPrintf(" [current node %x,next node %x, size %u, flag %x]\n",debug, debug->next,debug->size,debug->flag);
|
|
else
|
|
KPrintf(" \n");
|
|
}
|
|
if(debug->size == 0 || NONE == debug->next)
|
|
break;
|
|
};
|
|
}
|
|
|
|
|
|
#ifdef MEM_EXTERN_SRAM
|
|
KPrintf("\n\033[41;1mlist extern memory information\033[0m\n");
|
|
for(i = 0; i < EXTSRAM_MAX_NUM; i++) {
|
|
if(NONE != ExtByteManager[i].done){
|
|
KPrintf("\nlist extern sram[%d] memory information\n\n",i);
|
|
for(int lev = 0; lev < MEM_LINKNRS; lev++) {
|
|
KPrintf("\n %s level [%d],memory size[2^%d] \n",__func__, lev,lev +6);
|
|
for (debug = & ExtByteManager[i].dynamic_buddy_manager.mm_freenode_list[lev]; ; ) {
|
|
if(debug->next)
|
|
{
|
|
debug = debug->next;
|
|
|
|
if(debug->size > 0)
|
|
KPrintf(" [current node %x,next node %x, size %u, flag %x]\n",debug, debug->next,debug->size,debug->flag);
|
|
else
|
|
KPrintf(" \n");
|
|
}
|
|
if(debug->size == 0 || NONE == debug->next)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
FREE_LIST_UNLOCK(lock);
|
|
}
|
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0),
|
|
ShowBuddy,ShowBuddy,list memory usage information);
|
|
#endif
|
|
#endif
|
|
|