[lib][heap] have novm initialize itself, rename novm 'heap' to 'arena' to be less confusing
This commit is contained in:
@@ -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);
|
||||
|
||||
142
kernel/novm.c
142
kernel/novm.c
@@ -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: */
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user