diff mbox

[U-Boot,v10] Add dmmalloc module for DM.

Message ID 1351466451-8829-1-git-send-email-tmshlvck@gmail.com
State Deferred
Delegated to: Tom Rini
Headers show

Commit Message

Tomas Hlavacek Oct. 28, 2012, 11:20 p.m. UTC
Add pointer to the first early heap into GD structure.
Implement simple early_malloc and early_free functions.
Prepare for additional heaps and automated heap initialization.
Add temporary early_malloc_active function (to be replaced in future by
more coarse DM init flags).
Add DM specific malloc calls - dmmalloc, dmfree, dmrealloc and dmcalloc.

Signed-off-by: Tomas Hlavacek <tmshlvck@gmail.com>
---
Changes in v10:
   - Change GD type to struct early_heap_header *.
   - Move dmmalloc, dmfree, ... function from .h to dmmalloc.c .
   - Rework early_malloc_active() to use new GD_FLG_HEAP_INIT flag.
   - Add early_heap_active() and GD_FLG_EARLY_HEAP_DONE flag.
   - Rework dmrealloc() and dmfree() to use new flags and support relocation.
   - Rename early_heap_dump() to early_malloc_heap_dump().
   - Add early_malloc_dump.
   - Drop conditional undef CONFIG_SYS_EARLY_MALLOC in dmmalloc.h.
   - Moved struct early_block_header and macros to dmmalloc.c.

Changes in v9:
   - Rework early_malloc to keep track of allocated block size.
   - Add early_free and dmfree functions.
   - Rework dmrealloc.

Changes in v8:
   - Add dmcalloc() implementation.
   - Add comments to function prototypes in dmmalloc.h.

Changes in v7:
   - Rework check of first heap in early_brk().

Changes in v6:
   - Move dmmalloc() and all dm* functions to dmmalloc.h.
   - Fix bool expression in early_malloc_active().

 arch/arm/include/asm/global_data.h        |    8 +
 arch/avr32/include/asm/global_data.h      |    7 +
 arch/blackfin/include/asm/global_data.h   |    6 +
 arch/m68k/include/asm/global_data.h       |    8 +
 arch/microblaze/include/asm/global_data.h |    8 +
 arch/mips/include/asm/global_data.h       |    6 +
 arch/nds32/include/asm/global_data.h      |    8 +
 arch/nios2/include/asm/global_data.h      |    7 +
 arch/openrisc/include/asm/global_data.h   |    8 +
 arch/powerpc/include/asm/global_data.h    |    6 +
 arch/sandbox/include/asm/global_data.h    |    7 +
 arch/sh/include/asm/global_data.h         |    7 +
 arch/sparc/include/asm/global_data.h      |    6 +
 arch/x86/include/asm/global_data.h        |    8 +
 common/Makefile                           |    1 +
 common/dmmalloc.c                         |  297 +++++++++++++++++++++++++++++
 include/asm-generic/global_data_flags.h   |    6 +-
 include/dmmalloc.h                        |  132 +++++++++++++
 18 files changed, 534 insertions(+), 2 deletions(-)
 create mode 100644 common/dmmalloc.c
 create mode 100644 include/dmmalloc.h

Comments

