mirror of
https://github.com/ringtailsoftware/uvm32.git
synced 2026-06-05 22:43:39 +00:00
Example of setting up malloc heap on extram
This commit is contained in:
parent
7fae8c129f
commit
f27ed6213c
5 changed files with 369 additions and 0 deletions
12
apps/heap/Makefile
Normal file
12
apps/heap/Makefile
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
TOPDIR=../..
|
||||||
|
PROJECT:=$(shell basename ${PWD})
|
||||||
|
|
||||||
|
HEAP_SIZE=$(shell echo "1024 * 512" | bc)
|
||||||
|
OPT=-Os
|
||||||
|
CFLAGS=-DHEAP_SIZE=${HEAP_SIZE}
|
||||||
|
SRCS=${PROJECT}.c ${TOPDIR}/apps/crt0.S malloc_freelist.c
|
||||||
|
HOST_EXTRA=-e ${HEAP_SIZE} -i 100000
|
||||||
|
all: all_common
|
||||||
|
test: test_common
|
||||||
|
clean: clean_common
|
||||||
|
include ${TOPDIR}/apps/makefile.common
|
||||||
66
apps/heap/heap.c
Normal file
66
apps/heap/heap.c
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
#include "uvm32_target.h"
|
||||||
|
#include "malloc_freelist.h"
|
||||||
|
|
||||||
|
uint32_t* extram = (uint32_t*)UVM32_EXTRAM_BASE;
|
||||||
|
uint32_t extram_len = HEAP_SIZE;
|
||||||
|
|
||||||
|
void* memcpy(void* dst, const void* src, int len) {
|
||||||
|
uint8_t* d = (uint8_t*)dst;
|
||||||
|
const uint8_t* s = (const uint8_t*)src;
|
||||||
|
while (len--) {
|
||||||
|
*(d++) = *(s++);
|
||||||
|
}
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* memset(void* buf, int c, int len) {
|
||||||
|
uint8_t* b = (uint8_t*)buf;
|
||||||
|
while (len--) {
|
||||||
|
*(b++) = c;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* memmove(void* dest, const void* src, size_t len) {
|
||||||
|
char* d = dest;
|
||||||
|
const char* s = src;
|
||||||
|
if (d < s)
|
||||||
|
while (len--)
|
||||||
|
*d++ = *s++;
|
||||||
|
else {
|
||||||
|
const char* lasts = s + (len - 1);
|
||||||
|
char* lastd = d + (len - 1);
|
||||||
|
while (len--)
|
||||||
|
*lastd-- = *lasts--;
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
void force_crash(void) {
|
||||||
|
uint8_t *p = (uint8_t *)0;
|
||||||
|
p[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
malloc_addblock(extram, extram_len);
|
||||||
|
|
||||||
|
uint8_t* p1 = fl_malloc(128);
|
||||||
|
if (p1 == NULL) {
|
||||||
|
println("malloc failed");
|
||||||
|
} else {
|
||||||
|
println("malloc ok");
|
||||||
|
}
|
||||||
|
memset(p1, 'a', 128);
|
||||||
|
fl_free(p1);
|
||||||
|
|
||||||
|
uint8_t* p2 = fl_malloc(256);
|
||||||
|
if (p2 == NULL) {
|
||||||
|
println("malloc failed");
|
||||||
|
} else {
|
||||||
|
println("malloc ok");
|
||||||
|
}
|
||||||
|
memset(p2, 'b', 256);
|
||||||
|
fl_free(p2);
|
||||||
|
|
||||||
|
//force_crash(); // allows dump to be inspected
|
||||||
|
}
|
||||||
109
apps/heap/linkedlist.h
Normal file
109
apps/heap/linkedlist.h
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
// Copyright Embedded Artistry LLC 2017
|
||||||
|
// Released under CC0 1.0 Universal License
|
||||||
|
|
||||||
|
#ifndef __LL_H_
|
||||||
|
#define __LL_H_
|
||||||
|
|
||||||
|
#include "uvm32_target.h"
|
||||||
|
//#include <stdlib.h> //size_t, NULL
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define offsetof and container_of if we don't have them already
|
||||||
|
*/
|
||||||
|
#ifndef offsetof
|
||||||
|
#ifdef __compiler_offsetof
|
||||||
|
#define offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE, MEMBER)
|
||||||
|
#else
|
||||||
|
#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE*)0)->MEMBER)
|
||||||
|
#endif
|
||||||
|
#endif // offsetof
|
||||||
|
|
||||||
|
#ifndef container_of
|
||||||
|
#define container_of(ptr, type, member) \
|
||||||
|
({ \
|
||||||
|
const __typeof__(((type*)0)->member)* __mptr = (ptr); \
|
||||||
|
(type*)((char*)__mptr - offsetof(type, member)); \
|
||||||
|
})
|
||||||
|
#endif // container_of
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif //__cplusplus
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a doubly linked list structure.
|
||||||
|
* This structure should be embedded in a container structure that you want to list.
|
||||||
|
*/
|
||||||
|
typedef struct ll_head
|
||||||
|
{
|
||||||
|
struct ll_head* next; /**< Next pointer */
|
||||||
|
struct ll_head* prev; /**< Previous pointer */
|
||||||
|
} ll_t;
|
||||||
|
|
||||||
|
#define list_entry(ptr, type, member) container_of(ptr, type, member)
|
||||||
|
|
||||||
|
#define list_first_entry(head, type, member) list_entry((head)->next, type, member)
|
||||||
|
|
||||||
|
#define list_for_each(pos, head) for(pos = (head)->next; pos != (head); pos = pos->next)
|
||||||
|
|
||||||
|
#define list_for_each_safe(pos, n, head) \
|
||||||
|
for(pos = (head)->next, n = pos->next; pos != (head); pos = n, n = pos->next)
|
||||||
|
|
||||||
|
#define list_for_each_entry(pos, head, member) \
|
||||||
|
for(pos = list_entry((head)->next, __typeof__(*pos), member); &pos->member != (head); \
|
||||||
|
pos = list_entry(pos->member.next, __typeof__(*pos), member))
|
||||||
|
|
||||||
|
#define list_for_each_entry_safe(pos, n, head, member) \
|
||||||
|
for(pos = list_entry((head)->next, __typeof__(*pos), member), \
|
||||||
|
n = list_entry(pos->member.next, __typeof__(*pos), member); \
|
||||||
|
&pos->member != (head); pos = n, n = list_entry(n->member.next, __typeof__(*n), member))
|
||||||
|
|
||||||
|
#pragma mark - Init -
|
||||||
|
|
||||||
|
#define ll_head_INIT(name) \
|
||||||
|
{ \
|
||||||
|
&(name), &(name) \
|
||||||
|
}
|
||||||
|
#define LIST_INIT(name) struct ll_head name = ll_head_INIT(name)
|
||||||
|
|
||||||
|
#pragma mark - Add -
|
||||||
|
|
||||||
|
static inline void list_add_(struct ll_head* n, struct ll_head* prev, struct ll_head* next)
|
||||||
|
{
|
||||||
|
next->prev = n;
|
||||||
|
n->next = next;
|
||||||
|
n->prev = prev;
|
||||||
|
prev->next = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void list_add(struct ll_head* n, struct ll_head* head)
|
||||||
|
{
|
||||||
|
list_add_(n, head, head->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void list_add_tail(struct ll_head* n, struct ll_head* head)
|
||||||
|
{
|
||||||
|
list_add_(n, head->prev, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Delete -
|
||||||
|
|
||||||
|
static inline void list_del_(struct ll_head* prev, struct ll_head* next)
|
||||||
|
{
|
||||||
|
next->prev = prev;
|
||||||
|
prev->next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void list_del(struct ll_head* entry)
|
||||||
|
{
|
||||||
|
list_del_(entry->prev, entry->next);
|
||||||
|
entry->next = NULL;
|
||||||
|
entry->prev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif //__cplusplus
|
||||||
|
|
||||||
|
#endif // __LL_H_
|
||||||
152
apps/heap/malloc_freelist.c
Normal file
152
apps/heap/malloc_freelist.c
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
//#include <stdint.h>
|
||||||
|
#include "uvm32_target.h"
|
||||||
|
#include "linkedlist.h"
|
||||||
|
|
||||||
|
#pragma mark - Definitions -
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple macro for making sure memory addresses are aligned
|
||||||
|
* to the nearest power of two
|
||||||
|
*/
|
||||||
|
#ifndef align_up
|
||||||
|
#define align_up(num, align) (((num) + ((align)-1)) & ~((align)-1))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the container for our free-list.
|
||||||
|
* Node the usage of the linked list here: the library uses offsetof
|
||||||
|
* and container_of to manage the list and get back to the parent struct.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ll_t node;
|
||||||
|
size_t size;
|
||||||
|
char* block;
|
||||||
|
} alloc_node_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We vend a memory address to the user. This lets us translate back and forth
|
||||||
|
* between the vended pointer and the container we use for managing the data.
|
||||||
|
*/
|
||||||
|
#define ALLOC_HEADER_SZ offsetof(alloc_node_t, block)
|
||||||
|
|
||||||
|
// We are enforcing a minimum allocation size of 32B.
|
||||||
|
#define MIN_ALLOC_SZ ALLOC_HEADER_SZ + 32
|
||||||
|
|
||||||
|
#pragma mark - Prototypes -
|
||||||
|
|
||||||
|
static void defrag_free_list(void);
|
||||||
|
|
||||||
|
#pragma mark - Declarations -
|
||||||
|
|
||||||
|
// This macro simply declares and initializes our linked list
|
||||||
|
static LIST_INIT(free_list);
|
||||||
|
|
||||||
|
#pragma mark - Private Functions -
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When we free, we can take our node and check to see if any memory blocks
|
||||||
|
* can be combined into larger blocks. This will help us fight against
|
||||||
|
* memory fragmentation in a simple way.
|
||||||
|
*/
|
||||||
|
void defrag_free_list(void)
|
||||||
|
{
|
||||||
|
alloc_node_t *block, *last_block = NULL, *t;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(block, t, &free_list, node)
|
||||||
|
{
|
||||||
|
if(last_block)
|
||||||
|
{
|
||||||
|
if((((uintptr_t)&last_block->block) + last_block->size) == (uintptr_t)block)
|
||||||
|
{
|
||||||
|
last_block->size += ALLOC_HEADER_SZ + block->size;
|
||||||
|
list_del(&block->node);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_block = block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#pragma mark - APIs -
|
||||||
|
|
||||||
|
void* fl_malloc(size_t size)
|
||||||
|
{
|
||||||
|
void* ptr = NULL;
|
||||||
|
alloc_node_t* blk = NULL;
|
||||||
|
|
||||||
|
if(size > 0)
|
||||||
|
{
|
||||||
|
// Align the pointer
|
||||||
|
size = align_up(size, sizeof(void*));
|
||||||
|
|
||||||
|
// try to find a big enough block to alloc
|
||||||
|
list_for_each_entry(blk, &free_list, node)
|
||||||
|
{
|
||||||
|
if(blk->size >= size)
|
||||||
|
{
|
||||||
|
ptr = &blk->block;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// we found something
|
||||||
|
if(ptr)
|
||||||
|
{
|
||||||
|
// Can we split the block?
|
||||||
|
if((blk->size - size) >= MIN_ALLOC_SZ)
|
||||||
|
{
|
||||||
|
alloc_node_t* new_blk;
|
||||||
|
new_blk = (alloc_node_t*)((uintptr_t)(&blk->block) + size);
|
||||||
|
new_blk->size = blk->size - size - ALLOC_HEADER_SZ;
|
||||||
|
blk->size = size;
|
||||||
|
list_add_(&new_blk->node, &blk->node, blk->node.next);
|
||||||
|
}
|
||||||
|
|
||||||
|
list_del(&blk->node);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // else NULL
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fl_free(void* ptr)
|
||||||
|
{
|
||||||
|
alloc_node_t *blk, *free_blk;
|
||||||
|
|
||||||
|
// Don't free a NULL pointer..
|
||||||
|
if(ptr)
|
||||||
|
{
|
||||||
|
// we take the pointer and use container_of to get the corresponding alloc block
|
||||||
|
blk = container_of(ptr, alloc_node_t, block);
|
||||||
|
|
||||||
|
// Let's put it back in the proper spot
|
||||||
|
list_for_each_entry(free_blk, &free_list, node)
|
||||||
|
{
|
||||||
|
if(free_blk > blk)
|
||||||
|
{
|
||||||
|
list_add_(&blk->node, free_blk->node.prev, &free_blk->node);
|
||||||
|
goto blockadded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list_add_tail(&blk->node, &free_list);
|
||||||
|
|
||||||
|
blockadded:
|
||||||
|
// Let's see if we can combine any memory
|
||||||
|
defrag_free_list();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void malloc_addblock(void* addr, size_t size)
|
||||||
|
{
|
||||||
|
alloc_node_t* blk;
|
||||||
|
|
||||||
|
// let's align the start address of our block to the next pointer aligned number
|
||||||
|
blk = (void*)align_up((uintptr_t)addr, sizeof(void*));
|
||||||
|
|
||||||
|
// calculate actual size - remove our alignment and our header space from the availability
|
||||||
|
blk->size = (uintptr_t)addr + size - (uintptr_t)blk - ALLOC_HEADER_SZ;
|
||||||
|
|
||||||
|
// and now our giant block of memory is added to the list!
|
||||||
|
list_add(&blk->node, &free_list);
|
||||||
|
}
|
||||||
30
apps/heap/malloc_freelist.h
Normal file
30
apps/heap/malloc_freelist.h
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef __MALLOC_FREELIST_H_
|
||||||
|
#define __MALLOC_FREELIST_H_
|
||||||
|
|
||||||
|
#include "uvm32_target.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif //__cplusplus
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize malloc with a memory address and pool size
|
||||||
|
*/
|
||||||
|
void malloc_addblock(void* addr, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free-list malloc implementation
|
||||||
|
*/
|
||||||
|
void* fl_malloc(size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Corresponding free-list free implementation
|
||||||
|
*/
|
||||||
|
void fl_free(void* ptr);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif //__cplusplus
|
||||||
|
|
||||||
|
#endif //__MALLOC_FREELIST_H_
|
||||||
Loading…
Add table
Add a link
Reference in a new issue