You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
204 lines
7.5 KiB
204 lines
7.5 KiB
/*
|
|
* Copyright (c) Hisilicon Technologies Co., Ltd. 2020-2020. All rights reserved.
|
|
* Description: malloc function : First-fit allocation policies
|
|
* Author: SmartMedia_BSP
|
|
* Create: 2020-06-16
|
|
*/
|
|
|
|
#include <td_type.h>
|
|
#include <hlist.h>
|
|
#include <stdio.h>
|
|
|
|
#define MEM_ALLOC_MAGIC_NUM 0xACCA5995
|
|
typedef struct _mem_node {
|
|
uint32 magicnum;
|
|
struct node nodeinfo;
|
|
/* Size & flag of the current node (the high two bits represent a flag,and the rest bits specify the size) */
|
|
uint32 size_flag;
|
|
}mem_node;
|
|
|
|
#define around(size, align) (((size) + (align) - 1) & (~((align) - 1)))
|
|
|
|
#define MEM_NODE_HEAD_SIZE sizeof(struct _mem_node)
|
|
#define MEM_ALIGN_SIZE 4
|
|
#define MEM_NODE_USED_FLAG 0x80000000U
|
|
#define MEM_NODE_ALIGNED_FLAG 0x40000000U
|
|
#define MEM_NODE_ALIGNED_AND_USED_FLAG (MEM_NODE_USED_FLAG | MEM_NODE_ALIGNED_FLAG)
|
|
|
|
#define mem_node_get_used_flag(size_flag) ((size_flag) & MEM_NODE_USED_FLAG)
|
|
#define mem_node_set_used_flag(size_flag) ((size_flag) = ((size_flag) | MEM_NODE_USED_FLAG))
|
|
#define mem_node_get_aligned_gapsize(sizeAndFlag) ((sizeAndFlag) & ~MEM_NODE_ALIGNED_FLAG)
|
|
#define mem_node_get_aligned_flag(size_flag) ((size_flag) & MEM_NODE_ALIGNED_FLAG)
|
|
#define mem_node_set_aligned_flag(size_flag) ((size_flag) = ((size_flag) | MEM_NODE_ALIGNED_FLAG))
|
|
#define mem_node_get_size(size_flag) ((size_flag) & ~MEM_NODE_ALIGNED_AND_USED_FLAG)
|
|
|
|
#define mem_node_clear_used_aligned_flag(size_flag) ((size_flag) = (size_flag) & (~ (MEM_NODE_ALIGNED_AND_USED_FLAG)))
|
|
|
|
#define is_pow_two(value) ((((uintptr_t)(value)) & ((uintptr_t)(value) - 1)) == 0)
|
|
#define is_aligned(value, alignSize) ((((uintptr_t)(value)) & ((uintptr_t)((alignSize) - 1))) == 0)
|
|
|
|
void memlib_init(struct list *listhead, unsigned int base, unsigned int size)
|
|
{
|
|
mem_node *firstnode = (mem_node *)(uintptr_t)(base);
|
|
if (mem_node_get_used_flag(size) || mem_node_get_aligned_flag(size)) {
|
|
printf("malloc init failed, size:0x%x\n", size);
|
|
return;
|
|
}
|
|
list_init(listhead);
|
|
firstnode->magicnum = MEM_ALLOC_MAGIC_NUM;
|
|
firstnode->size_flag = size;
|
|
list_add_tail(listhead, &firstnode->nodeinfo);
|
|
printf("malloc init,base:0x%x, size:%s\n", base, u32tohstr(size, NULL));
|
|
}
|
|
|
|
static void *mem_find_freeblock(struct list *listhead, uint32 allocsize)
|
|
{
|
|
mem_node *entry = NULL;
|
|
mem_node *tmp = NULL;
|
|
mem_node *newnode = NULL;
|
|
unsigned int nodesize;
|
|
list_for_each_entry_safe(entry, tmp, listhead, mem_node, nodeinfo) {
|
|
nodesize = mem_node_get_size(entry->size_flag);
|
|
if ((!mem_node_get_used_flag(entry->size_flag)) && nodesize >= allocsize) {
|
|
if ((nodesize - allocsize) < (MEM_NODE_HEAD_SIZE + MEM_ALIGN_SIZE)) {
|
|
mem_node_set_used_flag(entry->size_flag);
|
|
return entry + 1;
|
|
} else {
|
|
newnode = (mem_node *)((uintptr_t)entry + allocsize);
|
|
newnode->magicnum = MEM_ALLOC_MAGIC_NUM;
|
|
newnode->size_flag = entry->size_flag - allocsize;
|
|
entry->size_flag = allocsize;
|
|
mem_node_set_used_flag(entry->size_flag);
|
|
list_insert_backward(&entry->nodeinfo, &newnode->nodeinfo); /* newnode 插入到 entry 后面 */
|
|
return entry + 1;
|
|
}
|
|
}
|
|
}
|
|
printf("no suitable free mem block\n");
|
|
return NULL;
|
|
}
|
|
|
|
void *memlib_malloc(struct list *listhead, uint32 bytes)
|
|
{
|
|
void *ptr = NULL;
|
|
if (bytes == 0) {
|
|
return NULL;
|
|
}
|
|
uint32 allocsize = around(bytes + MEM_NODE_HEAD_SIZE, MEM_ALIGN_SIZE);
|
|
ptr = mem_find_freeblock(listhead, allocsize);
|
|
return ptr;
|
|
}
|
|
|
|
void *memlib_memalign(struct list *listhead, uint32 alignment, uint32 bytes)
|
|
{
|
|
uint32 gap_size;
|
|
uint32 use_size;
|
|
void *ptr = NULL;
|
|
void *align_ptr = NULL;
|
|
mem_node *node = NULL;
|
|
if (bytes == 0 || alignment == 0 || !is_pow_two(alignment) || !is_aligned(alignment, sizeof(void*))) {
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* sizeof(gap_size) bytes stores offset between align_ptr and ptr,
|
|
* the ptr has been OS_MEM_ALIGN_SIZE(4 or 8) aligned, so maximum
|
|
* offset between alignedPtr and ptr is alignment - OS_MEM_ALIGN_SIZE
|
|
*/
|
|
if ((alignment - sizeof(gap_size)) > ((uint32)(-1) - bytes)) {
|
|
return NULL;
|
|
}
|
|
use_size = around(bytes + MEM_NODE_HEAD_SIZE + alignment - sizeof(gap_size), MEM_ALIGN_SIZE);
|
|
if (mem_node_get_used_flag(use_size) || mem_node_get_aligned_flag(use_size)) {
|
|
printf("size is too large:0x%x\n", use_size);
|
|
return NULL;
|
|
}
|
|
ptr = mem_find_freeblock(listhead, use_size);
|
|
if (ptr == NULL) {
|
|
return NULL;
|
|
}
|
|
align_ptr = (void *)around((uintptr_t)ptr, alignment);
|
|
if (ptr == align_ptr) {
|
|
return ptr;
|
|
}
|
|
gap_size = (uintptr_t)align_ptr - (uintptr_t)ptr;
|
|
mem_node_set_aligned_flag(gap_size);
|
|
node = (mem_node *)ptr - 1;
|
|
mem_node_set_aligned_flag(node->size_flag);
|
|
*(uint32 *)((uintptr_t)align_ptr - sizeof(gap_size)) = gap_size;
|
|
ptr = align_ptr;
|
|
return ptr;
|
|
}
|
|
void *memptr_to_node(void *ptr)
|
|
{
|
|
uint32 gapsize;
|
|
if (((uintptr_t)ptr) & (MEM_ALIGN_SIZE - 1)) {
|
|
printf("ptr not align by 4byte\n");
|
|
return NULL;
|
|
}
|
|
gapsize = *(uint32 *)((uintptr_t)ptr - sizeof(uint32));
|
|
if (mem_node_get_aligned_flag(gapsize) && mem_node_get_used_flag(gapsize)) {
|
|
printf("gapsize:0x%x error\n", gapsize);
|
|
return NULL;
|
|
}
|
|
if (mem_node_get_aligned_flag(gapsize)) {
|
|
gapsize = mem_node_get_aligned_gapsize(gapsize);
|
|
if ((gapsize & (MEM_ALIGN_SIZE - 1)) || (gapsize > ((uintptr_t)ptr - MEM_NODE_HEAD_SIZE))) {
|
|
return NULL;
|
|
}
|
|
ptr = (void *)((uintptr_t)ptr - gapsize);
|
|
}
|
|
return (void *)((uintptr_t)ptr - MEM_NODE_HEAD_SIZE);
|
|
}
|
|
|
|
void memlib_free(struct list *listhead, void *ptr)
|
|
{
|
|
mem_node *entry = NULL;
|
|
mem_node *next_entry = NULL;
|
|
mem_node *pre_entry = NULL;
|
|
if (ptr == NULL) {
|
|
return;
|
|
}
|
|
entry = (mem_node *)memptr_to_node(ptr);
|
|
if (entry == NULL) {
|
|
return;
|
|
}
|
|
if (entry->magicnum != MEM_ALLOC_MAGIC_NUM) {
|
|
printf("MAGIC NUM is wrong! magicnum:0x%x\n", entry->magicnum);
|
|
return;
|
|
}
|
|
if (!mem_node_get_used_flag(entry->size_flag)) {
|
|
return;
|
|
}
|
|
mem_node_clear_used_aligned_flag(entry->size_flag);
|
|
next_entry = list_next_entry(entry, listhead, mem_node, nodeinfo);
|
|
if (next_entry != NULL) {
|
|
if (!mem_node_get_used_flag(next_entry->size_flag)) {
|
|
entry->size_flag += next_entry->size_flag;
|
|
next_entry->magicnum = 0;
|
|
list_remove(&next_entry->nodeinfo);
|
|
}
|
|
}
|
|
pre_entry = list_prev_entry(entry, listhead, mem_node, nodeinfo);
|
|
if (pre_entry != NULL) {
|
|
if (!mem_node_get_used_flag(pre_entry->size_flag)) {
|
|
pre_entry->size_flag += entry->size_flag;
|
|
entry->magicnum = 0;
|
|
list_remove(&entry->nodeinfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
void memlib_show_memnode(struct list *listhead, unsigned int cnt)
|
|
{
|
|
mem_node *entry = NULL;
|
|
uint32 i = 0;
|
|
list_for_each_entry(entry, listhead, mem_node, nodeinfo) {
|
|
printf("%d:entry, magic:0x%x, size: %d, used:0x%x, aligned:0x%x\n", i++, entry->magicnum,
|
|
mem_node_get_size(entry->size_flag), mem_node_get_used_flag(entry->size_flag),
|
|
mem_node_get_aligned_flag(entry->size_flag));
|
|
if (cnt != 0 && i == cnt) {
|
|
break;
|
|
}
|
|
}
|
|
} |