]> git.sur5r.net Git - u-boot/commitdiff
Add a simple malloc() implementation for pre-relocation
authorSimon Glass <sjg@chromium.org>
Fri, 11 Jul 2014 04:23:28 +0000 (22:23 -0600)
committerSimon Glass <sjg@chromium.org>
Wed, 23 Jul 2014 13:05:40 +0000 (14:05 +0100)
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>
README
common/board_f.c
common/board_r.c
common/dlmalloc.c
include/asm-generic/global_data.h
lib/asm-offsets.c

diff --git a/README b/README
index 4ac73996983add08d11a15875fa203a5f8fd3393..11e9d31285377121394f1239fa7b9931016c3dfe 100644 (file)
--- a/README
+++ b/README
@@ -3736,6 +3736,19 @@ Configuration Settings:
 - CONFIG_SYS_MALLOC_LEN:
                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:
                Normally compressed uImages are limited to an
                uncompressed size of 8 MBytes. If this is not enough,
index bdab38e89de12967d8e5086880f8c1c51375a8c4..6b2e277bd79a7d9065bd6f7743874f0d742d7bf4 100644 (file)
@@ -767,6 +767,17 @@ static int mark_bootstage(void)
        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[] = {
 #ifdef CONFIG_SANDBOX
        setup_ram_buf,
@@ -824,6 +835,7 @@ static init_fnc_t init_sequence_f[] = {
        sdram_adjust_866,
        init_timebase,
 #endif
+       initf_malloc,
        init_baud_rate,         /* initialze baudrate settings */
        serial_init,            /* serial communications setup */
        console_init_f,         /* stage 1 init of console */
index 4479acbb727c612d6438f604d447b118a17df364..2298ba5761dba9a39ed5bc8ee2d5528a0bdc0ead 100644 (file)
@@ -259,6 +259,10 @@ static int initr_malloc(void)
 {
        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 */
        malloc_start = gd->relocaddr - TOTAL_MALLOC_LEN;
        mem_malloc_init((ulong)map_sysmem(malloc_start, TOTAL_MALLOC_LEN),
index d1cd561cb85544009cf71536137e051393dce0e5..26ba8fd622c6c4b9ae1a42bac441b0890b7e2474 100644 (file)
@@ -930,6 +930,8 @@ struct mallinfo mALLINFo();
 #endif /* 0 */                 /* Moved to malloc.h */
 
 #include <malloc.h>
+#include <asm/io.h>
+
 #ifdef DEBUG
 #if __STD_C
 static void malloc_update_mallinfo (void);
@@ -2174,6 +2176,20 @@ Void_t* mALLOc(bytes) size_t bytes;
 
   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 */
   if ((mem_malloc_start == 0) && (mem_malloc_end == 0)) {
     /* not initialized yet */
@@ -2437,6 +2453,12 @@ void fREe(mem) Void_t* mem;
   mchunkptr fwd;       /* misc temp for linking */
   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 */
     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 */
   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);
   newsize = oldsize = chunksize(oldp);
 
@@ -2933,6 +2962,12 @@ Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
     return NULL;
   else
   {
+#ifdef CONFIG_SYS_MALLOC_F_LEN
+       if (!(gd->flags & GD_FLG_RELOC)) {
+               MALLOC_ZERO(mem, sz);
+               return mem;
+       }
+#endif
     p = mem2chunk(mem);
 
     /* Two optional cases in which clearing not necessary */
index 2850ed8a69f486000a6fb435928757739b4d2033..f6a2a2068a49c38575d0fc3422e37526525d261d 100644 (file)
@@ -85,6 +85,11 @@ typedef struct global_data {
 #endif
        unsigned long timebase_h;
        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 */
 } gd_t;
 #endif
index 6ea7b03ad43d7a1629bba33cad784f9e7289feed..129bc3e2aff7eb18d80a4a10afe9cb5688f33384 100644 (file)
@@ -28,6 +28,9 @@ int main(void)
        DEFINE(GD_SIZE, sizeof(struct global_data));
 
        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)