Add a simple malloc() implementation for pre-relocation

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.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2014-07-10 22:23:28 -06:00
parent 4d94dfa059
commit d59476b644
6 changed files with 72 additions and 0 deletions

13
README
View file

@ -3736,6 +3736,19 @@ Configuration Settings:
- CONFIG_SYS_MALLOC_LEN: - CONFIG_SYS_MALLOC_LEN:
Size of DRAM reserved for malloc() use. Size of DRAM reserved for malloc() use.
- CONFIG_SYS_MALLOC_F_LEN
Size of the malloc() pool for use before relocation. If
this is defined, then a very simple malloc() implementation
will become available before relocation. The address is just
below the global data, and the stack is moved down to make
space.
This feature allocates regions with increasing addresses
within the region. calloc() is supported, but realloc()
is not available. free() is supported but does nothing.
The memory will be freed (or in fact just forgotton) when
U-Boot relocates itself.
- CONFIG_SYS_BOOTM_LEN: - CONFIG_SYS_BOOTM_LEN:
Normally compressed uImages are limited to an Normally compressed uImages are limited to an
uncompressed size of 8 MBytes. If this is not enough, uncompressed size of 8 MBytes. If this is not enough,

View file

@ -767,6 +767,17 @@ static int mark_bootstage(void)
return 0; return 0;
} }
static int initf_malloc(void)
{
#ifdef CONFIG_SYS_MALLOC_F_LEN
assert(gd->malloc_base); /* Set up by crt0.S */
gd->malloc_limit = gd->malloc_base + CONFIG_SYS_MALLOC_F_LEN;
gd->malloc_ptr = 0;
#endif
return 0;
}
static init_fnc_t init_sequence_f[] = { static init_fnc_t init_sequence_f[] = {
#ifdef CONFIG_SANDBOX #ifdef CONFIG_SANDBOX
setup_ram_buf, setup_ram_buf,
@ -824,6 +835,7 @@ static init_fnc_t init_sequence_f[] = {
sdram_adjust_866, sdram_adjust_866,
init_timebase, init_timebase,
#endif #endif
initf_malloc,
init_baud_rate, /* initialze baudrate settings */ init_baud_rate, /* initialze baudrate settings */
serial_init, /* serial communications setup */ serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */ console_init_f, /* stage 1 init of console */

View file

@ -259,6 +259,10 @@ static int initr_malloc(void)
{ {
ulong malloc_start; ulong malloc_start;
#ifdef CONFIG_SYS_MALLOC_F_LEN
debug("Pre-reloc malloc() used %#lx bytes (%ld KB)\n", gd->malloc_ptr,
gd->malloc_ptr / 1024);
#endif
/* The malloc area is immediately below the monitor copy in DRAM */ /* The malloc area is immediately below the monitor copy in DRAM */
malloc_start = gd->relocaddr - TOTAL_MALLOC_LEN; malloc_start = gd->relocaddr - TOTAL_MALLOC_LEN;
mem_malloc_init((ulong)map_sysmem(malloc_start, TOTAL_MALLOC_LEN), mem_malloc_init((ulong)map_sysmem(malloc_start, TOTAL_MALLOC_LEN),

View file

@ -930,6 +930,8 @@ struct mallinfo mALLINFo();
#endif /* 0 */ /* Moved to malloc.h */ #endif /* 0 */ /* Moved to malloc.h */
#include <malloc.h> #include <malloc.h>
#include <asm/io.h>
#ifdef DEBUG #ifdef DEBUG
#if __STD_C #if __STD_C
static void malloc_update_mallinfo (void); static void malloc_update_mallinfo (void);
@ -2174,6 +2176,20 @@ Void_t* mALLOc(bytes) size_t bytes;
INTERNAL_SIZE_T nb; INTERNAL_SIZE_T nb;
#ifdef CONFIG_SYS_MALLOC_F_LEN
if (!(gd->flags & GD_FLG_RELOC)) {
ulong new_ptr;
void *ptr;
new_ptr = gd->malloc_ptr + bytes;
if (new_ptr > gd->malloc_limit)
panic("Out of pre-reloc memory");
ptr = map_sysmem(gd->malloc_base + gd->malloc_ptr, bytes);
gd->malloc_ptr = ALIGN(new_ptr, sizeof(new_ptr));
return ptr;
}
#endif
/* check if mem_malloc_init() was run */ /* check if mem_malloc_init() was run */
if ((mem_malloc_start == 0) && (mem_malloc_end == 0)) { if ((mem_malloc_start == 0) && (mem_malloc_end == 0)) {
/* not initialized yet */ /* not initialized yet */
@ -2437,6 +2453,12 @@ void fREe(mem) Void_t* mem;
mchunkptr fwd; /* misc temp for linking */ mchunkptr fwd; /* misc temp for linking */
int islr; /* track whether merging with last_remainder */ int islr; /* track whether merging with last_remainder */
#ifdef CONFIG_SYS_MALLOC_F_LEN
/* free() is a no-op - all the memory will be freed on relocation */
if (!(gd->flags & GD_FLG_RELOC))
return;
#endif
if (mem == NULL) /* free(0) has no effect */ if (mem == NULL) /* free(0) has no effect */
return; return;
@ -2588,6 +2610,13 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
/* realloc of null is supposed to be same as malloc */ /* realloc of null is supposed to be same as malloc */
if (oldmem == NULL) return mALLOc(bytes); if (oldmem == NULL) return mALLOc(bytes);
#ifdef CONFIG_SYS_MALLOC_F_LEN
if (!(gd->flags & GD_FLG_RELOC)) {
/* This is harder to support and should not be needed */
panic("pre-reloc realloc() is not supported");
}
#endif
newp = oldp = mem2chunk(oldmem); newp = oldp = mem2chunk(oldmem);
newsize = oldsize = chunksize(oldp); newsize = oldsize = chunksize(oldp);
@ -2933,6 +2962,12 @@ Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
return NULL; return NULL;
else else
{ {
#ifdef CONFIG_SYS_MALLOC_F_LEN
if (!(gd->flags & GD_FLG_RELOC)) {
MALLOC_ZERO(mem, sz);
return mem;
}
#endif
p = mem2chunk(mem); p = mem2chunk(mem);
/* Two optional cases in which clearing not necessary */ /* Two optional cases in which clearing not necessary */

View file

@ -85,6 +85,11 @@ typedef struct global_data {
#endif #endif
unsigned long timebase_h; unsigned long timebase_h;
unsigned long timebase_l; unsigned long timebase_l;
#ifdef CONFIG_SYS_MALLOC_F_LEN
unsigned long malloc_base; /* base address of early malloc() */
unsigned long malloc_limit; /* limit address */
unsigned long malloc_ptr; /* current address */
#endif
struct arch_global_data arch; /* architecture-specific data */ struct arch_global_data arch; /* architecture-specific data */
} gd_t; } gd_t;
#endif #endif

View file

@ -28,6 +28,9 @@ int main(void)
DEFINE(GD_SIZE, sizeof(struct global_data)); DEFINE(GD_SIZE, sizeof(struct global_data));
DEFINE(GD_BD, offsetof(struct global_data, bd)); DEFINE(GD_BD, offsetof(struct global_data, bd));
#ifdef CONFIG_SYS_MALLOC_F_LEN
DEFINE(GD_MALLOC_BASE, offsetof(struct global_data, malloc_base));
#endif
#if defined(CONFIG_ARM) #if defined(CONFIG_ARM)