diff --git a/README b/README
index 3c93d05..23ec935 100644
--- a/README
+++ b/README
@@ -3703,6 +3703,22 @@ Configuration Settings:
 - CONFIG_SYS_MALLOC_LEN:
 		Size of DRAM reserved for malloc() use.
 
+- CONFIG_SYS_MALLOC_F_BASE
+- CONFIG_SYS_MALLOC_F_LEN
+		Address and size of the malloc() pool for use before
+		relocation. If these are defined, then a very simple
+		malloc() implementation will become available before
+		relocation. It 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 free (or in fact just forgotton) when
+		U-Boot relocates itself.
+
+		You should select an address which is available before
+		relocation. This might be on-chip SRAM. Be careful to avoid
+		collision between this region and the stack, which
+		typically grows downwards.
+
 - 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 4ea4cb2..cc040c7 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -776,6 +776,17 @@ static int mark_bootstage(void)
 	return 0;
 }
 
+static int initf_malloc(void)
+{
+#ifdef CONFIG_SYS_MALLOC_F_BASE
+	gd->malloc_base = CONFIG_SYS_MALLOC_F_BASE;
+	gd->malloc_limit = CONFIG_SYS_MALLOC_F_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,
@@ -833,6 +844,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 d2a59ee..e16f3ad 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_BASE
+	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 d1cd561..16d85c2 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_BASE
+	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_BASE
+	/* 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_BASE
+	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_BASE
+	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 e98b661..1070a75 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_BASE
+	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
