From 30bfd752b130eff3c194053465785d30009b2a22 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Wed, 14 Oct 2015 18:14:30 -0700 Subject: [PATCH 01/19] [lib][heap] first stab at breaking the heap into a generic heap layer and a specific implementation The old implementation is now called 'miniheap' --- lib/heap/heap.c | 628 ----------------------- lib/heap/heap_wrapper.c | 212 ++++++++ {include => lib/heap/include}/lib/heap.h | 17 +- lib/heap/miniheap/include/lib/miniheap.h | 45 ++ lib/heap/miniheap/miniheap.c | 456 ++++++++++++++++ lib/heap/miniheap/rules.mk | 10 + lib/heap/rules.mk | 6 +- 7 files changed, 729 insertions(+), 645 deletions(-) delete mode 100644 lib/heap/heap.c create mode 100644 lib/heap/heap_wrapper.c rename {include => lib/heap/include}/lib/heap.h (84%) create mode 100644 lib/heap/miniheap/include/lib/miniheap.h create mode 100644 lib/heap/miniheap/miniheap.c create mode 100644 lib/heap/miniheap/rules.mk diff --git a/lib/heap/heap.c b/lib/heap/heap.c deleted file mode 100644 index 7e99bf6d..00000000 --- a/lib/heap/heap.c +++ /dev/null @@ -1,628 +0,0 @@ -/* - * Copyright (c) 2008-2009,2012-2014 Travis Geiselbrecht - * Copyright (c) 2009 Corey Tabaka - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define LOCAL_TRACE 0 - -#define DEBUG_HEAP 0 -#define ALLOC_FILL 0x99 -#define FREE_FILL 0x77 -#define PADDING_FILL 0x55 -#define PADDING_SIZE 64 - -#define HEAP_MAGIC 'HEAP' - -#if WITH_KERNEL_VM - -#include -/* we will use kalloc routines to back our heap */ -#if !defined(HEAP_GROW_SIZE) -#define HEAP_GROW_SIZE (4 * 1024 * 1024) /* size the heap grows by when it runs out of memory */ -#endif - -STATIC_ASSERT(IS_PAGE_ALIGNED(HEAP_GROW_SIZE)); - -#elif WITH_STATIC_HEAP - -#if !defined(HEAP_START) || !defined(HEAP_LEN) -#error WITH_STATIC_HEAP set but no HEAP_START or HEAP_LEN defined -#endif - -#else -/* not a static vm, not using the kernel vm */ -extern int _end; -extern int _end_of_ram; - -/* default to using up the rest of memory after the kernel ends */ -/* may be modified by other parts of the system */ -uintptr_t _heap_start = (uintptr_t)&_end; -uintptr_t _heap_end = (uintptr_t)&_end_of_ram; - -#define HEAP_START ((uintptr_t)_heap_start) -#define HEAP_LEN ((uintptr_t)_heap_end - HEAP_START) -#endif - -struct free_heap_chunk { - struct list_node node; - size_t len; -}; - -struct heap { - void *base; - size_t len; - size_t remaining; - size_t low_watermark; - mutex_t lock; - struct list_node free_list; - struct list_node delayed_free_list; - spin_lock_t delayed_free_lock; -}; - -// heap static vars -static struct heap theheap; - -// structure placed at the beginning every allocation -struct alloc_struct_begin { -#if LK_DEBUGLEVEL > 1 - unsigned int magic; -#endif - void *ptr; - size_t size; -#if DEBUG_HEAP - void *padding_start; - size_t padding_size; -#endif -}; - -static ssize_t heap_grow(size_t len); - -static void dump_free_chunk(struct free_heap_chunk *chunk) -{ - dprintf(INFO, "\t\tbase %p, end 0x%lx, len 0x%zx\n", chunk, (vaddr_t)chunk + chunk->len, chunk->len); -} - -static void heap_dump(void) -{ - dprintf(INFO, "Heap dump:\n"); - dprintf(INFO, "\tbase %p, len 0x%zx\n", theheap.base, theheap.len); - dprintf(INFO, "\tfree list:\n"); - - mutex_acquire(&theheap.lock); - - struct free_heap_chunk *chunk; - list_for_every_entry(&theheap.free_list, chunk, struct free_heap_chunk, node) { - dump_free_chunk(chunk); - } - mutex_release(&theheap.lock); - - dprintf(INFO, "\tdelayed free list:\n"); - spin_lock_saved_state_t state; - spin_lock_irqsave(&theheap.delayed_free_lock, state); - list_for_every_entry(&theheap.delayed_free_list, chunk, struct free_heap_chunk, node) { - dump_free_chunk(chunk); - } - spin_unlock_irqrestore(&theheap.delayed_free_lock, state); -} - -static void heap_test(void) -{ - void *ptr[16]; - - ptr[0] = heap_alloc(8, 0); - ptr[1] = heap_alloc(32, 0); - ptr[2] = heap_alloc(7, 0); - ptr[3] = heap_alloc(0, 0); - ptr[4] = heap_alloc(98713, 0); - ptr[5] = heap_alloc(16, 0); - - heap_free(ptr[5]); - heap_free(ptr[1]); - heap_free(ptr[3]); - heap_free(ptr[0]); - heap_free(ptr[4]); - heap_free(ptr[2]); - - heap_dump(); - - int i; - for (i=0; i < 16; i++) - ptr[i] = 0; - - for (i=0; i < 32768; i++) { - unsigned int index = (unsigned int)rand() % 16; - - if ((i % (16*1024)) == 0) - printf("pass %d\n", i); - -// printf("index 0x%x\n", index); - if (ptr[index]) { -// printf("freeing ptr[0x%x] = %p\n", index, ptr[index]); - heap_free(ptr[index]); - ptr[index] = 0; - } - unsigned int align = 1 << ((unsigned int)rand() % 8); - ptr[index] = heap_alloc((unsigned int)rand() % 32768, align); -// printf("ptr[0x%x] = %p, align 0x%x\n", index, ptr[index], align); - - DEBUG_ASSERT(((addr_t)ptr[index] % align) == 0); -// heap_dump(); - } - - for (i=0; i < 16; i++) { - if (ptr[i]) - heap_free(ptr[i]); - } - - heap_dump(); -} - -// try to insert this free chunk into the free list, consuming the chunk by merging it with -// nearby ones if possible. Returns base of whatever chunk it became in the list. -static struct free_heap_chunk *heap_insert_free_chunk(struct free_heap_chunk *chunk) -{ -#if LK_DEBUGLEVEL > INFO - vaddr_t chunk_end = (vaddr_t)chunk + chunk->len; -#endif - - LTRACEF("chunk ptr %p, size 0x%zx\n", chunk, chunk->len); - - struct free_heap_chunk *next_chunk; - struct free_heap_chunk *last_chunk; - - mutex_acquire(&theheap.lock); - - theheap.remaining += chunk->len; - - // walk through the list, finding the node to insert before - list_for_every_entry(&theheap.free_list, next_chunk, struct free_heap_chunk, node) { - if (chunk < next_chunk) { - DEBUG_ASSERT(chunk_end <= (vaddr_t)next_chunk); - - list_add_before(&next_chunk->node, &chunk->node); - - goto try_merge; - } - } - - // walked off the end of the list, add it at the tail - list_add_tail(&theheap.free_list, &chunk->node); - - // try to merge with the previous chunk -try_merge: - last_chunk = list_prev_type(&theheap.free_list, &chunk->node, struct free_heap_chunk, node); - if (last_chunk) { - if ((vaddr_t)last_chunk + last_chunk->len == (vaddr_t)chunk) { - // easy, just extend the previous chunk - last_chunk->len += chunk->len; - - // remove ourself from the list - list_delete(&chunk->node); - - // set the chunk pointer to the newly extended chunk, in case - // it needs to merge with the next chunk below - chunk = last_chunk; - } - } - - // try to merge with the next chunk - if (next_chunk) { - if ((vaddr_t)chunk + chunk->len == (vaddr_t)next_chunk) { - // extend our chunk - chunk->len += next_chunk->len; - - // remove them from the list - list_delete(&next_chunk->node); - } - } - - mutex_release(&theheap.lock); - - return chunk; -} - -static struct free_heap_chunk *heap_create_free_chunk(void *ptr, size_t len, bool allow_debug) -{ - DEBUG_ASSERT((len % sizeof(void *)) == 0); // size must be aligned on pointer boundary - -#if DEBUG_HEAP - if (allow_debug) - memset(ptr, FREE_FILL, len); -#endif - - struct free_heap_chunk *chunk = (struct free_heap_chunk *)ptr; - chunk->len = len; - - return chunk; -} - -static void heap_free_delayed_list(void) -{ - struct list_node list; - - list_initialize(&list); - - spin_lock_saved_state_t state; - spin_lock_irqsave(&theheap.delayed_free_lock, state); - - struct free_heap_chunk *chunk; - while ((chunk = list_remove_head_type(&theheap.delayed_free_list, struct free_heap_chunk, node))) { - list_add_head(&list, &chunk->node); - } - spin_unlock_irqrestore(&theheap.delayed_free_lock, state); - - while ((chunk = list_remove_head_type(&list, struct free_heap_chunk, node))) { - LTRACEF("freeing chunk %p\n", chunk); - heap_insert_free_chunk(chunk); - } -} - -void *heap_alloc(size_t size, unsigned int alignment) -{ - void *ptr; -#if DEBUG_HEAP - size_t original_size = size; -#endif - - LTRACEF("size %zd, align %d\n", size, alignment); - - // deal with the pending free list - if (unlikely(!list_is_empty(&theheap.delayed_free_list))) { - heap_free_delayed_list(); - } - - // alignment must be power of 2 - if (alignment & (alignment - 1)) - return NULL; - - // we always put a size field + base pointer + magic in front of the allocation - size += sizeof(struct alloc_struct_begin); -#if DEBUG_HEAP - size += PADDING_SIZE; -#endif - - // make sure we allocate at least the size of a struct free_heap_chunk so that - // when we free it, we can create a struct free_heap_chunk struct and stick it - // in the spot - if (size < sizeof(struct free_heap_chunk)) - size = sizeof(struct free_heap_chunk); - - // round up size to a multiple of native pointer size - size = ROUNDUP(size, sizeof(void *)); - - // deal with nonzero alignments - if (alignment > 0) { - if (alignment < 16) - alignment = 16; - - // add alignment for worst case fit - size += alignment; - } - -#if WITH_KERNEL_VM - int retry_count = 0; -retry: -#endif - mutex_acquire(&theheap.lock); - - // walk through the list - ptr = NULL; - struct free_heap_chunk *chunk; - list_for_every_entry(&theheap.free_list, chunk, struct free_heap_chunk, node) { - DEBUG_ASSERT((chunk->len % sizeof(void *)) == 0); // len should always be a multiple of pointer size - - // is it big enough to service our allocation? - if (chunk->len >= size) { - ptr = chunk; - - // remove it from the list - struct list_node *next_node = list_next(&theheap.free_list, &chunk->node); - list_delete(&chunk->node); - - if (chunk->len > size + sizeof(struct free_heap_chunk)) { - // there's enough space in this chunk to create a new one after the allocation - struct free_heap_chunk *newchunk = heap_create_free_chunk((uint8_t *)ptr + size, chunk->len - size, true); - - // truncate this chunk - chunk->len -= chunk->len - size; - - // add the new one where chunk used to be - if (next_node) - list_add_before(next_node, &newchunk->node); - else - list_add_tail(&theheap.free_list, &newchunk->node); - } - - // the allocated size is actually the length of this chunk, not the size requested - DEBUG_ASSERT(chunk->len >= size); - size = chunk->len; - -#if DEBUG_HEAP - memset(ptr, ALLOC_FILL, size); -#endif - - ptr = (void *)((addr_t)ptr + sizeof(struct alloc_struct_begin)); - - // align the output if requested - if (alignment > 0) { - ptr = (void *)ROUNDUP((addr_t)ptr, (addr_t)alignment); - } - - struct alloc_struct_begin *as = (struct alloc_struct_begin *)ptr; - as--; -#if LK_DEBUGLEVEL > 1 - as->magic = HEAP_MAGIC; -#endif - as->ptr = (void *)chunk; - as->size = size; - theheap.remaining -= size; - - if (theheap.remaining < theheap.low_watermark) { - theheap.low_watermark = theheap.remaining; - } -#if DEBUG_HEAP - as->padding_start = ((uint8_t *)ptr + original_size); - as->padding_size = (((addr_t)chunk + size) - ((addr_t)ptr + original_size)); -// printf("padding start %p, size %u, chunk %p, size %u\n", as->padding_start, as->padding_size, chunk, size); - - memset(as->padding_start, PADDING_FILL, as->padding_size); -#endif - - break; - } - } - - mutex_release(&theheap.lock); - -#if WITH_KERNEL_VM - /* try to grow the heap if we can */ - if (ptr == NULL && retry_count == 0) { - size_t growby = MAX(HEAP_GROW_SIZE, ROUNDUP(size, PAGE_SIZE)); - - ssize_t err = heap_grow(growby); - if (err >= 0) { - retry_count++; - goto retry; - } - } -#endif - - LTRACEF("returning ptr %p\n", ptr); - - return ptr; -} - -void heap_free(void *ptr) -{ - if (ptr == 0) - return; - - LTRACEF("ptr %p\n", ptr); - - // check for the old allocation structure - struct alloc_struct_begin *as = (struct alloc_struct_begin *)ptr; - as--; - - DEBUG_ASSERT(as->magic == HEAP_MAGIC); - -#if DEBUG_HEAP - { - uint i; - uint8_t *pad = (uint8_t *)as->padding_start; - - for (i = 0; i < as->padding_size; i++) { - if (pad[i] != PADDING_FILL) { - printf("free at %p scribbled outside the lines:\n", ptr); - hexdump(pad, as->padding_size); - panic("die\n"); - } - } - } -#endif - - LTRACEF("allocation was %zd bytes long at ptr %p\n", as->size, as->ptr); - - // looks good, create a free chunk and add it to the pool - heap_insert_free_chunk(heap_create_free_chunk(as->ptr, as->size, true)); -} - -void heap_delayed_free(void *ptr) -{ - LTRACEF("ptr %p\n", ptr); - - // check for the old allocation structure - struct alloc_struct_begin *as = (struct alloc_struct_begin *)ptr; - as--; - - DEBUG_ASSERT(as->magic == HEAP_MAGIC); - - struct free_heap_chunk *chunk = heap_create_free_chunk(as->ptr, as->size, false); - - spin_lock_saved_state_t state; - spin_lock_irqsave(&theheap.delayed_free_lock, state); - list_add_head(&theheap.delayed_free_list, &chunk->node); - spin_unlock_irqrestore(&theheap.delayed_free_lock, state); -} - -void heap_get_stats(struct heap_stats *ptr) -{ - struct free_heap_chunk *chunk; - - if ((struct heap_stats*)NULL==ptr) { - return; - } - //flush the delayed free list - if (unlikely(!list_is_empty(&theheap.delayed_free_list))) { - heap_free_delayed_list(); - } - - ptr->heap_start = theheap.base; - ptr->heap_len = theheap.len; - ptr->heap_free=0; - ptr->heap_max_chunk = 0; - - mutex_acquire(&theheap.lock); - - list_for_every_entry(&theheap.free_list, chunk, struct free_heap_chunk, node) { - ptr->heap_free += chunk->len; - - if (chunk->len > ptr->heap_max_chunk) { - ptr->heap_max_chunk = chunk->len; - } - } - - ptr->heap_low_watermark = theheap.low_watermark; - - mutex_release(&theheap.lock); -} - -static ssize_t heap_grow(size_t size) -{ -#if WITH_KERNEL_VM - size = ROUNDUP(size, PAGE_SIZE); - - void *ptr = pmm_alloc_kpages(size / PAGE_SIZE, NULL); - if (!ptr) { - TRACEF("failed to grow kernel heap by 0x%zx bytes\n", size); - return ERR_NO_MEMORY; - } - - LTRACEF("growing heap by 0x%zx bytes, new ptr %p\n", size, ptr); - - heap_insert_free_chunk(heap_create_free_chunk(ptr, size, true)); - - /* change the heap start and end variables */ - if ((uintptr_t)ptr < (uintptr_t)theheap.base) - theheap.base = ptr; - - uintptr_t endptr = (uintptr_t)ptr + size; - if (endptr > (uintptr_t)theheap.base + theheap.len) { - theheap.len = (uintptr_t)endptr - (uintptr_t)theheap.base; - } - - return size; -#else - return ERR_NO_MEMORY; -#endif -} - -void heap_init(void) -{ - LTRACE_ENTRY; - - // create a mutex - mutex_init(&theheap.lock); - - // initialize the free list - list_initialize(&theheap.free_list); - - // initialize the delayed free list - list_initialize(&theheap.delayed_free_list); - spin_lock_init(&theheap.delayed_free_lock); - - // set the heap range -#if WITH_KERNEL_VM - theheap.base = pmm_alloc_kpages(HEAP_GROW_SIZE / PAGE_SIZE, NULL); - theheap.len = HEAP_GROW_SIZE; - - if (theheap.base == 0) { - panic("HEAP: error allocating initial heap size\n"); - } -#else - theheap.base = (void *)HEAP_START; - theheap.len = HEAP_LEN; -#endif - theheap.remaining = 0; // will get set by heap_insert_free_chunk() - theheap.low_watermark = theheap.len; - LTRACEF("base %p size %zd bytes\n", theheap.base, theheap.len); - - // create an initial free chunk - heap_insert_free_chunk(heap_create_free_chunk(theheap.base, theheap.len, false)); -} - -/* add a new block of memory to the heap */ -void heap_add_block(void *ptr, size_t len) -{ - heap_insert_free_chunk(heap_create_free_chunk(ptr, len, false)); -} - -#if LK_DEBUGLEVEL > 1 -#if WITH_LIB_CONSOLE - -#include - -static int cmd_heap(int argc, const cmd_args *argv); - -STATIC_COMMAND_START -STATIC_COMMAND("heap", "heap debug commands", &cmd_heap) -STATIC_COMMAND_END(heap); - -static int cmd_heap(int argc, const cmd_args *argv) -{ - if (argc < 2) { -notenoughargs: - printf("not enough arguments\n"); -usage: - printf("usage:\n"); - printf("\t%s info\n", argv[0].str); - printf("\t%s alloc [alignment]\n", argv[0].str); - printf("\t%s free
\n", argv[0].str); - return -1; - } - - if (strcmp(argv[1].str, "info") == 0) { - heap_dump(); - } else if (strcmp(argv[1].str, "alloc") == 0) { - if (argc < 3) goto notenoughargs; - - void *ptr = heap_alloc(argv[2].u, (argc >= 3) ? argv[3].u : 0); - printf("heap_alloc returns %p\n", ptr); - } else if (strcmp(argv[1].str, "free") == 0) { - if (argc < 2) goto notenoughargs; - - heap_free((void *)argv[2].u); - } else { - printf("unrecognized command\n"); - goto usage; - } - - return 0; -} - -#endif -#endif - -/* vim: set ts=4 sw=4 noexpandtab: */ - diff --git a/lib/heap/heap_wrapper.c b/lib/heap/heap_wrapper.c new file mode 100644 index 00000000..68df5f3f --- /dev/null +++ b/lib/heap/heap_wrapper.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2008-2014 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include + +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +struct list_node delayed_free_list = LIST_INITIAL_VALUE(delayed_free_list); +spin_lock_t delayed_free_lock = SPIN_LOCK_INITIAL_VALUE; + +static void heap_free_delayed_list(void) +{ + struct list_node list; + + list_initialize(&list); + + spin_lock_saved_state_t state; + spin_lock_irqsave(&delayed_free_lock, state); + + struct list_node *node; + while ((node = list_remove_head(&delayed_free_list))) { + list_add_head(&list, node); + } + spin_unlock_irqrestore(&delayed_free_lock, state); + + while ((node = list_remove_head(&list))) { + LTRACEF("freeing node %p\n", node); + heap_free(node); + } +} + +void *heap_alloc(size_t size, unsigned int alignment) +{ + LTRACEF("size %zd, align %d\n", size, alignment); + + // deal with the pending free list + if (unlikely(!list_is_empty(&delayed_free_list))) { + heap_free_delayed_list(); + } + + return miniheap_alloc(size, alignment); +} + +void heap_free(void *ptr) +{ + LTRACEF("ptr %p\n", ptr); + + miniheap_free(ptr); +} + +void heap_init(void) +{ + miniheap_init(); +} + +/* critical section time delayed free */ +void heap_delayed_free(void *ptr) +{ + LTRACEF("ptr %p\n", ptr); + + /* throw down a structure on the free block */ + /* XXX assumes the free block is large enough to hold a list node */ + struct list_node *node = (struct list_node *)ptr; + + spin_lock_saved_state_t state; + spin_lock_irqsave(&delayed_free_lock, state); + list_add_head(&delayed_free_list, node); + spin_unlock_irqrestore(&delayed_free_lock, state); +} + +static void heap_dump(void) +{ + miniheap_dump(); + + printf("\tdelayed free list:\n"); + spin_lock_saved_state_t state; + spin_lock_irqsave(&delayed_free_lock, state); + struct list_node *node; + list_for_every(&delayed_free_list, node) { + printf("\t\tnode %p\n", node); + } + spin_unlock_irqrestore(&delayed_free_lock, state); +} + +#if 0 +static void heap_test(void) +{ + void *ptr[16]; + + ptr[0] = heap_alloc(8, 0); + ptr[1] = heap_alloc(32, 0); + ptr[2] = heap_alloc(7, 0); + ptr[3] = heap_alloc(0, 0); + ptr[4] = heap_alloc(98713, 0); + ptr[5] = heap_alloc(16, 0); + + heap_free(ptr[5]); + heap_free(ptr[1]); + heap_free(ptr[3]); + heap_free(ptr[0]); + heap_free(ptr[4]); + heap_free(ptr[2]); + + heap_dump(); + + int i; + for (i=0; i < 16; i++) + ptr[i] = 0; + + for (i=0; i < 32768; i++) { + unsigned int index = (unsigned int)rand() % 16; + + if ((i % (16*1024)) == 0) + printf("pass %d\n", i); + +// printf("index 0x%x\n", index); + if (ptr[index]) { +// printf("freeing ptr[0x%x] = %p\n", index, ptr[index]); + heap_free(ptr[index]); + ptr[index] = 0; + } + unsigned int align = 1 << ((unsigned int)rand() % 8); + ptr[index] = heap_alloc((unsigned int)rand() % 32768, align); +// printf("ptr[0x%x] = %p, align 0x%x\n", index, ptr[index], align); + + DEBUG_ASSERT(((addr_t)ptr[index] % align) == 0); +// heap_dump(); + } + + for (i=0; i < 16; i++) { + if (ptr[i]) + heap_free(ptr[i]); + } + + heap_dump(); +} +#endif + + +#if LK_DEBUGLEVEL > 1 +#if WITH_LIB_CONSOLE + +#include + +static int cmd_heap(int argc, const cmd_args *argv); + +STATIC_COMMAND_START +STATIC_COMMAND("heap", "heap debug commands", &cmd_heap) +STATIC_COMMAND_END(heap); + +static int cmd_heap(int argc, const cmd_args *argv) +{ + if (argc < 2) { +notenoughargs: + printf("not enough arguments\n"); +usage: + printf("usage:\n"); + printf("\t%s info\n", argv[0].str); + printf("\t%s alloc [alignment]\n", argv[0].str); + printf("\t%s free
\n", argv[0].str); + return -1; + } + + if (strcmp(argv[1].str, "info") == 0) { + heap_dump(); // XXX + } else if (strcmp(argv[1].str, "alloc") == 0) { + if (argc < 3) goto notenoughargs; + + void *ptr = heap_alloc(argv[2].u, (argc >= 3) ? argv[3].u : 0); + printf("heap_alloc returns %p\n", ptr); + } else if (strcmp(argv[1].str, "free") == 0) { + if (argc < 2) goto notenoughargs; + + heap_free((void *)argv[2].u); + } else { + printf("unrecognized command\n"); + goto usage; + } + + return 0; +} + +#endif +#endif + + diff --git a/include/lib/heap.h b/lib/heap/include/lib/heap.h similarity index 84% rename from include/lib/heap.h rename to lib/heap/include/lib/heap.h index 0b0546f0..88799f4a 100644 --- a/include/lib/heap.h +++ b/lib/heap/include/lib/heap.h @@ -20,8 +20,7 @@ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef __LIB_HEAP_H -#define __LIB_HEAP_H +#pragma once #include #include @@ -29,25 +28,11 @@ __BEGIN_CDECLS; -struct heap_stats { - void* heap_start; - size_t heap_len; - size_t heap_free; - size_t heap_max_chunk; - size_t heap_low_watermark; -}; - void *heap_alloc(size_t, unsigned int alignment); void heap_free(void *); void heap_init(void); -void heap_add_block(void *, size_t); - -void heap_get_stats(struct heap_stats *ptr); - /* critical section time delayed free */ void heap_delayed_free(void *); __END_CDECLS; - -#endif diff --git a/lib/heap/miniheap/include/lib/miniheap.h b/lib/heap/miniheap/include/lib/miniheap.h new file mode 100644 index 00000000..ba62a5c6 --- /dev/null +++ b/lib/heap/miniheap/include/lib/miniheap.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#pragma once + +#include + +__BEGIN_CDECLS; + +struct miniheap_stats { + void* heap_start; + size_t heap_len; + size_t heap_free; + size_t heap_max_chunk; + size_t heap_low_watermark; +}; + +void miniheap_get_stats(struct miniheap_stats *ptr); + +void *miniheap_alloc(size_t, unsigned int alignment); +void miniheap_free(void *); + +void miniheap_init(void); +void miniheap_dump(void); + +__END_CDECLS; diff --git a/lib/heap/miniheap/miniheap.c b/lib/heap/miniheap/miniheap.c new file mode 100644 index 00000000..9976dd9c --- /dev/null +++ b/lib/heap/miniheap/miniheap.c @@ -0,0 +1,456 @@ +/* + * Copyright (c) 2008-2009,2012-2015 Travis Geiselbrecht + * Copyright (c) 2009 Corey Tabaka + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +#define DEBUG_HEAP 0 +#define ALLOC_FILL 0x99 +#define FREE_FILL 0x77 +#define PADDING_FILL 0x55 +#define PADDING_SIZE 64 + +#define HEAP_MAGIC 'HEAP' + +#if WITH_KERNEL_VM + +#include +/* we will use kalloc routines to back our heap */ +#if !defined(HEAP_GROW_SIZE) +#define HEAP_GROW_SIZE (4 * 1024 * 1024) /* size the heap grows by when it runs out of memory */ +#endif + +STATIC_ASSERT(IS_PAGE_ALIGNED(HEAP_GROW_SIZE)); + +#elif WITH_STATIC_HEAP + +#if !defined(HEAP_START) || !defined(HEAP_LEN) +#error WITH_STATIC_HEAP set but no HEAP_START or HEAP_LEN defined +#endif + +#else +/* not a static vm, not using the kernel vm */ +extern int _end; +extern int _end_of_ram; + +/* default to using up the rest of memory after the kernel ends */ +/* may be modified by other parts of the system */ +uintptr_t _heap_start = (uintptr_t)&_end; +uintptr_t _heap_end = (uintptr_t)&_end_of_ram; + +#define HEAP_START ((uintptr_t)_heap_start) +#define HEAP_LEN ((uintptr_t)_heap_end - HEAP_START) +#endif + +struct free_heap_chunk { + struct list_node node; + size_t len; +}; + +struct heap { + void *base; + size_t len; + size_t remaining; + size_t low_watermark; + mutex_t lock; + struct list_node free_list; +}; + +// heap static vars +static struct heap theheap; + +// structure placed at the beginning every allocation +struct alloc_struct_begin { +#if LK_DEBUGLEVEL > 1 + unsigned int magic; +#endif + void *ptr; + size_t size; +#if DEBUG_HEAP + void *padding_start; + size_t padding_size; +#endif +}; + +static ssize_t heap_grow(size_t len); + +static void dump_free_chunk(struct free_heap_chunk *chunk) +{ + dprintf(INFO, "\t\tbase %p, end 0x%lx, len 0x%zx\n", chunk, (vaddr_t)chunk + chunk->len, chunk->len); +} + +void miniheap_dump(void) +{ + dprintf(INFO, "Heap dump:\n"); + dprintf(INFO, "\tbase %p, len 0x%zx\n", theheap.base, theheap.len); + dprintf(INFO, "\tfree list:\n"); + + mutex_acquire(&theheap.lock); + + struct free_heap_chunk *chunk; + list_for_every_entry(&theheap.free_list, chunk, struct free_heap_chunk, node) { + dump_free_chunk(chunk); + } + mutex_release(&theheap.lock); + +} + +// try to insert this free chunk into the free list, consuming the chunk by merging it with +// nearby ones if possible. Returns base of whatever chunk it became in the list. +static struct free_heap_chunk *heap_insert_free_chunk(struct free_heap_chunk *chunk) +{ +#if LK_DEBUGLEVEL > INFO + vaddr_t chunk_end = (vaddr_t)chunk + chunk->len; +#endif + + LTRACEF("chunk ptr %p, size 0x%zx\n", chunk, chunk->len); + + struct free_heap_chunk *next_chunk; + struct free_heap_chunk *last_chunk; + + mutex_acquire(&theheap.lock); + + theheap.remaining += chunk->len; + + // walk through the list, finding the node to insert before + list_for_every_entry(&theheap.free_list, next_chunk, struct free_heap_chunk, node) { + if (chunk < next_chunk) { + DEBUG_ASSERT(chunk_end <= (vaddr_t)next_chunk); + + list_add_before(&next_chunk->node, &chunk->node); + + goto try_merge; + } + } + + // walked off the end of the list, add it at the tail + list_add_tail(&theheap.free_list, &chunk->node); + + // try to merge with the previous chunk +try_merge: + last_chunk = list_prev_type(&theheap.free_list, &chunk->node, struct free_heap_chunk, node); + if (last_chunk) { + if ((vaddr_t)last_chunk + last_chunk->len == (vaddr_t)chunk) { + // easy, just extend the previous chunk + last_chunk->len += chunk->len; + + // remove ourself from the list + list_delete(&chunk->node); + + // set the chunk pointer to the newly extended chunk, in case + // it needs to merge with the next chunk below + chunk = last_chunk; + } + } + + // try to merge with the next chunk + if (next_chunk) { + if ((vaddr_t)chunk + chunk->len == (vaddr_t)next_chunk) { + // extend our chunk + chunk->len += next_chunk->len; + + // remove them from the list + list_delete(&next_chunk->node); + } + } + + mutex_release(&theheap.lock); + + return chunk; +} + +static struct free_heap_chunk *heap_create_free_chunk(void *ptr, size_t len, bool allow_debug) +{ + DEBUG_ASSERT((len % sizeof(void *)) == 0); // size must be aligned on pointer boundary + +#if DEBUG_HEAP + if (allow_debug) + memset(ptr, FREE_FILL, len); +#endif + + struct free_heap_chunk *chunk = (struct free_heap_chunk *)ptr; + chunk->len = len; + + return chunk; +} + +void *miniheap_alloc(size_t size, unsigned int alignment) +{ + void *ptr; +#if DEBUG_HEAP + size_t original_size = size; +#endif + + LTRACEF("size %zd, align %d\n", size, alignment); + + // alignment must be power of 2 + if (alignment & (alignment - 1)) + return NULL; + + // we always put a size field + base pointer + magic in front of the allocation + size += sizeof(struct alloc_struct_begin); +#if DEBUG_HEAP + size += PADDING_SIZE; +#endif + + // make sure we allocate at least the size of a struct free_heap_chunk so that + // when we free it, we can create a struct free_heap_chunk struct and stick it + // in the spot + if (size < sizeof(struct free_heap_chunk)) + size = sizeof(struct free_heap_chunk); + + // round up size to a multiple of native pointer size + size = ROUNDUP(size, sizeof(void *)); + + // deal with nonzero alignments + if (alignment > 0) { + if (alignment < 16) + alignment = 16; + + // add alignment for worst case fit + size += alignment; + } + +#if WITH_KERNEL_VM + int retry_count = 0; +retry: +#endif + mutex_acquire(&theheap.lock); + + // walk through the list + ptr = NULL; + struct free_heap_chunk *chunk; + list_for_every_entry(&theheap.free_list, chunk, struct free_heap_chunk, node) { + DEBUG_ASSERT((chunk->len % sizeof(void *)) == 0); // len should always be a multiple of pointer size + + // is it big enough to service our allocation? + if (chunk->len >= size) { + ptr = chunk; + + // remove it from the list + struct list_node *next_node = list_next(&theheap.free_list, &chunk->node); + list_delete(&chunk->node); + + if (chunk->len > size + sizeof(struct free_heap_chunk)) { + // there's enough space in this chunk to create a new one after the allocation + struct free_heap_chunk *newchunk = heap_create_free_chunk((uint8_t *)ptr + size, chunk->len - size, true); + + // truncate this chunk + chunk->len -= chunk->len - size; + + // add the new one where chunk used to be + if (next_node) + list_add_before(next_node, &newchunk->node); + else + list_add_tail(&theheap.free_list, &newchunk->node); + } + + // the allocated size is actually the length of this chunk, not the size requested + DEBUG_ASSERT(chunk->len >= size); + size = chunk->len; + +#if DEBUG_HEAP + memset(ptr, ALLOC_FILL, size); +#endif + + ptr = (void *)((addr_t)ptr + sizeof(struct alloc_struct_begin)); + + // align the output if requested + if (alignment > 0) { + ptr = (void *)ROUNDUP((addr_t)ptr, (addr_t)alignment); + } + + struct alloc_struct_begin *as = (struct alloc_struct_begin *)ptr; + as--; +#if LK_DEBUGLEVEL > 1 + as->magic = HEAP_MAGIC; +#endif + as->ptr = (void *)chunk; + as->size = size; + theheap.remaining -= size; + + if (theheap.remaining < theheap.low_watermark) { + theheap.low_watermark = theheap.remaining; + } +#if DEBUG_HEAP + as->padding_start = ((uint8_t *)ptr + original_size); + as->padding_size = (((addr_t)chunk + size) - ((addr_t)ptr + original_size)); +// printf("padding start %p, size %u, chunk %p, size %u\n", as->padding_start, as->padding_size, chunk, size); + + memset(as->padding_start, PADDING_FILL, as->padding_size); +#endif + + break; + } + } + + mutex_release(&theheap.lock); + +#if WITH_KERNEL_VM + /* try to grow the heap if we can */ + if (ptr == NULL && retry_count == 0) { + size_t growby = MAX(HEAP_GROW_SIZE, ROUNDUP(size, PAGE_SIZE)); + + ssize_t err = heap_grow(growby); + if (err >= 0) { + retry_count++; + goto retry; + } + } +#endif + + LTRACEF("returning ptr %p\n", ptr); + + return ptr; +} + +void miniheap_free(void *ptr) +{ + if (ptr == 0) + return; + + LTRACEF("ptr %p\n", ptr); + + // check for the old allocation structure + struct alloc_struct_begin *as = (struct alloc_struct_begin *)ptr; + as--; + + DEBUG_ASSERT(as->magic == HEAP_MAGIC); + +#if DEBUG_HEAP + { + uint i; + uint8_t *pad = (uint8_t *)as->padding_start; + + for (i = 0; i < as->padding_size; i++) { + if (pad[i] != PADDING_FILL) { + printf("free at %p scribbled outside the lines:\n", ptr); + hexdump(pad, as->padding_size); + panic("die\n"); + } + } + } +#endif + + LTRACEF("allocation was %zd bytes long at ptr %p\n", as->size, as->ptr); + + // looks good, create a free chunk and add it to the pool + heap_insert_free_chunk(heap_create_free_chunk(as->ptr, as->size, true)); +} + +void miniheap_get_stats(struct miniheap_stats *ptr) +{ + struct free_heap_chunk *chunk; + + ptr->heap_start = theheap.base; + ptr->heap_len = theheap.len; + ptr->heap_free=0; + ptr->heap_max_chunk = 0; + + mutex_acquire(&theheap.lock); + + list_for_every_entry(&theheap.free_list, chunk, struct free_heap_chunk, node) { + ptr->heap_free += chunk->len; + + if (chunk->len > ptr->heap_max_chunk) { + ptr->heap_max_chunk = chunk->len; + } + } + + ptr->heap_low_watermark = theheap.low_watermark; + + mutex_release(&theheap.lock); +} + +static ssize_t heap_grow(size_t size) +{ +#if WITH_KERNEL_VM + size = ROUNDUP(size, PAGE_SIZE); + + void *ptr = pmm_alloc_kpages(size / PAGE_SIZE, NULL); + if (!ptr) { + TRACEF("failed to grow kernel heap by 0x%zx bytes\n", size); + return ERR_NO_MEMORY; + } + + LTRACEF("growing heap by 0x%zx bytes, new ptr %p\n", size, ptr); + + heap_insert_free_chunk(heap_create_free_chunk(ptr, size, true)); + + /* change the heap start and end variables */ + if ((uintptr_t)ptr < (uintptr_t)theheap.base) + theheap.base = ptr; + + uintptr_t endptr = (uintptr_t)ptr + size; + if (endptr > (uintptr_t)theheap.base + theheap.len) { + theheap.len = (uintptr_t)endptr - (uintptr_t)theheap.base; + } + + return size; +#else + return ERR_NO_MEMORY; +#endif +} + +void miniheap_init(void) +{ + LTRACE_ENTRY; + + // create a mutex + mutex_init(&theheap.lock); + + // initialize the free list + list_initialize(&theheap.free_list); + + // set the heap range +#if WITH_KERNEL_VM + theheap.base = pmm_alloc_kpages(HEAP_GROW_SIZE / PAGE_SIZE, NULL); + theheap.len = HEAP_GROW_SIZE; + + if (theheap.base == 0) { + panic("HEAP: error allocating initial heap size\n"); + } +#else + theheap.base = (void *)HEAP_START; + theheap.len = HEAP_LEN; +#endif + theheap.remaining = 0; // will get set by heap_insert_free_chunk() + theheap.low_watermark = theheap.len; + LTRACEF("base %p size %zd bytes\n", theheap.base, theheap.len); + + // create an initial free chunk + heap_insert_free_chunk(heap_create_free_chunk(theheap.base, theheap.len, false)); +} + diff --git a/lib/heap/miniheap/rules.mk b/lib/heap/miniheap/rules.mk new file mode 100644 index 00000000..c921d02f --- /dev/null +++ b/lib/heap/miniheap/rules.mk @@ -0,0 +1,10 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +GLOBAL_INCLUDES += $(LOCAL_DIR)/include + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/miniheap.c + +include make/module.mk diff --git a/lib/heap/rules.mk b/lib/heap/rules.mk index 5c9d2d49..bc91b910 100644 --- a/lib/heap/rules.mk +++ b/lib/heap/rules.mk @@ -1,8 +1,12 @@ LOCAL_DIR := $(GET_LOCAL_DIR) +GLOBAL_INCLUDES += $(LOCAL_DIR)/include + MODULE := $(LOCAL_DIR) MODULE_SRCS += \ - $(LOCAL_DIR)/heap.c + $(LOCAL_DIR)/heap_wrapper.c + +MODULE_DEPS := $(LOCAL_DIR)/miniheap include make/module.mk From 1193213dfd23bc8b3fe689be8ebcc39d6b858c3d Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Wed, 14 Oct 2015 19:56:24 -0700 Subject: [PATCH 02/19] WIP get dlmalloc working with a mmap() style allocator out of the heap wrapper --- include/kernel/vm.h | 2 + kernel/vm/pmm.c | 22 ++++ lib/{ => heap}/dlmalloc/dlmalloc.c | 27 +++- .../dlmalloc/include/lib/dlmalloc.h | 0 lib/{ => heap}/dlmalloc/rules.mk | 0 lib/heap/heap_wrapper.c | 117 +++++++++++++++++- lib/heap/include/lib/heap.h | 3 + lib/heap/miniheap/include/lib/miniheap.h | 2 +- lib/heap/miniheap/miniheap.c | 72 ++--------- lib/heap/rules.mk | 11 ++ platform/qemu-virt/rules.mk | 2 + 11 files changed, 191 insertions(+), 67 deletions(-) rename lib/{ => heap}/dlmalloc/dlmalloc.c (99%) rename lib/{ => heap}/dlmalloc/include/lib/dlmalloc.h (100%) rename lib/{ => heap}/dlmalloc/rules.mk (100%) diff --git a/include/kernel/vm.h b/include/kernel/vm.h index 433e7649..ec34da3a 100644 --- a/include/kernel/vm.h +++ b/include/kernel/vm.h @@ -175,6 +175,8 @@ void *pmm_alloc_kpages(uint count, struct list_node *list); /* Helper routine for pmm_alloc_kpages. */ static inline void *pmm_alloc_kpage(void) { return pmm_alloc_kpages(1, NULL); } +size_t pmm_free_kpages(void *ptr, uint count); + /* physical to virtual */ void *paddr_to_kvaddr(paddr_t pa); diff --git a/kernel/vm/pmm.c b/kernel/vm/pmm.c index fea77c86..0b9afc17 100644 --- a/kernel/vm/pmm.c +++ b/kernel/vm/pmm.c @@ -262,6 +262,28 @@ void *pmm_alloc_kpages(uint count, struct list_node *list) return paddr_to_kvaddr(pa); } +size_t pmm_free_kpages(void *_ptr, uint count) +{ + LTRACEF("ptr %p, count %u\n", _ptr, count); + + uint8_t *ptr = (uint8_t *)_ptr; + + struct list_node list; + list_initialize(&list); + + while (count > 0) { + vm_page_t *p = address_to_page(kvaddr_to_paddr(ptr)); + if (p) { + list_add_tail(&list, &p->node); + } + + ptr += PAGE_SIZE; + count--; + } + + return pmm_free(&list); +} + size_t pmm_alloc_contiguous(uint count, uint8_t alignment_log2, paddr_t *pa, struct list_node *list) { LTRACEF("count %u, align %u\n", count, alignment_log2); diff --git a/lib/dlmalloc/dlmalloc.c b/lib/heap/dlmalloc/dlmalloc.c similarity index 99% rename from lib/dlmalloc/dlmalloc.c rename to lib/heap/dlmalloc/dlmalloc.c index 8b8daae3..796d6353 100644 --- a/lib/dlmalloc/dlmalloc.c +++ b/lib/heap/dlmalloc/dlmalloc.c @@ -539,8 +539,31 @@ MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP #define LACKS_UNISTD_H #define LACKS_SYS_PARAM_H #define LACKS_SCHED_H -#define HAVE_MMAP 0 -#define HAVE_MORECORE 1 +#define HAVE_MMAP 1 +#include +#include +#include +#include + +static inline void *mmap(size_t len) { + void *ptr; + if (heap_grow_memory(&ptr, len) < 0) + return 0; + + return ptr; +} + +static inline int munmap(void *base, size_t len) { + heap_free_memory(base, len); + return 0; +} + +#define MMAP(s) mmap(s) +#define DIRECT_MMAP(s) mmap(s) +#define MUNMAP(b, s) munmap(b, s) +#define HAVE_MORECORE 0 +#define MORECORE dl_sbrk +void *dl_sbrk(long incr); #define USE_LOCKS 2 #include #define ABORT panic("dlmalloc abort\n") diff --git a/lib/dlmalloc/include/lib/dlmalloc.h b/lib/heap/dlmalloc/include/lib/dlmalloc.h similarity index 100% rename from lib/dlmalloc/include/lib/dlmalloc.h rename to lib/heap/dlmalloc/include/lib/dlmalloc.h diff --git a/lib/dlmalloc/rules.mk b/lib/heap/dlmalloc/rules.mk similarity index 100% rename from lib/dlmalloc/rules.mk rename to lib/heap/dlmalloc/rules.mk diff --git a/lib/heap/heap_wrapper.c b/lib/heap/heap_wrapper.c index 68df5f3f..0fc5d5ce 100644 --- a/lib/heap/heap_wrapper.c +++ b/lib/heap/heap_wrapper.c @@ -23,17 +23,82 @@ #include #include +#include +#include #include +#include #include #include #include -#include #define LOCAL_TRACE 0 struct list_node delayed_free_list = LIST_INITIAL_VALUE(delayed_free_list); spin_lock_t delayed_free_lock = SPIN_LOCK_INITIAL_VALUE; +#if WITH_LIB_HEAP_MINIHEAP +#include + +#define HEAP_ALLOC miniheap_alloc +#define HEAP_FREE miniheap_free +static inline void HEAP_INIT(void) { miniheap_init(NULL, 0); } +#define HEAP_DUMP miniheap_dump + +#elif WITH_LIB_HEAP_DLMALLOC +#include + +static inline void *HEAP_ALLOC(size_t size, unsigned int alignment) { + if (alignment == 0) + return dlmalloc(size); + else + return dlmemalign(alignment, size); +} + +static inline void HEAP_FREE(void *ptr) { dlfree(ptr); } +static inline void HEAP_INIT(void) {} +static inline void HEAP_DUMP(void) {} + +void *dl_sbrk(int incr) { + LTRACEF("incr %d\n", incr); + + panic("what"); +} + +#else +#error need to select valid heap implementation or provide wrapper +#endif + +#if WITH_KERNEL_VM + +#include + +/* we will use kalloc routines to back our heap */ +#if !defined(HEAP_GROW_SIZE) +#define HEAP_GROW_SIZE (64 * 1024) /* size the heap grows by when it runs out of memory */ +#endif + +STATIC_ASSERT(IS_PAGE_ALIGNED(HEAP_GROW_SIZE)); + +#elif WITH_STATIC_HEAP + +#if !defined(HEAP_START) || !defined(HEAP_LEN) +#error WITH_STATIC_HEAP set but no HEAP_START or HEAP_LEN defined +#endif + +#else +/* not a static vm, not using the kernel vm */ +extern int _end; +extern int _end_of_ram; + +/* default to using up the rest of memory after the kernel ends */ +/* may be modified by other parts of the system */ +uintptr_t _heap_start = (uintptr_t)&_end; +uintptr_t _heap_end = (uintptr_t)&_end_of_ram; + +#define HEAP_START ((uintptr_t)_heap_start) +#define HEAP_LEN ((uintptr_t)_heap_end - HEAP_START) +#endif + static void heap_free_delayed_list(void) { struct list_node list; @@ -64,19 +129,19 @@ void *heap_alloc(size_t size, unsigned int alignment) heap_free_delayed_list(); } - return miniheap_alloc(size, alignment); + return HEAP_ALLOC(size, alignment); } void heap_free(void *ptr) { LTRACEF("ptr %p\n", ptr); - miniheap_free(ptr); + HEAP_FREE(ptr); } void heap_init(void) { - miniheap_init(); + HEAP_INIT(); } /* critical section time delayed free */ @@ -96,7 +161,7 @@ void heap_delayed_free(void *ptr) static void heap_dump(void) { - miniheap_dump(); + HEAP_DUMP(); printf("\tdelayed free list:\n"); spin_lock_saved_state_t state; @@ -108,6 +173,48 @@ static void heap_dump(void) spin_unlock_irqrestore(&delayed_free_lock, state); } +/* called back from the heap implementation to allocate another block of memory */ +ssize_t heap_grow_memory(void **ptr, size_t size) +{ + LTRACEF("ptr %p, size 0x%zx\n", ptr, size); + +#if WITH_KERNEL_VM && !WITH_STATIC_HEAP + size = ROUNDUP(size, PAGE_SIZE); + LTRACEF("size now 0x%zx\n", size); + + *ptr = pmm_alloc_kpages(size / PAGE_SIZE, NULL); + if (!*ptr) { + TRACEF("failed to grow kernel heap by 0x%zx bytes\n", size); + return ERR_NO_MEMORY; + } +#else + static bool have_asked_for_memory = false; + + if (have_asked_for_memory) + return ERR_NO_MEMORY; + + *ptr = HEAP_START; + size = HEAP_LEN; + have_asked_for_memory = true; +#endif + + LTRACEF("returning %p, size 0x%zx\n", *ptr, size); + + return size; +} + +void heap_free_memory(void *ptr, size_t len) +{ + LTRACEF("ptr %p, len 0x%zx\n", ptr, len); + +#if WITH_KERNEL_VM && !WITH_STATIC_HEAP + DEBUG_ASSERT(IS_PAGE_ALIGNED((uintptr_t)ptr)); + DEBUG_ASSERT(IS_PAGE_ALIGNED(len)); + + pmm_free_kpages(ptr, len / PAGE_SIZE); +#endif +} + #if 0 static void heap_test(void) { diff --git a/lib/heap/include/lib/heap.h b/lib/heap/include/lib/heap.h index 88799f4a..b26703f0 100644 --- a/lib/heap/include/lib/heap.h +++ b/lib/heap/include/lib/heap.h @@ -35,4 +35,7 @@ void heap_init(void); /* critical section time delayed free */ void heap_delayed_free(void *); +ssize_t heap_grow_memory(void **ptr, size_t len); +void heap_free_memory(void *ptr, size_t len); + __END_CDECLS; diff --git a/lib/heap/miniheap/include/lib/miniheap.h b/lib/heap/miniheap/include/lib/miniheap.h index ba62a5c6..66bc9e47 100644 --- a/lib/heap/miniheap/include/lib/miniheap.h +++ b/lib/heap/miniheap/include/lib/miniheap.h @@ -39,7 +39,7 @@ void miniheap_get_stats(struct miniheap_stats *ptr); void *miniheap_alloc(size_t, unsigned int alignment); void miniheap_free(void *); -void miniheap_init(void); +void miniheap_init(void *ptr, size_t len); void miniheap_dump(void); __END_CDECLS; diff --git a/lib/heap/miniheap/miniheap.c b/lib/heap/miniheap/miniheap.c index 9976dd9c..802bdb5a 100644 --- a/lib/heap/miniheap/miniheap.c +++ b/lib/heap/miniheap/miniheap.c @@ -33,6 +33,7 @@ #include #include #include +#include #define LOCAL_TRACE 0 @@ -44,36 +45,6 @@ #define HEAP_MAGIC 'HEAP' -#if WITH_KERNEL_VM - -#include -/* we will use kalloc routines to back our heap */ -#if !defined(HEAP_GROW_SIZE) -#define HEAP_GROW_SIZE (4 * 1024 * 1024) /* size the heap grows by when it runs out of memory */ -#endif - -STATIC_ASSERT(IS_PAGE_ALIGNED(HEAP_GROW_SIZE)); - -#elif WITH_STATIC_HEAP - -#if !defined(HEAP_START) || !defined(HEAP_LEN) -#error WITH_STATIC_HEAP set but no HEAP_START or HEAP_LEN defined -#endif - -#else -/* not a static vm, not using the kernel vm */ -extern int _end; -extern int _end_of_ram; - -/* default to using up the rest of memory after the kernel ends */ -/* may be modified by other parts of the system */ -uintptr_t _heap_start = (uintptr_t)&_end; -uintptr_t _heap_end = (uintptr_t)&_end_of_ram; - -#define HEAP_START ((uintptr_t)_heap_start) -#define HEAP_LEN ((uintptr_t)_heap_end - HEAP_START) -#endif - struct free_heap_chunk { struct list_node node; size_t len; @@ -321,9 +292,7 @@ retry: #if WITH_KERNEL_VM /* try to grow the heap if we can */ if (ptr == NULL && retry_count == 0) { - size_t growby = MAX(HEAP_GROW_SIZE, ROUNDUP(size, PAGE_SIZE)); - - ssize_t err = heap_grow(growby); + ssize_t err = heap_grow(size); if (err >= 0) { retry_count++; goto retry; @@ -396,35 +365,30 @@ void miniheap_get_stats(struct miniheap_stats *ptr) static ssize_t heap_grow(size_t size) { -#if WITH_KERNEL_VM - size = ROUNDUP(size, PAGE_SIZE); - - void *ptr = pmm_alloc_kpages(size / PAGE_SIZE, NULL); - if (!ptr) { + void *ptr; + ssize_t allocated = heap_grow_memory(&ptr, size); + if (allocated <= 0) { TRACEF("failed to grow kernel heap by 0x%zx bytes\n", size); return ERR_NO_MEMORY; } - LTRACEF("growing heap by 0x%zx bytes, new ptr %p\n", size, ptr); + LTRACEF("growing heap by 0x%zx bytes, allocated 0x%zx, new ptr %p\n", size, allocated, ptr); - heap_insert_free_chunk(heap_create_free_chunk(ptr, size, true)); + heap_insert_free_chunk(heap_create_free_chunk(ptr, allocated, true)); /* change the heap start and end variables */ if ((uintptr_t)ptr < (uintptr_t)theheap.base) theheap.base = ptr; - uintptr_t endptr = (uintptr_t)ptr + size; + uintptr_t endptr = (uintptr_t)ptr + allocated; if (endptr > (uintptr_t)theheap.base + theheap.len) { theheap.len = (uintptr_t)endptr - (uintptr_t)theheap.base; } - return size; -#else - return ERR_NO_MEMORY; -#endif + return allocated; } -void miniheap_init(void) +void miniheap_init(void *ptr, size_t len) { LTRACE_ENTRY; @@ -435,22 +399,12 @@ void miniheap_init(void) list_initialize(&theheap.free_list); // set the heap range -#if WITH_KERNEL_VM - theheap.base = pmm_alloc_kpages(HEAP_GROW_SIZE / PAGE_SIZE, NULL); - theheap.len = HEAP_GROW_SIZE; - - if (theheap.base == 0) { - panic("HEAP: error allocating initial heap size\n"); - } -#else - theheap.base = (void *)HEAP_START; - theheap.len = HEAP_LEN; -#endif + theheap.base = 0; + theheap.len = 0; theheap.remaining = 0; // will get set by heap_insert_free_chunk() theheap.low_watermark = theheap.len; - LTRACEF("base %p size %zd bytes\n", theheap.base, theheap.len); // create an initial free chunk - heap_insert_free_chunk(heap_create_free_chunk(theheap.base, theheap.len, false)); + //heap_insert_free_chunk(heap_create_free_chunk(theheap.base, theheap.len, false)); } diff --git a/lib/heap/rules.mk b/lib/heap/rules.mk index bc91b910..5095beb5 100644 --- a/lib/heap/rules.mk +++ b/lib/heap/rules.mk @@ -7,6 +7,17 @@ MODULE := $(LOCAL_DIR) MODULE_SRCS += \ $(LOCAL_DIR)/heap_wrapper.c +# pick a heap implementation +ifndef LK_HEAP_IMPLEMENTATION +LK_HEAP_IMPLEMENTATION=miniheap +endif +ifeq ($(LK_HEAP_IMPLEMENTATION),miniheap) MODULE_DEPS := $(LOCAL_DIR)/miniheap +endif +ifeq ($(LK_HEAP_IMPLEMENTATION),dlmalloc) +MODULE_DEPS := $(LOCAL_DIR)/dlmalloc +endif + +GLOBAL_DEFINES += LK_HEAP_IMPLEMENTATION=$(LK_HEAP_IMPLEMENTATION) include make/module.mk diff --git a/platform/qemu-virt/rules.mk b/platform/qemu-virt/rules.mk index f0a6d890..9b85d4d8 100644 --- a/platform/qemu-virt/rules.mk +++ b/platform/qemu-virt/rules.mk @@ -13,6 +13,8 @@ ARM_CPU ?= cortex-a15 endif WITH_SMP ?= 1 +LK_HEAP_IMPLEMENTATION ?= dlmalloc + GLOBAL_INCLUDES += \ $(LOCAL_DIR)/include From 6bd49c391785b8d79a6eeaa5a246360feea66310 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Thu, 15 Oct 2015 14:53:00 -0700 Subject: [PATCH 03/19] [lib][heap] more WIP on heap stuffs --- lib/heap/dlmalloc/dlmalloc.c | 13 +++++++++---- lib/heap/heap_wrapper.c | 14 ++++++++------ lib/heap/miniheap/miniheap.c | 12 ++---------- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/lib/heap/dlmalloc/dlmalloc.c b/lib/heap/dlmalloc/dlmalloc.c index 796d6353..a71168b9 100644 --- a/lib/heap/dlmalloc/dlmalloc.c +++ b/lib/heap/dlmalloc/dlmalloc.c @@ -558,14 +558,19 @@ static inline int munmap(void *base, size_t len) { return 0; } +static int direct_mmap(size_t s) +{ + panic("direct map"); + return 0; +} + #define MMAP(s) mmap(s) -#define DIRECT_MMAP(s) mmap(s) +#define DIRECT_MMAP(s) direct_mmap(s) #define MUNMAP(b, s) munmap(b, s) +#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T /* disable direct mapping of chunks */ +#define DEFAULT_GRANULARITY PAGE_SIZE // (64*1024) #define HAVE_MORECORE 0 -#define MORECORE dl_sbrk -void *dl_sbrk(long incr); #define USE_LOCKS 2 -#include #define ABORT panic("dlmalloc abort\n") #define MALLOC_FAILURE_ACTION //dprintf(INFO, "dlmalloc failure\n"); #endif /* LK */ diff --git a/lib/heap/heap_wrapper.c b/lib/heap/heap_wrapper.c index 0fc5d5ce..00f0f718 100644 --- a/lib/heap/heap_wrapper.c +++ b/lib/heap/heap_wrapper.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2014 Travis Geiselbrecht + * Copyright (c) 2008-2015 Travis Geiselbrecht * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -31,8 +31,9 @@ #include #include -#define LOCAL_TRACE 0 +#define LOCAL_TRACE 1 +/* delayed free list */ struct list_node delayed_free_list = LIST_INITIAL_VALUE(delayed_free_list); spin_lock_t delayed_free_lock = SPIN_LOCK_INITIAL_VALUE; @@ -122,7 +123,7 @@ static void heap_free_delayed_list(void) void *heap_alloc(size_t size, unsigned int alignment) { - LTRACEF("size %zd, align %d\n", size, alignment); + LTRACEF("size %zd, align %u\n", size, alignment); // deal with the pending free list if (unlikely(!list_is_empty(&delayed_free_list))) { @@ -193,7 +194,8 @@ ssize_t heap_grow_memory(void **ptr, size_t size) if (have_asked_for_memory) return ERR_NO_MEMORY; - *ptr = HEAP_START; + // XXX dont return all of the range on the first call + *ptr = (void *)HEAP_START; size = HEAP_LEN; have_asked_for_memory = true; #endif @@ -295,11 +297,11 @@ usage: } if (strcmp(argv[1].str, "info") == 0) { - heap_dump(); // XXX + heap_dump(); } else if (strcmp(argv[1].str, "alloc") == 0) { if (argc < 3) goto notenoughargs; - void *ptr = heap_alloc(argv[2].u, (argc >= 3) ? argv[3].u : 0); + void *ptr = heap_alloc(argv[2].u, (argc >= 4) ? argv[3].u : 0); printf("heap_alloc returns %p\n", ptr); } else if (strcmp(argv[1].str, "free") == 0) { if (argc < 2) goto notenoughargs; diff --git a/lib/heap/miniheap/miniheap.c b/lib/heap/miniheap/miniheap.c index 802bdb5a..cf77e933 100644 --- a/lib/heap/miniheap/miniheap.c +++ b/lib/heap/miniheap/miniheap.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -214,10 +213,8 @@ void *miniheap_alloc(size_t size, unsigned int alignment) size += alignment; } -#if WITH_KERNEL_VM int retry_count = 0; retry: -#endif mutex_acquire(&theheap.lock); // walk through the list @@ -289,7 +286,6 @@ retry: mutex_release(&theheap.lock); -#if WITH_KERNEL_VM /* try to grow the heap if we can */ if (ptr == NULL && retry_count == 0) { ssize_t err = heap_grow(size); @@ -298,7 +294,6 @@ retry: goto retry; } } -#endif LTRACEF("returning ptr %p\n", ptr); @@ -372,7 +367,7 @@ static ssize_t heap_grow(size_t size) return ERR_NO_MEMORY; } - LTRACEF("growing heap by 0x%zx bytes, allocated 0x%zx, new ptr %p\n", size, allocated, ptr); + LTRACEF("growing heap by 0x%zx bytes, allocated 0x%zx, new ptr %p\n", size, (size_t)allocated, ptr); heap_insert_free_chunk(heap_create_free_chunk(ptr, allocated, true)); @@ -402,9 +397,6 @@ void miniheap_init(void *ptr, size_t len) theheap.base = 0; theheap.len = 0; theheap.remaining = 0; // will get set by heap_insert_free_chunk() - theheap.low_watermark = theheap.len; - - // create an initial free chunk - //heap_insert_free_chunk(heap_create_free_chunk(theheap.base, theheap.len, false)); + theheap.low_watermark = 0; } From 6b06d322a2e5c6972c8dd37fbefc300531bc3684 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Thu, 15 Oct 2015 15:22:30 -0700 Subject: [PATCH 04/19] [lib][heap] add info dump for dlmalloc, wire in heap trimming code --- lib/heap/dlmalloc/dlmalloc.c | 4 +++- lib/heap/heap_wrapper.c | 38 +++++++++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/lib/heap/dlmalloc/dlmalloc.c b/lib/heap/dlmalloc/dlmalloc.c index a71168b9..40796bd1 100644 --- a/lib/heap/dlmalloc/dlmalloc.c +++ b/lib/heap/dlmalloc/dlmalloc.c @@ -568,11 +568,13 @@ static int direct_mmap(size_t s) #define DIRECT_MMAP(s) direct_mmap(s) #define MUNMAP(b, s) munmap(b, s) #define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T /* disable direct mapping of chunks */ -#define DEFAULT_GRANULARITY PAGE_SIZE // (64*1024) +#define DEFAULT_GRANULARITY (64*1024) +#define MMAP_CLEARS 0 #define HAVE_MORECORE 0 #define USE_LOCKS 2 #define ABORT panic("dlmalloc abort\n") #define MALLOC_FAILURE_ACTION //dprintf(INFO, "dlmalloc failure\n"); +#define MALLOC_INSPECT_ALL 1 #endif /* LK */ #ifndef WIN32 diff --git a/lib/heap/heap_wrapper.c b/lib/heap/heap_wrapper.c index 00f0f718..66732aa5 100644 --- a/lib/heap/heap_wrapper.c +++ b/lib/heap/heap_wrapper.c @@ -38,18 +38,22 @@ struct list_node delayed_free_list = LIST_INITIAL_VALUE(delayed_free_list); spin_lock_t delayed_free_lock = SPIN_LOCK_INITIAL_VALUE; #if WITH_LIB_HEAP_MINIHEAP +/* miniheap implementation */ #include #define HEAP_ALLOC miniheap_alloc #define HEAP_FREE miniheap_free static inline void HEAP_INIT(void) { miniheap_init(NULL, 0); } #define HEAP_DUMP miniheap_dump +static inline void HEAP_TRIM(void) {} +/* end miniheap implementation */ #elif WITH_LIB_HEAP_DLMALLOC +/* dlmalloc implementation */ #include static inline void *HEAP_ALLOC(size_t size, unsigned int alignment) { - if (alignment == 0) + if (alignment < 8) return dlmalloc(size); else return dlmemalign(alignment, size); @@ -57,14 +61,30 @@ static inline void *HEAP_ALLOC(size_t size, unsigned int alignment) { static inline void HEAP_FREE(void *ptr) { dlfree(ptr); } static inline void HEAP_INIT(void) {} -static inline void HEAP_DUMP(void) {} -void *dl_sbrk(int incr) { - LTRACEF("incr %d\n", incr); +static inline void HEAP_DUMP(void) { + struct mallinfo minfo = dlmallinfo(); - panic("what"); + printf("\tmallinfo:\n"); + printf("\t\tarena space 0x%zx\n", minfo.arena); + printf("\t\tfree chunks 0x%zx\n", minfo.ordblks); + printf("\t\tspace in mapped regions 0x%zx\n", minfo.hblkhd); + printf("\t\tmax total allocated 0x%zx\n", minfo.usmblks); + printf("\t\ttotal allocated 0x%zx\n", minfo.uordblks); + printf("\t\tfree 0x%zx\n", minfo.fordblks); + printf("\t\treleasable space 0x%zx\n", minfo.keepcost); + + printf("\theap block list:\n"); + void dump_callback(void *start, void *end, size_t used_bytes, void *arg) { + printf("\t\tstart %p end %p used_bytes %zu\n", start, end, used_bytes); + } + + dlmalloc_inspect_all(&dump_callback, NULL); } +static inline void HEAP_TRIM(void) { dlmalloc_trim(0); } + +/* end dlmalloc implementation */ #else #error need to select valid heap implementation or provide wrapper #endif @@ -145,6 +165,11 @@ void heap_init(void) HEAP_INIT(); } +void heap_trim(void) +{ + HEAP_TRIM(); +} + /* critical section time delayed free */ void heap_delayed_free(void *ptr) { @@ -291,6 +316,7 @@ notenoughargs: usage: printf("usage:\n"); printf("\t%s info\n", argv[0].str); + printf("\t%s trim\n", argv[0].str); printf("\t%s alloc [alignment]\n", argv[0].str); printf("\t%s free
\n", argv[0].str); return -1; @@ -298,6 +324,8 @@ usage: if (strcmp(argv[1].str, "info") == 0) { heap_dump(); + } else if (strcmp(argv[1].str, "trim") == 0) { + heap_trim(); } else if (strcmp(argv[1].str, "alloc") == 0) { if (argc < 3) goto notenoughargs; From 3bbc7ac101f92fba3614cc53835a6970700ae2c5 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Thu, 15 Oct 2015 15:27:03 -0700 Subject: [PATCH 05/19] WIP patch from erik --- include/kernel/novm.h | 36 ++++++ include/lib/page_alloc.h | 54 +++++++++ include/malloc.h | 5 + kernel/novm.c | 252 +++++++++++++++++++++++++++++++++++++++ kernel/rules.mk | 2 + lib/heap/page_alloc.c | 122 +++++++++++++++++++ lib/heap/rules.mk | 3 +- lib/libc/malloc.c | 20 ++++ top/main.c | 5 + 9 files changed, 498 insertions(+), 1 deletion(-) create mode 100644 include/kernel/novm.h create mode 100644 include/lib/page_alloc.h create mode 100644 kernel/novm.c create mode 100644 lib/heap/page_alloc.c diff --git a/include/kernel/novm.h b/include/kernel/novm.h new file mode 100644 index 00000000..648b9eba --- /dev/null +++ b/include/kernel/novm.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015 Google, Inc. All rights reserved + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef __KERNEL_NOVM_H +#define __KERNEL_NOVM_H + +#include + +void novm_init(void); +void *novm_alloc_pages(size_t pages); +void novm_free_pages(void* address, size_t pages); + +// You can call this once and it will give you some possibly unaligned memory +// that would otherwise go to waste. The memory can't be freed. +void *novm_alloc_unaligned(size_t *size_return); + +#endif diff --git a/include/lib/page_alloc.h b/include/lib/page_alloc.h new file mode 100644 index 00000000..b625fe05 --- /dev/null +++ b/include/lib/page_alloc.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2015 Google, Inc. All rights reserved + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef __LIB_PAGE_ALLOC_H +#define __LIB_PAGE_ALLOC_H + +#include +#include +#include + +__BEGIN_CDECLS; + +#if WITH_KERNEL_VM + +typedef struct list_node page_alloc_handle; + +#else + +typedef struct { + void* address; + size_t pages; +} page_alloc_handle; + +#endif + +void *page_alloc(size_t pages, page_alloc_handle *list); +void page_free(page_alloc_handle *list); + +// You can call this once at the start, and it will either return a page or it +// will return some non-page-aligned memory that would otherwise go to waste. +void *page_first_alloc(size_t *size_return); + +__END_CDECLS; + +#endif diff --git a/include/malloc.h b/include/malloc.h index a93b0562..9eeaca38 100644 --- a/include/malloc.h +++ b/include/malloc.h @@ -34,6 +34,11 @@ void *memalign(size_t boundary, size_t size) __MALLOC; void *calloc(size_t count, size_t size) __MALLOC; void *realloc(void *ptr, size_t size) __MALLOC; void free(void *ptr); +/* Allocate a number of contiguous 4k pages. These pages cannot be freed with + * free(), but the handle must be passed to free_pages. + */ +void *allocate_pages(void **handle_return, int pages); +void free_pages(void *handle); __END_CDECLS diff --git a/kernel/novm.c b/kernel/novm.c new file mode 100644 index 00000000..66b0ff17 --- /dev/null +++ b/kernel/novm.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2015 Google, Inc. All rights reserved + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "kernel/novm.h" + +#include +#include +#include +#include + +#if WITH_STATIC_HEAP + +#define DEFAULT_MAP_SIZE (HEAP_LEN >> PAGE_SIZE_SHIFT) + +#else + +/* not a static vm, not using the kernel vm */ +extern int _end; +extern int _end_of_ram; + +/* default to using up the rest of memory after the kernel ends */ +/* may be modified by other parts of the system */ + +#define HEAP_START ((uintptr_t)&_end) +#define HEAP_LEN ((uintptr_t)&_end_of_ram - HEAP_START) + +#define MAP_SIZE (HEAP_LEN >> PAGE_SIZE_SHIFT) +// The map is one byte per page, but we can't statically size that because +// the C compiler doesn't think the difference between two addresses is a +// compile time constant. +// Instead, the default bytemap starts with this many bytes, which covers a +// quarter megabyte if page size is 4k. If that's not enough, we steal the +// first of the plentiful pages for the map. +#define DEFAULT_MAP_SIZE 64 + +#endif + +char allocation_map[DEFAULT_MAP_SIZE]; + +struct novm { + mutex_t lock; + size_t pages; + char* map; + char* heap_base; + uintptr_t heap_size; +}; + +static bool in_heap(struct novm *n, void* p) +{ + char *ptr = (char *)p; + char *base = n->heap_base; + return ptr >= base && ptr < base + n->heap_size; +} + +struct novm sram_heap; +struct novm sdram_heap; + +// We divide the memory up into pages. If there is memory we can use before +// the first aligned page address, then we record it here and the heap will use +// it. +#define MINIMUM_USEFUL_UNALIGNED_SIZE 64 +static void* unaligned_area = NULL; +static size_t unaligned_size = 0; + +void *novm_alloc_unaligned(size_t *size_return) { + if (unaligned_area != NULL) { + *size_return = unaligned_size; + void *result = unaligned_area; + unaligned_area = NULL; + return result; + } + *size_return = PAGE_SIZE; + return novm_alloc_pages(1); +} + +void novm_init_helper( + struct novm* n, uintptr_t heap_start, + uintptr_t heap_size, char* default_map, size_t default_map_size) +{ + uintptr_t start = ROUNDUP(heap_start, PAGE_SIZE); + uintptr_t size = ROUNDDOWN(heap_start + heap_size, PAGE_SIZE) - start; + mutex_init(&n->lock); + size_t map_size = size >> PAGE_SIZE_SHIFT; + char* map = default_map; + if (map == NULL || default_map_size < map_size) { + map = (char *)heap_start; + // Grab enough map for 16Mbyte of heap each time around the loop. + while (start - heap_start < map_size) { + start += PAGE_SIZE; + size -= PAGE_SIZE; + map_size--; + } + if ((char *)start - (map + map_size) >= MINIMUM_USEFUL_UNALIGNED_SIZE) { + unaligned_area = map + map_size; + unaligned_size = (char *)start - (map + map_size); + } + } else if (start - heap_start >= MINIMUM_USEFUL_UNALIGNED_SIZE) { + unaligned_area = (char *)heap_start; + unaligned_size = start - heap_start; + } + n->map = map; + memset(n->map, 0, map_size); + n->pages = map_size; + n->heap_base = (char *)start; + n->heap_size = size; +} + +void novm_init(void) { + novm_init_helper(&sram_heap, HEAP_START, HEAP_LEN, allocation_map, DEFAULT_MAP_SIZE); + +#ifdef SDRAM_BASE +#define SDRAM_MAP_SIZE (SDRAM_SIZE >> PAGE_SIZE_SHIFT) + static char sdram_map[SDRAM_MAP_SIZE]; + novm_init_helper(&sdram_heap, SDRAM_BASE, SDRAM_BASE + SDRAM_SIZE, sdram_map, SDRAM_MAP_SIZE); +#endif +} + +void *novm_alloc_helper(struct novm *n, size_t pages) +{ + mutex_acquire(&n->lock); + for (size_t i = 0; i <= n->pages - pages; i++) { + bool found = true; + for (size_t j = 0; j < pages; j++) { + if (n->map[i + j] != 0) { + i += j; + found = false; + break; + } + } + if (found) { + memset(n->map + i, 1, pages); + mutex_release(&n->lock); + return n->heap_base + (i << PAGE_SIZE_SHIFT); + } + } + mutex_release(&n->lock); + return NULL; +} + +void* novm_alloc_pages(size_t pages) +{ + void* result = novm_alloc_helper(&sram_heap, pages); + if (result != NULL) return result; +#ifdef SDRAM_BASE + return novm_alloc_helper(&sdram_heap, pages); +#endif + return NULL; +} + + +void novm_free_pages(void* address, size_t pages) +{ +#ifdef SDRAM_BASE + struct novm *n = in_heap(&sram_heap, address) ? &sram_heap : &sdram_heap; +#else + struct novm *n = &sram_heap; +#endif + + DEBUG_ASSERT(in_heap(n, address)); + + size_t index = ((char *)address - (char*)(n->heap_base)) >> PAGE_SIZE_SHIFT; + char *map = n->map; + + mutex_acquire(&n->lock); + for (size_t i = 0; i < pages; i++) map[index + i] = 0; + mutex_release(&n->lock); +} + +#if LK_DEBUGLEVEL > 1 +#if WITH_LIB_CONSOLE + +#include + +static int cmd_novm(int argc, const cmd_args *argv); +static void novm_dump(void); + +STATIC_COMMAND_START +STATIC_COMMAND("novm", "page allocator (for devices without VM support) debug commands", &cmd_novm) +STATIC_COMMAND_END(novm); + +static int cmd_novm(int argc, const cmd_args *argv) +{ + if (argc != 2) { +notenoughargs: + printf("not enough arguments\n"); +usage: + printf("usage:\n"); + printf("\t%s info\n", argv[0].str); + return -1; + } + + if (strcmp(argv[1].str, "info") == 0) { + novm_dump(); + } else { + printf("unrecognized command\n"); + goto usage; + } + + return 0; +} + +static void novm_dump_area(struct novm *n) { + mutex_acquire(&n->lock); + printf(" %d pages, each %zdk (%zdk in all)\n", n->pages, PAGE_SIZE >> 10, (PAGE_SIZE * n->pages) >> 10); + printf(" %p-%p\n", (void *)n->heap_base, (char *)n->heap_base + n->heap_size); +#define MAX_PRINT 1024u + unsigned i; + for (i = 0; i < MAX_PRINT && i < n->pages; i++) { + if ((i & 63) == 0) printf(" "); + printf("%c", n->map[i] ? '*' : '.'); + if ((i & 63) == 63) printf("\n"); + } + if (i == MAX_PRINT && n->pages > MAX_PRINT) printf(" ..."); + printf("\n"); + mutex_release(&n->lock); +} + +static void novm_dump(void) +{ + printf("SRAM area:\n"); + novm_dump_area(&sram_heap); +#ifdef SDRAM_BASE + printf("SDRAM area:\n"); + novm_dump_area(&sdram_heap); +#endif +} + +#endif +#endif + +/* vim: set ts=4 sw=4 noexpandtab: */ + diff --git a/kernel/rules.mk b/kernel/rules.mk index aab917b3..578d10b8 100644 --- a/kernel/rules.mk +++ b/kernel/rules.mk @@ -19,6 +19,8 @@ MODULE_SRCS := \ ifeq ($(WITH_KERNEL_VM),1) MODULE_DEPS += kernel/vm +else +MODULE_SRCS += $(LOCAL_DIR)/novm.c endif include make/module.mk diff --git a/lib/heap/page_alloc.c b/lib/heap/page_alloc.c new file mode 100644 index 00000000..62903c24 --- /dev/null +++ b/lib/heap/page_alloc.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2015 Google, Inc. All rights reserved + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#if WITH_KERNEL_VM +#include +#else +#include +#endif +#include +#include + +void *page_alloc(size_t pages, page_alloc_handle *handle) +{ +#if WITH_KERNEL_VM + if (handle != NULL) list_initialize(handle); + void *result = pmm_alloc_kpages(pages, handle); + if (!result) { + TRACEF("failed to grow kernel heap by 0x%zx bytes\n", + pages * PAGE_SIZE); + return 0; + } + return result; +#else + void *result = novm_alloc_pages(pages); + if (handle == NULL) return result; + if (result == NULL) { + handle->address = NULL; + handle->pages = 0; + return NULL; + } else { + handle->address = result; + handle->pages = pages; + return result; + } +#endif +} + +void page_free(page_alloc_handle *handle) { +#if WITH_KERNEL_VM + pmm_free(handle); +#else + novm_free_pages(handle->address, handle->pages); +#endif +} + +void *page_first_alloc(size_t *size_return) { +#if WITH_KERNEL_VM + return page_alloc(1, NULL); +#else + return novm_alloc_unaligned(size_return); +#endif +} + + +#if LK_DEBUGLEVEL > 1 +#if WITH_LIB_CONSOLE + +#include + +static int cmd_page_alloc(int argc, const cmd_args *argv); +static void page_alloc_dump(void); + +STATIC_COMMAND_START +STATIC_COMMAND("page_alloc", "page allocator debug commands", &cmd_page_alloc) +STATIC_COMMAND_END(page_alloc); + +static int cmd_page_alloc(int argc, const cmd_args *argv) +{ + if (argc != 2) { +notenoughargs: + printf("not enough arguments\n"); +usage: + printf("usage:\n"); + printf("\t%s info\n", argv[0].str); + return -1; + } + + if (strcmp(argv[1].str, "info") == 0) { + page_alloc_dump(); + } else { + printf("unrecognized command\n"); + goto usage; + } + + return 0; +} + +static void page_alloc_dump(void) +{ +#ifdef WITH_KERNEL_VM + dprintf(INFO, "Page allocator is based on pmm\n"); +#else + dprintf(INFO, "Page allocator is based on novm\n"); +#endif +} + +#endif +#endif + +/* vim: set ts=4 sw=4 noexpandtab: */ diff --git a/lib/heap/rules.mk b/lib/heap/rules.mk index 5095beb5..fabad3a6 100644 --- a/lib/heap/rules.mk +++ b/lib/heap/rules.mk @@ -5,7 +5,8 @@ GLOBAL_INCLUDES += $(LOCAL_DIR)/include MODULE := $(LOCAL_DIR) MODULE_SRCS += \ - $(LOCAL_DIR)/heap_wrapper.c + $(LOCAL_DIR)/heap_wrapper.c \ + $(LOCAL_DIR)/page_alloc.c # pick a heap implementation ifndef LK_HEAP_IMPLEMENTATION diff --git a/lib/libc/malloc.c b/lib/libc/malloc.c index cbad393c..0190b788 100644 --- a/lib/libc/malloc.c +++ b/lib/libc/malloc.c @@ -24,6 +24,7 @@ #include #include #include +#include void *malloc(size_t size) { @@ -69,3 +70,22 @@ void free(void *ptr) return heap_free(ptr); } +void *allocate_pages(void **handle_return, int pages) +{ + page_alloc_handle *handle = + (page_alloc_handle *)malloc(sizeof(page_alloc_handle)); + void* address = page_alloc(pages, handle); + if (address == NULL) { + *handle_return = NULL; + return NULL; + } else { + *handle_return = handle; + return address; + } +} + +void free_pages(void* handle) +{ + page_free((page_alloc_handle *)handle); + free(handle); +} diff --git a/top/main.c b/top/main.c index 03875108..df6675c9 100644 --- a/top/main.c +++ b/top/main.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -102,6 +103,10 @@ void lk_main(ulong arg0, ulong arg1, ulong arg2, ulong arg3) dprintf(INFO, "boot args 0x%lx 0x%lx 0x%lx 0x%lx\n", lk_boot_args[0], lk_boot_args[1], lk_boot_args[2], lk_boot_args[3]); +#if !WITH_KERNEL_VM + novm_init(); +#endif + // bring up the kernel heap dprintf(SPEW, "initializing heap\n"); lk_primary_cpu_init_level(LK_INIT_LEVEL_TARGET_EARLY, LK_INIT_LEVEL_HEAP - 1); From 80bf0a48b4f52de8f2e3fc335d9cc450de91cafa Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Thu, 15 Oct 2015 15:46:35 -0700 Subject: [PATCH 06/19] [lib][heap] fix some formatting and a bug or two in the novm and page alloc stuff --- include/lib/page_alloc.h | 2 +- kernel/novm.c | 187 ++++++++++++++++++++------------------- lib/heap/page_alloc.c | 62 +++++++------ 3 files changed, 126 insertions(+), 125 deletions(-) diff --git a/include/lib/page_alloc.h b/include/lib/page_alloc.h index b625fe05..e28674ab 100644 --- a/include/lib/page_alloc.h +++ b/include/lib/page_alloc.h @@ -36,7 +36,7 @@ typedef struct list_node page_alloc_handle; #else typedef struct { - void* address; + void* address; size_t pages; } page_alloc_handle; diff --git a/kernel/novm.c b/kernel/novm.c index 66b0ff17..aaf67f38 100644 --- a/kernel/novm.c +++ b/kernel/novm.c @@ -55,21 +55,21 @@ extern int _end_of_ram; #endif -char allocation_map[DEFAULT_MAP_SIZE]; +static char allocation_map[DEFAULT_MAP_SIZE]; struct novm { - mutex_t lock; + mutex_t lock; size_t pages; - char* map; + char* map; char* heap_base; uintptr_t heap_size; }; static bool in_heap(struct novm *n, void* p) { - char *ptr = (char *)p; - char *base = n->heap_base; - return ptr >= base && ptr < base + n->heap_size; + char *ptr = (char *)p; + char *base = n->heap_base; + return ptr >= base && ptr < base + n->heap_size; } struct novm sram_heap; @@ -82,42 +82,43 @@ struct novm sdram_heap; static void* unaligned_area = NULL; static size_t unaligned_size = 0; -void *novm_alloc_unaligned(size_t *size_return) { - if (unaligned_area != NULL) { - *size_return = unaligned_size; - void *result = unaligned_area; - unaligned_area = NULL; - return result; - } - *size_return = PAGE_SIZE; - return novm_alloc_pages(1); +void *novm_alloc_unaligned(size_t *size_return) +{ + if (unaligned_area != NULL) { + *size_return = unaligned_size; + void *result = unaligned_area; + unaligned_area = NULL; + return result; + } + *size_return = PAGE_SIZE; + return novm_alloc_pages(1); } void novm_init_helper( struct novm* n, uintptr_t heap_start, - uintptr_t heap_size, char* default_map, size_t default_map_size) + uintptr_t heap_size, char* default_map, size_t default_map_size) { - uintptr_t start = ROUNDUP(heap_start, PAGE_SIZE); - uintptr_t size = ROUNDDOWN(heap_start + heap_size, PAGE_SIZE) - start; - mutex_init(&n->lock); + uintptr_t start = ROUNDUP(heap_start, PAGE_SIZE); + uintptr_t size = ROUNDDOWN(heap_start + heap_size, PAGE_SIZE) - start; + mutex_init(&n->lock); size_t map_size = size >> PAGE_SIZE_SHIFT; char* map = default_map; if (map == NULL || default_map_size < map_size) { - map = (char *)heap_start; - // Grab enough map for 16Mbyte of heap each time around the loop. - while (start - heap_start < map_size) { - start += PAGE_SIZE; - size -= PAGE_SIZE; - map_size--; - } - if ((char *)start - (map + map_size) >= MINIMUM_USEFUL_UNALIGNED_SIZE) { - unaligned_area = map + map_size; - unaligned_size = (char *)start - (map + map_size); - } + map = (char *)heap_start; + // Grab enough map for 16Mbyte of heap each time around the loop. + while (start - heap_start < map_size) { + start += PAGE_SIZE; + size -= PAGE_SIZE; + map_size--; + } + if ((char *)start - (map + map_size) >= MINIMUM_USEFUL_UNALIGNED_SIZE) { + unaligned_area = map + map_size; + unaligned_size = (char *)start - (map + map_size); + } } else if (start - heap_start >= MINIMUM_USEFUL_UNALIGNED_SIZE) { - unaligned_area = (char *)heap_start; - unaligned_size = start - heap_start; - } + unaligned_area = (char *)heap_start; + unaligned_size = start - heap_start; + } n->map = map; memset(n->map, 0, map_size); n->pages = map_size; @@ -125,44 +126,45 @@ void novm_init_helper( n->heap_size = size; } -void novm_init(void) { - novm_init_helper(&sram_heap, HEAP_START, HEAP_LEN, allocation_map, DEFAULT_MAP_SIZE); +void novm_init(void) +{ + novm_init_helper(&sram_heap, HEAP_START, HEAP_LEN, allocation_map, DEFAULT_MAP_SIZE); #ifdef SDRAM_BASE #define SDRAM_MAP_SIZE (SDRAM_SIZE >> PAGE_SIZE_SHIFT) - static char sdram_map[SDRAM_MAP_SIZE]; - novm_init_helper(&sdram_heap, SDRAM_BASE, SDRAM_BASE + SDRAM_SIZE, sdram_map, SDRAM_MAP_SIZE); + static char sdram_map[SDRAM_MAP_SIZE]; + novm_init_helper(&sdram_heap, SDRAM_BASE, SDRAM_SIZE, sdram_map, SDRAM_MAP_SIZE); #endif } void *novm_alloc_helper(struct novm *n, size_t pages) { - mutex_acquire(&n->lock); - for (size_t i = 0; i <= n->pages - pages; i++) { - bool found = true; - for (size_t j = 0; j < pages; j++) { - if (n->map[i + j] != 0) { - i += j; - found = false; - break; - } - } - if (found) { - memset(n->map + i, 1, pages); - mutex_release(&n->lock); - return n->heap_base + (i << PAGE_SIZE_SHIFT); - } - } - mutex_release(&n->lock); - return NULL; + mutex_acquire(&n->lock); + for (size_t i = 0; i <= n->pages - pages; i++) { + bool found = true; + for (size_t j = 0; j < pages; j++) { + if (n->map[i + j] != 0) { + i += j; + found = false; + break; + } + } + if (found) { + memset(n->map + i, 1, pages); + mutex_release(&n->lock); + return n->heap_base + (i << PAGE_SIZE_SHIFT); + } + } + mutex_release(&n->lock); + return NULL; } void* novm_alloc_pages(size_t pages) { - void* result = novm_alloc_helper(&sram_heap, pages); + void* result = novm_alloc_helper(&sram_heap, pages); if (result != NULL) return result; #ifdef SDRAM_BASE - return novm_alloc_helper(&sdram_heap, pages); + return novm_alloc_helper(&sdram_heap, pages); #endif return NULL; } @@ -176,14 +178,14 @@ void novm_free_pages(void* address, size_t pages) struct novm *n = &sram_heap; #endif - DEBUG_ASSERT(in_heap(n, address)); + DEBUG_ASSERT(in_heap(n, address)); - size_t index = ((char *)address - (char*)(n->heap_base)) >> PAGE_SIZE_SHIFT; + size_t index = ((char *)address - (char*)(n->heap_base)) >> PAGE_SIZE_SHIFT; char *map = n->map; - mutex_acquire(&n->lock); - for (size_t i = 0; i < pages; i++) map[index + i] = 0; - mutex_release(&n->lock); + mutex_acquire(&n->lock); + for (size_t i = 0; i < pages; i++) map[index + i] = 0; + mutex_release(&n->lock); } #if LK_DEBUGLEVEL > 1 @@ -200,48 +202,49 @@ STATIC_COMMAND_END(novm); static int cmd_novm(int argc, const cmd_args *argv) { - if (argc != 2) { + if (argc != 2) { notenoughargs: - printf("not enough arguments\n"); + printf("not enough arguments\n"); usage: - printf("usage:\n"); - printf("\t%s info\n", argv[0].str); - return -1; - } + printf("usage:\n"); + printf("\t%s info\n", argv[0].str); + return -1; + } - if (strcmp(argv[1].str, "info") == 0) { - novm_dump(); - } else { - printf("unrecognized command\n"); - goto usage; - } + if (strcmp(argv[1].str, "info") == 0) { + novm_dump(); + } else { + printf("unrecognized command\n"); + goto usage; + } - return 0; + return 0; } -static void novm_dump_area(struct novm *n) { - mutex_acquire(&n->lock); - printf(" %d pages, each %zdk (%zdk in all)\n", n->pages, PAGE_SIZE >> 10, (PAGE_SIZE * n->pages) >> 10); - printf(" %p-%p\n", (void *)n->heap_base, (char *)n->heap_base + n->heap_size); +static void novm_dump_area(struct novm *n) +{ + mutex_acquire(&n->lock); + printf(" %d pages, each %zdk (%zdk in all)\n", n->pages, PAGE_SIZE >> 10, (PAGE_SIZE * n->pages) >> 10); + printf(" %p-%p\n", (void *)n->heap_base, (char *)n->heap_base + n->heap_size); #define MAX_PRINT 1024u - unsigned i; - for (i = 0; i < MAX_PRINT && i < n->pages; i++) { - if ((i & 63) == 0) printf(" "); - printf("%c", n->map[i] ? '*' : '.'); - if ((i & 63) == 63) printf("\n"); - } - if (i == MAX_PRINT && n->pages > MAX_PRINT) printf(" ..."); - printf("\n"); - mutex_release(&n->lock); + unsigned i; + for (i = 0; i < MAX_PRINT && i < n->pages; i++) { + if ((i & 63) == 0) printf(" "); + printf("%c", n->map[i] ? '*' : '.'); + if ((i & 63) == 63) printf("\n"); + } + if (i == MAX_PRINT && n->pages > MAX_PRINT) printf(" ..."); + printf("\n"); + mutex_release(&n->lock); } static void novm_dump(void) { - printf("SRAM area:\n"); - novm_dump_area(&sram_heap); + printf("SRAM area:\n"); + novm_dump_area(&sram_heap); #ifdef SDRAM_BASE - printf("SDRAM area:\n"); - novm_dump_area(&sdram_heap); + printf("SDRAM area:\n"); + novm_dump_area(&sdram_heap); #endif } diff --git a/lib/heap/page_alloc.c b/lib/heap/page_alloc.c index 62903c24..ca33079a 100644 --- a/lib/heap/page_alloc.c +++ b/lib/heap/page_alloc.c @@ -34,24 +34,24 @@ void *page_alloc(size_t pages, page_alloc_handle *handle) { #if WITH_KERNEL_VM - if (handle != NULL) list_initialize(handle); - void *result = pmm_alloc_kpages(pages, handle); - if (!result) { - TRACEF("failed to grow kernel heap by 0x%zx bytes\n", - pages * PAGE_SIZE); - return 0; - } + if (handle != NULL) list_initialize(handle); + void *result = pmm_alloc_kpages(pages, handle); + if (!result) { + TRACEF("failed to grow kernel heap by 0x%zx bytes\n", + pages * PAGE_SIZE); + return 0; + } return result; #else void *result = novm_alloc_pages(pages); if (handle == NULL) return result; if (result == NULL) { - handle->address = NULL; - handle->pages = 0; - return NULL; + handle->address = NULL; + handle->pages = 0; + return NULL; } else { - handle->address = result; - handle->pages = pages; + handle->address = result; + handle->pages = pages; return result; } #endif @@ -59,7 +59,7 @@ void *page_alloc(size_t pages, page_alloc_handle *handle) void page_free(page_alloc_handle *handle) { #if WITH_KERNEL_VM - pmm_free(handle); + pmm_free(handle); #else novm_free_pages(handle->address, handle->pages); #endif @@ -67,9 +67,9 @@ void page_free(page_alloc_handle *handle) { void *page_first_alloc(size_t *size_return) { #if WITH_KERNEL_VM - return page_alloc(1, NULL); + return page_alloc(1, NULL); #else - return novm_alloc_unaligned(size_return); + return novm_alloc_unaligned(size_return); #endif } @@ -88,35 +88,33 @@ STATIC_COMMAND_END(page_alloc); static int cmd_page_alloc(int argc, const cmd_args *argv) { - if (argc != 2) { + if (argc != 2) { notenoughargs: - printf("not enough arguments\n"); + printf("not enough arguments\n"); usage: - printf("usage:\n"); - printf("\t%s info\n", argv[0].str); - return -1; - } + printf("usage:\n"); + printf("\t%s info\n", argv[0].str); + return -1; + } - if (strcmp(argv[1].str, "info") == 0) { - page_alloc_dump(); - } else { - printf("unrecognized command\n"); - goto usage; - } + if (strcmp(argv[1].str, "info") == 0) { + page_alloc_dump(); + } else { + printf("unrecognized command\n"); + goto usage; + } - return 0; + return 0; } static void page_alloc_dump(void) { #ifdef WITH_KERNEL_VM - dprintf(INFO, "Page allocator is based on pmm\n"); + dprintf(INFO, "Page allocator is based on pmm\n"); #else - dprintf(INFO, "Page allocator is based on novm\n"); + dprintf(INFO, "Page allocator is based on novm\n"); #endif } #endif #endif - -/* vim: set ts=4 sw=4 noexpandtab: */ From e9a6bd0ea1512f0399076953273008dbf78b8aa3 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Thu, 15 Oct 2015 16:52:02 -0700 Subject: [PATCH 07/19] WIP get the heap code pointing at the new page allocator --- include/kernel/novm.h | 4 ++++ include/lib/page_alloc.h | 20 +++++++------------- include/malloc.h | 5 ----- kernel/novm.c | 1 + lib/heap/heap_wrapper.c | 17 ++++++++++++++--- lib/heap/miniheap/miniheap.c | 6 +++--- lib/heap/page_alloc.c | 35 ++++++++++++++++------------------- lib/libc/malloc.c | 19 ------------------- 8 files changed, 45 insertions(+), 62 deletions(-) diff --git a/include/kernel/novm.h b/include/kernel/novm.h index 648b9eba..adce5b52 100644 --- a/include/kernel/novm.h +++ b/include/kernel/novm.h @@ -24,6 +24,10 @@ #define __KERNEL_NOVM_H #include +#include + +#define PAGE_ALIGN(x) ALIGN(x, PAGE_SIZE) +#define IS_PAGE_ALIGNED(x) IS_ALIGNED(x, PAGE_SIZE) void novm_init(void); void *novm_alloc_pages(size_t pages); diff --git a/include/lib/page_alloc.h b/include/lib/page_alloc.h index e28674ab..abbeac79 100644 --- a/include/lib/page_alloc.h +++ b/include/lib/page_alloc.h @@ -27,23 +27,17 @@ #include #include -__BEGIN_CDECLS; - +// to pick up PAGE_SIZE, PAGE_ALIGN, etc #if WITH_KERNEL_VM - -typedef struct list_node page_alloc_handle; - +#include #else - -typedef struct { - void* address; - size_t pages; -} page_alloc_handle; - +#include #endif -void *page_alloc(size_t pages, page_alloc_handle *list); -void page_free(page_alloc_handle *list); +__BEGIN_CDECLS; + +void *page_alloc(size_t pages); +void page_free(void *ptr, size_t pages); // You can call this once at the start, and it will either return a page or it // will return some non-page-aligned memory that would otherwise go to waste. diff --git a/include/malloc.h b/include/malloc.h index 9eeaca38..a93b0562 100644 --- a/include/malloc.h +++ b/include/malloc.h @@ -34,11 +34,6 @@ void *memalign(size_t boundary, size_t size) __MALLOC; void *calloc(size_t count, size_t size) __MALLOC; void *realloc(void *ptr, size_t size) __MALLOC; void free(void *ptr); -/* Allocate a number of contiguous 4k pages. These pages cannot be freed with - * free(), but the handle must be passed to free_pages. - */ -void *allocate_pages(void **handle_return, int pages); -void free_pages(void *handle); __END_CDECLS diff --git a/kernel/novm.c b/kernel/novm.c index aaf67f38..5a55e83a 100644 --- a/kernel/novm.c +++ b/kernel/novm.c @@ -100,6 +100,7 @@ void novm_init_helper( { uintptr_t start = ROUNDUP(heap_start, PAGE_SIZE); uintptr_t size = ROUNDDOWN(heap_start + heap_size, PAGE_SIZE) - start; + mutex_init(&n->lock); size_t map_size = size >> PAGE_SIZE_SHIFT; char* map = default_map; diff --git a/lib/heap/heap_wrapper.c b/lib/heap/heap_wrapper.c index 66732aa5..8ba101aa 100644 --- a/lib/heap/heap_wrapper.c +++ b/lib/heap/heap_wrapper.c @@ -25,11 +25,13 @@ #include #include #include +#include #include #include #include #include #include +#include #define LOCAL_TRACE 1 @@ -204,6 +206,16 @@ ssize_t heap_grow_memory(void **ptr, size_t size) { LTRACEF("ptr %p, size 0x%zx\n", ptr, size); + size = ROUNDUP(size, PAGE_SIZE); + *ptr = page_alloc(size / PAGE_SIZE); + + LTRACEF("returning ptr %p\n", *ptr); + + return size; + +#if 0 + LTRACEF("ptr %p, size 0x%zx\n", ptr, size); + #if WITH_KERNEL_VM && !WITH_STATIC_HEAP size = ROUNDUP(size, PAGE_SIZE); LTRACEF("size now 0x%zx\n", size); @@ -228,18 +240,17 @@ ssize_t heap_grow_memory(void **ptr, size_t size) LTRACEF("returning %p, size 0x%zx\n", *ptr, size); return size; +#endif } void heap_free_memory(void *ptr, size_t len) { LTRACEF("ptr %p, len 0x%zx\n", ptr, len); -#if WITH_KERNEL_VM && !WITH_STATIC_HEAP DEBUG_ASSERT(IS_PAGE_ALIGNED((uintptr_t)ptr)); DEBUG_ASSERT(IS_PAGE_ALIGNED(len)); - pmm_free_kpages(ptr, len / PAGE_SIZE); -#endif + page_free(ptr, len / PAGE_SIZE); } #if 0 diff --git a/lib/heap/miniheap/miniheap.c b/lib/heap/miniheap/miniheap.c index cf77e933..f1baf7e8 100644 --- a/lib/heap/miniheap/miniheap.c +++ b/lib/heap/miniheap/miniheap.c @@ -372,7 +372,7 @@ static ssize_t heap_grow(size_t size) heap_insert_free_chunk(heap_create_free_chunk(ptr, allocated, true)); /* change the heap start and end variables */ - if ((uintptr_t)ptr < (uintptr_t)theheap.base) + if ((uintptr_t)ptr < (uintptr_t)theheap.base || theheap.base == 0) theheap.base = ptr; uintptr_t endptr = (uintptr_t)ptr + allocated; @@ -394,8 +394,8 @@ void miniheap_init(void *ptr, size_t len) list_initialize(&theheap.free_list); // set the heap range - theheap.base = 0; - theheap.len = 0; + theheap.base = ptr; + theheap.len = len; theheap.remaining = 0; // will get set by heap_insert_free_chunk() theheap.low_watermark = 0; } diff --git a/lib/heap/page_alloc.c b/lib/heap/page_alloc.c index ca33079a..3ba15c76 100644 --- a/lib/heap/page_alloc.c +++ b/lib/heap/page_alloc.c @@ -13,7 +13,8 @@ * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE @@ -23,6 +24,7 @@ #include #include +#include #if WITH_KERNEL_VM #include #else @@ -31,11 +33,13 @@ #include #include -void *page_alloc(size_t pages, page_alloc_handle *handle) -{ +void *page_alloc(size_t pages) { #if WITH_KERNEL_VM - if (handle != NULL) list_initialize(handle); - void *result = pmm_alloc_kpages(pages, handle); + /* throw the list away, we can reconstruct it later */ + struct list_node list; + list_initialize(&list); + + void *result = pmm_alloc_kpages(pages, &list); if (!result) { TRACEF("failed to grow kernel heap by 0x%zx bytes\n", pages * PAGE_SIZE); @@ -44,30 +48,23 @@ void *page_alloc(size_t pages, page_alloc_handle *handle) return result; #else void *result = novm_alloc_pages(pages); - if (handle == NULL) return result; - if (result == NULL) { - handle->address = NULL; - handle->pages = 0; - return NULL; - } else { - handle->address = result; - handle->pages = pages; - return result; - } + return result; #endif } -void page_free(page_alloc_handle *handle) { +void page_free(void *ptr, size_t pages) { #if WITH_KERNEL_VM - pmm_free(handle); + DEBUG_ASSERT(IS_PAGE_ALIGNED((uintptr_t)ptr)); + + pmm_free_kpages(ptr, pages); #else - novm_free_pages(handle->address, handle->pages); + novm_free_pages(ptr, pages); #endif } void *page_first_alloc(size_t *size_return) { #if WITH_KERNEL_VM - return page_alloc(1, NULL); + return page_alloc(1); #else return novm_alloc_unaligned(size_return); #endif diff --git a/lib/libc/malloc.c b/lib/libc/malloc.c index 0190b788..dd1abd37 100644 --- a/lib/libc/malloc.c +++ b/lib/libc/malloc.c @@ -70,22 +70,3 @@ void free(void *ptr) return heap_free(ptr); } -void *allocate_pages(void **handle_return, int pages) -{ - page_alloc_handle *handle = - (page_alloc_handle *)malloc(sizeof(page_alloc_handle)); - void* address = page_alloc(pages, handle); - if (address == NULL) { - *handle_return = NULL; - return NULL; - } else { - *handle_return = handle; - return address; - } -} - -void free_pages(void* handle) -{ - page_free((page_alloc_handle *)handle); - free(handle); -} From 7c09e82033ec183c3fc8f1a6a05a0253784023e5 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Thu, 15 Oct 2015 17:22:16 -0700 Subject: [PATCH 08/19] [make] make sure MEMBASE and MEMSIZE are always set exactly once --- arch/arm/rules.mk | 4 ++++ arch/arm64/rules.mk | 3 +++ arch/microblaze/rules.mk | 4 ++++ arch/or1k/rules.mk | 4 ++++ platform/alterasoc/rules.mk | 4 ---- platform/am335x/rules.mk | 1 - platform/armemu/rules.mk | 4 ---- platform/bcm2835/rules.mk | 2 -- platform/lpc43xx/rules.mk | 3 --- platform/microblaze/rules.mk | 4 ---- platform/omap3/rules.mk | 2 +- platform/or1ksim/rules.mk | 4 ---- platform/qemu-virt/rules.mk | 2 -- platform/stm32f1xx/rules.mk | 3 --- platform/stm32f2xx/rules.mk | 3 --- platform/stm32f4xx/rules.mk | 3 --- platform/stm32f7xx/rules.mk | 1 - platform/zynq/rules.mk | 2 -- 18 files changed, 16 insertions(+), 37 deletions(-) diff --git a/arch/arm/rules.mk b/arch/arm/rules.mk index 985aaf78..4dcd0b1d 100644 --- a/arch/arm/rules.mk +++ b/arch/arm/rules.mk @@ -286,6 +286,10 @@ ifeq ($(MEMVARS_SET),0) $(error missing MEMBASE or MEMSIZE variable, please set in target rules.mk) endif +GLOBAL_DEFINES += \ + MEMBASE=$(MEMBASE) \ + MEMSIZE=$(MEMSIZE) + LIBGCC := $(shell $(TOOLCHAIN_PREFIX)gcc $(GLOBAL_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(THUMBCFLAGS) -print-libgcc-file-name) $(info LIBGCC = $(LIBGCC)) diff --git a/arch/arm64/rules.mk b/arch/arm64/rules.mk index 28d08da8..1970c859 100644 --- a/arch/arm64/rules.mk +++ b/arch/arm64/rules.mk @@ -84,6 +84,9 @@ KERNEL_LOAD_OFFSET ?= 0 endif +GLOBAL_DEFINES += \ + MEMBASE=$(MEMBASE) \ + MEMSIZE=$(MEMSIZE) # try to find the toolchain include $(LOCAL_DIR)/toolchain.mk diff --git a/arch/microblaze/rules.mk b/arch/microblaze/rules.mk index 7c3ebe21..64fda155 100644 --- a/arch/microblaze/rules.mk +++ b/arch/microblaze/rules.mk @@ -51,6 +51,10 @@ KERNEL_BASE ?= $(MEMBASE) KERNEL_LOAD_OFFSET ?= 0 VECTOR_BASE_PHYS ?= 0 +GLOBAL_DEFINES += \ + MEMBASE=$(MEMBASE) \ + MEMSIZE=$(MEMSIZE) + # potentially generated files that should be cleaned out with clean make rule GENERATED += \ $(BUILDDIR)/linker.ld diff --git a/arch/or1k/rules.mk b/arch/or1k/rules.mk index 046b9bf4..d7967f61 100644 --- a/arch/or1k/rules.mk +++ b/arch/or1k/rules.mk @@ -40,6 +40,10 @@ GLOBAL_DEFINES += \ KERNEL_BASE=$(KERNEL_BASE) \ KERNEL_LOAD_OFFSET=$(KERNEL_LOAD_OFFSET) +GLOBAL_DEFINES += \ + MEMBASE=$(MEMBASE) \ + MEMSIZE=$(MEMSIZE) + # potentially generated files that should be cleaned out with clean make rule GENERATED += \ $(BUILDDIR)/linker.ld diff --git a/platform/alterasoc/rules.mk b/platform/alterasoc/rules.mk index 1122ea4c..2960ce42 100644 --- a/platform/alterasoc/rules.mk +++ b/platform/alterasoc/rules.mk @@ -23,10 +23,6 @@ MODULE_SRCS += \ MEMBASE := 0x0 MEMSIZE ?= 0x10000000 # 256MB -GLOBAL_DEFINES += \ - MEMBASE=$(MEMBASE) \ - MEMSIZE=$(MEMSIZE) - LINKER_SCRIPT += \ $(BUILDDIR)/system-onesegment.ld diff --git a/platform/am335x/rules.mk b/platform/am335x/rules.mk index 0b2ac024..b0a76ec3 100644 --- a/platform/am335x/rules.mk +++ b/platform/am335x/rules.mk @@ -35,7 +35,6 @@ LINKER_SCRIPT += \ $(BUILDDIR)/system-onesegment.ld GLOBAL_DEFINES += \ - MEMBASE=$(MEMBASE) \ SDRAM_BASE=$(MEMBASE) \ SDRAM_SIZE=$(MEMSIZE) \ diff --git a/platform/armemu/rules.mk b/platform/armemu/rules.mk index df4d187e..198e0ecb 100644 --- a/platform/armemu/rules.mk +++ b/platform/armemu/rules.mk @@ -32,10 +32,6 @@ MODULE_DEPS += \ MEMBASE := 0x0 MEMSIZE := 0x400000 # 4MB -GLOBAL_DEFINES += \ - MEMBASE=$(MEMBASE) \ - MEMSIZE=$(MEMSIZE) - LINKER_SCRIPT += \ $(BUILDDIR)/system-onesegment.ld diff --git a/platform/bcm2835/rules.mk b/platform/bcm2835/rules.mk index e67c3e47..a2e1dc4a 100644 --- a/platform/bcm2835/rules.mk +++ b/platform/bcm2835/rules.mk @@ -36,8 +36,6 @@ KERNEL_LOAD_OFFSET := 0x00008000 # loaded 32KB into physical KERNEL_BASE = 0x80000000 GLOBAL_DEFINES += \ - MEMBASE=$(MEMBASE) \ - MEMSIZE=$(MEMSIZE) \ ARM_ARCH_WAIT_FOR_SECONDARIES=1 LINKER_SCRIPT += \ diff --git a/platform/lpc43xx/rules.mk b/platform/lpc43xx/rules.mk index 58d813ea..959d8e9a 100644 --- a/platform/lpc43xx/rules.mk +++ b/platform/lpc43xx/rules.mk @@ -9,9 +9,6 @@ MEMSIZE ?= 40960 ARCH := arm ARM_CPU := cortex-m4 -GLOBAL_DEFINES += \ - MEMSIZE=$(MEMSIZE) - GLOBAL_INCLUDES += \ $(LOCAL_DIR)/include diff --git a/platform/microblaze/rules.mk b/platform/microblaze/rules.mk index 0cb726f7..3676821f 100644 --- a/platform/microblaze/rules.mk +++ b/platform/microblaze/rules.mk @@ -21,8 +21,4 @@ MEMSIZE ?= 0x20000 # 128KB MODULE_DEPS += \ -GLOBAL_DEFINES += \ - MEMBASE=$(MEMBASE) \ - MEMSIZE=$(MEMSIZE) - include make/module.mk diff --git a/platform/omap3/rules.mk b/platform/omap3/rules.mk index 8550027a..c511e8a0 100644 --- a/platform/omap3/rules.mk +++ b/platform/omap3/rules.mk @@ -26,7 +26,7 @@ MODULE_SRCS += \ MEMBASE := 0x80000000 -GLOBAL_DEFINES += MEMBASE=$(MEMBASE) \ +GLOBAL_DEFINES += \ WITH_CPU_EARLY_INIT=1 LINKER_SCRIPT += \ diff --git a/platform/or1ksim/rules.mk b/platform/or1ksim/rules.mk index fac536a8..d9f967a5 100644 --- a/platform/or1ksim/rules.mk +++ b/platform/or1ksim/rules.mk @@ -24,8 +24,4 @@ WITH_KERNEL_VM=1 KERNEL_BASE = 0xc0000000 -GLOBAL_DEFINES += \ - MEMBASE=$(MEMBASE) \ - MEMSIZE=$(MEMSIZE) - include make/module.mk diff --git a/platform/qemu-virt/rules.mk b/platform/qemu-virt/rules.mk index 9b85d4d8..6fda02f7 100644 --- a/platform/qemu-virt/rules.mk +++ b/platform/qemu-virt/rules.mk @@ -37,8 +37,6 @@ MODULE_DEPS += \ dev/virtio/net \ GLOBAL_DEFINES += \ - MEMBASE=$(MEMBASE) \ - MEMSIZE=$(MEMSIZE) \ PLATFORM_SUPPORTS_PANIC_SHELL=1 GLOBAL_DEFINES += MMU_WITH_TRAMPOLINE=1 \ # use the trampoline translation table in start.S diff --git a/platform/stm32f1xx/rules.mk b/platform/stm32f1xx/rules.mk index 75b35750..aa090277 100644 --- a/platform/stm32f1xx/rules.mk +++ b/platform/stm32f1xx/rules.mk @@ -36,9 +36,6 @@ GLOBAL_DEFINES += \ MEMSIZE ?= 20480 endif -GLOBAL_DEFINES += \ - MEMSIZE=$(MEMSIZE) - GLOBAL_INCLUDES += \ $(LOCAL_DIR)/include diff --git a/platform/stm32f2xx/rules.mk b/platform/stm32f2xx/rules.mk index aa529788..fc612c9b 100644 --- a/platform/stm32f2xx/rules.mk +++ b/platform/stm32f2xx/rules.mk @@ -30,9 +30,6 @@ ifeq ($(FOUND_CHIP),) $(error unknown STM32F2xx chip $(STM32_CHIP)) endif -GLOBAL_DEFINES += \ - MEMSIZE=$(MEMSIZE) - GLOBAL_INCLUDES += \ $(LOCAL_DIR)/include diff --git a/platform/stm32f4xx/rules.mk b/platform/stm32f4xx/rules.mk index 1c61982b..47976853 100644 --- a/platform/stm32f4xx/rules.mk +++ b/platform/stm32f4xx/rules.mk @@ -26,9 +26,6 @@ ifeq ($(FOUND_CHIP),) $(error unknown STM32F4xx chip $(STM32_CHIP)) endif -GLOBAL_DEFINES += \ - MEMSIZE=$(MEMSIZE) - GLOBAL_INCLUDES += \ $(LOCAL_DIR)/include \ $(LOCAL_DIR)/include/dev diff --git a/platform/stm32f7xx/rules.mk b/platform/stm32f7xx/rules.mk index 54d5490c..4836af17 100644 --- a/platform/stm32f7xx/rules.mk +++ b/platform/stm32f7xx/rules.mk @@ -24,7 +24,6 @@ $(error unknown STM32F7xx chip $(STM32_CHIP)) endif GLOBAL_DEFINES += \ - MEMSIZE=$(MEMSIZE) \ PLATFORM_SUPPORTS_PANIC_SHELL=1 GLOBAL_INCLUDES += \ diff --git a/platform/zynq/rules.mk b/platform/zynq/rules.mk index 542aa88f..fb2e5484 100644 --- a/platform/zynq/rules.mk +++ b/platform/zynq/rules.mk @@ -76,8 +76,6 @@ endif KERNEL_BASE = 0xc0000000 GLOBAL_DEFINES += \ - MEMBASE=$(MEMBASE) \ - MEMSIZE=$(MEMSIZE) \ SDRAM_SIZE=$(ZYNQ_SDRAM_SIZE) LINKER_SCRIPT += \ From fab92f3179b2ce18e967c946a2ccdc1123a118b3 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Thu, 15 Oct 2015 18:15:45 -0700 Subject: [PATCH 09/19] [lib][heap] have novm initialize itself, rename novm 'heap' to 'arena' to be less confusing --- include/kernel/novm.h | 3 +- kernel/novm.c | 142 ++++++++++++++++++++--------------- lib/heap/heap_wrapper.c | 63 +++------------- lib/heap/miniheap/miniheap.c | 6 +- lib/heap/page_alloc.c | 2 +- platform/stm32f7xx/rules.mk | 2 + top/main.c | 4 - 7 files changed, 100 insertions(+), 122 deletions(-) diff --git a/include/kernel/novm.h b/include/kernel/novm.h index adce5b52..eabc9ba7 100644 --- a/include/kernel/novm.h +++ b/include/kernel/novm.h @@ -29,10 +29,11 @@ #define PAGE_ALIGN(x) ALIGN(x, PAGE_SIZE) #define IS_PAGE_ALIGNED(x) IS_ALIGNED(x, PAGE_SIZE) -void novm_init(void); void *novm_alloc_pages(size_t pages); void novm_free_pages(void* address, size_t pages); +status_t novm_alloc_specific_pages(void *address, size_t pages); + // You can call this once and it will give you some possibly unaligned memory // that would otherwise go to waste. The memory can't be freed. void *novm_alloc_unaligned(size_t *size_return); diff --git a/kernel/novm.c b/kernel/novm.c index 5a55e83a..294932aa 100644 --- a/kernel/novm.c +++ b/kernel/novm.c @@ -25,55 +25,32 @@ #include #include +#include #include #include +#include +#include -#if WITH_STATIC_HEAP - -#define DEFAULT_MAP_SIZE (HEAP_LEN >> PAGE_SIZE_SHIFT) - -#else +struct novm_arena { + mutex_t lock; + size_t pages; + char *map; + char *base; + size_t size; +}; /* not a static vm, not using the kernel vm */ extern int _end; extern int _end_of_ram; -/* default to using up the rest of memory after the kernel ends */ -/* may be modified by other parts of the system */ - -#define HEAP_START ((uintptr_t)&_end) -#define HEAP_LEN ((uintptr_t)&_end_of_ram - HEAP_START) - -#define MAP_SIZE (HEAP_LEN >> PAGE_SIZE_SHIFT) -// The map is one byte per page, but we can't statically size that because -// the C compiler doesn't think the difference between two addresses is a -// compile time constant. -// Instead, the default bytemap starts with this many bytes, which covers a -// quarter megabyte if page size is 4k. If that's not enough, we steal the -// first of the plentiful pages for the map. -#define DEFAULT_MAP_SIZE 64 - -#endif +#define MEM_START ((uintptr_t)&_end) +#define MEM_SIZE ((MEMBASE + MEMSIZE) - MEM_START) +#define DEFAULT_MAP_SIZE (MEMSIZE >> PAGE_SIZE_SHIFT) static char allocation_map[DEFAULT_MAP_SIZE]; -struct novm { - mutex_t lock; - size_t pages; - char* map; - char* heap_base; - uintptr_t heap_size; -}; - -static bool in_heap(struct novm *n, void* p) -{ - char *ptr = (char *)p; - char *base = n->heap_base; - return ptr >= base && ptr < base + n->heap_size; -} - -struct novm sram_heap; -struct novm sdram_heap; +struct novm_arena mem_arena; +struct novm_arena sdram_arena; // We divide the memory up into pages. If there is memory we can use before // the first aligned page address, then we record it here and the heap will use @@ -94,8 +71,15 @@ void *novm_alloc_unaligned(size_t *size_return) return novm_alloc_pages(1); } +static bool in_arena(struct novm_arena *n, void* p) +{ + char *ptr = (char *)p; + char *base = n->base; + return ptr >= base && ptr < base + n->size; +} + void novm_init_helper( - struct novm* n, uintptr_t heap_start, + struct novm_arena* n, uintptr_t heap_start, uintptr_t heap_size, char* default_map, size_t default_map_size) { uintptr_t start = ROUNDUP(heap_start, PAGE_SIZE); @@ -123,22 +107,30 @@ void novm_init_helper( n->map = map; memset(n->map, 0, map_size); n->pages = map_size; - n->heap_base = (char *)start; - n->heap_size = size; + n->base = (char *)start; + n->size = size; } -void novm_init(void) +void novm_init_preheap(uint level) { - novm_init_helper(&sram_heap, HEAP_START, HEAP_LEN, allocation_map, DEFAULT_MAP_SIZE); + novm_init_helper(&mem_arena, MEM_START, MEM_SIZE, allocation_map, DEFAULT_MAP_SIZE); #ifdef SDRAM_BASE #define SDRAM_MAP_SIZE (SDRAM_SIZE >> PAGE_SIZE_SHIFT) static char sdram_map[SDRAM_MAP_SIZE]; - novm_init_helper(&sdram_heap, SDRAM_BASE, SDRAM_SIZE, sdram_map, SDRAM_MAP_SIZE); + novm_init_helper(&sdram_arena, SDRAM_BASE, SDRAM_SIZE, sdram_map, SDRAM_MAP_SIZE); +#endif + +#if 0 + /* mark pieces of the novm as used */ + novm_alloc_specific_pages(&__data_start, + ROUNDUP((uintptr_t)&_end - (uintptr_t)&__data_start, PAGE_SIZE) / PAGE_SIZE); #endif } -void *novm_alloc_helper(struct novm *n, size_t pages) +LK_INIT_HOOK(novm_preheap, &novm_init_preheap, LK_INIT_LEVEL_HEAP - 1); + +void *novm_alloc_helper(struct novm_arena *n, size_t pages) { mutex_acquire(&n->lock); for (size_t i = 0; i <= n->pages - pages; i++) { @@ -153,7 +145,7 @@ void *novm_alloc_helper(struct novm *n, size_t pages) if (found) { memset(n->map + i, 1, pages); mutex_release(&n->lock); - return n->heap_base + (i << PAGE_SIZE_SHIFT); + return n->base + (i << PAGE_SIZE_SHIFT); } } mutex_release(&n->lock); @@ -162,26 +154,25 @@ void *novm_alloc_helper(struct novm *n, size_t pages) void* novm_alloc_pages(size_t pages) { - void* result = novm_alloc_helper(&sram_heap, pages); + void* result = novm_alloc_helper(&mem_arena, pages); if (result != NULL) return result; #ifdef SDRAM_BASE - return novm_alloc_helper(&sdram_heap, pages); + return novm_alloc_helper(&sdram_arena, pages); #endif return NULL; } - void novm_free_pages(void* address, size_t pages) { #ifdef SDRAM_BASE - struct novm *n = in_heap(&sram_heap, address) ? &sram_heap : &sdram_heap; + struct novm_arena *n = in_arena(&mem_arena, address) ? &mem_arena : &sdram_arena; #else - struct novm *n = &sram_heap; + struct novm_arena *n = &mem_arena; #endif - DEBUG_ASSERT(in_heap(n, address)); + DEBUG_ASSERT(in_arena(n, address)); - size_t index = ((char *)address - (char*)(n->heap_base)) >> PAGE_SIZE_SHIFT; + size_t index = ((char *)address - (char*)(n->base)) >> PAGE_SIZE_SHIFT; char *map = n->map; mutex_acquire(&n->lock); @@ -189,6 +180,37 @@ void novm_free_pages(void* address, size_t pages) mutex_release(&n->lock); } +status_t novm_alloc_specific_pages(void *address, size_t pages) +{ + TRACEF("address %p, pages %zu\n", address, pages); + + struct novm_arena *n = in_arena(&mem_arena, address) ? &mem_arena : NULL; +#ifdef SDRAM_BASE + if (!n) + n = in_arena(&sdram_arena, address) ? &sdram_arena : NULL; +#endif + if (!n) + return ERR_NOT_FOUND; + + size_t index = ((char *)address - (char*)(n->base)) >> PAGE_SIZE_SHIFT; + char *map = n->map; + + status_t err = NO_ERROR; + + mutex_acquire(&n->lock); + for (size_t i = 0; i < pages; i++) { + if (map[index + i] != 0) { + err = ERR_NO_MEMORY; + break; + } + map[index + i] = 1; + } + mutex_release(&n->lock); + + return err; +} + + #if LK_DEBUGLEVEL > 1 #if WITH_LIB_CONSOLE @@ -222,11 +244,11 @@ usage: return 0; } -static void novm_dump_area(struct novm *n) +static void novm_dump_area(struct novm_arena *n) { mutex_acquire(&n->lock); printf(" %d pages, each %zdk (%zdk in all)\n", n->pages, PAGE_SIZE >> 10, (PAGE_SIZE * n->pages) >> 10); - printf(" %p-%p\n", (void *)n->heap_base, (char *)n->heap_base + n->heap_size); + printf(" %p-%p\n", (void *)n->base, (char *)n->base + n->size); #define MAX_PRINT 1024u unsigned i; for (i = 0; i < MAX_PRINT && i < n->pages; i++) { @@ -241,16 +263,14 @@ static void novm_dump_area(struct novm *n) static void novm_dump(void) { - printf("SRAM area:\n"); - novm_dump_area(&sram_heap); + printf("main memory arena:\n"); + novm_dump_area(&mem_arena); #ifdef SDRAM_BASE - printf("SDRAM area:\n"); - novm_dump_area(&sdram_heap); + printf("SDRAM arena:\n"); + novm_dump_area(&sdram_arena); #endif } #endif #endif -/* vim: set ts=4 sw=4 noexpandtab: */ - diff --git a/lib/heap/heap_wrapper.c b/lib/heap/heap_wrapper.c index 8ba101aa..071a3586 100644 --- a/lib/heap/heap_wrapper.c +++ b/lib/heap/heap_wrapper.c @@ -33,7 +33,7 @@ #include #include -#define LOCAL_TRACE 1 +#define LOCAL_TRACE 0 /* delayed free list */ struct list_node delayed_free_list = LIST_INITIAL_VALUE(delayed_free_list); @@ -45,7 +45,12 @@ spin_lock_t delayed_free_lock = SPIN_LOCK_INITIAL_VALUE; #define HEAP_ALLOC miniheap_alloc #define HEAP_FREE miniheap_free -static inline void HEAP_INIT(void) { miniheap_init(NULL, 0); } +static inline void HEAP_INIT(void) { + /* start the heap off with some spare memory in the page allocator */ + size_t len; + void *ptr = page_first_alloc(&len); + miniheap_init(ptr, len); +} #define HEAP_DUMP miniheap_dump static inline void HEAP_TRIM(void) {} @@ -91,35 +96,14 @@ static inline void HEAP_TRIM(void) { dlmalloc_trim(0); } #error need to select valid heap implementation or provide wrapper #endif -#if WITH_KERNEL_VM +#if WITH_STATIC_HEAP -#include - -/* we will use kalloc routines to back our heap */ -#if !defined(HEAP_GROW_SIZE) -#define HEAP_GROW_SIZE (64 * 1024) /* size the heap grows by when it runs out of memory */ -#endif - -STATIC_ASSERT(IS_PAGE_ALIGNED(HEAP_GROW_SIZE)); - -#elif WITH_STATIC_HEAP +#error "fix static heap post page allocator and novm stuff" #if !defined(HEAP_START) || !defined(HEAP_LEN) #error WITH_STATIC_HEAP set but no HEAP_START or HEAP_LEN defined #endif -#else -/* not a static vm, not using the kernel vm */ -extern int _end; -extern int _end_of_ram; - -/* default to using up the rest of memory after the kernel ends */ -/* may be modified by other parts of the system */ -uintptr_t _heap_start = (uintptr_t)&_end; -uintptr_t _heap_end = (uintptr_t)&_end_of_ram; - -#define HEAP_START ((uintptr_t)_heap_start) -#define HEAP_LEN ((uintptr_t)_heap_end - HEAP_START) #endif static void heap_free_delayed_list(void) @@ -212,35 +196,6 @@ ssize_t heap_grow_memory(void **ptr, size_t size) LTRACEF("returning ptr %p\n", *ptr); return size; - -#if 0 - LTRACEF("ptr %p, size 0x%zx\n", ptr, size); - -#if WITH_KERNEL_VM && !WITH_STATIC_HEAP - size = ROUNDUP(size, PAGE_SIZE); - LTRACEF("size now 0x%zx\n", size); - - *ptr = pmm_alloc_kpages(size / PAGE_SIZE, NULL); - if (!*ptr) { - TRACEF("failed to grow kernel heap by 0x%zx bytes\n", size); - return ERR_NO_MEMORY; - } -#else - static bool have_asked_for_memory = false; - - if (have_asked_for_memory) - return ERR_NO_MEMORY; - - // XXX dont return all of the range on the first call - *ptr = (void *)HEAP_START; - size = HEAP_LEN; - have_asked_for_memory = true; -#endif - - LTRACEF("returning %p, size 0x%zx\n", *ptr, size); - - return size; -#endif } void heap_free_memory(void *ptr, size_t len) diff --git a/lib/heap/miniheap/miniheap.c b/lib/heap/miniheap/miniheap.c index f1baf7e8..7e9f61b4 100644 --- a/lib/heap/miniheap/miniheap.c +++ b/lib/heap/miniheap/miniheap.c @@ -385,7 +385,7 @@ static ssize_t heap_grow(size_t size) void miniheap_init(void *ptr, size_t len) { - LTRACE_ENTRY; + LTRACEF("ptr %p, len %zu\n", ptr, len); // create a mutex mutex_init(&theheap.lock); @@ -398,5 +398,9 @@ void miniheap_init(void *ptr, size_t len) theheap.len = len; theheap.remaining = 0; // will get set by heap_insert_free_chunk() theheap.low_watermark = 0; + + // if passed a default range, use it + if (len > 0) + heap_insert_free_chunk(heap_create_free_chunk(ptr, len, true)); } diff --git a/lib/heap/page_alloc.c b/lib/heap/page_alloc.c index 3ba15c76..b418506c 100644 --- a/lib/heap/page_alloc.c +++ b/lib/heap/page_alloc.c @@ -64,13 +64,13 @@ void page_free(void *ptr, size_t pages) { void *page_first_alloc(size_t *size_return) { #if WITH_KERNEL_VM + *size_return = PAGE_SIZE; return page_alloc(1); #else return novm_alloc_unaligned(size_return); #endif } - #if LK_DEBUGLEVEL > 1 #if WITH_LIB_CONSOLE diff --git a/platform/stm32f7xx/rules.mk b/platform/stm32f7xx/rules.mk index 4836af17..d63eff1a 100644 --- a/platform/stm32f7xx/rules.mk +++ b/platform/stm32f7xx/rules.mk @@ -23,6 +23,8 @@ ifeq ($(FOUND_CHIP),) $(error unknown STM32F7xx chip $(STM32_CHIP)) endif +LK_HEAP_IMPLEMENTATION ?= miniheap + GLOBAL_DEFINES += \ PLATFORM_SUPPORTS_PANIC_SHELL=1 diff --git a/top/main.c b/top/main.c index df6675c9..3e6c3091 100644 --- a/top/main.c +++ b/top/main.c @@ -103,10 +103,6 @@ void lk_main(ulong arg0, ulong arg1, ulong arg2, ulong arg3) dprintf(INFO, "boot args 0x%lx 0x%lx 0x%lx 0x%lx\n", lk_boot_args[0], lk_boot_args[1], lk_boot_args[2], lk_boot_args[3]); -#if !WITH_KERNEL_VM - novm_init(); -#endif - // bring up the kernel heap dprintf(SPEW, "initializing heap\n"); lk_primary_cpu_init_level(LK_INIT_LEVEL_TARGET_EARLY, LK_INIT_LEVEL_HEAP - 1); From 38f20ec0a164aab2db996f29baa1f553d22ea97a Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Mon, 19 Oct 2015 12:46:31 -0700 Subject: [PATCH 10/19] [lib][console] add pointer type arg, switch some users to it. Patch courtesy Erik Corry --- app/tests/mem_tests.c | 2 +- include/lib/console.h | 1 + lib/buildsig/buildsig.c | 2 +- lib/cksum/debug.c | 8 ++++---- lib/console/console.c | 4 +++- lib/debugcommands/debugcommands.c | 2 +- lib/heap/heap_wrapper.c | 2 +- platform/zynq/spiflash.c | 2 +- 8 files changed, 13 insertions(+), 10 deletions(-) diff --git a/app/tests/mem_tests.c b/app/tests/mem_tests.c index fdd14fe1..0b76e646 100644 --- a/app/tests/mem_tests.c +++ b/app/tests/mem_tests.c @@ -225,7 +225,7 @@ usage: free(ptr); #endif } else if (argc == 3) { - void *ptr = (void *)argv[1].u; + void *ptr = argv[1].p; size_t len = argv[2].u; /* run the tests */ diff --git a/include/lib/console.h b/include/lib/console.h index a81aefc4..f270b3fe 100644 --- a/include/lib/console.h +++ b/include/lib/console.h @@ -32,6 +32,7 @@ typedef struct { const char *str; unsigned long u; + void* p; long i; bool b; } cmd_args; diff --git a/lib/buildsig/buildsig.c b/lib/buildsig/buildsig.c index 3436a1a3..54a676f7 100644 --- a/lib/buildsig/buildsig.c +++ b/lib/buildsig/buildsig.c @@ -130,7 +130,7 @@ usage: if (!strcmp(argv[1].str, "dump")) { const void *offset = &__rom_start; if (argc >= 3) { - offset = (void *)argv[2].u; + offset = argv[2].p; } const lk_version_t *v; diff --git a/lib/cksum/debug.c b/lib/cksum/debug.c index 14606d6f..132cc00c 100644 --- a/lib/cksum/debug.c +++ b/lib/cksum/debug.c @@ -56,7 +56,7 @@ static int cmd_crc16(int argc, const cmd_args *argv) return -1; } - uint16_t crc = crc16((void *)argv[1].u, argv[2].u); + uint16_t crc = crc16(argv[1].p, argv[2].u); printf("0x%hx\n", crc); @@ -71,7 +71,7 @@ static int cmd_crc32(int argc, const cmd_args *argv) return -1; } - uint32_t crc = crc32(0, (void *)argv[1].u, argv[2].u); + uint32_t crc = crc32(0, argv[1].p, argv[2].u); printf("0x%x\n", crc); @@ -86,7 +86,7 @@ static int cmd_adler32(int argc, const cmd_args *argv) return -1; } - uint32_t crc = adler32(0, (void *)argv[1].u, argv[2].u); + uint32_t crc = adler32(0, argv[1].p, argv[2].u); printf("0x%x\n", crc); @@ -101,7 +101,7 @@ static int cmd_cksum_bench(int argc, const cmd_args *argv) bool freebuf; if (argc > 1) { - buf = (void *)argv[1].u; + buf = argv[1].p; freebuf = false; } else { buf = malloc(BUFSIZE); diff --git a/lib/console/console.c b/lib/console/console.c index 59514863..bdcab58f 100644 --- a/lib/console/console.c +++ b/lib/console/console.c @@ -538,7 +538,9 @@ static void convert_args(int argc, cmd_args *argv) int i; for (i = 0; i < argc; i++) { - argv[i].u = atoul(argv[i].str); + unsigned long u = atoul(argv[i].str); + argv[i].u = u; + argv[i].p = (void*)u; argv[i].i = atol(argv[i].str); if (!strcmp(argv[i].str, "true") || !strcmp(argv[i].str, "on")) { diff --git a/lib/debugcommands/debugcommands.c b/lib/debugcommands/debugcommands.c index 85df564e..c73ab4e8 100644 --- a/lib/debugcommands/debugcommands.c +++ b/lib/debugcommands/debugcommands.c @@ -306,7 +306,7 @@ static int cmd_chain(int argc, const cmd_args *argv) return -1; } - arch_chain_load((void *)argv[1].u, 0, 0, 0, 0); + arch_chain_load(argv[1].p, 0, 0, 0, 0); return 0; } diff --git a/lib/heap/heap_wrapper.c b/lib/heap/heap_wrapper.c index 071a3586..d2aa6c9e 100644 --- a/lib/heap/heap_wrapper.c +++ b/lib/heap/heap_wrapper.c @@ -300,7 +300,7 @@ usage: } else if (strcmp(argv[1].str, "free") == 0) { if (argc < 2) goto notenoughargs; - heap_free((void *)argv[2].u); + heap_free(argv[2].p); } else { printf("unrecognized command\n"); goto usage; diff --git a/platform/zynq/spiflash.c b/platform/zynq/spiflash.c index 488cf5fd..98b66d8f 100644 --- a/platform/zynq/spiflash.c +++ b/platform/zynq/spiflash.c @@ -526,7 +526,7 @@ usage: return -1; } - status_t err = qspi_write_page(&flash.qspi, argv[2].u, (void *)argv[4].u); + status_t err = qspi_write_page(&flash.qspi, argv[2].u, argv[4].p); printf("write_page returns %d\n", err); } else if (!strcmp(argv[1].str, "erase")) { if (argc < 3) goto notenoughargs; From 35b2f85f6ad9ed49388636f2b4bce1c6977873ca Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Mon, 19 Oct 2015 12:47:29 -0700 Subject: [PATCH 11/19] [kernel][novm] fix bug in big block allocs, add some prettier debug Patch courtesy Erik Corry --- kernel/novm.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/kernel/novm.c b/kernel/novm.c index 294932aa..121e1405 100644 --- a/kernel/novm.c +++ b/kernel/novm.c @@ -132,6 +132,7 @@ LK_INIT_HOOK(novm_preheap, &novm_init_preheap, LK_INIT_LEVEL_HEAP - 1); void *novm_alloc_helper(struct novm_arena *n, size_t pages) { + if (pages > n->pages) return NULL; // Unsigned types! mutex_acquire(&n->lock); for (size_t i = 0; i <= n->pages - pages; i++) { bool found = true; @@ -225,17 +226,29 @@ STATIC_COMMAND_END(novm); static int cmd_novm(int argc, const cmd_args *argv) { - if (argc != 2) { + if (argc < 2) { notenoughargs: printf("not enough arguments\n"); usage: printf("usage:\n"); printf("\t%s info\n", argv[0].str); + printf("\t%s alloc \n", argv[0].str); + printf("\t%s free address \n", argv[0].str); return -1; } if (strcmp(argv[1].str, "info") == 0) { novm_dump(); + } else if (strcmp(argv[1].str, "alloc") == 0) { + if (argc < 3) goto notenoughargs; + + void *ptr = novm_alloc_pages(argv[2].u); + printf("novm_alloc_pages returns %p\n", ptr); + } else if (strcmp(argv[1].str, "free") == 0) { + if (argc < 3) goto notenoughargs; + size_t pages = (argc >= 4) ? argv[3].u : 1; + novm_free_pages(argv[2].p, pages); + printf("novm_free_pages: %zd pages at %p\n", pages, argv[2].p); } else { printf("unrecognized command\n"); goto usage; @@ -249,14 +262,19 @@ static void novm_dump_area(struct novm_arena *n) mutex_acquire(&n->lock); printf(" %d pages, each %zdk (%zdk in all)\n", n->pages, PAGE_SIZE >> 10, (PAGE_SIZE * n->pages) >> 10); printf(" %p-%p\n", (void *)n->base, (char *)n->base + n->size); -#define MAX_PRINT 1024u unsigned i; + size_t in_use = 0; + for (i = 0; i < n->pages; i++) if (n->map[i] != 0) in_use++; + printf(" %zd/%zd in use\n", in_use, n->pages); +#define MAX_PRINT 1024u for (i = 0; i < MAX_PRINT && i < n->pages; i++) { if ((i & 63) == 0) printf(" "); printf("%c", n->map[i] ? '*' : '.'); if ((i & 63) == 63) printf("\n"); } - if (i == MAX_PRINT && n->pages > MAX_PRINT) printf(" ..."); + if (i == MAX_PRINT && n->pages > MAX_PRINT) { + printf(" etc., %zd more pages.", n->pages - MAX_PRINT); + } printf("\n"); mutex_release(&n->lock); } From 6aa5f51cf99719966feda68ee3ed24f7d71bc416 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Mon, 19 Oct 2015 12:57:55 -0700 Subject: [PATCH 12/19] [target][stm32746g-eval2] remove STATIC_HEAP STATIC_HEAP is mostly obsoleted by the page based heap novm pooling system. May add it back at some time, but at the moment it's unused. --- target/stm32746g-eval2/rules.mk | 8 -------- 1 file changed, 8 deletions(-) diff --git a/target/stm32746g-eval2/rules.mk b/target/stm32746g-eval2/rules.mk index 7e5ebdd4..f878bb7b 100644 --- a/target/stm32746g-eval2/rules.mk +++ b/target/stm32746g-eval2/rules.mk @@ -8,13 +8,9 @@ PLATFORM := stm32f7xx SDRAM_SIZE := 0x02000000 SDRAM_BASE := 0xc0000000 -LCD_M_SIZE := 0x0012c000 EXT_SRAM_BASE := 0x68000000 EXT_SRAM_SIZE := 0x00200000 -HEAP_START := 0xc012c000 -HEAP_SIZE := 0x01ed4000 - GLOBAL_DEFINES += \ ENABLE_UART1=1 \ ENABLE_SDRAM=1 \ @@ -23,10 +19,6 @@ GLOBAL_DEFINES += \ EXT_SRAM_BASE=$(EXT_SRAM_BASE) \ EXT_SRAM_SIZE=$(EXT_SRAM_SIZE) \ ENABLE_EXT_SRAM=1 \ -\ - WITH_STATIC_HEAP=1 \ - HEAP_START=$(HEAP_START) \ - HEAP_LEN=$(HEAP_SIZE) \ \ PKTBUF_POOL_SIZE=16 From 65de7f865ce2fe9f3e0f5687ad730ccdcb89ea23 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Mon, 19 Oct 2015 13:02:19 -0700 Subject: [PATCH 13/19] [lib][heap] fix crash when page allocator runs out of memory --- lib/heap/heap_wrapper.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/heap/heap_wrapper.c b/lib/heap/heap_wrapper.c index d2aa6c9e..1048cb67 100644 --- a/lib/heap/heap_wrapper.c +++ b/lib/heap/heap_wrapper.c @@ -192,6 +192,8 @@ ssize_t heap_grow_memory(void **ptr, size_t size) size = ROUNDUP(size, PAGE_SIZE); *ptr = page_alloc(size / PAGE_SIZE); + if (!*ptr) + return ERR_NO_MEMORY; LTRACEF("returning ptr %p\n", *ptr); From 1c6e80f17136badd9b6c3065e149d9034eaf1f19 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Mon, 19 Oct 2015 14:02:30 -0700 Subject: [PATCH 14/19] [lib][heap] factor out the heap_grow api and have miniheap & dlmalloc call page_alloc directly --- include/lib/page_alloc.h | 6 +++++ lib/heap/dlmalloc/dlmalloc.c | 51 ++++++++++++++++++------------------ lib/heap/heap_wrapper.c | 25 ------------------ lib/heap/include/lib/heap.h | 3 --- lib/heap/miniheap/miniheap.c | 15 ++++++----- lib/heap/page_alloc.c | 16 ++++++----- 6 files changed, 49 insertions(+), 67 deletions(-) diff --git a/include/lib/page_alloc.h b/include/lib/page_alloc.h index abbeac79..858d83fe 100644 --- a/include/lib/page_alloc.h +++ b/include/lib/page_alloc.h @@ -34,6 +34,12 @@ #include #endif +/* A simple page-aligned wrapper around the pmm or novm implementation of + * the underlying physical page allocator. Used by system heaps or any + * other user that wants pages of memory but doesn't want to use LK + * specific apis. + */ + __BEGIN_CDECLS; void *page_alloc(size_t pages); diff --git a/lib/heap/dlmalloc/dlmalloc.c b/lib/heap/dlmalloc/dlmalloc.c index 40796bd1..2a88d758 100644 --- a/lib/heap/dlmalloc/dlmalloc.c +++ b/lib/heap/dlmalloc/dlmalloc.c @@ -541,31 +541,11 @@ MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP #define LACKS_SCHED_H #define HAVE_MMAP 1 #include -#include -#include +#include +#include #include - -static inline void *mmap(size_t len) { - void *ptr; - if (heap_grow_memory(&ptr, len) < 0) - return 0; - - return ptr; -} - -static inline int munmap(void *base, size_t len) { - heap_free_memory(base, len); - return 0; -} - -static int direct_mmap(size_t s) -{ - panic("direct map"); - return 0; -} - #define MMAP(s) mmap(s) -#define DIRECT_MMAP(s) direct_mmap(s) +#define DIRECT_MMAP(s) mmap(s) #define MUNMAP(b, s) munmap(b, s) #define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T /* disable direct mapping of chunks */ #define DEFAULT_GRANULARITY (64*1024) @@ -573,7 +553,7 @@ static int direct_mmap(size_t s) #define HAVE_MORECORE 0 #define USE_LOCKS 2 #define ABORT panic("dlmalloc abort\n") -#define MALLOC_FAILURE_ACTION //dprintf(INFO, "dlmalloc failure\n"); +#define MALLOC_FAILURE_ACTION // dprintf(INFO, "dlmalloc failure\n"); #define MALLOC_INSPECT_ALL 1 #endif /* LK */ @@ -1682,7 +1662,28 @@ unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); #if HAVE_MMAP -#ifndef WIN32 +#if defined(LK) + +/* LK specific stuff here */ +static inline void *mmap(size_t len) { + DEBUG_ASSERT(IS_PAGE_ALIGNED(len)); + + void *ptr = page_alloc(len / PAGE_SIZE); + if (!ptr) + return MFAIL; + return ptr; +} + +static inline int munmap(void *base, size_t len) { + DEBUG_ASSERT(IS_PAGE_ALIGNED((uintptr_t)base)); + DEBUG_ASSERT(IS_PAGE_ALIGNED(len)); + + page_free(base, len / PAGE_SIZE); + return 0; +} + +#elif !defined(WIN32) + #define MUNMAP_DEFAULT(a, s) munmap((a), (s)) #define MMAP_PROT (PROT_READ|PROT_WRITE) #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) diff --git a/lib/heap/heap_wrapper.c b/lib/heap/heap_wrapper.c index 1048cb67..6aca578c 100644 --- a/lib/heap/heap_wrapper.c +++ b/lib/heap/heap_wrapper.c @@ -185,31 +185,6 @@ static void heap_dump(void) spin_unlock_irqrestore(&delayed_free_lock, state); } -/* called back from the heap implementation to allocate another block of memory */ -ssize_t heap_grow_memory(void **ptr, size_t size) -{ - LTRACEF("ptr %p, size 0x%zx\n", ptr, size); - - size = ROUNDUP(size, PAGE_SIZE); - *ptr = page_alloc(size / PAGE_SIZE); - if (!*ptr) - return ERR_NO_MEMORY; - - LTRACEF("returning ptr %p\n", *ptr); - - return size; -} - -void heap_free_memory(void *ptr, size_t len) -{ - LTRACEF("ptr %p, len 0x%zx\n", ptr, len); - - DEBUG_ASSERT(IS_PAGE_ALIGNED((uintptr_t)ptr)); - DEBUG_ASSERT(IS_PAGE_ALIGNED(len)); - - page_free(ptr, len / PAGE_SIZE); -} - #if 0 static void heap_test(void) { diff --git a/lib/heap/include/lib/heap.h b/lib/heap/include/lib/heap.h index b26703f0..88799f4a 100644 --- a/lib/heap/include/lib/heap.h +++ b/lib/heap/include/lib/heap.h @@ -35,7 +35,4 @@ void heap_init(void); /* critical section time delayed free */ void heap_delayed_free(void *); -ssize_t heap_grow_memory(void **ptr, size_t len); -void heap_free_memory(void *ptr, size_t len); - __END_CDECLS; diff --git a/lib/heap/miniheap/miniheap.c b/lib/heap/miniheap/miniheap.c index 7e9f61b4..facb318d 100644 --- a/lib/heap/miniheap/miniheap.c +++ b/lib/heap/miniheap/miniheap.c @@ -33,6 +33,7 @@ #include #include #include +#include #define LOCAL_TRACE 0 @@ -360,27 +361,27 @@ void miniheap_get_stats(struct miniheap_stats *ptr) static ssize_t heap_grow(size_t size) { - void *ptr; - ssize_t allocated = heap_grow_memory(&ptr, size); - if (allocated <= 0) { + size = ROUNDUP(size, PAGE_SIZE); + void *ptr = page_alloc(size / PAGE_SIZE); + if (!ptr) { TRACEF("failed to grow kernel heap by 0x%zx bytes\n", size); return ERR_NO_MEMORY; } - LTRACEF("growing heap by 0x%zx bytes, allocated 0x%zx, new ptr %p\n", size, (size_t)allocated, ptr); + LTRACEF("growing heap by 0x%zx bytes, new ptr %p\n", size, ptr); - heap_insert_free_chunk(heap_create_free_chunk(ptr, allocated, true)); + heap_insert_free_chunk(heap_create_free_chunk(ptr, size, true)); /* change the heap start and end variables */ if ((uintptr_t)ptr < (uintptr_t)theheap.base || theheap.base == 0) theheap.base = ptr; - uintptr_t endptr = (uintptr_t)ptr + allocated; + uintptr_t endptr = (uintptr_t)ptr + size; if (endptr > (uintptr_t)theheap.base + theheap.len) { theheap.len = (uintptr_t)endptr - (uintptr_t)theheap.base; } - return allocated; + return size; } void miniheap_init(void *ptr, size_t len) diff --git a/lib/heap/page_alloc.c b/lib/heap/page_alloc.c index b418506c..89ea076b 100644 --- a/lib/heap/page_alloc.c +++ b/lib/heap/page_alloc.c @@ -25,13 +25,20 @@ #include #include +#include +#include #if WITH_KERNEL_VM #include #else #include #endif -#include -#include + +/* A simple page-aligned wrapper around the pmm or novm implementation of + * the underlying physical page allocator. Used by system heaps or any + * other user that wants pages of memory but doesn't want to use LK + * specific apis. + */ +#define LOCAL_TRACE 0 void *page_alloc(size_t pages) { #if WITH_KERNEL_VM @@ -40,11 +47,6 @@ void *page_alloc(size_t pages) { list_initialize(&list); void *result = pmm_alloc_kpages(pages, &list); - if (!result) { - TRACEF("failed to grow kernel heap by 0x%zx bytes\n", - pages * PAGE_SIZE); - return 0; - } return result; #else void *result = novm_alloc_pages(pages); From 1485131d002702331ca5ad9a355cfcb56310c1a1 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Mon, 19 Oct 2015 14:57:51 -0700 Subject: [PATCH 15/19] [lib][heap] refactor top level malloc/free into lib/heap Flatten a level by moving malloc/free/new and friends into lib/heap. Punch realloc and a few others directly through into the underlying heap implementation. Remove heap_alloc and heap_free entirely. --- arch/arm64/mmu.c | 6 +- include/malloc.h | 13 +-- lib/heap/dlmalloc/dlmalloc.c | 1 + lib/heap/heap_wrapper.c | 130 +++++++++++++++-------- lib/heap/include/lib/heap.h | 10 +- lib/heap/miniheap/include/lib/miniheap.h | 2 + lib/heap/miniheap/miniheap.c | 28 ++++- lib/{libc => heap}/new.cpp | 12 +-- lib/heap/page_alloc.c | 16 ++- lib/heap/rules.mk | 5 + lib/libc/malloc.c | 72 ------------- lib/libc/rules.mk | 8 +- 12 files changed, 155 insertions(+), 148 deletions(-) rename lib/{libc => heap}/new.cpp (89%) delete mode 100644 lib/libc/malloc.c diff --git a/arch/arm64/mmu.c b/arch/arm64/mmu.c index 055364f0..c723bf83 100644 --- a/arch/arm64/mmu.c +++ b/arch/arm64/mmu.c @@ -193,12 +193,12 @@ static int alloc_page_table(paddr_t *paddrp, uint page_size_shift) if (ret != count) return ERR_NO_MEMORY; } else { - vaddr = heap_alloc(size, size); + vaddr = memalign(size, size); if (!vaddr) return ERR_NO_MEMORY; ret = arch_mmu_query((vaddr_t)vaddr, paddrp, NULL); if (ret) { - heap_free(vaddr); + free(vaddr); return ret; } } @@ -218,7 +218,7 @@ static void free_page_table(void *vaddr, paddr_t paddr, uint page_size_shift) panic("bad page table paddr 0x%lx\n", paddr); pmm_free_page(page); } else { - heap_free(vaddr); + free(vaddr); } } diff --git a/include/malloc.h b/include/malloc.h index a93b0562..abafbe95 100644 --- a/include/malloc.h +++ b/include/malloc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Travis Geiselbrecht + * Copyright (c) 2008-2015 Travis Geiselbrecht * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -27,15 +27,8 @@ #include #include -__BEGIN_CDECLS - -void *malloc(size_t size) __MALLOC; -void *memalign(size_t boundary, size_t size) __MALLOC; -void *calloc(size_t count, size_t size) __MALLOC; -void *realloc(void *ptr, size_t size) __MALLOC; -void free(void *ptr); - -__END_CDECLS +/* lib/heap provides malloc/free definitions */ +#include #endif diff --git a/lib/heap/dlmalloc/dlmalloc.c b/lib/heap/dlmalloc/dlmalloc.c index 2a88d758..f13d8b9d 100644 --- a/lib/heap/dlmalloc/dlmalloc.c +++ b/lib/heap/dlmalloc/dlmalloc.c @@ -555,6 +555,7 @@ MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP #define ABORT panic("dlmalloc abort\n") #define MALLOC_FAILURE_ACTION // dprintf(INFO, "dlmalloc failure\n"); #define MALLOC_INSPECT_ALL 1 +#define REALLOC_ZERO_BYTES_FREES 1 #endif /* LK */ #ifndef WIN32 diff --git a/lib/heap/heap_wrapper.c b/lib/heap/heap_wrapper.c index 6aca578c..1856b8cd 100644 --- a/lib/heap/heap_wrapper.c +++ b/lib/heap/heap_wrapper.c @@ -43,8 +43,18 @@ spin_lock_t delayed_free_lock = SPIN_LOCK_INITIAL_VALUE; /* miniheap implementation */ #include -#define HEAP_ALLOC miniheap_alloc +static inline void *HEAP_MALLOC(size_t s) { return miniheap_alloc(s, 0); } +static inline void *HEAP_REALLOC(void *ptr, size_t s) { return miniheap_realloc(ptr, s); } +static inline void *HEAP_MEMALIGN(size_t boundary, size_t s) { return miniheap_alloc(s, boundary); } #define HEAP_FREE miniheap_free +static inline void *HEAP_CALLOC(size_t n, size_t s) { + size_t realsize = n * s; + + void *ptr = miniheap_alloc(n * s, 0); + if (likely(ptr)) + memset(ptr, 0, realsize); + return ptr; +} static inline void HEAP_INIT(void) { /* start the heap off with some spare memory in the page allocator */ size_t len; @@ -52,21 +62,18 @@ static inline void HEAP_INIT(void) { miniheap_init(ptr, len); } #define HEAP_DUMP miniheap_dump -static inline void HEAP_TRIM(void) {} +#define HEAP_TRIM miniheap_trim /* end miniheap implementation */ #elif WITH_LIB_HEAP_DLMALLOC /* dlmalloc implementation */ #include -static inline void *HEAP_ALLOC(size_t size, unsigned int alignment) { - if (alignment < 8) - return dlmalloc(size); - else - return dlmemalign(alignment, size); -} - -static inline void HEAP_FREE(void *ptr) { dlfree(ptr); } +#define HEAP_MALLOC(s) dlmalloc(s) +#define HEAP_CALLOC(n, s) dlcalloc(n, s) +#define HEAP_MEMALIGN(b, s) dlmemalign(b, s) +#define HEAP_REALLOC(p, s) dlrealloc(p, s) +#define HEAP_FREE(p) dlfree(p) static inline void HEAP_INIT(void) {} static inline void HEAP_DUMP(void) { @@ -96,16 +103,6 @@ static inline void HEAP_TRIM(void) { dlmalloc_trim(0); } #error need to select valid heap implementation or provide wrapper #endif -#if WITH_STATIC_HEAP - -#error "fix static heap post page allocator and novm stuff" - -#if !defined(HEAP_START) || !defined(HEAP_LEN) -#error WITH_STATIC_HEAP set but no HEAP_START or HEAP_LEN defined -#endif - -#endif - static void heap_free_delayed_list(void) { struct list_node list; @@ -123,29 +120,10 @@ static void heap_free_delayed_list(void) while ((node = list_remove_head(&list))) { LTRACEF("freeing node %p\n", node); - heap_free(node); + HEAP_FREE(node); } } -void *heap_alloc(size_t size, unsigned int alignment) -{ - LTRACEF("size %zd, align %u\n", size, alignment); - - // deal with the pending free list - if (unlikely(!list_is_empty(&delayed_free_list))) { - heap_free_delayed_list(); - } - - return HEAP_ALLOC(size, alignment); -} - -void heap_free(void *ptr) -{ - LTRACEF("ptr %p\n", ptr); - - HEAP_FREE(ptr); -} - void heap_init(void) { HEAP_INIT(); @@ -153,9 +131,69 @@ void heap_init(void) void heap_trim(void) { + // deal with the pending free list + if (unlikely(!list_is_empty(&delayed_free_list))) { + heap_free_delayed_list(); + } + HEAP_TRIM(); } +void *malloc(size_t size) +{ + LTRACEF("size %zd\n", size); + + // deal with the pending free list + if (unlikely(!list_is_empty(&delayed_free_list))) { + heap_free_delayed_list(); + } + + return HEAP_MALLOC(size); +} + +void *memalign(size_t boundary, size_t size) +{ + LTRACEF("boundary %zu, size %zd\n", boundary, size); + + // deal with the pending free list + if (unlikely(!list_is_empty(&delayed_free_list))) { + heap_free_delayed_list(); + } + + return HEAP_MEMALIGN(boundary, size); +} + +void *calloc(size_t count, size_t size) +{ + LTRACEF("count %zu, size %zd\n", count, size); + + // deal with the pending free list + if (unlikely(!list_is_empty(&delayed_free_list))) { + heap_free_delayed_list(); + } + + return HEAP_CALLOC(count, size); +} + +void *realloc(void *ptr, size_t size) +{ + LTRACEF("ptr %p, size %zd\n", ptr, size); + + // deal with the pending free list + if (unlikely(!list_is_empty(&delayed_free_list))) { + heap_free_delayed_list(); + } + + return HEAP_REALLOC(ptr, size); +} + +void free(void *ptr) +{ + LTRACEF("ptr %p\n", ptr); + + HEAP_FREE(ptr); +} + /* critical section time delayed free */ void heap_delayed_free(void *ptr) { @@ -261,6 +299,7 @@ usage: printf("\t%s info\n", argv[0].str); printf("\t%s trim\n", argv[0].str); printf("\t%s alloc [alignment]\n", argv[0].str); + printf("\t%s realloc \n", argv[0].str); printf("\t%s free
\n", argv[0].str); return -1; } @@ -272,12 +311,17 @@ usage: } else if (strcmp(argv[1].str, "alloc") == 0) { if (argc < 3) goto notenoughargs; - void *ptr = heap_alloc(argv[2].u, (argc >= 4) ? argv[3].u : 0); - printf("heap_alloc returns %p\n", ptr); + void *ptr = memalign((argc >= 4) ? argv[3].u : 0, argv[2].u); + printf("memalign returns %p\n", ptr); + } else if (strcmp(argv[1].str, "realloc") == 0) { + if (argc < 4) goto notenoughargs; + + void *ptr = realloc(argv[2].p, argv[3].u); + printf("realloc returns %p\n", ptr); } else if (strcmp(argv[1].str, "free") == 0) { if (argc < 2) goto notenoughargs; - heap_free(argv[2].p); + free(argv[2].p); } else { printf("unrecognized command\n"); goto usage; diff --git a/lib/heap/include/lib/heap.h b/lib/heap/include/lib/heap.h index 88799f4a..0a52485e 100644 --- a/lib/heap/include/lib/heap.h +++ b/lib/heap/include/lib/heap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2014 Travis Geiselbrecht + * Copyright (c) 2008-2015 Travis Geiselbrecht * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -28,8 +28,12 @@ __BEGIN_CDECLS; -void *heap_alloc(size_t, unsigned int alignment); -void heap_free(void *); +/* standard heap definitions */ +void *malloc(size_t size) __MALLOC; +void *memalign(size_t boundary, size_t size) __MALLOC; +void *calloc(size_t count, size_t size) __MALLOC; +void *realloc(void *ptr, size_t size) __MALLOC; +void free(void *ptr); void heap_init(void); /* critical section time delayed free */ diff --git a/lib/heap/miniheap/include/lib/miniheap.h b/lib/heap/miniheap/include/lib/miniheap.h index 66bc9e47..b157d3f1 100644 --- a/lib/heap/miniheap/include/lib/miniheap.h +++ b/lib/heap/miniheap/include/lib/miniheap.h @@ -37,9 +37,11 @@ struct miniheap_stats { void miniheap_get_stats(struct miniheap_stats *ptr); void *miniheap_alloc(size_t, unsigned int alignment); +void *miniheap_realloc(void *, size_t); void miniheap_free(void *); void miniheap_init(void *ptr, size_t len); void miniheap_dump(void); +void miniheap_trim(void); __END_CDECLS; diff --git a/lib/heap/miniheap/miniheap.c b/lib/heap/miniheap/miniheap.c index facb318d..e4a7f090 100644 --- a/lib/heap/miniheap/miniheap.c +++ b/lib/heap/miniheap/miniheap.c @@ -301,9 +301,30 @@ retry: return ptr; } +void *miniheap_realloc(void *ptr, size_t size) +{ + /* slow implementation */ + if (!ptr) + return miniheap_alloc(size, 0); + if (size == 0) { + miniheap_free(ptr); + return NULL; + } + + // XXX better implementation + void *p = miniheap_alloc(size, 0); + if (!p) + return NULL; + + memcpy(p, ptr, size); // XXX wrong + miniheap_free(ptr); + + return p; +} + void miniheap_free(void *ptr) { - if (ptr == 0) + if (!ptr) return; LTRACEF("ptr %p\n", ptr); @@ -359,6 +380,11 @@ void miniheap_get_stats(struct miniheap_stats *ptr) mutex_release(&theheap.lock); } +void miniheap_trim(void) +{ + /* currently does nothing */ +} + static ssize_t heap_grow(size_t size) { size = ROUNDUP(size, PAGE_SIZE); diff --git a/lib/libc/new.cpp b/lib/heap/new.cpp similarity index 89% rename from lib/libc/new.cpp rename to lib/heap/new.cpp index e9ebaae1..15c01840 100644 --- a/lib/libc/new.cpp +++ b/lib/heap/new.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Travis Geiselbrecht + * Copyright (c) 2006-2015 Travis Geiselbrecht * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -26,26 +26,26 @@ void *operator new(size_t s) { - return heap_alloc(s, 0); + return malloc(s); } void *operator new[](size_t s) { - return heap_alloc(s, 0); + return malloc(s); } void *operator new(size_t , void *p) { - return p; + return p; } void operator delete(void *p) { - return heap_free(p); + return free(p); } void operator delete[](void *p) { - return heap_free(p); + return free(p); } diff --git a/lib/heap/page_alloc.c b/lib/heap/page_alloc.c index 89ea076b..92d93bea 100644 --- a/lib/heap/page_alloc.c +++ b/lib/heap/page_alloc.c @@ -40,13 +40,19 @@ */ #define LOCAL_TRACE 0 +#if WITH_STATIC_HEAP + +#error "fix static heap post page allocator and novm stuff" + +#if !defined(HEAP_START) || !defined(HEAP_LEN) +#error WITH_STATIC_HEAP set but no HEAP_START or HEAP_LEN defined +#endif + +#endif + void *page_alloc(size_t pages) { #if WITH_KERNEL_VM - /* throw the list away, we can reconstruct it later */ - struct list_node list; - list_initialize(&list); - - void *result = pmm_alloc_kpages(pages, &list); + void *result = pmm_alloc_kpages(pages, NULL); return result; #else void *result = novm_alloc_pages(pages); diff --git a/lib/heap/rules.mk b/lib/heap/rules.mk index fabad3a6..d332d922 100644 --- a/lib/heap/rules.mk +++ b/lib/heap/rules.mk @@ -8,6 +8,11 @@ MODULE_SRCS += \ $(LOCAL_DIR)/heap_wrapper.c \ $(LOCAL_DIR)/page_alloc.c +ifeq ($(WITH_CPP_SUPPORT),true) +MODULE_SRCS += \ + $(LOCAL_DIR)/new.cpp +endif + # pick a heap implementation ifndef LK_HEAP_IMPLEMENTATION LK_HEAP_IMPLEMENTATION=miniheap diff --git a/lib/libc/malloc.c b/lib/libc/malloc.c deleted file mode 100644 index dd1abd37..00000000 --- a/lib/libc/malloc.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2008 Travis Geiselbrecht - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include -#include -#include -#include -#include - -void *malloc(size_t size) -{ - return heap_alloc(size, 0); -} - -void *memalign(size_t boundary, size_t size) -{ - return heap_alloc(size, boundary); -} - -void *calloc(size_t count, size_t size) -{ - void *ptr; - size_t realsize = count * size; - - ptr = heap_alloc(realsize, 0); - if (!ptr) - return NULL; - - memset(ptr, 0, realsize); - return ptr; -} - -void *realloc(void *ptr, size_t size) -{ - if (!ptr) - return malloc(size); - - // XXX better implementation - void *p = malloc(size); - if (!p) - return NULL; - - memcpy(p, ptr, size); // XXX wrong - free(ptr); - - return p; -} - -void free(void *ptr) -{ - return heap_free(ptr); -} - diff --git a/lib/libc/rules.mk b/lib/libc/rules.mk index d2130509..6548dc7c 100644 --- a/lib/libc/rules.mk +++ b/lib/libc/rules.mk @@ -2,6 +2,9 @@ LOCAL_DIR := $(GET_LOCAL_DIR) MODULE := $(LOCAL_DIR) +MODULE_DEPS := \ + lib/heap + MODULE_SRCS += \ $(LOCAL_DIR)/atoi.c \ $(LOCAL_DIR)/bsearch.c \ @@ -15,13 +18,8 @@ MODULE_SRCS += \ $(LOCAL_DIR)/qsort.c \ $(LOCAL_DIR)/eabi.c -ifneq ($(WITH_CUSTOM_MALLOC),true) -MODULE_SRCS += $(LOCAL_DIR)/malloc.c -endif - ifeq ($(WITH_CPP_SUPPORT),true) MODULE_SRCS += \ - $(LOCAL_DIR)/new.cpp \ $(LOCAL_DIR)/atexit.c \ $(LOCAL_DIR)/pure_virtual.cpp endif From 7682dff72fd4aa6dcd4c5d80a4cffbda1f1e3878 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Tue, 20 Oct 2015 16:14:16 -0700 Subject: [PATCH 16/19] [init] bump the earliest init trace level out to TARGET_EARLY On STM32f7xx this is the earliest point that we can printf, and it makes sense to be more conservative than before. This is probably a pretty common spot to be able to finally printf. --- top/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/top/init.c b/top/init.c index 19caed5a..a443544e 100644 --- a/top/init.c +++ b/top/init.c @@ -37,7 +37,7 @@ #define LOCAL_TRACE 0 #define TRACE_INIT (LK_DEBUGLEVEL >= 2) #ifndef EARLIEST_TRACE_LEVEL -#define EARLIEST_TRACE_LEVEL LK_INIT_LEVEL_ARCH_EARLY +#define EARLIEST_TRACE_LEVEL LK_INIT_LEVEL_TARGET_EARLY #endif extern const struct lk_init_struct __lk_init[]; From 8d49a21989bf74122b46193949cdc6c2a2e8ab19 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Tue, 20 Oct 2015 16:18:57 -0700 Subject: [PATCH 17/19] [kernel][novm] refactor the novm code to handle multiple installable arenas Only initialize the first arena, and allow installing more from platform code as more memory banks are brought up. Move novm into a separate module. --- include/kernel/novm.h | 10 +- kernel/{ => novm}/novm.c | 208 +++++++++++++++++++++++---------------- kernel/novm/rules.mk | 8 ++ kernel/rules.mk | 2 +- lib/heap/page_alloc.c | 2 +- 5 files changed, 141 insertions(+), 89 deletions(-) rename kernel/{ => novm}/novm.c (53%) create mode 100644 kernel/novm/rules.mk diff --git a/include/kernel/novm.h b/include/kernel/novm.h index eabc9ba7..41ae73f6 100644 --- a/include/kernel/novm.h +++ b/include/kernel/novm.h @@ -24,18 +24,24 @@ #define __KERNEL_NOVM_H #include +#include #include #define PAGE_ALIGN(x) ALIGN(x, PAGE_SIZE) #define IS_PAGE_ALIGNED(x) IS_ALIGNED(x, PAGE_SIZE) -void *novm_alloc_pages(size_t pages); -void novm_free_pages(void* address, size_t pages); +#define NOVM_ARENA_ANY (-1) +#define NOVM_ARENA_MAIN (0) +#define NOVM_ARENA_SECONDARY (1) +void *novm_alloc_pages(size_t pages, int arena_index); +void novm_free_pages(void* address, size_t pages); status_t novm_alloc_specific_pages(void *address, size_t pages); // You can call this once and it will give you some possibly unaligned memory // that would otherwise go to waste. The memory can't be freed. void *novm_alloc_unaligned(size_t *size_return); +void novm_add_arena(const char *name, uintptr_t arena_start, uintptr_t arena_size); + #endif diff --git a/kernel/novm.c b/kernel/novm/novm.c similarity index 53% rename from kernel/novm.c rename to kernel/novm/novm.c index 121e1405..ff9b478d 100644 --- a/kernel/novm.c +++ b/kernel/novm/novm.c @@ -23,22 +23,33 @@ #include "kernel/novm.h" +#include #include -#include #include #include #include #include -#include +#include + +#define LOCAL_TRACE 0 struct novm_arena { mutex_t lock; + const char *name; size_t pages; char *map; char *base; size_t size; + + // We divide the memory up into pages. If there is memory we can use before + // the first aligned page address, then we record it here and the heap will use + // it. +#define MINIMUM_USEFUL_UNALIGNED_SIZE 64 + void* unaligned_area; + size_t unaligned_size; }; + /* not a static vm, not using the kernel vm */ extern int _end; extern int _end_of_ram; @@ -47,63 +58,67 @@ extern int _end_of_ram; #define MEM_SIZE ((MEMBASE + MEMSIZE) - MEM_START) #define DEFAULT_MAP_SIZE (MEMSIZE >> PAGE_SIZE_SHIFT) -static char allocation_map[DEFAULT_MAP_SIZE]; - -struct novm_arena mem_arena; -struct novm_arena sdram_arena; - -// We divide the memory up into pages. If there is memory we can use before -// the first aligned page address, then we record it here and the heap will use -// it. -#define MINIMUM_USEFUL_UNALIGNED_SIZE 64 -static void* unaligned_area = NULL; -static size_t unaligned_size = 0; +/* a static list of arenas */ +#ifndef NOVM_MAX_ARENAS +#define NOVM_MAX_ARENAS 1 +#endif +struct novm_arena arena[NOVM_MAX_ARENAS]; void *novm_alloc_unaligned(size_t *size_return) { - if (unaligned_area != NULL) { - *size_return = unaligned_size; - void *result = unaligned_area; - unaligned_area = NULL; + /* only do the unaligned thing in the first arena */ + if (arena[0].unaligned_area != NULL) { + *size_return = arena[0].unaligned_size; + void *result = arena[0].unaligned_area; + arena[0].unaligned_area = NULL; + arena[0].unaligned_size = 0; return result; } *size_return = PAGE_SIZE; - return novm_alloc_pages(1); + return novm_alloc_pages(1, NOVM_ARENA_ANY); } static bool in_arena(struct novm_arena *n, void* p) { + if (n->size == 0) + return false; + char *ptr = (char *)p; char *base = n->base; return ptr >= base && ptr < base + n->size; } -void novm_init_helper( - struct novm_arena* n, uintptr_t heap_start, - uintptr_t heap_size, char* default_map, size_t default_map_size) +static void novm_init_helper(struct novm_arena* n, const char *name, + uintptr_t arena_start, uintptr_t arena_size, + char* default_map, size_t default_map_size) { - uintptr_t start = ROUNDUP(heap_start, PAGE_SIZE); - uintptr_t size = ROUNDDOWN(heap_start + heap_size, PAGE_SIZE) - start; + uintptr_t start = ROUNDUP(arena_start, PAGE_SIZE); + uintptr_t size = ROUNDDOWN(arena_start + arena_size, PAGE_SIZE) - start; mutex_init(&n->lock); + size_t map_size = size >> PAGE_SIZE_SHIFT; char* map = default_map; if (map == NULL || default_map_size < map_size) { - map = (char *)heap_start; - // Grab enough map for 16Mbyte of heap each time around the loop. - while (start - heap_start < map_size) { + // allocate the map out of the arena itself + map = (char *)arena_start; + + // Grab enough map for 16Mbyte of arena each time around the loop. + while (start - arena_start < map_size) { start += PAGE_SIZE; size -= PAGE_SIZE; map_size--; } - if ((char *)start - (map + map_size) >= MINIMUM_USEFUL_UNALIGNED_SIZE) { - unaligned_area = map + map_size; - unaligned_size = (char *)start - (map + map_size); + + if ((char *)start - (map + ROUNDUP(map_size, 4)) >= MINIMUM_USEFUL_UNALIGNED_SIZE) { + n->unaligned_area = map + ROUNDUP(map_size, 4); + n->unaligned_size = (char *)start - (map + ROUNDUP(map_size, 4)); } - } else if (start - heap_start >= MINIMUM_USEFUL_UNALIGNED_SIZE) { - unaligned_area = (char *)heap_start; - unaligned_size = start - heap_start; + } else if (start - arena_start >= MINIMUM_USEFUL_UNALIGNED_SIZE) { + n->unaligned_area = (char *)arena_start; + n->unaligned_size = start - arena_start; } + n->name = name; n->map = map; memset(n->map, 0, map_size); n->pages = map_size; @@ -111,28 +126,30 @@ void novm_init_helper( n->size = size; } -void novm_init_preheap(uint level) +void novm_add_arena(const char *name, uintptr_t arena_start, uintptr_t arena_size) { - novm_init_helper(&mem_arena, MEM_START, MEM_SIZE, allocation_map, DEFAULT_MAP_SIZE); - -#ifdef SDRAM_BASE -#define SDRAM_MAP_SIZE (SDRAM_SIZE >> PAGE_SIZE_SHIFT) - static char sdram_map[SDRAM_MAP_SIZE]; - novm_init_helper(&sdram_arena, SDRAM_BASE, SDRAM_SIZE, sdram_map, SDRAM_MAP_SIZE); -#endif - -#if 0 - /* mark pieces of the novm as used */ - novm_alloc_specific_pages(&__data_start, - ROUNDUP((uintptr_t)&_end - (uintptr_t)&__data_start, PAGE_SIZE) / PAGE_SIZE); -#endif + for (uint i = 0; i < NOVM_MAX_ARENAS; i++) { + if (arena[i].pages == 0) { + novm_init_helper(&arena[i], name, arena_start, arena_size, NULL, 0); + return; + } + } + panic("novm_add_arena: too many arenas added, bump NOVM_MAX_ARENAS!\n"); } -LK_INIT_HOOK(novm_preheap, &novm_init_preheap, LK_INIT_LEVEL_HEAP - 1); +static void novm_init(uint level) +{ + static char mem_allocation_map[DEFAULT_MAP_SIZE]; + novm_init_helper(&arena[0], "main", MEM_START, MEM_SIZE, mem_allocation_map, DEFAULT_MAP_SIZE); +} + +LK_INIT_HOOK(novm, &novm_init, LK_INIT_LEVEL_PLATFORM_EARLY - 1); void *novm_alloc_helper(struct novm_arena *n, size_t pages) { - if (pages > n->pages) return NULL; // Unsigned types! + if (pages == 0 || pages > n->pages) + return NULL; + mutex_acquire(&n->lock); for (size_t i = 0; i <= n->pages - pages; i++) { bool found = true; @@ -150,26 +167,42 @@ void *novm_alloc_helper(struct novm_arena *n, size_t pages) } } mutex_release(&n->lock); + return NULL; } -void* novm_alloc_pages(size_t pages) +void* novm_alloc_pages(size_t pages, int arena_index) { - void* result = novm_alloc_helper(&mem_arena, pages); - if (result != NULL) return result; -#ifdef SDRAM_BASE - return novm_alloc_helper(&sdram_arena, pages); -#endif + LTRACEF("pages %zu\n", pages); + + if (arena_index < 0) { + /* allocate from any arena */ + for (uint i = 0; i < NOVM_MAX_ARENAS; i++) { + void *result = novm_alloc_helper(&arena[i], pages); + if (result) + return result; + } + } else if (arena_index < NOVM_MAX_ARENAS) { + /* allocate from a specific index */ + return novm_alloc_helper(&arena[arena_index], pages); + } + return NULL; } void novm_free_pages(void* address, size_t pages) { -#ifdef SDRAM_BASE - struct novm_arena *n = in_arena(&mem_arena, address) ? &mem_arena : &sdram_arena; -#else - struct novm_arena *n = &mem_arena; -#endif + LTRACEF("address %p, pages %zu\n", address, pages); + + struct novm_arena *n = NULL; + for (uint i = 0; i < NOVM_MAX_ARENAS; i++) { + if (in_arena(&arena[i], address)) { + n = &arena[i]; + break; + } + } + if (!n) + return; DEBUG_ASSERT(in_arena(n, address)); @@ -183,13 +216,15 @@ void novm_free_pages(void* address, size_t pages) status_t novm_alloc_specific_pages(void *address, size_t pages) { - TRACEF("address %p, pages %zu\n", address, pages); + LTRACEF("address %p, pages %zu\n", address, pages); - struct novm_arena *n = in_arena(&mem_arena, address) ? &mem_arena : NULL; -#ifdef SDRAM_BASE - if (!n) - n = in_arena(&sdram_arena, address) ? &sdram_arena : NULL; -#endif + struct novm_arena *n = NULL; + for (uint i = 0; i < NOVM_MAX_ARENAS; i++) { + if (in_arena(&arena[i], address)) { + n = &arena[i]; + break; + } + } if (!n) return ERR_NOT_FOUND; @@ -232,23 +267,24 @@ notenoughargs: usage: printf("usage:\n"); printf("\t%s info\n", argv[0].str); - printf("\t%s alloc \n", argv[0].str); - printf("\t%s free address \n", argv[0].str); + printf("\t%s alloc [arena #]\n", argv[0].str); + printf("\t%s free
[numberofpages]\n", argv[0].str); return -1; } if (strcmp(argv[1].str, "info") == 0) { novm_dump(); - } else if (strcmp(argv[1].str, "alloc") == 0) { - if (argc < 3) goto notenoughargs; + } else if (strcmp(argv[1].str, "alloc") == 0) { + if (argc < 3) goto notenoughargs; - void *ptr = novm_alloc_pages(argv[2].u); - printf("novm_alloc_pages returns %p\n", ptr); - } else if (strcmp(argv[1].str, "free") == 0) { - if (argc < 3) goto notenoughargs; - size_t pages = (argc >= 4) ? argv[3].u : 1; - novm_free_pages(argv[2].p, pages); - printf("novm_free_pages: %zd pages at %p\n", pages, argv[2].p); + int arena_index = (argc >= 4) ? argv[3].i : NOVM_ARENA_ANY; + void *ptr = novm_alloc_pages(argv[2].u, arena_index); + printf("novm_alloc_pages returns %p\n", ptr); + } else if (strcmp(argv[1].str, "free") == 0) { + if (argc < 3) goto notenoughargs; + size_t pages = (argc >= 4) ? argv[3].u : 1; + novm_free_pages(argv[2].p, pages); + printf("novm_free_pages: %zd pages at %p\n", pages, argv[2].p); } else { printf("unrecognized command\n"); goto usage; @@ -257,11 +293,16 @@ usage: return 0; } -static void novm_dump_area(struct novm_arena *n) +static void novm_dump_arena(struct novm_arena *n) { + if (n->pages == 0) { + return; + } + mutex_acquire(&n->lock); - printf(" %d pages, each %zdk (%zdk in all)\n", n->pages, PAGE_SIZE >> 10, (PAGE_SIZE * n->pages) >> 10); - printf(" %p-%p\n", (void *)n->base, (char *)n->base + n->size); + printf("name '%s', %d pages, each %zdk (%zdk in all)\n", n->name, n->pages, PAGE_SIZE >> 10, (PAGE_SIZE * n->pages) >> 10); + printf(" range: %p-%p\n", (void *)n->base, (char *)n->base + n->size); + printf(" unaligned range: %p-%p\n", n->unaligned_area, n->unaligned_area + n->unaligned_size); unsigned i; size_t in_use = 0; for (i = 0; i < n->pages; i++) if (n->map[i] != 0) in_use++; @@ -281,12 +322,9 @@ static void novm_dump_area(struct novm_arena *n) static void novm_dump(void) { - printf("main memory arena:\n"); - novm_dump_area(&mem_arena); -#ifdef SDRAM_BASE - printf("SDRAM arena:\n"); - novm_dump_area(&sdram_arena); -#endif + for (uint i = 0; i < NOVM_MAX_ARENAS; i++) { + novm_dump_arena(&arena[i]); + } } #endif diff --git a/kernel/novm/rules.mk b/kernel/novm/rules.mk new file mode 100644 index 00000000..73e4db8f --- /dev/null +++ b/kernel/novm/rules.mk @@ -0,0 +1,8 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/novm.c + +include make/module.mk diff --git a/kernel/rules.mk b/kernel/rules.mk index 578d10b8..95f5f369 100644 --- a/kernel/rules.mk +++ b/kernel/rules.mk @@ -20,7 +20,7 @@ MODULE_SRCS := \ ifeq ($(WITH_KERNEL_VM),1) MODULE_DEPS += kernel/vm else -MODULE_SRCS += $(LOCAL_DIR)/novm.c +MODULE_DEPS += kernel/novm endif include make/module.mk diff --git a/lib/heap/page_alloc.c b/lib/heap/page_alloc.c index 92d93bea..15924b18 100644 --- a/lib/heap/page_alloc.c +++ b/lib/heap/page_alloc.c @@ -55,7 +55,7 @@ void *page_alloc(size_t pages) { void *result = pmm_alloc_kpages(pages, NULL); return result; #else - void *result = novm_alloc_pages(pages); + void *result = novm_alloc_pages(pages, NOVM_ARENA_ANY); return result; #endif } From 9ef65bb98bbcc8c46501577fa9aae8c51180458e Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Tue, 20 Oct 2015 16:20:07 -0700 Subject: [PATCH 18/19] [platform][stm32f7xx] add the sdram memory as a novm arena --- platform/stm32f7xx/init.c | 4 ++++ platform/stm32f7xx/rules.mk | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/platform/stm32f7xx/init.c b/platform/stm32f7xx/init.c index 079eabb1..9e05cf6c 100644 --- a/platform/stm32f7xx/init.c +++ b/platform/stm32f7xx/init.c @@ -28,6 +28,7 @@ #include #include #include +#include #include uint32_t SystemCoreClock = HSI_VALUE; @@ -291,6 +292,9 @@ void platform_early_init(void) #if defined(ENABLE_SDRAM) /* initialize SDRAM */ stm32_sdram_init((sdram_config_t *)&target_sdram_config); + + /* add a novm arena for it */ + novm_add_arena("sdram", SDRAM_BASE, SDRAM_SIZE); #endif mpu_init(); diff --git a/platform/stm32f7xx/rules.mk b/platform/stm32f7xx/rules.mk index d63eff1a..73151323 100644 --- a/platform/stm32f7xx/rules.mk +++ b/platform/stm32f7xx/rules.mk @@ -26,7 +26,8 @@ endif LK_HEAP_IMPLEMENTATION ?= miniheap GLOBAL_DEFINES += \ - PLATFORM_SUPPORTS_PANIC_SHELL=1 + PLATFORM_SUPPORTS_PANIC_SHELL=1 \ + NOVM_MAX_ARENAS=2 GLOBAL_INCLUDES += \ $(LOCAL_DIR)/include From 8fa97e8552f538aef07dcdb7decdbb671298bd69 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Tue, 20 Oct 2015 16:20:33 -0700 Subject: [PATCH 19/19] [target][[stm32f746g-disco] allocate the LCD framebuffer out of the novm arena --- target/stm32f746g-disco/init.c | 9 +++++---- target/stm32f746g-disco/lcd.c | 11 +++++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/target/stm32f746g-disco/init.c b/target/stm32f746g-disco/init.c index 270cbc9b..cc7f54d0 100644 --- a/target/stm32f746g-disco/init.c +++ b/target/stm32f746g-disco/init.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -34,13 +35,13 @@ #include #include #include -#include +#include #if WITH_LIB_MINIP #include #endif -extern uint8_t BSP_LCD_Init(uint32_t fb_address); +extern uint8_t BSP_LCD_Init(void); const sdram_config_t target_sdram_config = { .bus_width = SDRAM_BUS_WIDTH_16, @@ -61,8 +62,8 @@ void target_early_init(void) /* now that the uart gpios are configured, enable the debug uart */ stm32_debug_early_init(); - /* The lcd framebuffer starts at the base of SDRAM */ - BSP_LCD_Init(SDRAM_BASE); + /* start the lcd */ + BSP_LCD_Init(); } static uint8_t* gen_mac_address(void) diff --git a/target/stm32f746g-disco/lcd.c b/target/stm32f746g-disco/lcd.c index 3eadeefd..25b26b87 100644 --- a/target/stm32f746g-disco/lcd.c +++ b/target/stm32f746g-disco/lcd.c @@ -57,6 +57,7 @@ #include #include #include +#include #include /* @@ -345,7 +346,7 @@ static void BSP_LCD_ClockConfig(LTDC_HandleTypeDef *hltdc, void *Params) * @brief Initializes the LCD. * @retval LCD state */ -uint8_t BSP_LCD_Init(uint32_t fb_address) +uint8_t BSP_LCD_Init(void) { /* Timing Configuration */ ltdc_handle.Init.HorizontalSync = (RK043FN48H_HSYNC - 1); @@ -382,7 +383,13 @@ uint8_t BSP_LCD_Init(uint32_t fb_address) HAL_LTDC_Init(<dc_handle); - BSP_LCD_LayerDefaultInit(0, fb_address); + /* allocate the framebuffer */ + size_t fb_size_pages = PAGE_ALIGN(RK043FN48H_WIDTH * RK043FN48H_HEIGHT * 4) / PAGE_SIZE; + void *fb_address = novm_alloc_pages(fb_size_pages, NOVM_ARENA_SECONDARY); + if (!fb_address) + panic("failed to allocate framebuffer for LCD\n"); + + BSP_LCD_LayerDefaultInit(0, (uint32_t)fb_address); BSP_LCD_SelectLayer(0); /* clear framebuffer */