/** * @file * Dynamic memory manager * * This is a lightweight replacement for the standard C library malloc(). */ #include "generic/printf.h" #ifdef SUPPORT_MS_EXTENSIONS /* #pragma bss_seg( ".mem_heap_bss") */ /* #pragma data_seg( ".mem_heap_data") */ #pragma const_seg( ".mem_heap_const") #pragma code_seg( ".mem_heap_code") #endif static inline void *sbrk(int incr); typedef unsigned char u8_t; typedef signed char err_t; typedef unsigned int u32_t, mem_ptr_t; typedef unsigned int mem_size_t; #define MEM_HEAP_NO_SYS 0 //0:使用操作系统,1:不使用操作系统 #define MEM_HEAP_ERROR_CHECK 1 #define MEM_HEAP_CLR_MAGIC (u8_t)0xff #define MEM_HEAP_OVERFLOW_MAGIC 0x53555aca #define SBRK_PIECE_SIZE (20*1024*1024) /** All allocated blocks will be MEM_HEAP_MIN_SIZE bytes big, at least! * MEM_HEAP_MIN_SIZE can be overridden to suit your needs. Smaller values save space, * larger values could prevent too small blocks to fragment the RAM too much. */ #define MEM_HEAP_MIN_SIZE 4 #define MEM_HEAP_STATS 1 //统计功能 /** print debug message only if debug message type is enabled... */ #define MEM_HEAP_PLATFORM_ASSERT(x) \ ASSERT(x) /* ASSERT("\"%s\" failed at line %d in %s\n", x, __LINE__, __FILE__); */ #define MEM_HEAP_PLATFORM_DIAG(x) do {printf x;} while(0) //#define MEM_HEAP_NOASSERT /** flag for LWIP_DEBUGF to enable that debug message */ #define MEM_HEAP_DBG_ON 0x80U /** flag for LWIP_DEBUGF to disable that debug message */ #define MEM_HEAP_DBG_OFF 0x00U /** flag for LWIP_DEBUGF to halt after printing this debug message */ #define MEM_HEAP_DBG_HALT 0x08U #define MEM_HEAP_DEBUG (MEM_HEAP_DBG_ON) /* ------------------------------------ ---------- MEM_HEAP options ---------- ------------------------------------ */ /** * MEM_HEAP_ALIGNMENT: should be set to the alignment of the CPU * 4 byte alignment -> #define MEM_HEAP_ALIGNMENT 4 * 2 byte alignment -> #define MEM_HEAP_ALIGNMENT 2 */ #define MEM_HEAP_ALIGNMENT 4 /** * MEM_SIZE: the size of the heap memory. If the application will send * a lot of data that needs to be copied, this should be set high. */ #define MEM_HEAP_START_SIZE 0//8*1024*1024 #ifdef MEM_HEAP_DEBUG #define MEM_HEAP_DEBUGF(debug, message) do { \ if ((debug) & MEM_HEAP_DBG_ON) { \ MEM_HEAP_PLATFORM_DIAG(message); \ if ((debug) & MEM_HEAP_DBG_HALT) { \ while(1); \ } \ } \ } while(0) #else /* MEM_HEAP_DEBUG */ #define MEM_HEAP_DEBUGF(debug, message) #endif /* MEM_HEAP_DEBUG */ #ifndef MEM_HEAP_NOASSERT #define MEM_HEAP_ASSERT(message, assertion) do { if(!(assertion)) \ MEM_HEAP_PLATFORM_ASSERT(message); } while(0) #else /* MEM_HEAP_NOASSERT */ #define MEM_HEAP_ASSERT(message, assertion) #endif /* MEM_HEAP_NOASSERT */ #if MEM_HEAP_STATS struct stats_mem { #ifdef MEM_HEAP_DEBUG const char *name; #endif /* MEM_HEAP_DEBUG */ mem_size_t avail; mem_size_t used; mem_size_t max; u32_t err; u32_t illegal; }; struct stats_ { struct stats_mem mem; }; #define STATS_INC(x) ++mem_heap.mem_stats.x #define STATS_DEC(x) --mem_heap.mem_stats.x #define STATS_INC_USED(x, y) do { mem_heap.mem_stats.x.used += y; \ if (mem_heap.mem_stats.x.max < mem_heap.mem_stats.x.used) { \ mem_heap.mem_stats.x.max = mem_heap.mem_stats.x.used; \ } \ } while(0) #define MEM_STATS_AVAIL(x, y) mem_heap.mem_stats.mem.x = y #define MEM_STATS_INC(x) STATS_INC(mem.x) #define MEM_STATS_INC_USED(x, y) STATS_INC_USED(mem, y) #define MEM_STATS_DEC_USED(x, y) mem_heap.mem_stats.mem.x -= y #else #define MEM_STATS_AVAIL(x, y) #define MEM_STATS_INC(x) #define MEM_STATS_INC_USED(x, y) #define MEM_STATS_DEC_USED(x, y) #endif #if !MEM_HEAP_NO_SYS /*#include "os/os_api.h" */ #include "system/spinlock.h" /*typedef OS_MUTEX sys_mutex_t; // type of mutex */ /* Protect the heap only by using a semaphore */ #define MEM_HEAP_WAIT_MUTEX_TIMEOUT 0 #define MEM_HEAP_DECL_PROTECT() u16 oserr #define MEM_HEAP_PROTECT() spin_lock(&mem_heap.lock) //os_mutex_pend(&mem_heap.mem_mutex,MEM_HEAP_WAIT_MUTEX_TIMEOUT)//os_mutex_pend(&mem_heap.mem_mutex,MEM_HEAP_WAIT_MUTEX_TIMEOUT,0) #define MEM_HEAP_UNPROTECT() spin_unlock(&mem_heap.lock) //os_mutex_post(&mem_heap.mem_mutex) #else /* !MEM_HEAP_NO_SYS */ #define sys_mutex_new() 0 #define MEM_HEAP_DECL_PROTECT() #define MEM_HEAP_PROTECT() #define MEM_HEAP_UNPROTECT() #endif /** * The heap is made up as a list of structs of this type. * This does not have to be aligned since for getting its size, * we only use the macro SIZEOF_STRUCT_MEM, which automatically alignes. */ #define MEM_USED 0x5a5aeaae #define MEM_UNUSED 0xa5abcdef struct mem { #if MEM_HEAP_ERROR_CHECK == 1 u32_t check_before; #endif /** index of the next struct */ struct mem *next; /** index of the previous struct */ struct mem *prev; /** MEM_USED: this area is used; MEM_UNUSED: this area is unused */ u32_t used; u32 rets_addr; #if MEM_HEAP_ERROR_CHECK == 1 u32_t check_after; #endif }; /* some alignment macros: we define them here for better source code layout */ #define MIN_SIZE_ALIGNED MEM_HEAP_ALIGN_SIZE(MEM_HEAP_MIN_SIZE) #define SIZEOF_STRUCT_MEM MEM_HEAP_ALIGN_SIZE(sizeof(struct mem)) #define MEM_SIZE_ALIGNED MEM_HEAP_ALIGN_SIZE(MEM_HEAP_SIZE) /** Calculate memory size for an aligned buffer - returns the next highest * multiple of MEM_HEAP_ALIGNMENT (e.g. MEM_HEAP_ALIGN_SIZE(3) and * MEM_HEAP_ALIGN_SIZE(4) will both yield 4 for MEM_HEAP_ALIGNMENT == 4). */ #define MEM_HEAP_ALIGN_SIZE(size) (((size) + MEM_HEAP_ALIGNMENT - 1) & ~(MEM_HEAP_ALIGNMENT-1)) /** Align a memory pointer to the alignment defined by MEM_HEAP_ALIGNMENT * so that ADDR % MEM_HEAP_ALIGNMENT == 0 */ #define MEM_HEAP_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_HEAP_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_HEAP_ALIGNMENT-1))) struct _mem_heap { /** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */ u8_t *ram; /** the last entry, always unused! */ struct mem *ram_end; /** pointer to the lowest free block, this is used for faster search */ struct mem *lfree; /** record the last sbrk end*/ u8_t *sbrk_end; /** record total mem_heap size */ mem_ptr_t mem_heap_size; #if !MEM_HEAP_NO_SYS /*sys_mutex_t mem_mutex;*/ spinlock_t lock; #endif #if MEM_HEAP_STATS struct stats_ mem_stats; #endif u8_t mem_init; }; static struct _mem_heap mem_heap = { .mem_init = 0, }; extern u32 MALLOC_SIZE[]; extern u32 HEAP_BEGIN; extern u32 HEAP_END; #if MEM_HEAP_STATS static void mem_stats_init(void) { #ifdef MEM_HEAP_DEBUG mem_heap.mem_stats.mem.name = "MEM_HEAP"; #endif } void malloc_stats(void) { MEM_HEAP_PLATFORM_DIAG(("\nMEM_HEAP %s\n", mem_heap.mem_stats.mem.name)); MEM_HEAP_PLATFORM_DIAG(("total: %u\n", (u32)MALLOC_SIZE)); MEM_HEAP_PLATFORM_DIAG(("left: %u\n", ((u32)MALLOC_SIZE - (u32)mem_heap.mem_stats.mem.used))); /*MEM_HEAP_PLATFORM_DIAG(("avail: %u\n", (u32)mem_heap.mem_stats.mem.avail)); MEM_HEAP_PLATFORM_DIAG(("used: %u\n", (u32)mem_heap.mem_stats.mem.used));*/ MEM_HEAP_PLATFORM_DIAG(("max: %u\n", (u32)mem_heap.mem_stats.mem.max)); /*MEM_HEAP_PLATFORM_DIAG(("err: %u\n", (u32)mem_heap.mem_stats.mem.err));*/ } #endif u32 get_free_heap_size(void) { #if MEM_HEAP_STATS return (u32)MALLOC_SIZE - (u32)mem_heap.mem_stats.mem.used; #else return 0; #endif } void malloc_dump() { struct mem *mem; struct mem *sbrk_lfree = 0; MEM_HEAP_PROTECT(); u32 max_free = 0; for (sbrk_lfree ? (mem = sbrk_lfree) : (mem = mem_heap.lfree); mem != mem_heap.ram_end; mem = mem->next) { if (mem->used == MEM_USED) { printf("mem_used: %x - %x, size=%x, call_from=%x\n", (u32)mem, (u32)mem->next, (u32)mem->next - (u32)mem, mem->rets_addr); } else { printf("mem_free: %x - %x, size=%x\n", (u32)mem, (u32)mem->next, (u32)mem->next - (u32)mem); if (max_free < ((u32)mem->next - (u32)mem)) { max_free = (u32)mem->next - (u32)mem; } } } MEM_HEAP_UNPROTECT(); #if MEM_HEAP_STATS u32 last_free = (u8 *)&HEAP_END - (u8 *)mem_heap.ram_end; if (max_free < last_free) { max_free = last_free; } float fragment = 100 - 100.0 * max_free / ((u32)MALLOC_SIZE - (u32)mem_heap.mem_stats.mem.used); printf("fragment: %f \r\n", fragment); #endif } #if !MEM_HEAP_NO_SYS static err_t sys_mutex_new(void) { spin_lock_init(&mem_heap.lock); /*u16 err; err =os_mutex_create(&mem_heap.mem_mutex) ; MEM_HEAP_ASSERT("sys_mutex_new ",err == OS_ERR_NONE ); if(err) return err;*/ return 0; } #endif /** * "Plug holes" by combining adjacent empty struct mems. * After this function is through, there should not exist * one empty struct mem pointing to another empty struct mem. * * @param mem this points to a struct mem which just has been freed * @internal this function is only called by mem_free() and mem_trim() * * This assumes access to the heap is protected by the calling function * already. */ static struct mem * plug_holes(struct mem *mem) { struct mem *mem2 = mem; struct mem *nmem; struct mem *pmem; // MEM_HEAP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= mem_heap.ram); // MEM_HEAP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)mem_heap.ram_end); MEM_HEAP_ASSERT("plug_holes: mem->used == MEM_UNUSED", mem->used == MEM_UNUSED); /* plug hole forward */ // MEM_HEAP_ASSERT("plug_holes: mem->next <= ram_end", mem->next <= mem_heap.ram_end); nmem = mem->next; if (mem != nmem && nmem->used == MEM_UNUSED && (u8_t *)nmem != (u8_t *)mem_heap.ram_end) { /* if mem->next is unused and not end of ram, combine mem and mem->next */ if (mem_heap.lfree == nmem) { mem_heap.lfree = mem; } mem->next = nmem->next; nmem->next->prev = mem; MEM_STATS_DEC_USED(used, SIZEOF_STRUCT_MEM); } /* plug hole backward */ pmem = mem->prev; /* printf("pmem : 0x%x, 0x%x", pmem, mem->rets_addr); */ if (pmem && pmem != mem && pmem->used == MEM_UNUSED) { /* if mem->prev is unused, combine mem and mem->prev */ if (mem_heap.lfree == mem) { mem_heap.lfree = pmem; } pmem->next = mem->next; mem->next->prev = pmem; mem2 = pmem; MEM_STATS_DEC_USED(used, SIZEOF_STRUCT_MEM); } return mem2; } /** * Zero the heap and initialize start, end and lowest-free */ static void mem_heap_init(void) { u8_t *sbrk_start; struct mem *mem; if (mem_heap.mem_init) { return; } #if MEM_HEAP_STATS mem_stats_init(); #endif MEM_HEAP_ASSERT("Sanity check alignment", (SIZEOF_STRUCT_MEM & (MEM_HEAP_ALIGNMENT - 1)) == 0); mem_heap.mem_heap_size = MEM_HEAP_START_SIZE; sbrk_start = sbrk(MEM_HEAP_START_SIZE + (2 * SIZEOF_STRUCT_MEM) + MEM_HEAP_ALIGNMENT); /* align the heap */ mem_heap.ram = (u8_t *)MEM_HEAP_ALIGN(sbrk_start); /* initialize the start of the heap */ mem = (struct mem *)mem_heap.ram; mem->next = (struct mem *)&mem_heap.ram[mem_heap.mem_heap_size + SIZEOF_STRUCT_MEM]; mem->prev = mem; mem->used = MEM_UNUSED; /* initialize the end of the heap */ mem_heap.ram_end = (struct mem *)(void *)&mem_heap.ram[mem_heap.mem_heap_size + SIZEOF_STRUCT_MEM]; mem_heap.ram_end->used = MEM_USED; mem_heap.ram_end->next = mem_heap.ram_end; mem_heap.ram_end->prev = (struct mem *)mem_heap.ram; #if MEM_HEAP_ERROR_CHECK == 1 mem->check_before = MEM_HEAP_OVERFLOW_MAGIC; mem->check_after = MEM_HEAP_OVERFLOW_MAGIC; mem_heap.ram_end->check_before = MEM_HEAP_OVERFLOW_MAGIC; mem_heap.ram_end->check_after = MEM_HEAP_OVERFLOW_MAGIC; #endif mem_heap.sbrk_end = sbrk_start + MEM_HEAP_START_SIZE + (2 * SIZEOF_STRUCT_MEM) + MEM_HEAP_ALIGNMENT; /* initialize the lowest-free pointer to the start of the heap */ mem_heap.lfree = (struct mem *)mem_heap.ram; MEM_STATS_AVAIL(avail, mem_heap.mem_heap_size); if (sys_mutex_new() != 0) { MEM_HEAP_ASSERT("failed to create mem_mutex", 0); } /*malloc_stats();*/ mem_heap.mem_init = 1; } /** * Put a struct mem back on the heap * * @param rmem is the data portion of a struct mem as returned by a previous * call to mem_malloc() */ void free(void *rmem) { struct mem *mem; MEM_HEAP_DECL_PROTECT(); /*u32 rets_addr; __asm__ volatile("%0 = rets ;" : "=r"(rets_addr)); printf("??????????????????????????free: %x, %x\n", rmem, rets_addr);*/ if (rmem == (void *)0) { // MEM_HEAP_DEBUGF(MEM_HEAP_DEBUG, ("mem_free(p == NULL) was called.\n")); return; } MEM_HEAP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_HEAP_ALIGNMENT - 1)) == 0); // MEM_HEAP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)mem_heap.ram && // (u8_t *)rmem < (u8_t *)mem_heap.ram_end); // if ((u8_t *)rmem < (u8_t *)mem_heap.ram || (u8_t *)rmem >= (u8_t *)mem_heap.ram_end) { // MEM_HEAP_DEBUGF(MEM_HEAP_DEBUG, ("mem_free: illegal memory\n")); // /* protect mem stats from concurrent access */ // MEM_HEAP_PROTECT(); // MEM_STATS_INC(illegal); // MEM_HEAP_UNPROTECT(); // return; // } /* protect the heap from concurrent access */ MEM_HEAP_PROTECT(); /* Get the corresponding struct mem ... */ mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); #if MEM_HEAP_ERROR_CHECK == 1 MEM_HEAP_ASSERT("mem_free: mem->check_before", mem->check_before == MEM_HEAP_OVERFLOW_MAGIC); MEM_HEAP_ASSERT("mem_free: mem->check_after", mem->check_after == MEM_HEAP_OVERFLOW_MAGIC); memset(rmem, MEM_HEAP_CLR_MAGIC, (u8_t *)mem->next - (u8_t *)rmem); #endif /* ... which has to be in a used state ... */ MEM_HEAP_ASSERT("mem_free: mem->used", mem->used == MEM_USED); /* ... and is now unused. */ mem->used = MEM_UNUSED; if (mem < mem_heap.lfree) { /* the newly freed struct is now the lowest */ mem_heap.lfree = mem; } MEM_STATS_DEC_USED(used, ((mem_size_t)mem->next - (mem_size_t)mem - SIZEOF_STRUCT_MEM)); /* finally, see if prev or next are free also */ mem = plug_holes(mem); MEM_HEAP_UNPROTECT(); } void *get_malloc_caddr(u8 *addr, u32 offset) { #if MEM_HEAP_ERROR_CHECK struct mem *mem2 = (struct mem *)(addr - SIZEOF_STRUCT_MEM); return (void *)(&mem2->check_before); #else return NULL; #endif } static u8 call_from_zalloc = 0; /** * Adam's mem_malloc() plus solution for bug #17922 * Allocate a block of memory with a minimum of 'size' bytes. * * @param size is the minimum size of the requested block in bytes. * @return pointer to allocated memory or NULL if no free memory was found. * * Note that the returned value will always be aligned (as defined by MEM_HEAP_ALIGNMENT). */ static u32 rets_addr; void *malloc(unsigned long size) { struct mem *mem, *mem2; struct mem *sbrk_lfree = 0; MEM_HEAP_DECL_PROTECT(); if (call_from_zalloc == 0) { __asm__ volatile("%0 = rets ;" : "=r"(rets_addr)); } if (size == 0) { return (void *)0; } mem_heap_init(); /* Expand the size of the allocated memory region so that we can adjust for alignment. */ size = MEM_HEAP_ALIGN_SIZE(size); if (size < MIN_SIZE_ALIGNED) { /* every data block must be at least MIN_SIZE_ALIGNED long */ size = MIN_SIZE_ALIGNED; } MEM_HEAP_PROTECT(); if (size > mem_heap.mem_heap_size) { /*MEM_HEAP_DEBUGF(MEM_HEAP_DEBUG, ("malloc 0x%x > mem_heap_size(0x%x).\n", size, mem_heap.mem_heap_size));*/ /* protect the heap from concurrent access */ goto SBRK_MEM; } MALLOC: /* Scan through the heap searching for a free block that is big enough, * beginning with the lowest free block. */ for (sbrk_lfree ? (mem = sbrk_lfree) : (mem = mem_heap.lfree); mem != mem_heap.ram_end; mem = mem->next) { if ((mem->used == MEM_UNUSED) && ((mem_ptr_t)(mem->next) - ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM)) >= size) { /* mem is not used and at least perfect fit is possible: * mem->next - ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */ if ((mem_ptr_t)(mem->next) - ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) { /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem') * -> split large block, create empty remainder, * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if * mem->next - ((mem_ptr_t)mem + (2*SIZEOF_STRUCT_MEM)) == size, * struct mem would fit in but no data between mem2 and mem2->next * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty * region that couldn't hold data, but when mem->next gets freed, * the 2 regions would be combined, resulting in more free memory */ mem2 = (struct mem *)((mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size); /* create mem2 struct */ mem2->used = MEM_UNUSED; mem2->next = mem->next; mem2->prev = mem; #if MEM_HEAP_ERROR_CHECK == 1 mem2->check_after = MEM_HEAP_OVERFLOW_MAGIC; mem2->check_before = MEM_HEAP_OVERFLOW_MAGIC; #endif /* and insert it between mem and mem->next */ mem->next = mem2; mem->used = MEM_USED; mem2->next->prev = mem2; MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM)); } else { /* (a mem2 struct does no fit into the user data space of mem and mem->next will always * be used at this point: if not we have 2 unused structs in a row, plug_holes should have * take care of this). * -> near fit or excact fit: do not split, no mem2 creation * also can't move mem->next directly behind mem, since mem->next * will always be used at this point! */ mem->used = MEM_USED; MEM_STATS_INC_USED(used, ((mem_ptr_t)mem->next - (mem_ptr_t)mem - SIZEOF_STRUCT_MEM)); } if (mem == mem_heap.lfree) { struct mem *cur = mem_heap.lfree; /* Find next free block after mem and update lowest free pointer */ while ((cur->used == MEM_USED) && cur != mem_heap.ram_end) { cur = cur->next; } mem_heap.lfree = cur; MEM_HEAP_ASSERT("mem_malloc: !mem_heap.lfree->used", ((mem_heap.lfree == mem_heap.ram_end) || (mem_heap.lfree->used == MEM_UNUSED))); } MEM_HEAP_UNPROTECT(); // MEM_HEAP_ASSERT("mem_malloc: allocated memory not above ram_end.", // (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)mem_heap.ram_end); MEM_HEAP_ASSERT("mem_malloc: allocated memory properly aligned.", ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_HEAP_ALIGNMENT == 0); MEM_HEAP_ASSERT("mem_malloc: sanity check alignment", (((mem_ptr_t)mem) & (MEM_HEAP_ALIGNMENT - 1)) == 0); /* printf("malloc:0x%x size:0x%x\n",(u8_t *)mem + SIZEOF_STRUCT_MEM,size); */ /*if (call_from_zalloc == 0) { printf("??????????????????????????malloc: %d, %x, %x\n", size, rets_addr, (u8 *)mem + SIZEOF_STRUCT_MEM); }*/ mem->rets_addr = rets_addr; /*printf("malloc: %x\n", (u8 *)mem + SIZEOF_STRUCT_MEM);*/ return (u8_t *)mem + SIZEOF_STRUCT_MEM; } } SBRK_MEM: #define SBRK_PTR_ALIGN_FORWARD(ptr) (struct mem *)(((mem_ptr_t)ptr) & ~(mem_ptr_t)(MEM_HEAP_ALIGNMENT-1)) #define SBRK_PTR_ALIGN_BACKWARD(ptr) (struct mem *)(((mem_ptr_t)ptr + MEM_HEAP_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_HEAP_ALIGNMENT-1)) // MEM_HEAP_DEBUGF(MEM_HEAP_DEBUG, (" +SBRK_MEM\r\n")); ; u8_t ram_end_prev_unused_flag; u8_t *sbrk_ptr; struct mem *sbrk_head = (struct mem *) - 1; struct mem *new_ram_end; mem_size_t mem_heap_incr_size; mem_size_t remain_size, need_size; need_size = size + 2 * SIZEOF_STRUCT_MEM + 2 * MEM_HEAP_ALIGNMENT; if (mem_heap.ram_end->prev->used == MEM_UNUSED) { ram_end_prev_unused_flag = 1; sbrk_ptr = sbrk(0);//detect sbrk_ptr if (mem_heap.sbrk_end != sbrk_ptr) { //discontinuous remain_size = 0; } else { remain_size = (mem_size_t)mem_heap.ram_end - ((mem_size_t)(mem_heap.ram_end->prev) + SIZEOF_STRUCT_MEM); } mem_heap_incr_size = need_size - remain_size; } else { ram_end_prev_unused_flag = 0; mem_heap_incr_size = need_size; } sbrk_ptr = sbrk(mem_heap_incr_size); if (sbrk_ptr == (void *) - 1) { MEM_HEAP_DEBUGF(MEM_HEAP_DEBUG, ("1sbrk ret == NULL,sbrk_malloc: could not allocate %d bytes\n", (mem_size_t)mem_heap_incr_size)); MEM_STATS_INC(err); MEM_HEAP_UNPROTECT(); malloc_dump(); return (void *)0; } if (mem_heap.sbrk_end != sbrk_ptr) { //discontinuous sbrk_head = SBRK_PTR_ALIGN_BACKWARD(sbrk_ptr); sbrk_head->prev = mem_heap.ram_end; sbrk_head->used = MEM_UNUSED; #if MEM_HEAP_ERROR_CHECK == 1 sbrk_head->check_after = MEM_HEAP_OVERFLOW_MAGIC; sbrk_head->check_before = MEM_HEAP_OVERFLOW_MAGIC; #endif mem_heap.ram_end->next = sbrk_head; } mem_heap.sbrk_end = sbrk_ptr + mem_heap_incr_size; new_ram_end = (struct mem *)((u8_t *)(SBRK_PTR_ALIGN_FORWARD(mem_heap.sbrk_end)) - SIZEOF_STRUCT_MEM); new_ram_end->used = MEM_USED; new_ram_end->next = new_ram_end; #if MEM_HEAP_ERROR_CHECK == 1 new_ram_end->check_after = MEM_HEAP_OVERFLOW_MAGIC; new_ram_end->check_before = MEM_HEAP_OVERFLOW_MAGIC; #endif if (sbrk_head == (struct mem *) - 1) { //continuous if (ram_end_prev_unused_flag) { new_ram_end->prev = mem_heap.ram_end->prev; mem_heap.ram_end->prev->next = new_ram_end; } else { new_ram_end->prev = mem_heap.ram_end; mem_heap.ram_end->next = new_ram_end; mem_heap.ram_end->used = MEM_UNUSED; } } else { new_ram_end->prev = sbrk_head; sbrk_head->next = new_ram_end; } mem_heap.ram_end = new_ram_end; mem_heap.mem_heap_size += mem_heap_incr_size; MEM_STATS_AVAIL(avail, mem_heap.mem_heap_size); sbrk_lfree = new_ram_end->prev; goto MALLOC; } /** * Contiguously allocates enough space for count objects that are size bytes * of memory each and returns a pointer to the allocated memory. * * The allocated memory is filled with bytes of value zero. * * @param count number of objects to allocate * @param size size of the objects to allocate * @return pointer to allocated memory / NULL pointer if there is an error */ void *calloc(unsigned long count, unsigned long size) { void *p; /* allocate 'count' objects of size 'size' */ p = malloc(count * size); if (p) { /* zero the memory */ memset(p, 0, count * size); } return p; } void *zalloc(unsigned long size) { void *p; __asm__ volatile("%0 = rets ;" : "=r"(rets_addr)); call_from_zalloc = 1; p = malloc(size); /*printf("??????????????????????????malloc: %d, %x, %x\n", size, rets_addr, p);*/ call_from_zalloc = 0; if (p) { memset(p, 0, size); } return p; } void *realloc(void *rmem, unsigned long newsize) { mem_size_t size; struct mem *new_mem; struct mem *mem, *mem2; void *new_rmem = (void *)0; /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */ MEM_HEAP_DECL_PROTECT(); /* Expand the size of the allocated memory region so that we can adjust for alignment. */ newsize = MEM_HEAP_ALIGN_SIZE(newsize); if (newsize < MIN_SIZE_ALIGNED) { /* every data block must be at least MIN_SIZE_ALIGNED long */ newsize = MIN_SIZE_ALIGNED; } mem_heap_init(); if (rmem == (void *)0) { rmem = malloc(newsize); return rmem; } // MEM_HEAP_ASSERT("realloc: legal memory", ((u8_t *)rmem >= (u8_t *)mem_heap.ram && // (u8_t *)rmem < (u8_t *)mem_heap.ram_end)); // // if ((u8_t *)rmem < (u8_t *)mem_heap.ram || (u8_t *)rmem >= (u8_t *)mem_heap.ram_end) { // MEM_HEAP_DEBUGF(MEM_HEAP_DEBUG, ("realloc: illegal memory\n")); // /* protect mem stats from concurrent access */ // MEM_HEAP_PROTECT(); // MEM_STATS_INC(illegal); // MEM_HEAP_UNPROTECT(); // return rmem; // } #define USE_FIX_MALLOC 1 /* protect the heap from concurrent access */ MEM_HEAP_PROTECT(); /* Get the corresponding struct mem ... */ mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); /* ... and its offset pointer */ size = (mem_size_t)(mem->next) - (mem_size_t)mem - SIZEOF_STRUCT_MEM; #if USE_FIX_MALLOC == 0 MEM_HEAP_UNPROTECT(); #endif if (newsize > size) { #if USE_FIX_MALLOC == 1 if ((mem->next->used == MEM_UNUSED) && ((mem_size_t)(mem->next->next) - (mem_size_t)mem - SIZEOF_STRUCT_MEM >= newsize)) { new_mem = (struct mem *)((mem_size_t)mem + SIZEOF_STRUCT_MEM + newsize); if ((mem_size_t)(mem->next->next) - (mem_size_t)new_mem >= SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED) { if (mem_heap.lfree == mem->next) { mem_heap.lfree = new_mem; } if (mem_heap.ram_end->prev == mem->next) { mem_heap.ram_end->prev = new_mem; } mem->next->next->prev = new_mem; new_mem->next = mem->next->next; new_mem->prev = mem; new_mem->used = MEM_UNUSED; #if MEM_HEAP_ERROR_CHECK == 1 new_mem->check_after = MEM_HEAP_OVERFLOW_MAGIC; new_mem->check_before = MEM_HEAP_OVERFLOW_MAGIC; #endif mem->next = new_mem; MEM_STATS_INC_USED(used, (newsize - size)); } else { MEM_STATS_INC_USED(used, ((mem_size_t)mem->next->next - (mem_size_t)mem->next - SIZEOF_STRUCT_MEM)); if (mem_heap.lfree == mem->next) { struct mem *cur = mem->next->next; while ((cur->used == MEM_USED) && cur != mem_heap.ram_end) { cur = cur->next; } mem_heap.lfree = cur; } if (mem_heap.ram_end->prev == mem->next) { mem_heap.ram_end->prev = mem; } mem->next->next->prev = mem; mem->next = mem->next->next; } MEM_HEAP_UNPROTECT(); return rmem; } else { MEM_HEAP_UNPROTECT(); new_rmem = malloc(newsize); if (new_rmem != (void *)0) { memmove(new_rmem, rmem, size); free(rmem); rmem = new_rmem; return rmem; } else { MEM_HEAP_DEBUGF(MEM_HEAP_DEBUG, ("mem_realloc: could not allocate %d bytes\n", (mem_size_t)newsize)); return (void *)0; } } #else new_rmem = malloc(newsize); if (new_rmem != (void *)0) { memmove(new_rmem, rmem, size); free(rmem); rmem = new_rmem; return rmem; } else { MEM_HEAP_DEBUGF(MEM_HEAP_DEBUG, ("mem_realloc: could not allocate %d bytes\n", (mem_size_t)newsize)); return (void *)0; } #endif } else if (newsize < size) { #if USE_FIX_MALLOC == 1 mem2 = mem->next; if (mem2->used == MEM_UNUSED) { /* The next struct is unused, we can simply move it at little */ struct mem *next; /* remember the old next pointer */ next = mem2->next; /* create new struct mem which is moved directly after the shrinked mem */ new_mem = (struct mem *)((mem_size_t)mem + SIZEOF_STRUCT_MEM + newsize); if (mem_heap.lfree == mem2) { mem_heap.lfree = new_mem; } if (mem_heap.ram_end->prev == mem2) { mem_heap.ram_end->prev = new_mem; } #if MEM_HEAP_ERROR_CHECK == 1 new_mem->check_after = MEM_HEAP_OVERFLOW_MAGIC; new_mem->check_before = MEM_HEAP_OVERFLOW_MAGIC; #endif mem2 = new_mem; mem2->used = MEM_UNUSED; /* restore the next pointer */ mem2->next = next; /* link it back to mem */ mem2->prev = mem; /* link mem to it */ mem->next = mem2; /* last thing to restore linked list: as we have moved mem2, * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not * the end of the heap */ if (mem2->next != mem_heap.ram_end) { //imposible? mem2->next->prev = mem2; } MEM_STATS_DEC_USED(used, (size - newsize)); /* no need to plug holes, we've already done that */ } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) { /* Next struct is used but there's room for another struct mem with * at least MIN_SIZE_ALIGNED of data. * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED'). * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty * region that couldn't hold data, but when mem->next gets freed, * the 2 regions would be combined, resulting in more free memory */ new_mem = (struct mem *)((mem_size_t)mem + SIZEOF_STRUCT_MEM + newsize); #if MEM_HEAP_ERROR_CHECK == 1 new_mem->check_after = MEM_HEAP_OVERFLOW_MAGIC; new_mem->check_before = MEM_HEAP_OVERFLOW_MAGIC; #endif mem2 = new_mem; if (mem2 < mem_heap.lfree) { mem_heap.lfree = mem2; } mem2->used = MEM_UNUSED; mem2->next = mem->next; mem2->prev = mem; mem->next = mem2; if (mem2->next != mem_heap.ram_end) { mem2->next->prev = mem2; } if (mem_heap.ram_end->prev == mem) { mem_heap.ram_end->prev = mem2; } MEM_STATS_DEC_USED(used, (size - newsize - SIZEOF_STRUCT_MEM)); /* the original mem->next is used, so no need to plug holes! */ } /* else { next struct mem is used but size between mem and mem2 is not big enough to create another struct mem -> don't do anyhting. -> the remaining space stays unused since it is too small } */ MEM_HEAP_UNPROTECT(); return rmem; #else return rmem; #endif } else if (newsize == size) { #if USE_FIX_MALLOC == 1 MEM_HEAP_UNPROTECT(); #endif /* No change in size, simply return */ return rmem; } return (void *)0; } #if MEM_HEAP_ERROR_CHECK == 1 void mem_heap_check(const char *const func, unsigned int line) { MEM_HEAP_DECL_PROTECT(); MEM_HEAP_PROTECT(); struct mem *mem; for (mem = (struct mem *)mem_heap.ram; mem != mem_heap.ram_end->prev; mem = mem->next) { if (((u32_t)mem > (u32_t)mem_heap.ram + mem_heap.mem_heap_size + SIZEOF_STRUCT_MEM) || ((u32_t)mem < (u32_t)mem_heap.ram) || ((u32_t)mem->next > (u32_t)mem_heap.ram + mem_heap.mem_heap_size + SIZEOF_STRUCT_MEM) || ((u32_t)mem->next < (u32_t)mem_heap.ram) || ((u32_t)mem->prev > (u32_t)mem_heap.ram + mem_heap.mem_heap_size + SIZEOF_STRUCT_MEM) || ((u32_t)mem->prev < (u32_t)mem_heap.ram) || ((mem->used != MEM_USED) && (mem->used != MEM_UNUSED)) || (mem->check_before != MEM_HEAP_OVERFLOW_MAGIC) || (mem->check_after != MEM_HEAP_OVERFLOW_MAGIC) ) { printf("{%s, %d", func, line); printf("\n\n\n\n\n\n\n\nmem_heap was maliciously modified:\n"\ "mem_heap.ram = 0x%x\n"\ "mem_heap.mem_heap_size = 0x%x\n"\ "mem = 0x%x\n"\ "mem->next = 0x%x\n"\ "mem->prev = 0x%x\n"\ "mem->used = 0x%x\n"\ "mem->rets_addr = 0x%x\n"\ "mem->check_before = 0x%x\n"\ "mem->check_after = 0x%x\n\n\n\n\n\n\n\n\n", \ (u32_t)mem_heap.ram, mem_heap.mem_heap_size, (u32_t)mem, (u32_t)mem->next, (u32_t)mem->prev, mem->used, mem->rets_addr, mem->check_before, mem->check_after); while (1); } } // if(func) // { // puts("}"); // } MEM_HEAP_UNPROTECT(); } #endif #define SBRK_INTERNAL #ifdef SBRK_INTERNAL static void *sbrk(int increment) { static unsigned char *__init_addr = 0; unsigned char *ret; if (__init_addr == 0) { __init_addr = (u8 *)&HEAP_BEGIN; } if ((__init_addr + increment >= (u8 *)&HEAP_END) && (increment > 0)) { return (void *) - 1; } ret = __init_addr; __init_addr += increment; // printf("increment = %x sbrk %x %x %x", increment , ret ,&HEAP_BEGIN ,&HEAP_END ) ; return ret; } #endif void *pvPortMalloc(unsigned long xWantedSize) { return malloc(xWantedSize); } void vPortFree(void *pv) { free(pv); } void *kmalloc(unsigned long size, int flags) { return malloc(size); } void *vmalloc(unsigned long size) { return malloc(size); } void vfree(void *addr) { free(addr); } void *kzalloc(unsigned int len, int a) { return calloc(1, len); } void kfree(void *p) { free(p); } void memory_init(void) { }