diff --git a/README b/README
index 4ac73996983add08d11a15875fa203a5f8fd3393..11e9d31285377121394f1239fa7b9931016c3dfe 100644
--- 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,
diff --git a/common/board_f.c b/common/board_f.c
index bdab38e89de12967d8e5086880f8c1c51375a8c4..6b2e277bd79a7d9065bd6f7743874f0d742d7bf4 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -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 */
diff --git a/common/board_r.c b/common/board_r.c
index 4479acbb727c612d6438f604d447b118a17df364..2298ba5761dba9a39ed5bc8ee2d5528a0bdc0ead 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -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),
diff --git a/common/dlmalloc.c b/common/dlmalloc.c
index d1cd561cb85544009cf71536137e051393dce0e5..26ba8fd622c6c4b9ae1a42bac441b0890b7e2474 100644
--- a/common/dlmalloc.c
+++ b/common/dlmalloc.c
@@ -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 */
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index 2850ed8a69f486000a6fb435928757739b4d2033..f6a2a2068a49c38575d0fc3422e37526525d261d 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -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
diff --git a/lib/asm-offsets.c b/lib/asm-offsets.c
index 6ea7b03ad43d7a1629bba33cad784f9e7289feed..129bc3e2aff7eb18d80a4a10afe9cb5688f33384 100644
--- a/lib/asm-offsets.c
+++ b/lib/asm-offsets.c
@@ -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)