From: Robin Krens Date: Mon, 22 Jul 2019 18:22:23 +0000 (+0800) Subject: fixed-sized memory pool allocator X-Git-Url: https://robinkrens.nl/gitweb/?a=commitdiff_plain;h=6a0dad9f096144560b4b06da489ea8f88b0145ee;p=cortex-from-scratch fixed-sized memory pool allocator --- diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..e69de29 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..eb5ac97 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +You are free to: + + * Share — copy and redistribute the material in any medium or format + * Adapt — remix, transform, and build upon the material + +Under the following terms: + + * Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. + * NonCommercial — You may not use the material for commercial purposes. + * ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original. + + + diff --git a/Makefile b/Makefile index 788955b..d7e1652 100644 --- a/Makefile +++ b/Makefile @@ -1,33 +1,39 @@ # Copyright 2019 - Robin Krens +# +# TODO: Somehow integrate this assembly start.asm (start.o) +# + # Cross compilers links CC=arm-none-eabi-gcc LD=arm-none-eabi-ld -AR=$(TOOLROOT)/arm-none-eabi-ar AS=arm-none-eabi-as MKIMG=arm-none-eabi-objcopy # Compiler flags # TODO:Cortex-m3 or Cortex-m0? LDFLAGS+= -mthumb -mcpu=cortex-m3 -CFLAGS+= -mcpu=cortex-m3 -mthumb -g +ASFLAGS+= -mcpu=cortex-m3 -mthumb -g +CFLAGS+= -mcpu=cortex-m3 -mthumb -g -ffreestanding + +ODIR = obj +_OBJ = main.o uart.o ivt.o systick.o sysinfo.o lib.o regf.o pool.o +OBJ = $(patsubst %, $(ODIR)/%,$(_OBJ)) + + +$(ODIR)/%.o: %.c $(DEPS) + @mkdir -p $(@D) + $(CC) -c $< $(CFLAGS) -I./include -o $@ # Start up machine assembly as: - $(AS) $(CFLAGS) -o start.o start.asm + $(AS) $(ASFLAGS) -o start.o start.asm # Compile and link all -all: - $(AS) $(CFLAGS) -o start.o start.asm - $(CC) $(CFLAGS) -c -I./include -ffreestanding -o main.o main.c - $(CC) $(CFLAGS) -c -I./include -ffreestanding -o uart.o uart.c - $(CC) $(CFLAGS) -c -I./include -ffreestanding -o ivt.o ivt.c - $(CC) $(CFLAGS) -c -I./include -ffreestanding -o systick.o systick.c - $(CC) $(CFLAGS) -c -I./include -ffreestanding -o sysinfo.o sysinfo.c - $(CC) $(CFLAGS) -c -I./include -ffreestanding -o lib.o lib.c - $(CC) $(CFLAGS) -c -I./include -ffreestanding -o mm.o mm.c - $(CC) $(CFLAGS) -c -I./include -ffreestanding -o regf.o regf.c - $(LD) -nostartfiles -T link.ld -o start.out start.o main.o uart.o ivt.o systick.o sysinfo.o lib.o mm.o regf.o - $(MKIMG) -Obinary -R .data start.out kernel.bin +kernel: $(OBJ) + $(AS) $(ASFLAGS) -o start.o start.asm + $(LD) -nostartfiles -Map $@.MAP -T link.ld -o $@.ELF start.o $^ --print-memory-usage + @echo "Creating binary..." + $(MKIMG) -Obinary -R .data $@.ELF $@.bin # Run in Qemu; note this is a patched version for stm32-f103c8 run: @@ -35,23 +41,28 @@ run: # Examine all sections examine-all: - arm-none-eabi-objdump -D start.out | less + arm-none-eabi-objdump -D kernel.ELF | less # Examine just headers examine-header: - arm-none-eabi-objdump -x start.out | less + arm-none-eabi-objdump -x kernel.ELF | less # Flash kernel to board flash: stm32flash -w kernel.bin -v /dev/ttyUSB0 +.PHONY: clean -%.o: %.c - $(CC) -c $(CFLAGS) $< -o $@ - $(CC) -MM $(CFLAGS) $< > $*.d +clean: + rm -rf $(ODIR)/*.o start.o kernel.* -%.o: %.s - $(CC) -c $(CFLAGS) $< -o $@ +# Altijd handig deze template +#%.o: %.c +# $(CC) -c $(CFLAGS) $< -o $@ +# $(CC) -MM $(CFLAGS) $< > $*.d +# +#%.o: %.s +# $(CC) -c $(CFLAGS) $< -o $@ diff --git a/include/mmap.h b/include/mmap.h index 6f4fabb..aa8a902 100644 --- a/include/mmap.h +++ b/include/mmap.h @@ -16,6 +16,7 @@ /* SYSTEM CONTROL BLOCK REGISTER */ #define SCB_VTOR ((volatile uint32_t *)( 0xE000ED08)) // VECTOR TABLE #define SCB_VTOR_ST ((volatile uint32_t *)( 0xE000ED04)) // STATUS OF VECTOR +#define SCB_CCR ((volatile uint32_t *)( 0xE000ED14)) // SET SOFTWARE TRAPS /* NESTED VECTOR INTERRUPT CONTROL REGISTER */ #define NVIC_ISER0 ((volatile uint32_t*)( 0xE000E100)) // interrupt set enable register diff --git a/include/stm32.h b/include/stm32.h index 62ee93e..bc510d4 100644 --- a/include/stm32.h +++ b/include/stm32.h @@ -30,10 +30,15 @@ extern void addrtohex(const uint32_t); /* MM.C */ extern void mm_init(); -extern void * mm_alloc(size_t); +extern void * malloc(size_t); extern void free(void *); extern void test_memory(uint32_t *); +/* POOL.c */ +extern void pool_init(size_t, unsigned int, uint32_t *); +extern void * alloc(); +extern void free(); + /* REGF.C */ extern void regw_u8(volatile uint32_t *, uint8_t, short, short); extern void regw_u32(volatile uint32_t *, uint32_t, short, short); diff --git a/ivt.c b/ivt.c index 973d306..33a2bd4 100644 --- a/ivt.c +++ b/ivt.c @@ -1,3 +1,13 @@ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/7/20 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * + * */ + #include #include #include @@ -105,10 +115,11 @@ void ivt_init() { // don't need to relocate or init this here extern void * reset, * nmi, * hardfault; - for (int i = 1; i <= 6 ; i++) { + for (int i = 1; i <= 64 ; i++) { ivt_set_gate(i, dummy_isr, 0); } + /* the vector table starts at 0x0. Since the address 0x0 point to * bootcode, it is on ROM or FLASH. The vector table can be * relocated to other memory locations. We can do this by setting diff --git a/link.ld b/link.ld index 085ab79..db37888 100644 --- a/link.ld +++ b/link.ld @@ -21,7 +21,7 @@ SECTIONS { *(.data) } - .bss : ALIGN(256) + .bss : ALIGN(256) { *(.bss) } diff --git a/main.c b/main.c index 73e55e0..19d0eb5 100644 --- a/main.c +++ b/main.c @@ -48,11 +48,11 @@ void main() uart_init(); //uart_puts("LOADING SYSTEM 0.1 ...\n"); systick_init(); - mm_init(); +// mm_init(); sysinfo(); - //int * p2 = mm_alloc(512); - //memset(p2, 'a', 512); + + pool_init(20, 5, 0x20000800); //addrtohex(p2); //addrtohex(*p2); diff --git a/mm.c b/mm.c index 77029e7..1e20f75 100644 --- a/mm.c +++ b/mm.c @@ -1,59 +1,82 @@ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/7/20 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * Simple bitmap on bitband memory implementation for kernel + * heap. Sensitive to fragmentation over time. Bitband + * memory makes it possible to access each bit of memory + * atomically. + * + * DEPRECATED + * + * */ + + #include #include #include #include #include -/* TOTAL SRAM MEMORY: 64kB - * 64 chunks of 1kB - * 128 chunks of 512 bytes - * SIMPLE BITMAP IMPLEMENTATION + +#define CHUNKS 256 + +#define MEM_VALUE(addr) *((volatile uint32_t *) (addr)) +#define MEM_ADDR(addr) ((uint32_t *) (addr)) +#define BITBAND(a, b) ((a & 0xF0000000) + 0x02000000 + ((a &0xFFFFF)<<5) + (b<<2)) +#define INDEXTOADDR(a) (((a & 0xFFFFF) >> 5) + ((a & 0xFF000000) - 0x02000000)) + + +/* Total SRAM: ~ 64kB + * Divided into chunks (256 bytes) + * Each bit will index a chunk + * Bits needed: 0x100 (= 4 uint32_t) * */ +//uint32_t chunk_index[4]; -#define CHUNKS 128 -#define FREE 0x00 -#define ALLOC 0x01 +void mm_init() { -#define BASE 0x20000400 -#define SET_SIZE(s) (s << 8) -#define SET_FLAGS(f) (f << 24) -#define IS_ALLOC(c) ((c >> 24) & 0x0F ) -#define PADDR(i) (0x20000400 + (i * 0x200)) -#define I_OFFSET(p) ((p - 0x20000400)) +// memset(&chunk_index, 0, sizeof(uint32_t) * 4); -uint32_t chunk[CHUNKS]; -/* - * | FLAGS | SIZE | RESERVED | - * | 0x00 | 0x0000 | 0x00 | - * - * */ +// uint32_t *p = MEM_ADDR(0x20000278); + +// extern stub(); +// stub(); + // __asm__ __volatile__ ("udiv r1, r3 ,%0" :: "r"(0)); +// +// for(;;); +// *p = (uint32_t volatile) 0x12345678; +// *x = (uint32_t volatile) 0x12345679; +// addrtohex(p); +// addrtohex(*p); +// MEM_ADDR(x) = 0x1; +// + +// char * new = malloc(10); +// addrtohex(new); +// char * new2 = malloc(10); +// addrtohex(new2); -void mm_init() { - // interrupt vector - chunk[0] = SET_SIZE(96) | SET_FLAGS(ALLOC); + //uint32_t * test = MEM_ADDR(0x20000000); + //uint32_t random_location = MEM_VALUE(0x20000000); - // test - /* uart_puts("ALLOC:\n"); - int * p = mm_alloc(100); - *p = 0x12345678; + //uint32_t random_location = 0x20000900; - addrtohex(p); - addrtohex(*p); + //MEM_VALUE(random_location); + //MEM_VALUE(BITBAND(random_location, 0)) = 0x1; - uart_puts("FREE:\n"); + //addrtohex(MEM_VALUE(random_location)); - int * p2 = mm_alloc(100); - *p2 = 0xFFFFAAAA; - addrtohex(p2); - addrtohex(*p2); - free(p); - free(p2); */ + } void test_memory(uint32_t * ptr) { @@ -66,37 +89,43 @@ void mm_init() { } +/* BIT BAND SCAN */ -void * mm_alloc(size_t size) { // in bytes + /* uint32_t fits(uint32_t * current, size_t size) { + + uint32_t addr_start = current; + + for (int i = 1; i < size; i++) { + current + 4; // next bit offset is 0x4 + if ((MEM_VALUE(current)) == 0x1) + return 0x0; + } + return addr_start; + } */ - if (size > 512) { - uart_puts("SYSERROR: WE CAN'T ALLOCATE THAT MUCH!\n"); - return NULL; - } - /* check which chunk is free */ - for (int i = 1; i < CHUNKS; i++) { - if (!IS_ALLOC(chunk[i])) { - chunk[i] = SET_SIZE(size) | SET_FLAGS(ALLOC); - return (void *) PADDR(i); - } - } - - uart_puts("SYSERROR: OUT OF MEMORY\n"); - return NULL; -} +/* void * malloc(size_t size) { -void free(void *ptr) { + if (size < 256) { - uint32_t index = (uint32_t) I_OFFSET(ptr) / 0x200; + extern char * _endofbss; - uint32_t tmp = chunk[index]; - if (!IS_ALLOC(tmp)) - uart_puts("SYSERROR: ALREADY FREED!\n"); + uint32_t start = (uint32_t) &chunk_index[0]; + uint32_t current; + int offset = 0x100; - else if(index < CHUNKS) { - chunk[index] = SET_FLAGS(FREE) | SET_SIZE(0); + uint32_t * index = MEM_ADDR(BITBAND(start, 0)); + for(int i = 0; i < CHUNKS; i++) { + if (*index == 0x0) { + addrtohex(*index); + *index = 0x1; + return INDEXTOADDR(((uint32_t)index)) + (i * offset); + } + index += 0x04; + } + return NULL; } - -} +} */ + + diff --git a/pool.c b/pool.c new file mode 100644 index 0000000..fa08c29 --- /dev/null +++ b/pool.c @@ -0,0 +1,122 @@ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/7/20 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * Fixed-sized memory pool allocation. A so called + * memory-pool (i.e. 4kB * 12 blocks) can be + * initialized. Note: this allocator is for use on + * processors without an MMU (memory management + * unit). A MPU (memory protection unit), if + * available can be used to protect certain zones. + * + * This work is based on an article of Ben Kenwright + * + * Preconditions: programmer should make sure the + * SRAM entry point + (blocks * blocksize) is free. + * + * $SAMPLE USAGE$ + * KERNEL: can use initialize a big pool for all + * user tasks + * + * USER TASKS/PROCESS: can use this to dynamically + * allocate their own memory (i.e. heap) + * + * + * * */ + +#include +#include +#include +#include +#include + + +struct MEMPOOL { + + unsigned short blocks; + unsigned short block_size; + unsigned short free_blocks; + unsigned short blocks_alloc; + uint32_t * SRAM_entry; + uint32_t * m_next; + +}; + +struct MEMPOOL mem; + + +void pool_init(size_t size_arg, unsigned int blocks_arg, uint32_t * entry_SRAM) { + + mem.blocks = blocks_arg; + mem.block_size = size_arg; + mem.SRAM_entry = entry_SRAM; + memset(entry_SRAM, 0x00, (sizeof(char) * (size_arg * blocks_arg))); + mem.free_blocks = blocks_arg; + mem.m_next = mem.SRAM_entry; + + +/* uint32_t * a = alloc(); + uint32_t * b = alloc(); + uint32_t * c = alloc(); + free(c); + uint32_t * d = alloc(); + + addrtohex(a); + addrtohex(b); + addrtohex(c); + addrtohex(d); */ + + } + + + /* void deletepool() { + mem.SRAM_entry = NULL; + } */ + +uint32_t * AddrFromIndex(unsigned int i) { + return mem.SRAM_entry + ( i * mem.block_size ); + + } + +unsigned int IndexFromAddr(const uint32_t * p) { + return (((unsigned int)(p - mem.SRAM_entry)) / mem.block_size); + +} + +void * alloc() { + if (mem.blocks_alloc < mem.blocks ) { + unsigned int * p = (unsigned int *)AddrFromIndex( mem.blocks_alloc ); + *p = mem.blocks_alloc + 1; + mem.blocks_alloc++; + } + + void* ret = NULL; + if ( mem.free_blocks > 0 ) { + ret = (void*)mem.m_next; + --mem.free_blocks; + if (mem.free_blocks!=0) { + mem.m_next = AddrFromIndex( *((unsigned int*)mem.m_next) ); + } + else { + mem.m_next = NULL; + } + } + + return ret; + } + +void free(void* p) { + if (mem.m_next != NULL) { + (*(unsigned int *)p) = IndexFromAddr( mem.m_next ); + mem.m_next = (uint32_t *)p; + } + else { + *((unsigned int*)p) = mem.blocks; + mem.m_next = (uint32_t *) p; + } + + ++mem.free_blocks; + }