Mateusz Zalega Nov. 5, 2013, 3:26 p.m. UTC | #1
On 10/29/12 00:20, Tomas Hlavacek wrote:
> Add pointer to the first early heap into GD structure.
> Implement simple early_malloc and early_free functions.
> Prepare for additional heaps and automated heap initialization.
> Add temporary early_malloc_active function (to be replaced in future by
> more coarse DM init flags).
> Add DM specific malloc calls - dmmalloc, dmfree, dmrealloc and dmcalloc.
> 
> Signed-off-by: Tomas Hlavacek <tmshlvck@gmail.com>
> ---
> Changes in v10:
>    - Change GD type to struct early_heap_header *.
>    - Move dmmalloc, dmfree, ... function from .h to dmmalloc.c .
>    - Rework early_malloc_active() to use new GD_FLG_HEAP_INIT flag.
>    - Add early_heap_active() and GD_FLG_EARLY_HEAP_DONE flag.
>    - Rework dmrealloc() and dmfree() to use new flags and support relocation.
>    - Rename early_heap_dump() to early_malloc_heap_dump().
>    - Add early_malloc_dump.
>    - Drop conditional undef CONFIG_SYS_EARLY_MALLOC in dmmalloc.h.
>    - Moved struct early_block_header and macros to dmmalloc.c.
> 
> Changes in v9:
>    - Rework early_malloc to keep track of allocated block size.
>    - Add early_free and dmfree functions.
>    - Rework dmrealloc.
> 
> Changes in v8:
>    - Add dmcalloc() implementation.
>    - Add comments to function prototypes in dmmalloc.h.
> 
> Changes in v7:
>    - Rework check of first heap in early_brk().
> 
> Changes in v6:
>    - Move dmmalloc() and all dm* functions to dmmalloc.h.
>    - Fix bool expression in early_malloc_active().
> 
>  arch/arm/include/asm/global_data.h        |    8 +
>  arch/avr32/include/asm/global_data.h      |    7 +
>  arch/blackfin/include/asm/global_data.h   |    6 +
>  arch/m68k/include/asm/global_data.h       |    8 +
>  arch/microblaze/include/asm/global_data.h |    8 +
>  arch/mips/include/asm/global_data.h       |    6 +
>  arch/nds32/include/asm/global_data.h      |    8 +
>  arch/nios2/include/asm/global_data.h      |    7 +
>  arch/openrisc/include/asm/global_data.h   |    8 +
>  arch/powerpc/include/asm/global_data.h    |    6 +
>  arch/sandbox/include/asm/global_data.h    |    7 +
>  arch/sh/include/asm/global_data.h         |    7 +
>  arch/sparc/include/asm/global_data.h      |    6 +
>  arch/x86/include/asm/global_data.h        |    8 +
>  common/Makefile                           |    1 +
>  common/dmmalloc.c                         |  297 +++++++++++++++++++++++++++++
>  include/asm-generic/global_data_flags.h   |    6 +-
>  include/dmmalloc.h                        |  132 +++++++++++++
>  18 files changed, 534 insertions(+), 2 deletions(-)
>  create mode 100644 common/dmmalloc.c
>  create mode 100644 include/dmmalloc.h
> 
> diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
> index 2b9af93..01075dc 100644
> --- a/arch/arm/include/asm/global_data.h
> +++ b/arch/arm/include/asm/global_data.h
> @@ -23,6 +23,11 @@
>  
>  #ifndef	__ASM_GBL_DATA_H
>  #define __ASM_GBL_DATA_H
> +
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +#include <dmmalloc.h>
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
> +
>  /*
>   * The following data structure is placed in some memory which is
>   * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
> @@ -82,6 +87,9 @@ typedef	struct	global_data {
>  	unsigned long	post_log_res; /* success of POST test */
>  	unsigned long	post_init_f_time; /* When post_init_f started */
>  #endif
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +	struct early_heap_header *early_heap;	/* heap for early_malloc */
> +#endif
>  } gd_t;
>  
>  #include <asm-generic/global_data_flags.h>
> diff --git a/arch/avr32/include/asm/global_data.h b/arch/avr32/include/asm/global_data.h
> index bf661e2..ba9cf0e 100644
> --- a/arch/avr32/include/asm/global_data.h
> +++ b/arch/avr32/include/asm/global_data.h
> @@ -22,6 +22,10 @@
>  #ifndef __ASM_GLOBAL_DATA_H__
>  #define __ASM_GLOBAL_DATA_H__
>  
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +#include <dmmalloc.h>
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
> +
>  /*
>   * The following data structure is placed in some memory wich is
>   * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
> @@ -48,6 +52,9 @@ typedef	struct	global_data {
>  #endif
>  	void		**jt;		/* jump table */
>  	char		env_buf[32];	/* buffer for getenv() before reloc. */
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +	struct early_heap_header *early_heap;	/* heap for early_malloc */
> +#endif
>  } gd_t;
>  
>  #include <asm-generic/global_data_flags.h>
> diff --git a/arch/blackfin/include/asm/global_data.h b/arch/blackfin/include/asm/global_data.h
> index d91e5a4..daeb314 100644
> --- a/arch/blackfin/include/asm/global_data.h
> +++ b/arch/blackfin/include/asm/global_data.h
> @@ -29,6 +29,9 @@
>  #define __ASM_GBL_DATA_H
>  
>  #include <asm/u-boot.h>
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +#include <dmmalloc.h>
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
>  
>  /*
>   * The following data structure is placed in some memory wich is
> @@ -57,6 +60,9 @@ typedef struct global_data {
>  
>  	void	**jt;			/* jump table */
>  	char	env_buf[32];		/* buffer for getenv() before reloc. */
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +	struct early_heap_header *early_heap;	/* heap for early_malloc */
> +#endif
>  } gd_t;
>  
>  #include <asm-generic/global_data_flags.h>
> diff --git a/arch/m68k/include/asm/global_data.h b/arch/m68k/include/asm/global_data.h
> index 0cdb11c..dad2ba5 100644
> --- a/arch/m68k/include/asm/global_data.h
> +++ b/arch/m68k/include/asm/global_data.h
> @@ -23,6 +23,11 @@
>  
>  #ifndef	__ASM_GBL_DATA_H
>  #define __ASM_GBL_DATA_H
> +
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +#include <dmmalloc.h>
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
> +
>  /*
>   * The following data structure is placed in some memory wich is
>   * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
> @@ -66,6 +71,9 @@ typedef	struct	global_data {
>  #endif
>  	void		**jt;		/* Standalone app jump table */
>  	char		env_buf[32];	/* buffer for getenv() before reloc. */
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +	struct early_heap_header *early_heap;	/* heap for early_malloc */
> +#endif
>  } gd_t;
>  
>  #include <asm-generic/global_data_flags.h>
> diff --git a/arch/microblaze/include/asm/global_data.h b/arch/microblaze/include/asm/global_data.h
> index 2111c7c..f6609b8 100644
> --- a/arch/microblaze/include/asm/global_data.h
> +++ b/arch/microblaze/include/asm/global_data.h
> @@ -24,6 +24,11 @@
>  
>  #ifndef	__ASM_GBL_DATA_H
>  #define __ASM_GBL_DATA_H
> +
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +#include <dmmalloc.h>
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
> +
>  /*
>   * The following data structure is placed in some memory wich is
>   * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
> @@ -46,6 +51,9 @@ typedef	struct	global_data {
>  	unsigned long	fb_base;	/* base address of frame buffer */
>  	void		**jt;		/* jump table */
>  	char		env_buf[32];	/* buffer for getenv() before reloc. */
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +	struct early_heap_header *early_heap;	/* heap for early_malloc */
> +#endif
>  } gd_t;
>  
>  #include <asm-generic/global_data_flags.h>
> diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h
> index a735a8a..c9b76f6 100644
> --- a/arch/mips/include/asm/global_data.h
> +++ b/arch/mips/include/asm/global_data.h
> @@ -25,6 +25,9 @@
>  #define __ASM_GBL_DATA_H
>  
>  #include <asm/regdef.h>
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +#include <dmmalloc.h>
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
>  
>  /*
>   * The following data structure is placed in some memory wich is
> @@ -59,6 +62,9 @@ typedef	struct	global_data {
>  	unsigned long	env_valid;	/* Checksum of Environment valid? */
>  	void		**jt;		/* jump table */
>  	char		env_buf[32];	/* buffer for getenv() before reloc. */
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +	struct early_heap_header *early_heap;	/* heap for early_malloc */
> +#endif
>  } gd_t;
>  
>  #include <asm-generic/global_data_flags.h>
> diff --git a/arch/nds32/include/asm/global_data.h b/arch/nds32/include/asm/global_data.h
> index b1feb2c..6d972c2 100644
> --- a/arch/nds32/include/asm/global_data.h
> +++ b/arch/nds32/include/asm/global_data.h
> @@ -33,6 +33,11 @@
>  
>  #ifndef	__ASM_GBL_DATA_H
>  #define __ASM_GBL_DATA_H
> +
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +#include <dmmalloc.h>
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
> +
>  /*
>   * The following data structure is placed in some memory wich is
>   * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
> @@ -63,6 +68,9 @@ typedef	struct global_data {
>  
>  	void		**jt;		/* jump table */
>  	char		env_buf[32];	/* buffer for getenv() before reloc. */
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +	struct early_heap_header *early_heap;	/* heap for early_malloc */
> +#endif
>  } gd_t;
>  
>  #include <asm-generic/global_data_flags.h>
> diff --git a/arch/nios2/include/asm/global_data.h b/arch/nios2/include/asm/global_data.h
> index 413b485..441e566 100644
> --- a/arch/nios2/include/asm/global_data.h
> +++ b/arch/nios2/include/asm/global_data.h
> @@ -23,6 +23,10 @@
>  #ifndef	__ASM_NIOS2_GLOBALDATA_H_
>  #define __ASM_NIOS2_GLOBALDATA_H_
>  
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +#include <dmmalloc.h>
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
> +
>  typedef	struct	global_data {
>  	bd_t		*bd;
>  	unsigned long	flags;
> @@ -42,6 +46,9 @@ typedef	struct	global_data {
>  #endif
>  	void		**jt;		/* Standalone app jump table */
>  	char		env_buf[32];	/* buffer for getenv() before reloc. */
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +	struct early_heap_header *early_heap;	/* heap for early_malloc */
> +#endif
>  } gd_t;
>  
>  #include <asm-generic/global_data_flags.h>
> diff --git a/arch/openrisc/include/asm/global_data.h b/arch/openrisc/include/asm/global_data.h
> index 96f3f1c..94fcef1 100644
> --- a/arch/openrisc/include/asm/global_data.h
> +++ b/arch/openrisc/include/asm/global_data.h
> @@ -24,6 +24,11 @@
>  
>  #ifndef __ASM_GBL_DATA_H
>  #define __ASM_GBL_DATA_H
> +
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +#include <dmmalloc.h>
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
> +
>  /*
>   * The following data structure is placed in some memory wich is
>   * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
> @@ -44,6 +49,9 @@ typedef struct global_data {
>  	unsigned long	fb_base;	/* base address of frame buffer */
>  	void		**jt;		/* jump table */
>  	char		env_buf[32];	/* buffer for getenv() before reloc. */
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +	struct early_heap_header *early_heap;	/* heap for early_malloc */
> +#endif
>  } gd_t;
>  
>  #include <asm-generic/global_data_flags.h>
> diff --git a/arch/powerpc/include/asm/global_data.h b/arch/powerpc/include/asm/global_data.h
> index 374fc6d..ed67bfd 100644
> --- a/arch/powerpc/include/asm/global_data.h
> +++ b/arch/powerpc/include/asm/global_data.h
> @@ -26,6 +26,9 @@
>  
>  #include "config.h"
>  #include "asm/types.h"
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +#include <dmmalloc.h>
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
>  
>  /*
>   * The following data structure is placed in some memory wich is
> @@ -182,6 +185,9 @@ typedef	struct	global_data {
>  #endif
>  	void		**jt;		/* jump table */
>  	char		env_buf[32];	/* buffer for getenv() before reloc. */
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +	struct early_heap_header *early_heap;	/* heap for early_malloc */
> +#endif
>  } gd_t;
>  
>  #include <asm-generic/global_data_flags.h>
> diff --git a/arch/sandbox/include/asm/global_data.h b/arch/sandbox/include/asm/global_data.h
> index 78a751d..0d4b4b0 100644
> --- a/arch/sandbox/include/asm/global_data.h
> +++ b/arch/sandbox/include/asm/global_data.h
> @@ -33,6 +33,10 @@
>   * up the memory controller so that we can use RAM).
>   */
>  
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +#include <dmmalloc.h>
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
> +
>  typedef	struct global_data {
>  	bd_t		*bd;
>  	unsigned long	flags;
> @@ -46,6 +50,9 @@ typedef	struct global_data {
>  	const void	*fdt_blob;	/* Our device tree, NULL if none */
>  	void		**jt;		/* jump table */
>  	char		env_buf[32];	/* buffer for getenv() before reloc. */
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +	struct early_heap_header *early_heap;	/* heap for early_malloc */
> +#endif
>  } gd_t;
>  
>  #include <asm-generic/global_data_flags.h>
> diff --git a/arch/sh/include/asm/global_data.h b/arch/sh/include/asm/global_data.h
> index 9a2c193..acacae7 100644
> --- a/arch/sh/include/asm/global_data.h
> +++ b/arch/sh/include/asm/global_data.h
> @@ -27,6 +27,10 @@
>  #ifndef	__ASM_SH_GLOBALDATA_H_
>  #define __ASM_SH_GLOBALDATA_H_
>  
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +#include <dmmalloc.h>
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
> +
>  typedef	struct global_data
>  {
>  	bd_t		*bd;
> @@ -42,6 +46,9 @@ typedef	struct global_data
>  	unsigned long	env_valid;	/* Checksum of Environment valid */
>  	void		**jt;		/* Standalone app jump table */
>  	char		env_buf[32];	/* buffer for getenv() before reloc. */
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +	struct early_heap_header *early_heap;	/* heap for early_malloc */
> +#endif
>  } gd_t;
>  
>  #include <asm-generic/global_data_flags.h>
> diff --git a/arch/sparc/include/asm/global_data.h b/arch/sparc/include/asm/global_data.h
> index aa63b35..aad97e1 100644
> --- a/arch/sparc/include/asm/global_data.h
> +++ b/arch/sparc/include/asm/global_data.h
> @@ -28,6 +28,9 @@
>  #define __ASM_GBL_DATA_H
>  
>  #include "asm/types.h"
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +#include <dmmalloc.h>
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
>  
>  /*
>   * The following data structure is placed in some memory wich is
> @@ -74,6 +77,9 @@ typedef struct global_data {
>  #endif
>  	void	**jt;			/* jump table */
>  	char	env_buf[32];		/* buffer for getenv() before reloc. */
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +	struct early_heap_header *early_heap;	/* heap for early_malloc */
> +#endif
>  } gd_t;
>  
>  #include <asm-generic/global_data_flags.h>
> diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h
> index bce999f..9eff403 100644
> --- a/arch/x86/include/asm/global_data.h
> +++ b/arch/x86/include/asm/global_data.h
> @@ -23,6 +23,11 @@
>  
>  #ifndef	__ASM_GBL_DATA_H
>  #define __ASM_GBL_DATA_H
> +
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +#include <dmmalloc.h>
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
> +
>  /*
>   * The following data structure is placed in some memory wich is
>   * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
> @@ -57,6 +62,9 @@ typedef	struct global_data {
>  	unsigned long	reset_status;	/* reset status register at boot */
>  	void		**jt;		/* jump table */
>  	char		env_buf[32];	/* buffer for getenv() before reloc. */
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +	struct early_heap_header *early_heap;	/* heap for early_malloc */
> +#endif
>  } gd_t;
>  
>  static inline gd_t *get_fs_gd_ptr(void)
> diff --git a/common/Makefile b/common/Makefile
> index fdfead7..bfb4d7a 100644
> --- a/common/Makefile
> +++ b/common/Makefile
> @@ -209,6 +209,7 @@ COBJS-y += dlmalloc.o
>  COBJS-y += image.o
>  COBJS-y += memsize.o
>  COBJS-y += stdio.o
> +COBJS-$(CONFIG_DM) += dmmalloc.o
>  
>  
>  COBJS	:= $(sort $(COBJS-y))
> diff --git a/common/dmmalloc.c b/common/dmmalloc.c
> new file mode 100644
> index 0000000..4a1a241
> --- /dev/null
> +++ b/common/dmmalloc.c
> @@ -0,0 +1,297 @@
> +/*
> + * (C) Copyright 2012
> + * Tomas Hlavacek (tmshlvck@gmail.com)
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#include <common.h> /* for ROUND_UP */
> +#include <asm/u-boot.h>
> +#include <asm/global_data.h> /* for gd_t and gd */
> +#include <asm/types.h> /* for phys_addr_t and size_addt_t */
> +
> +#include <dmmalloc.h>
> +#include <malloc.h>
> +
> +#include <linux/compiler.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +
> +struct early_block_header {
> +	size_t size;
> +};
> +
> +#define BLOCK_DATA(header) ((void *)(((struct early_block_header *)header)+1))
> +#define BLOCK_HEADER(addr) (((struct early_block_header *)addr)-1)
> +#define BLOCK_USED_FLAG 0x80000000
> +#define BLOCK_SIZE(size) (size & (~BLOCK_USED_FLAG))
> +#define BLOCK_USED(size) ((size & BLOCK_USED_FLAG) == BLOCK_USED_FLAG)
> +#define BLOCK_FREE(size) (!BLOCK_USED(size))
> +#define BLOCK_SET_FREE(size) BLOCK_SIZE(size)
> +#define BLOCK_SET_USED(size) (size | BLOCK_USED_FLAG)
> +
> +
> +__weak struct early_heap_header *early_brk(size_t size)
> +{
> +	struct early_heap_header *h;
> +	struct early_block_header *b;
> +
> +	if (gd->early_heap != NULL)
> +		return NULL;
> +
> +	h = (struct early_heap_header *)CONFIG_SYS_EARLY_HEAP_ADDR;
> +	b = (struct early_block_header *)(h + 1);
> +
> +	size = CONFIG_SYS_EARLY_HEAP_SIZE;
> +	h->size = size;
> +	h->early_heap_next = NULL;
> +	b->size = size - sizeof(struct early_heap_header) -
> +			sizeof(struct early_block_header);
> +	b->size = BLOCK_SET_FREE(b->size);
> +
> +	return h;
> +}
> +
> +static struct early_block_header *find_free_space(struct early_heap_header *h,
> +							size_t size)
> +{
> +	struct early_block_header *b;
> +
> +	b = (struct early_block_header *)(h+1);
> +	while ((phys_addr_t)b + sizeof(struct early_block_header)
> +			< (phys_addr_t)h + h->size) {
> +		if (BLOCK_FREE(b->size) && (BLOCK_SIZE(b->size) >= size))
> +			return b;
> +		b = (struct early_block_header *)((phys_addr_t)b +
> +				sizeof(struct early_block_header) +
> +				BLOCK_SIZE(b->size));
> +	}
> +
> +	return NULL;
> +}
> +
> +static struct early_block_header *split_block(struct early_block_header *b,
> +	       size_t size)
> +{
> +	struct early_block_header *nb;
> +
> +	if ((BLOCK_SIZE(b->size) < size) || (BLOCK_USED(b->size)))
> +		return NULL;
> +
> +	if (BLOCK_SIZE(b->size) <= (size + sizeof(struct early_block_header)))
> +		return b;
> +
> +	nb = (struct early_block_header *)((phys_addr_t)b +
> +		sizeof(struct early_block_header) + size);
> +	nb->size = b->size - size - sizeof(struct early_block_header);
> +	b->size = size;
> +
> +	return b;
> +}
> +
> +void *early_malloc(size_t size)
> +{
> +	struct early_heap_header *h;
> +	struct early_block_header *b;
> +
> +	size = roundup(size, sizeof(phys_addr_t));
> +	if (size == 0)
> +		return NULL;
> +
> +	if (gd->early_heap == NULL)
> +		gd->early_heap = early_brk(size);
> +
> +	if (gd->early_heap == NULL) {
> +		debug("early_brk failed to initialize heap\n");
> +		return NULL;
> +	}
> +
> +	h = gd->early_heap;
> +	while (1) {
> +		b = find_free_space(h, size);
> +		if (b != NULL)
> +			break;
> +
> +		if (h->early_heap_next != NULL)
> +			h = h->early_heap_next;
> +		else
> +			break;
> +	}
> +
> +	if (b == NULL) {
> +		h->early_heap_next = early_brk(size+
> +				sizeof(struct early_heap_header)+
> +				sizeof(struct early_block_header));
> +		h = h->early_heap_next;
> +		if (h == NULL) {
> +			debug("early_brk failed to extend heap by %d B\n",
> +					size);
> +			return NULL;
> +		}
> +
> +		b = find_free_space(h, size);
> +		if (b == NULL) {
> +			debug("early_malloc failed to extend heap by %d B\n",
> +					size);
> +			return NULL;
> +		}
> +	}
> +
> +	if (b->size != size)
> +		b = split_block(b, size);
> +	if (b == NULL) {
> +		debug("early_malloc failed to split block to %d B\n", size);
> +		return NULL;
> +	}
> +
> +	b->size = BLOCK_SET_USED(b->size);
> +
> +	return BLOCK_DATA(b);
> +}
> +
> +void early_free(void *addr)
> +{
> +	struct early_block_header *h = BLOCK_HEADER(addr);
> +	assert(BLOCK_USED(h->size));
> +	h->size = BLOCK_SET_FREE(h->size);
> +}
> +
> +void early_malloc_heap_dump(struct early_heap_header *h)
> +{
> +	struct early_block_header *b;
> +
> +	debug("heap: h=%p, h->size=%d\n", h, h->size);
> +
> +	b = (struct early_block_header *)(h+1);
> +	while ((phys_addr_t)b + sizeof(struct early_block_header)
> +			< (phys_addr_t)h + h->size) {
> +		debug("block: h=%p h->size=%d b=%p b->size=%d b->(used)=%d\n",
> +				h, h->size, b, BLOCK_SIZE(b->size),
> +				BLOCK_USED(b->size));
> +		assert(BLOCK_SIZE(b->size) > 0);
> +		b = (struct early_block_header *)((phys_addr_t)b +
> +				sizeof(struct early_block_header) +
> +				BLOCK_SIZE(b->size));
> +	}
> +	debug("--- heap dump end ---\n");
> +}
> +
> +void early_malloc_dump(void)
> +{
> +	struct early_heap_header *h = gd->early_heap;
> +	while (h != NULL) {
> +		early_malloc_heap_dump(h);
> +		h = h->early_heap_next;
> +	}
> +}
> +
> +static int early_malloc_active(void)
> +{
> +	return ((gd->flags & GD_FLG_HEAP_INIT) != GD_FLG_HEAP_INIT);
> +}
> +
> +static int early_heap_active(void)
> +{
> +	return ((gd->flags & GD_FLG_EARLY_HEAP_DONE) !=
> +			GD_FLG_EARLY_HEAP_DONE);
> +}
> +
> +static int early_address(void *ptr)
> +{
> +	struct early_heap_header *h = gd->early_heap;
> +	while (h != NULL) {
> +		if (((phys_addr_t)ptr >= (phys_addr_t)h) &&
> +				((phys_addr_t)ptr < (phys_addr_t)h + h->size))
> +			return 1;
> +
> +		h = h->early_heap_next;
> +	}
> +
> +	return 0;
> +}
> +
> +
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
> +
> +
> +void *dmmalloc(size_t size)
> +{
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +	if (early_malloc_active())
> +		return early_malloc(size);
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
> +	return malloc(size);
> +}
> +
> +void dmfree(void *ptr)
> +{
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +	if (early_heap_active()) {
> +		if (early_address(ptr))
> +			early_free(ptr);
> +		return;
> +	}
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
> +	free(ptr);
> +}
> +
> +void *dmcalloc(size_t n, size_t elem_size)
> +{
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +	char *addr;
> +	int size = elem_size * n;
> +
> +	if (early_malloc_active()) {
> +		addr = early_malloc(size);
> +		memset(addr, 0, size);
> +		return addr;
> +	}
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
> +	return calloc(n, elem_size);
> +}
> +
> +void *dmrealloc(void *oldaddr, size_t bytes)
> +{
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +	char *addr;
> +	struct early_block_header *h;
> +
> +	if (early_heap_active() && early_address(oldaddr)) {
> +		addr = dmmalloc(bytes);
> +		if (addr == NULL)
> +			return NULL;
> +
> +		h = BLOCK_HEADER(oldaddr);
> +		if (BLOCK_FREE(h->size))
> +			return NULL;
> +
> +		if (bytes > BLOCK_SIZE(h->size))
> +			bytes = BLOCK_SIZE(h->size);
> +
> +		memcpy(addr, oldaddr, bytes);
> +		dmfree(oldaddr);
> +		return addr;
> +	}
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
> +	return realloc(oldaddr, bytes);
> +}
> +
> diff --git a/include/asm-generic/global_data_flags.h b/include/asm-generic/global_data_flags.h
> index bb57fb6..97db2c2 100644
> --- a/include/asm-generic/global_data_flags.h
> +++ b/include/asm-generic/global_data_flags.h
> @@ -13,8 +13,8 @@
>  /*
>   * Global Data Flags
>   *
> - * Note: The low 16 bits are expected for common code.  If your arch
> - *       really needs to add your own, use the high 16bits.
> + * Note: The low 18 bits are expected for common code.  If your arch
> + *       really needs to add your own, use the high 14 bits.
>   */
>  #define GD_FLG_RELOC		0x0001	/* Code was relocated to RAM */
>  #define GD_FLG_DEVINIT		0x0002	/* Devices have been initialized */
> @@ -24,5 +24,7 @@
>  #define GD_FLG_LOGINIT		0x0020	/* Log Buffer has been initialized */
>  #define GD_FLG_DISABLE_CONSOLE	0x0040	/* Disable console (in & out) */
>  #define GD_FLG_ENV_READY	0x0080	/* Environment imported into hash table */
> +#define GD_FLG_HEAP_INIT	0x0100	/* malloc() in RAM is available */
> +#define GD_FLG_EARLY_HEAP_DONE	0x0200	/* early_malloc() heap relocated. */
>  
>  #endif
> diff --git a/include/dmmalloc.h b/include/dmmalloc.h
> new file mode 100644
> index 0000000..c99f423
> --- /dev/null
> +++ b/include/dmmalloc.h
> @@ -0,0 +1,132 @@
> +/*
> + * (C) Copyright 2012
> + * Tomas Hlavacek (tmshlvck@gmail.com)
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#ifndef __INCLUDE_DMMALLOC_H
> +#define __INCLUDE_DMMALLOC_H
> +
> +#include <config.h>
> +#include <linux/stddef.h> /* for size_t */
> +#include <malloc.h>
> +
> +#ifdef CONFIG_SYS_EARLY_MALLOC
> +
> +/**
> + * struct early_heap_header - header preceding an early heap
> + * @size - length of the heap in bytes (including the heap header).
> + * @early_heap_next - pointer to the following heap.
> + *
> + * Heaps are organized in the single direction linked list. Each heap
> + * contains own size. Pointer to the first (left-most) heap is
> + * contained in global data.
> + */
> +struct early_heap_header {
> +	size_t size;
> +	void *early_heap_next;
> +};
> +
> +/**
> + * early_brk() - obtain address of the heap
> + * @size:	Minimal size of the new early heap to be allocated.
> + *
> + * Function returns a new heap pointer.
> + *
> + * Allocate and initialize early_heap at least size bytes long.
> + * This function can be platform dependent or board dependent but sensible
> + * default is provided.
> + */
> +struct early_heap_header *early_brk(size_t size);
> +
> +/**
> + * early_malloc() - malloc operating on the early_heap(s)
> + * @size:	Size in bytes.
> + *
> + * Function returns a pointer to the allocated block.
> + */
> +void *early_malloc(size_t size);
> +
> +/**
> + * early_free() - free operating on the early_heap(s)
> + * @addr:	Pointer to the allocated block to be released.
> + */
> +void early_free(void *addr);
> +
> +/**
> + * early_malloc_heap_dump() - print blocks contained in an early_heap
> + * @h:		Address of the early heap.
> + */
> +void early_malloc_heap_dump(struct early_heap_header *h);
> +
> +/**
> + * early_malloc_dump() - print blocks contained in all early_heaps
> + */
> +void early_malloc_dump(void);
> +
> +
> +#endif /* CONFIG_SYS_EARLY_MALLOC */
> +
> +#ifdef CONFIG_DM
> +
> +/*
> + * DM versions of malloc* functions. In early init it calls early_malloc.
> + * It wraps around normal malloc* functions afterwards.
> + */
> +
> +/**
> + * dmmalloc() - malloc working seamlessly in early as well as in RAM stages
> + * @size:	Size of the block to be allocated.
> + *
> + * Function returns an address of the newly allocated block when successful
> + * or NULL otherwise.
> + */
> +void *dmmalloc(size_t size);
> +
> +/**
> + * dmfree() - free working seamlessly in early as well as in RAM stages
> + * @ptr:	Pointer to the allocated block to be released.
> + */
> +void dmfree(void *ptr);
> +
> +/**
> + * dmcalloc() - calloc working seamlessly in early as well as in RAM stages
> + * @n:		Number of elements to be allocated.
> + * @elem_size:	Size of elements to be allocated.
> + *
> + * Function returns a pointer to newly the allocated area (n*elem_size) long.
> + */
> +void *dmcalloc(size_t n, size_t elem_size);
> +
> +/**
> + * dmrealloc() - realloc working seamlessly in early as well as in RAM stages
> + * @oldaddr:	Pointer to the old memory block.
> + * @bytes:	New size to of the block to be reallocated.
> + *
> + * Function returns an address of the newly allocated block when successful
> + * or NULL otherwise.
> + *
> + * Data are copied from the block specified by oldaddr to the new block.
> + */
> +void *dmrealloc(void *oldaddr, size_t bytes);
> +
> +#endif /* CONFIG_DM */
> +#endif /* __INCLUDE_DMMALLOC_H */
> +
> 

