[lib][heap] have novm initialize itself, rename novm 'heap' to 'arena' to be less confusing

This commit is contained in:
Travis Geiselbrecht
2015-10-15 18:15:45 -07:00
parent 7c09e82033
commit fab92f3179
7 changed files with 100 additions and 122 deletions

View File

@@ -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);

View File

@@ -25,55 +25,32 @@
#include <assert.h>
#include <kernel/mutex.h>
#include <trace.h>
#include <stdlib.h>
#include <string.h>
#include <lk/init.h>
#include <err.h>
#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: */

View File

@@ -33,7 +33,7 @@
#include <lib/console.h>
#include <lib/page_alloc.h>
#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 <kernel/vm.h>
/* 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)

View File

@@ -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));
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);