From: Simon Glass <simon.glass@canonical.com> If we are to have driver model before relocation we need to support some way of calling memory allocation routines. The standard malloc() is pretty complicated: 1. It uses some BSS memory for its state, and BSS is not available before relocation 2. It supports algorithms for reducing memory fragmentation and improving performace of free(). Before relocation we could happily just not support free(). 3. It includes about 4KB of code (Thumb 2) and 1KB of data. However since this has been loaded anyway this is not really a problem. The simplest way to support pre-relocation malloc() is to reserve an area of memory and allocate it in increasing blocks as needed. This implementation does this. To enable it, you need to define the size of the malloc() pool as described in the README. It will be located above the pre-relocation stack on supported architectures. Note that this implementation is only useful on machines which have some memory available before dram_init() is called - this includes those that do no DRAM init (like tegra) and those that do it in SPL (quite a few boards). Enabling driver model preior to relocation for the rest of the boards is left for a later exercise. Changes from original commit: - Squash in commit 'malloc: Redirect to malloc_simple before relocation' - Modify dlmalloc/dlfree/dlrealloc/dlmemalign (new 2.8.6 names) - Add #ifdef __UBOOT__ wrapper around the checks - Redirect to malloc_simple()/memalign_simple() instead of embedding code - Add declarations for malloc_simple() and memalign_simple() to malloc.h - Move global_data.h include and DECLARE_GLOBAL_DATA_PTR to top - Add proper documentation for the two new functions Signed-off-by: Simon Glass <sjg@chromium.org> Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> (cherry picked from commit d59476b6446799c21e64147d86483140154c1886) --- common/dlmalloc.c | 38 ++++++++++++++++++++++++++++++++++++++ include/malloc.h | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/common/dlmalloc.c b/common/dlmalloc.c index baa9b500e10..f0b6db20f5c 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -565,6 +565,7 @@ MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP #include <log.h> #include <malloc.h> #include <mapmem.h> +#include <vsprintf.h> #include <asm/global_data.h> DECLARE_GLOBAL_DATA_PTR; @@ -4583,6 +4584,11 @@ static void* tmalloc_small(mstate m, size_t nb) { void* dlmalloc(size_t bytes) { #ifdef __UBOOT__ +#if CONFIG_IS_ENABLED(SYS_MALLOC_F) + if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT)) + return malloc_simple(bytes); +#endif + /* Return NULL if not initialized yet */ if (!mem_malloc_start && !mem_malloc_end) return NULL; @@ -4725,6 +4731,13 @@ void* dlmalloc(size_t bytes) { /* ---------------------------- free --------------------------- */ void dlfree(void* mem) { +#ifdef __UBOOT__ +#if CONFIG_IS_ENABLED(SYS_MALLOC_F) + /* free() is a no-op - all the memory will be freed on relocation */ + if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT)) + return; +#endif +#endif /* Consolidate freed chunks with preceeding or succeeding bordering free chunks, if they exist, and then place in a bin. Intermixed @@ -5228,6 +5241,14 @@ static void internal_inspect_all(mstate m, #if !ONLY_MSPACES void* dlrealloc(void* oldmem, size_t bytes) { +#ifdef __UBOOT__ +#if CONFIG_IS_ENABLED(SYS_MALLOC_F) + if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT)) { + /* This is harder to support and should not be needed */ + panic("pre-reloc realloc() is not supported"); + } +#endif +#endif void* mem = 0; if (oldmem == 0) { mem = dlmalloc(bytes); @@ -5304,6 +5325,12 @@ void* dlrealloc_in_place(void* oldmem, size_t bytes) { } void* dlmemalign(size_t alignment, size_t bytes) { +#ifdef __UBOOT__ +#if CONFIG_IS_ENABLED(SYS_MALLOC_F) + if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT)) + return memalign_simple(alignment, bytes); +#endif +#endif if (alignment <= MALLOC_ALIGNMENT) { return dlmalloc(bytes); } @@ -6366,4 +6393,15 @@ void mem_malloc_init(ulong start, ulong size) memset((void *)mem_malloc_start, '\0', size); #endif } + +int initf_malloc(void) +{ +#if CONFIG_IS_ENABLED(SYS_MALLOC_F) + assert(gd->malloc_base); /* Set up by crt0.S */ + gd->malloc_limit = CONFIG_VAL(SYS_MALLOC_F_LEN); + gd->malloc_ptr = 0; +#endif + + return 0; +} #endif /* __UBOOT__ */ diff --git a/include/malloc.h b/include/malloc.h index e0a5b732203..d5cccc96e50 100644 --- a/include/malloc.h +++ b/include/malloc.h @@ -650,6 +650,42 @@ void mem_malloc_init(ulong start, ulong size); * Return: Previous break value on success, MORECORE_FAILURE on error */ void *sbrk(ptrdiff_t increment); + +/** + * malloc_simple() - Allocate memory from the simple malloc pool + * + * Allocates memory from a simple pool used before full malloc() is available. + * This is used before relocation when BSS is not yet available for dlmalloc's + * state. Memory allocated with this function cannot be freed. + * + * @size: Number of bytes to allocate + * Return: Pointer to allocated memory, or NULL if pool is exhausted + */ +void *malloc_simple(size_t size); + +/** + * memalign_simple() - Allocate aligned memory from the simple malloc pool + * + * Allocates aligned memory from a simple pool used before full malloc() is + * available. This is used before relocation when BSS is not yet available + * for dlmalloc's state. Memory allocated with this function cannot be freed. + * + * @alignment: Required alignment (must be a power of 2) + * @bytes: Number of bytes to allocate + * Return: Pointer to allocated memory, or NULL if pool is exhausted + */ +void *memalign_simple(size_t alignment, size_t bytes); + +/** + * initf_malloc() - Set up the early malloc() pool + * + * Sets up the simple malloc() pool which is used before full malloc() + * is available after relocation. + * + * Return: 0 (always succeeds) + */ +int initf_malloc(void); + #endif /* __UBOOT__ */ #ifdef __cplusplus -- 2.43.0