*you may stop your scrolling now*

Hello,
does it ring a bell? I need to get it (or an equivalent solution) to
work before implementing a working DM2-I2C uclass. I don't see any
replies to the original v10 e-mail. Why wasn't it accepted into U-Boot?
Should I work on top of this patch, or start from scratch?

Regards,
Tom Rini Nov. 5, 2013, 5:17 p.m. UTC | #2
On Tue, Nov 05, 2013 at 04:26:25PM +0100, Mateusz Zalega wrote:

> On 10/29/12 00:20, Tomas Hlavacek wrote:
> > Add pointer to the first early heap into GD structure.
> > Implement simple early_malloc and early_free functions.
> > Prepare for additional heaps and automated heap initialization.
> > Add temporary early_malloc_active function (to be replaced in future by
> > more coarse DM init flags).
> > Add DM specific malloc calls - dmmalloc, dmfree, dmrealloc and dmcalloc.
> > 
> > Signed-off-by: Tomas Hlavacek <tmshlvck@gmail.com>
[snip]
> does it ring a bell? I need to get it (or an equivalent solution) to
> work before implementing a working DM2-I2C uclass. I don't see any
> replies to the original v10 e-mail. Why wasn't it accepted into U-Boot?
> Should I work on top of this patch, or start from scratch?

The patch itself was OK, but the rest of the DM work did not end up
going in, so there was no user of this change.  If you have a user,
please re-use his patch (and it'll need a v11 to apply again on top of
tree and comply with SPDX licenisng tags) and push it forward, thanks!
Mateusz Zalega Nov. 5, 2013, 5:26 p.m. UTC | #3
>>> Add pointer to the first early heap into GD structure.
>>> Implement simple early_malloc and early_free functions.
>>> Prepare for additional heaps and automated heap initialization.
>>> Add temporary early_malloc_active function (to be replaced in future by
>>> more coarse DM init flags).
>>> Add DM specific malloc calls - dmmalloc, dmfree, dmrealloc and dmcalloc.
>>>
>>> Signed-off-by: Tomas Hlavacek <tmshlvck@gmail.com>
> [snip]
>> does it ring a bell? I need to get it (or an equivalent solution) to
>> work before implementing a working DM2-I2C uclass. I don't see any
>> replies to the original v10 e-mail. Why wasn't it accepted into U-Boot?
>> Should I work on top of this patch, or start from scratch?
> 
> The patch itself was OK, but the rest of the DM work did not end up
> going in, so there was no user of this change.  If you have a user,
> please re-use his patch (and it'll need a v11 to apply again on top of
> tree and comply with SPDX licenisng tags) and push it forward, thanks!
> 

will do, thx!
diff mbox

Patch

diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index 2b9af93..01075dc 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -23,6 +23,11 @@ 
 
 #ifndef	__ASM_GBL_DATA_H
 #define __ASM_GBL_DATA_H
+
+#ifdef CONFIG_SYS_EARLY_MALLOC
+#include <dmmalloc.h>
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+
 /*
  * The following data structure is placed in some memory which is
  * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
@@ -82,6 +87,9 @@  typedef	struct	global_data {
 	unsigned long	post_log_res; /* success of POST test */
 	unsigned long	post_init_f_time; /* When post_init_f started */
 #endif
+#ifdef CONFIG_SYS_EARLY_MALLOC
+	struct early_heap_header *early_heap;	/* heap for early_malloc */
+#endif
 } gd_t;
 
 #include <asm-generic/global_data_flags.h>
diff --git a/arch/avr32/include/asm/global_data.h b/arch/avr32/include/asm/global_data.h
index bf661e2..ba9cf0e 100644
--- a/arch/avr32/include/asm/global_data.h
+++ b/arch/avr32/include/asm/global_data.h
@@ -22,6 +22,10 @@ 
 #ifndef __ASM_GLOBAL_DATA_H__
 #define __ASM_GLOBAL_DATA_H__
 
+#ifdef CONFIG_SYS_EARLY_MALLOC
+#include <dmmalloc.h>
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+
 /*
  * The following data structure is placed in some memory wich is
  * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
@@ -48,6 +52,9 @@  typedef	struct	global_data {
 #endif
 	void		**jt;		/* jump table */
 	char		env_buf[32];	/* buffer for getenv() before reloc. */
+#ifdef CONFIG_SYS_EARLY_MALLOC
+	struct early_heap_header *early_heap;	/* heap for early_malloc */
+#endif
 } gd_t;
 
 #include <asm-generic/global_data_flags.h>
diff --git a/arch/blackfin/include/asm/global_data.h b/arch/blackfin/include/asm/global_data.h
index d91e5a4..daeb314 100644
--- a/arch/blackfin/include/asm/global_data.h
+++ b/arch/blackfin/include/asm/global_data.h
@@ -29,6 +29,9 @@ 
 #define __ASM_GBL_DATA_H
 
 #include <asm/u-boot.h>
+#ifdef CONFIG_SYS_EARLY_MALLOC
+#include <dmmalloc.h>
+#endif /* CONFIG_SYS_EARLY_MALLOC */
 
 /*
  * The following data structure is placed in some memory wich is
@@ -57,6 +60,9 @@  typedef struct global_data {
 
 	void	**jt;			/* jump table */
 	char	env_buf[32];		/* buffer for getenv() before reloc. */
+#ifdef CONFIG_SYS_EARLY_MALLOC
+	struct early_heap_header *early_heap;	/* heap for early_malloc */
+#endif
 } gd_t;
 
 #include <asm-generic/global_data_flags.h>
diff --git a/arch/m68k/include/asm/global_data.h b/arch/m68k/include/asm/global_data.h
index 0cdb11c..dad2ba5 100644
--- a/arch/m68k/include/asm/global_data.h
+++ b/arch/m68k/include/asm/global_data.h
@@ -23,6 +23,11 @@ 
 
 #ifndef	__ASM_GBL_DATA_H
 #define __ASM_GBL_DATA_H
+
+#ifdef CONFIG_SYS_EARLY_MALLOC
+#include <dmmalloc.h>
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+
 /*
  * The following data structure is placed in some memory wich is
  * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
@@ -66,6 +71,9 @@  typedef	struct	global_data {
 #endif
 	void		**jt;		/* Standalone app jump table */
 	char		env_buf[32];	/* buffer for getenv() before reloc. */
+#ifdef CONFIG_SYS_EARLY_MALLOC
+	struct early_heap_header *early_heap;	/* heap for early_malloc */
+#endif
 } gd_t;
 
 #include <asm-generic/global_data_flags.h>
diff --git a/arch/microblaze/include/asm/global_data.h b/arch/microblaze/include/asm/global_data.h
index 2111c7c..f6609b8 100644
--- a/arch/microblaze/include/asm/global_data.h
+++ b/arch/microblaze/include/asm/global_data.h
@@ -24,6 +24,11 @@ 
 
 #ifndef	__ASM_GBL_DATA_H
 #define __ASM_GBL_DATA_H
+
+#ifdef CONFIG_SYS_EARLY_MALLOC
+#include <dmmalloc.h>
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+
 /*
  * The following data structure is placed in some memory wich is
  * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
@@ -46,6 +51,9 @@  typedef	struct	global_data {
 	unsigned long	fb_base;	/* base address of frame buffer */
 	void		**jt;		/* jump table */
 	char		env_buf[32];	/* buffer for getenv() before reloc. */
+#ifdef CONFIG_SYS_EARLY_MALLOC
+	struct early_heap_header *early_heap;	/* heap for early_malloc */
+#endif
 } gd_t;
 
 #include <asm-generic/global_data_flags.h>
diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h
index a735a8a..c9b76f6 100644
--- a/arch/mips/include/asm/global_data.h
+++ b/arch/mips/include/asm/global_data.h
@@ -25,6 +25,9 @@ 
 #define __ASM_GBL_DATA_H
 
 #include <asm/regdef.h>
+#ifdef CONFIG_SYS_EARLY_MALLOC
+#include <dmmalloc.h>
+#endif /* CONFIG_SYS_EARLY_MALLOC */
 
 /*
  * The following data structure is placed in some memory wich is
@@ -59,6 +62,9 @@  typedef	struct	global_data {
 	unsigned long	env_valid;	/* Checksum of Environment valid? */
 	void		**jt;		/* jump table */
 	char		env_buf[32];	/* buffer for getenv() before reloc. */
+#ifdef CONFIG_SYS_EARLY_MALLOC
+	struct early_heap_header *early_heap;	/* heap for early_malloc */
+#endif
 } gd_t;
 
 #include <asm-generic/global_data_flags.h>
diff --git a/arch/nds32/include/asm/global_data.h b/arch/nds32/include/asm/global_data.h
index b1feb2c..6d972c2 100644
--- a/arch/nds32/include/asm/global_data.h
+++ b/arch/nds32/include/asm/global_data.h
@@ -33,6 +33,11 @@ 
 
 #ifndef	__ASM_GBL_DATA_H
 #define __ASM_GBL_DATA_H
+
+#ifdef CONFIG_SYS_EARLY_MALLOC
+#include <dmmalloc.h>
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+
 /*
  * The following data structure is placed in some memory wich is
  * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
@@ -63,6 +68,9 @@  typedef	struct global_data {
 
 	void		**jt;		/* jump table */
 	char		env_buf[32];	/* buffer for getenv() before reloc. */
+#ifdef CONFIG_SYS_EARLY_MALLOC
+	struct early_heap_header *early_heap;	/* heap for early_malloc */
+#endif
 } gd_t;
 
 #include <asm-generic/global_data_flags.h>
diff --git a/arch/nios2/include/asm/global_data.h b/arch/nios2/include/asm/global_data.h
index 413b485..441e566 100644
--- a/arch/nios2/include/asm/global_data.h
+++ b/arch/nios2/include/asm/global_data.h
@@ -23,6 +23,10 @@ 
 #ifndef	__ASM_NIOS2_GLOBALDATA_H_
 #define __ASM_NIOS2_GLOBALDATA_H_
 
+#ifdef CONFIG_SYS_EARLY_MALLOC
+#include <dmmalloc.h>
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+
 typedef	struct	global_data {
 	bd_t		*bd;
 	unsigned long	flags;
@@ -42,6 +46,9 @@  typedef	struct	global_data {
 #endif
 	void		**jt;		/* Standalone app jump table */
 	char		env_buf[32];	/* buffer for getenv() before reloc. */
+#ifdef CONFIG_SYS_EARLY_MALLOC
+	struct early_heap_header *early_heap;	/* heap for early_malloc */
+#endif
 } gd_t;
 
 #include <asm-generic/global_data_flags.h>
diff --git a/arch/openrisc/include/asm/global_data.h b/arch/openrisc/include/asm/global_data.h
index 96f3f1c..94fcef1 100644
--- a/arch/openrisc/include/asm/global_data.h
+++ b/arch/openrisc/include/asm/global_data.h
@@ -24,6 +24,11 @@ 
 
 #ifndef __ASM_GBL_DATA_H
 #define __ASM_GBL_DATA_H
+
+#ifdef CONFIG_SYS_EARLY_MALLOC
+#include <dmmalloc.h>
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+
 /*
  * The following data structure is placed in some memory wich is
  * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
@@ -44,6 +49,9 @@  typedef struct global_data {
 	unsigned long	fb_base;	/* base address of frame buffer */
 	void		**jt;		/* jump table */
 	char		env_buf[32];	/* buffer for getenv() before reloc. */
+#ifdef CONFIG_SYS_EARLY_MALLOC
+	struct early_heap_header *early_heap;	/* heap for early_malloc */
+#endif
 } gd_t;
 
 #include <asm-generic/global_data_flags.h>
diff --git a/arch/powerpc/include/asm/global_data.h b/arch/powerpc/include/asm/global_data.h
index 374fc6d..ed67bfd 100644
--- a/arch/powerpc/include/asm/global_data.h
+++ b/arch/powerpc/include/asm/global_data.h
@@ -26,6 +26,9 @@ 
 
 #include "config.h"
 #include "asm/types.h"
+#ifdef CONFIG_SYS_EARLY_MALLOC
+#include <dmmalloc.h>
+#endif /* CONFIG_SYS_EARLY_MALLOC */
 
 /*
  * The following data structure is placed in some memory wich is
@@ -182,6 +185,9 @@  typedef	struct	global_data {
 #endif
 	void		**jt;		/* jump table */
 	char		env_buf[32];	/* buffer for getenv() before reloc. */
+#ifdef CONFIG_SYS_EARLY_MALLOC
+	struct early_heap_header *early_heap;	/* heap for early_malloc */
+#endif
 } gd_t;
 
 #include <asm-generic/global_data_flags.h>
diff --git a/arch/sandbox/include/asm/global_data.h b/arch/sandbox/include/asm/global_data.h
index 78a751d..0d4b4b0 100644
--- a/arch/sandbox/include/asm/global_data.h
+++ b/arch/sandbox/include/asm/global_data.h
@@ -33,6 +33,10 @@ 
  * up the memory controller so that we can use RAM).
  */
 
+#ifdef CONFIG_SYS_EARLY_MALLOC
+#include <dmmalloc.h>
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+
 typedef	struct global_data {
 	bd_t		*bd;
 	unsigned long	flags;
@@ -46,6 +50,9 @@  typedef	struct global_data {
 	const void	*fdt_blob;	/* Our device tree, NULL if none */
 	void		**jt;		/* jump table */
 	char		env_buf[32];	/* buffer for getenv() before reloc. */
+#ifdef CONFIG_SYS_EARLY_MALLOC
+	struct early_heap_header *early_heap;	/* heap for early_malloc */
+#endif
 } gd_t;
 
 #include <asm-generic/global_data_flags.h>
diff --git a/arch/sh/include/asm/global_data.h b/arch/sh/include/asm/global_data.h
index 9a2c193..acacae7 100644
--- a/arch/sh/include/asm/global_data.h
+++ b/arch/sh/include/asm/global_data.h
@@ -27,6 +27,10 @@ 
 #ifndef	__ASM_SH_GLOBALDATA_H_
 #define __ASM_SH_GLOBALDATA_H_
 
+#ifdef CONFIG_SYS_EARLY_MALLOC
+#include <dmmalloc.h>
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+
 typedef	struct global_data
 {
 	bd_t		*bd;
@@ -42,6 +46,9 @@  typedef	struct global_data
 	unsigned long	env_valid;	/* Checksum of Environment valid */
 	void		**jt;		/* Standalone app jump table */
 	char		env_buf[32];	/* buffer for getenv() before reloc. */
+#ifdef CONFIG_SYS_EARLY_MALLOC
+	struct early_heap_header *early_heap;	/* heap for early_malloc */
+#endif
 } gd_t;
 
 #include <asm-generic/global_data_flags.h>
diff --git a/arch/sparc/include/asm/global_data.h b/arch/sparc/include/asm/global_data.h
index aa63b35..aad97e1 100644
--- a/arch/sparc/include/asm/global_data.h
+++ b/arch/sparc/include/asm/global_data.h
@@ -28,6 +28,9 @@ 
 #define __ASM_GBL_DATA_H
 
 #include "asm/types.h"
+#ifdef CONFIG_SYS_EARLY_MALLOC
+#include <dmmalloc.h>
+#endif /* CONFIG_SYS_EARLY_MALLOC */
 
 /*
  * The following data structure is placed in some memory wich is
@@ -74,6 +77,9 @@  typedef struct global_data {
 #endif
 	void	**jt;			/* jump table */
 	char	env_buf[32];		/* buffer for getenv() before reloc. */
+#ifdef CONFIG_SYS_EARLY_MALLOC
+	struct early_heap_header *early_heap;	/* heap for early_malloc */
+#endif
 } gd_t;
 
 #include <asm-generic/global_data_flags.h>
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h
index bce999f..9eff403 100644
--- a/arch/x86/include/asm/global_data.h
+++ b/arch/x86/include/asm/global_data.h
@@ -23,6 +23,11 @@ 
 
 #ifndef	__ASM_GBL_DATA_H
 #define __ASM_GBL_DATA_H
+
+#ifdef CONFIG_SYS_EARLY_MALLOC
+#include <dmmalloc.h>
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+
 /*
  * The following data structure is placed in some memory wich is
  * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
@@ -57,6 +62,9 @@  typedef	struct global_data {
 	unsigned long	reset_status;	/* reset status register at boot */
 	void		**jt;		/* jump table */
 	char		env_buf[32];	/* buffer for getenv() before reloc. */
+#ifdef CONFIG_SYS_EARLY_MALLOC
+	struct early_heap_header *early_heap;	/* heap for early_malloc */
+#endif
 } gd_t;
 
 static inline gd_t *get_fs_gd_ptr(void)
diff --git a/common/Makefile b/common/Makefile
index fdfead7..bfb4d7a 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -209,6 +209,7 @@  COBJS-y += dlmalloc.o
 COBJS-y += image.o
 COBJS-y += memsize.o
 COBJS-y += stdio.o
+COBJS-$(CONFIG_DM) += dmmalloc.o
 
 
 COBJS	:= $(sort $(COBJS-y))
diff --git a/common/dmmalloc.c b/common/dmmalloc.c
new file mode 100644
index 0000000..4a1a241
--- /dev/null
+++ b/common/dmmalloc.c
@@ -0,0 +1,297 @@ 
+/*
+ * (C) Copyright 2012
+ * Tomas Hlavacek (tmshlvck@gmail.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h> /* for ROUND_UP */
+#include <asm/u-boot.h>
+#include <asm/global_data.h> /* for gd_t and gd */
+#include <asm/types.h> /* for phys_addr_t and size_addt_t */
+
+#include <dmmalloc.h>
+#include <malloc.h>
+
+#include <linux/compiler.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+
+#ifdef CONFIG_SYS_EARLY_MALLOC
+
+struct early_block_header {
+	size_t size;
+};
+
+#define BLOCK_DATA(header) ((void *)(((struct early_block_header *)header)+1))
+#define BLOCK_HEADER(addr) (((struct early_block_header *)addr)-1)
+#define BLOCK_USED_FLAG 0x80000000
+#define BLOCK_SIZE(size) (size & (~BLOCK_USED_FLAG))
+#define BLOCK_USED(size) ((size & BLOCK_USED_FLAG) == BLOCK_USED_FLAG)
+#define BLOCK_FREE(size) (!BLOCK_USED(size))
+#define BLOCK_SET_FREE(size) BLOCK_SIZE(size)
+#define BLOCK_SET_USED(size) (size | BLOCK_USED_FLAG)
+
+
+__weak struct early_heap_header *early_brk(size_t size)
+{
+	struct early_heap_header *h;
+	struct early_block_header *b;
+
+	if (gd->early_heap != NULL)
+		return NULL;
+
+	h = (struct early_heap_header *)CONFIG_SYS_EARLY_HEAP_ADDR;
+	b = (struct early_block_header *)(h + 1);
+
+	size = CONFIG_SYS_EARLY_HEAP_SIZE;
+	h->size = size;
+	h->early_heap_next = NULL;
+	b->size = size - sizeof(struct early_heap_header) -
+			sizeof(struct early_block_header);
+	b->size = BLOCK_SET_FREE(b->size);
+
+	return h;
+}
+
+static struct early_block_header *find_free_space(struct early_heap_header *h,
+							size_t size)
+{
+	struct early_block_header *b;
+
+	b = (struct early_block_header *)(h+1);
+	while ((phys_addr_t)b + sizeof(struct early_block_header)
+			< (phys_addr_t)h + h->size) {
+		if (BLOCK_FREE(b->size) && (BLOCK_SIZE(b->size) >= size))
+			return b;
+		b = (struct early_block_header *)((phys_addr_t)b +
+				sizeof(struct early_block_header) +
+				BLOCK_SIZE(b->size));
+	}
+
+	return NULL;
+}
+
+static struct early_block_header *split_block(struct early_block_header *b,
+	       size_t size)
+{
+	struct early_block_header *nb;
+
+	if ((BLOCK_SIZE(b->size) < size) || (BLOCK_USED(b->size)))
+		return NULL;
+
+	if (BLOCK_SIZE(b->size) <= (size + sizeof(struct early_block_header)))
+		return b;
+
+	nb = (struct early_block_header *)((phys_addr_t)b +
+		sizeof(struct early_block_header) + size);
+	nb->size = b->size - size - sizeof(struct early_block_header);
+	b->size = size;
+
+	return b;
+}
+
+void *early_malloc(size_t size)
+{
+	struct early_heap_header *h;
+	struct early_block_header *b;
+
+	size = roundup(size, sizeof(phys_addr_t));
+	if (size == 0)
+		return NULL;
+
+	if (gd->early_heap == NULL)
+		gd->early_heap = early_brk(size);
+
+	if (gd->early_heap == NULL) {
+		debug("early_brk failed to initialize heap\n");
+		return NULL;
+	}
+
+	h = gd->early_heap;
+	while (1) {
+		b = find_free_space(h, size);
+		if (b != NULL)
+			break;
+
+		if (h->early_heap_next != NULL)
+			h = h->early_heap_next;
+		else
+			break;
+	}
+
+	if (b == NULL) {
+		h->early_heap_next = early_brk(size+
+				sizeof(struct early_heap_header)+
+				sizeof(struct early_block_header));
+		h = h->early_heap_next;
+		if (h == NULL) {
+			debug("early_brk failed to extend heap by %d B\n",
+					size);
+			return NULL;
+		}
+
+		b = find_free_space(h, size);
+		if (b == NULL) {
+			debug("early_malloc failed to extend heap by %d B\n",
+					size);
+			return NULL;
+		}
+	}
+
+	if (b->size != size)
+		b = split_block(b, size);
+	if (b == NULL) {
+		debug("early_malloc failed to split block to %d B\n", size);
+		return NULL;
+	}
+
+	b->size = BLOCK_SET_USED(b->size);
+
+	return BLOCK_DATA(b);
+}
+
+void early_free(void *addr)
+{
+	struct early_block_header *h = BLOCK_HEADER(addr);
+	assert(BLOCK_USED(h->size));
+	h->size = BLOCK_SET_FREE(h->size);
+}
+
+void early_malloc_heap_dump(struct early_heap_header *h)
+{
+	struct early_block_header *b;
+
+	debug("heap: h=%p, h->size=%d\n", h, h->size);
+
+	b = (struct early_block_header *)(h+1);
+	while ((phys_addr_t)b + sizeof(struct early_block_header)
+			< (phys_addr_t)h + h->size) {
+		debug("block: h=%p h->size=%d b=%p b->size=%d b->(used)=%d\n",
+				h, h->size, b, BLOCK_SIZE(b->size),
+				BLOCK_USED(b->size));
+		assert(BLOCK_SIZE(b->size) > 0);
+		b = (struct early_block_header *)((phys_addr_t)b +
+				sizeof(struct early_block_header) +
+				BLOCK_SIZE(b->size));
+	}
+	debug("--- heap dump end ---\n");
+}
+
+void early_malloc_dump(void)
+{
+	struct early_heap_header *h = gd->early_heap;
+	while (h != NULL) {
+		early_malloc_heap_dump(h);
+		h = h->early_heap_next;
+	}
+}
+
+static int early_malloc_active(void)
+{
+	return ((gd->flags & GD_FLG_HEAP_INIT) != GD_FLG_HEAP_INIT);
+}
+
+static int early_heap_active(void)
+{
+	return ((gd->flags & GD_FLG_EARLY_HEAP_DONE) !=
+			GD_FLG_EARLY_HEAP_DONE);
+}
+
+static int early_address(void *ptr)
+{
+	struct early_heap_header *h = gd->early_heap;
+	while (h != NULL) {
+		if (((phys_addr_t)ptr >= (phys_addr_t)h) &&
+				((phys_addr_t)ptr < (phys_addr_t)h + h->size))
+			return 1;
+
+		h = h->early_heap_next;
+	}
+
+	return 0;
+}
+
+
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+
+
+void *dmmalloc(size_t size)
+{
+#ifdef CONFIG_SYS_EARLY_MALLOC
+	if (early_malloc_active())
+		return early_malloc(size);
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+	return malloc(size);
+}
+
+void dmfree(void *ptr)
+{
+#ifdef CONFIG_SYS_EARLY_MALLOC
+	if (early_heap_active()) {
+		if (early_address(ptr))
+			early_free(ptr);
+		return;
+	}
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+	free(ptr);
+}
+
+void *dmcalloc(size_t n, size_t elem_size)
+{
+#ifdef CONFIG_SYS_EARLY_MALLOC
+	char *addr;
+	int size = elem_size * n;
+
+	if (early_malloc_active()) {
+		addr = early_malloc(size);
+		memset(addr, 0, size);
+		return addr;
+	}
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+	return calloc(n, elem_size);
+}
+
+void *dmrealloc(void *oldaddr, size_t bytes)
+{
+#ifdef CONFIG_SYS_EARLY_MALLOC
+	char *addr;
+	struct early_block_header *h;
+
+	if (early_heap_active() && early_address(oldaddr)) {
+		addr = dmmalloc(bytes);
+		if (addr == NULL)
+			return NULL;
+
+		h = BLOCK_HEADER(oldaddr);
+		if (BLOCK_FREE(h->size))
+			return NULL;
+
+		if (bytes > BLOCK_SIZE(h->size))
+			bytes = BLOCK_SIZE(h->size);
+
+		memcpy(addr, oldaddr, bytes);
+		dmfree(oldaddr);
+		return addr;
+	}
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+	return realloc(oldaddr, bytes);
+}
+
diff --git a/include/asm-generic/global_data_flags.h b/include/asm-generic/global_data_flags.h
index bb57fb6..97db2c2 100644
--- a/include/asm-generic/global_data_flags.h
+++ b/include/asm-generic/global_data_flags.h
@@ -13,8 +13,8 @@ 
 /*
  * Global Data Flags
  *
- * Note: The low 16 bits are expected for common code.  If your arch
- *       really needs to add your own, use the high 16bits.
+ * Note: The low 18 bits are expected for common code.  If your arch
+ *       really needs to add your own, use the high 14 bits.
  */
 #define GD_FLG_RELOC		0x0001	/* Code was relocated to RAM */
 #define GD_FLG_DEVINIT		0x0002	/* Devices have been initialized */
@@ -24,5 +24,7 @@ 
 #define GD_FLG_LOGINIT		0x0020	/* Log Buffer has been initialized */
 #define GD_FLG_DISABLE_CONSOLE	0x0040	/* Disable console (in & out) */
 #define GD_FLG_ENV_READY	0x0080	/* Environment imported into hash table */
+#define GD_FLG_HEAP_INIT	0x0100	/* malloc() in RAM is available */
+#define GD_FLG_EARLY_HEAP_DONE	0x0200	/* early_malloc() heap relocated. */
 
 #endif
diff --git a/include/dmmalloc.h b/include/dmmalloc.h
new file mode 100644
index 0000000..c99f423
--- /dev/null
+++ b/include/dmmalloc.h
@@ -0,0 +1,132 @@ 
+/*
+ * (C) Copyright 2012
+ * Tomas Hlavacek (tmshlvck@gmail.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __INCLUDE_DMMALLOC_H
+#define __INCLUDE_DMMALLOC_H
+
+#include <config.h>
+#include <linux/stddef.h> /* for size_t */
+#include <malloc.h>
+
+#ifdef CONFIG_SYS_EARLY_MALLOC
+
+/**
+ * struct early_heap_header - header preceding an early heap
+ * @size - length of the heap in bytes (including the heap header).
+ * @early_heap_next - pointer to the following heap.
+ *
+ * Heaps are organized in the single direction linked list. Each heap
+ * contains own size. Pointer to the first (left-most) heap is
+ * contained in global data.
+ */
+struct early_heap_header {
+	size_t size;
+	void *early_heap_next;
+};
+
+/**
+ * early_brk() - obtain address of the heap
+ * @size:	Minimal size of the new early heap to be allocated.
+ *
+ * Function returns a new heap pointer.
+ *
+ * Allocate and initialize early_heap at least size bytes long.
+ * This function can be platform dependent or board dependent but sensible
+ * default is provided.
+ */
+struct early_heap_header *early_brk(size_t size);
+
+/**
+ * early_malloc() - malloc operating on the early_heap(s)
+ * @size:	Size in bytes.
+ *
+ * Function returns a pointer to the allocated block.
+ */
+void *early_malloc(size_t size);
+
+/**
+ * early_free() - free operating on the early_heap(s)
+ * @addr:	Pointer to the allocated block to be released.
+ */
+void early_free(void *addr);
+
+/**
+ * early_malloc_heap_dump() - print blocks contained in an early_heap
+ * @h:		Address of the early heap.
+ */
+void early_malloc_heap_dump(struct early_heap_header *h);
+
+/**
+ * early_malloc_dump() - print blocks contained in all early_heaps
+ */
+void early_malloc_dump(void);
+
+
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+
+#ifdef CONFIG_DM
+
+/*
+ * DM versions of malloc* functions. In early init it calls early_malloc.
+ * It wraps around normal malloc* functions afterwards.
+ */
+
+/**
+ * dmmalloc() - malloc working seamlessly in early as well as in RAM stages
+ * @size:	Size of the block to be allocated.
+ *
+ * Function returns an address of the newly allocated block when successful
+ * or NULL otherwise.
+ */
+void *dmmalloc(size_t size);
+
+/**
+ * dmfree() - free working seamlessly in early as well as in RAM stages
+ * @ptr:	Pointer to the allocated block to be released.
+ */
+void dmfree(void *ptr);
+
+/**
+ * dmcalloc() - calloc working seamlessly in early as well as in RAM stages
+ * @n:		Number of elements to be allocated.
+ * @elem_size:	Size of elements to be allocated.
+ *
+ * Function returns a pointer to newly the allocated area (n*elem_size) long.
+ */
+void *dmcalloc(size_t n, size_t elem_size);
+
+/**
+ * dmrealloc() - realloc working seamlessly in early as well as in RAM stages
+ * @oldaddr:	Pointer to the old memory block.
+ * @bytes:	New size to of the block to be reallocated.
+ *
+ * Function returns an address of the newly allocated block when successful
+ * or NULL otherwise.
+ *
+ * Data are copied from the block specified by oldaddr to the new block.
+ */
+void *dmrealloc(void *oldaddr, size_t bytes);
+
+#endif /* CONFIG_DM */
+#endif /* __INCLUDE_DMMALLOC_H */
+