[U-Boot] [PATCH 1/1] [RFC] DM: early_malloc for DM added.

Modular early_malloc for DM with support for more heaps and lightweight first heap on stack.
(RFC. Not intended for merging!)
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com --- arch/arm/include/asm/global_data.h | 1 + arch/arm/lib/board.c | 5 ++ arch/avr32/include/asm/global_data.h | 1 + arch/avr32/lib/board.c | 4 ++ arch/blackfin/include/asm/global_data.h | 1 + arch/blackfin/lib/board.c | 4 ++ arch/m68k/include/asm/global_data.h | 1 + arch/m68k/lib/board.c | 4 ++ arch/microblaze/include/asm/global_data.h | 1 + arch/microblaze/lib/board.c | 5 ++ arch/mips/include/asm/global_data.h | 1 + arch/mips/lib/board.c | 4 ++ arch/nds32/include/asm/global_data.h | 1 + arch/nds32/lib/board.c | 4 ++ arch/nios2/include/asm/global_data.h | 1 + arch/nios2/lib/board.c | 4 ++ arch/openrisc/include/asm/global_data.h | 1 + arch/openrisc/lib/board.c | 4 ++ arch/powerpc/include/asm/global_data.h | 1 + arch/powerpc/lib/board.c | 4 ++ arch/sandbox/include/asm/global_data.h | 1 + arch/sandbox/lib/board.c | 4 ++ arch/sh/include/asm/global_data.h | 1 + arch/sparc/include/asm/global_data.h | 1 + arch/sparc/lib/board.c | 4 ++ arch/x86/include/asm/global_data.h | 1 + arch/x86/lib/board.c | 4 ++ common/Makefile | 1 + common/earlymalloc.c | 91 +++++++++++++++++++++++++++++ include/earlymalloc.h | 48 +++++++++++++++ 30 files changed, 208 insertions(+) create mode 100644 common/earlymalloc.c create mode 100644 include/earlymalloc.h
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h index c3ff789..71ae6dc 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -84,6 +84,7 @@ 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 + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index 500e216..ad124c6 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -52,6 +52,7 @@ #include <fdtdec.h> #include <post.h> #include <logbuff.h> +#include <earlymalloc.h>
#ifdef CONFIG_BITBANGMII #include <miiphy.h> @@ -273,6 +274,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + gd->mon_len = _bss_end_ofs; #ifdef CONFIG_OF_EMBED /* Get a pointer to the FDT */ diff --git a/arch/avr32/include/asm/global_data.h b/arch/avr32/include/asm/global_data.h index 5c654bd..5edb1f0 100644 --- a/arch/avr32/include/asm/global_data.h +++ b/arch/avr32/include/asm/global_data.h @@ -50,6 +50,7 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/avr32/lib/board.c b/arch/avr32/lib/board.c index 63fe297..8cb56df 100644 --- a/arch/avr32/lib/board.c +++ b/arch/avr32/lib/board.c @@ -149,6 +149,10 @@ void board_init_f(ulong board_type) memset(&gd_data, 0, sizeof(gd_data)); gd = &gd_data;
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + /* Perform initialization sequence */ board_early_init_f(); cpu_init(); diff --git a/arch/blackfin/include/asm/global_data.h b/arch/blackfin/include/asm/global_data.h index 67aa30f..33d3cec 100644 --- a/arch/blackfin/include/asm/global_data.h +++ b/arch/blackfin/include/asm/global_data.h @@ -59,6 +59,7 @@ typedef struct global_data {
void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/blackfin/lib/board.c b/arch/blackfin/lib/board.c index e3ee4cd..f8dade6 100644 --- a/arch/blackfin/lib/board.c +++ b/arch/blackfin/lib/board.c @@ -250,6 +250,10 @@ void board_init_f(ulong bootflag) bd->bi_memstart = CONFIG_SYS_SDRAM_BASE; bd->bi_memsize = CONFIG_SYS_MAX_RAM_SIZE;
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + /* Initialize */ serial_early_puts("IRQ init\n"); irq_init(); diff --git a/arch/m68k/include/asm/global_data.h b/arch/m68k/include/asm/global_data.h index 0ba2b43..ddd76f9 100644 --- a/arch/m68k/include/asm/global_data.h +++ b/arch/m68k/include/asm/global_data.h @@ -68,6 +68,7 @@ typedef struct global_data { #endif void **jt; /* Standalone app jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/m68k/lib/board.c b/arch/m68k/lib/board.c index 1526967..a420d21 100644 --- a/arch/m68k/lib/board.c +++ b/arch/m68k/lib/board.c @@ -227,6 +227,10 @@ board_init_f (ulong bootflag) /* Clear initial global data */ memset ((void *) gd, 0, sizeof (gd_t));
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) { hang (); diff --git a/arch/microblaze/include/asm/global_data.h b/arch/microblaze/include/asm/global_data.h index 6e8537c..4e340e6 100644 --- a/arch/microblaze/include/asm/global_data.h +++ b/arch/microblaze/include/asm/global_data.h @@ -47,6 +47,7 @@ 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. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/microblaze/lib/board.c b/arch/microblaze/lib/board.c index 9828b76..302a323 100644 --- a/arch/microblaze/lib/board.c +++ b/arch/microblaze/lib/board.c @@ -101,6 +101,11 @@ void board_init (void) asm ("nop"); /* FIXME gd is not initialize - wait */ memset ((void *)gd, 0, GENERATED_GBL_DATA_SIZE); memset ((void *)bd, 0, GENERATED_BD_INFO_SIZE); + + /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + gd->bd = bd; gd->baudrate = CONFIG_BAUDRATE; bd->bi_baudrate = CONFIG_BAUDRATE; diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h index f6cf9fe..9656fd6 100644 --- a/arch/mips/include/asm/global_data.h +++ b/arch/mips/include/asm/global_data.h @@ -61,6 +61,7 @@ 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. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/mips/lib/board.c b/arch/mips/lib/board.c index d998f0e..f40258c 100644 --- a/arch/mips/lib/board.c +++ b/arch/mips/lib/board.c @@ -160,6 +160,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) hang(); diff --git a/arch/nds32/include/asm/global_data.h b/arch/nds32/include/asm/global_data.h index de20a0a..313fecb 100644 --- a/arch/nds32/include/asm/global_data.h +++ b/arch/nds32/include/asm/global_data.h @@ -65,6 +65,7 @@ typedef struct global_data {
void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/nds32/lib/board.c b/arch/nds32/lib/board.c index 074aabf..34fff30 100644 --- a/arch/nds32/lib/board.c +++ b/arch/nds32/lib/board.c @@ -190,6 +190,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, GENERATED_GBL_DATA_SIZE);
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + gd->mon_len = (unsigned int)(&__bss_end__) - (unsigned int)(&_start);
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { diff --git a/arch/nios2/include/asm/global_data.h b/arch/nios2/include/asm/global_data.h index 4b86fbd..02f93d3 100644 --- a/arch/nios2/include/asm/global_data.h +++ b/arch/nios2/include/asm/global_data.h @@ -42,6 +42,7 @@ typedef struct global_data { #endif void **jt; /* Standalone app jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* flags */ diff --git a/arch/nios2/lib/board.c b/arch/nios2/lib/board.c index 65de26e..87e0559 100644 --- a/arch/nios2/lib/board.c +++ b/arch/nios2/lib/board.c @@ -97,6 +97,10 @@ void board_init (void)
memset( gd, 0, GENERATED_GBL_DATA_SIZE );
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + gd->bd = (bd_t *)(gd+1); /* At end of global data */ gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/openrisc/include/asm/global_data.h b/arch/openrisc/include/asm/global_data.h index 36de9d0..032b6b2 100644 --- a/arch/openrisc/include/asm/global_data.h +++ b/arch/openrisc/include/asm/global_data.h @@ -46,6 +46,7 @@ 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. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/openrisc/lib/board.c b/arch/openrisc/lib/board.c index 85aa189..2a92899 100644 --- a/arch/openrisc/lib/board.c +++ b/arch/openrisc/lib/board.c @@ -86,6 +86,10 @@ void board_init(void)
memset((void *)gd, 0, GENERATED_GBL_DATA_SIZE);
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + gd->bd = (bd_t *)(gd+1); /* At end of global data */ gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/powerpc/include/asm/global_data.h b/arch/powerpc/include/asm/global_data.h index 01f1d4a..0839d03 100644 --- a/arch/powerpc/include/asm/global_data.h +++ b/arch/powerpc/include/asm/global_data.h @@ -184,6 +184,7 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/powerpc/lib/board.c b/arch/powerpc/lib/board.c index 3f9af1d..ac88ae2 100644 --- a/arch/powerpc/lib/board.c +++ b/arch/powerpc/lib/board.c @@ -389,6 +389,10 @@ void board_init_f(ulong bootflag) memset((void *) gd, 0, sizeof(gd_t)); #endif
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) if ((*init_fnc_ptr) () != 0) hang(); diff --git a/arch/sandbox/include/asm/global_data.h b/arch/sandbox/include/asm/global_data.h index 8d47191..54342c0 100644 --- a/arch/sandbox/include/asm/global_data.h +++ b/arch/sandbox/include/asm/global_data.h @@ -47,6 +47,7 @@ typedef struct global_data { phys_size_t ram_size; /* RAM size */ void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/sandbox/lib/board.c b/arch/sandbox/lib/board.c index b7997e9..3d06cfc 100644 --- a/arch/sandbox/lib/board.c +++ b/arch/sandbox/lib/board.c @@ -156,6 +156,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) hang(); diff --git a/arch/sh/include/asm/global_data.h b/arch/sh/include/asm/global_data.h index 1b782fc..180f56e 100644 --- a/arch/sh/include/asm/global_data.h +++ b/arch/sh/include/asm/global_data.h @@ -42,6 +42,7 @@ 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. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */ diff --git a/arch/sparc/include/asm/global_data.h b/arch/sparc/include/asm/global_data.h index 613e2d8..82ed56f 100644 --- a/arch/sparc/include/asm/global_data.h +++ b/arch/sparc/include/asm/global_data.h @@ -76,6 +76,7 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/sparc/lib/board.c b/arch/sparc/lib/board.c index 519a4fb..86ee8db 100644 --- a/arch/sparc/lib/board.c +++ b/arch/sparc/lib/board.c @@ -179,6 +179,10 @@ void board_init_f(ulong bootflag) /* Clear initial global data */ memset((void *)gd, 0, sizeof(gd_t));
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + gd->bd = (bd_t *) (gd + 1); /* At end of global data */ gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 908a02c..171f85b 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -59,6 +59,7 @@ 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. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
static inline gd_t *get_fs_gd_ptr(void) diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index 5f0b62c..5ff4f42 100644 --- a/arch/x86/lib/board.c +++ b/arch/x86/lib/board.c @@ -220,6 +220,10 @@ void board_init_f(ulong boot_flags) { gd->flags = boot_flags;
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + do_init_loop(init_sequence_f);
/* diff --git a/common/Makefile b/common/Makefile index 2a31c62..744beb8 100644 --- a/common/Makefile +++ b/common/Makefile @@ -188,6 +188,7 @@ COBJS-y += console.o COBJS-y += dlmalloc.o COBJS-y += memsize.o COBJS-y += stdio.o +COBJS-y += earlymalloc.o
COBJS := $(sort $(COBJS-y)) diff --git a/common/earlymalloc.c b/common/earlymalloc.c new file mode 100644 index 0000000..6ba4df6 --- /dev/null +++ b/common/earlymalloc.c @@ -0,0 +1,91 @@ +/* + * (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 <earlymalloc.h> + +DECLARE_GLOBAL_DATA_PTR; + + +void early_heap_init(void *heap, size_t size) +{ + struct early_heap_header *h = heap; + + h->free_space_pointer = (void *)(roundup((phys_addr_t)heap + + sizeof(struct early_heap_header), + sizeof(phys_addr_t))); + h->free_bytes = size - roundup(sizeof(struct early_heap_header), + sizeof(phys_addr_t)); + h->next_early_heap = NULL; +} + +void *early_malloc(size_t size) +{ + phys_addr_t addr; + struct early_heap_header *h; + + /* Align size. */ + size = roundup(size, sizeof(phys_addr_t)); + + /* Choose early_heap with enough space. */ + h = gd->early_heap_first; + while ((h->free_bytes < size)&&(h->next_early_heap != NULL)) + h = h->next_early_heap; + + if(h->free_bytes < size) { + debug("Early heap overflow. Heap %08lX, free %d, required %d.", + h, h->free_bytes, size); + return NULL; + } + + /* Choose block beginning address and mark next free space. */ + addr = h->free_space_pointer; + + h->free_space_pointer += size; + h->free_bytes -= size; + + return (void *)addr; +} + + +int early_malloc_isaddress(void *addr) +{ + if ((phys_addr_t)addr < (phys_addr_t)gd->early_heap_first) + return 0; + + if ((phys_addr_t)addr >= (phys_addr_t)gd->early_heap_first + + CONFIG_SYS_EARLY_HEAP_SIZE) + return 0; + + return 1; +} + +int early_malloc_finished(void) +{ + return gd->flags & GD_FLG_RELOC; +} + diff --git a/include/earlymalloc.h b/include/earlymalloc.h new file mode 100644 index 0000000..345bdef --- /dev/null +++ b/include/earlymalloc.h @@ -0,0 +1,48 @@ +/* + * (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_EARLYMALLOC_H +#define __INCLUDE_EARLYMALLOC_H + +#include <linux/stddef.h> /* for size_t */ + +struct early_heap_header { + void *free_space_pointer; + size_t free_bytes; + void *next_early_heap; +}; + +void early_heap_init(void *heap, size_t size); +void *early_malloc(size_t size); +int early_malloc_isaddress(void *addr); +int early_malloc_finished(void); + +#ifndef CONFIG_SYS_EARLY_HEAP_SIZE +#define CONFIG_SYS_EARLY_HEAP_SIZE 256 +#endif /* CONFIG_SYS_EARLY_HEAP_SIZE */ + +#define DECLARE_EARLY_HEAP_ON_STACK char __early_heap[CONFIG_SYS_EARLY_HEAP_SIZE]; \ + gd->early_heap_first = (void *)__early_heap + +#endif /* __INCLUDE_EARLYMALLOC_H */ +

Dear Tomas Hlavacek,
Modular early_malloc for DM with support for more heaps and lightweight first heap on stack.
(RFC. Not intended for merging!)
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com
[...]
CCing Graeme
Best regards, Marek Vasut

Hello Marek and Greame!
Thanks.
I want to add that this patch contains only the early_malloc() backend for prospective dm_malloc(). There are no relocation support or helpers whatsoever yet.
The aim is to present the way of grabbing a chunk of stack and using this memory as the early heap and collect the feedback.
Tomas
On Mon, Aug 27, 2012 at 2:18 PM, Marek Vasut marek.vasut@gmail.com wrote:
Dear Tomas Hlavacek,
Modular early_malloc for DM with support for more heaps and lightweight first heap on stack.
(RFC. Not intended for merging!)
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com
[...]
CCing Graeme
Best regards, Marek Vasut

Modular early_malloc for DM with support for more heaps and lightweight first heap on stack.
(Not intended for merging!)
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com --- arch/arm/include/asm/global_data.h | 1 + arch/arm/lib/board.c | 5 ++ arch/avr32/include/asm/global_data.h | 1 + arch/avr32/lib/board.c | 4 ++ arch/blackfin/include/asm/global_data.h | 1 + arch/blackfin/lib/board.c | 4 ++ arch/m68k/include/asm/global_data.h | 1 + arch/m68k/lib/board.c | 4 ++ arch/microblaze/include/asm/global_data.h | 1 + arch/microblaze/lib/board.c | 5 ++ arch/mips/include/asm/global_data.h | 1 + arch/mips/lib/board.c | 4 ++ arch/nds32/include/asm/global_data.h | 1 + arch/nds32/lib/board.c | 4 ++ arch/nios2/include/asm/global_data.h | 1 + arch/nios2/lib/board.c | 4 ++ arch/openrisc/include/asm/global_data.h | 1 + arch/openrisc/lib/board.c | 4 ++ arch/powerpc/include/asm/global_data.h | 1 + arch/powerpc/lib/board.c | 4 ++ arch/sandbox/include/asm/global_data.h | 1 + arch/sandbox/lib/board.c | 4 ++ arch/sh/include/asm/global_data.h | 1 + arch/sparc/include/asm/global_data.h | 1 + arch/sparc/lib/board.c | 4 ++ arch/x86/include/asm/global_data.h | 1 + arch/x86/lib/board.c | 4 ++ common/Makefile | 1 + common/earlymalloc.c | 91 +++++++++++++++++++++++++++++ include/earlymalloc.h | 49 ++++++++++++++++ 30 files changed, 209 insertions(+) create mode 100644 common/earlymalloc.c create mode 100644 include/earlymalloc.h
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h index c3ff789..8563d49 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -84,6 +84,7 @@ 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 + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index 500e216..ad124c6 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -52,6 +52,7 @@ #include <fdtdec.h> #include <post.h> #include <logbuff.h> +#include <earlymalloc.h>
#ifdef CONFIG_BITBANGMII #include <miiphy.h> @@ -273,6 +274,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + gd->mon_len = _bss_end_ofs; #ifdef CONFIG_OF_EMBED /* Get a pointer to the FDT */ diff --git a/arch/avr32/include/asm/global_data.h b/arch/avr32/include/asm/global_data.h index 5c654bd..9ae7c5e 100644 --- a/arch/avr32/include/asm/global_data.h +++ b/arch/avr32/include/asm/global_data.h @@ -50,6 +50,7 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/avr32/lib/board.c b/arch/avr32/lib/board.c index 63fe297..8cb56df 100644 --- a/arch/avr32/lib/board.c +++ b/arch/avr32/lib/board.c @@ -149,6 +149,10 @@ void board_init_f(ulong board_type) memset(&gd_data, 0, sizeof(gd_data)); gd = &gd_data;
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + /* Perform initialization sequence */ board_early_init_f(); cpu_init(); diff --git a/arch/blackfin/include/asm/global_data.h b/arch/blackfin/include/asm/global_data.h index 67aa30f..33d3cec 100644 --- a/arch/blackfin/include/asm/global_data.h +++ b/arch/blackfin/include/asm/global_data.h @@ -59,6 +59,7 @@ typedef struct global_data {
void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/blackfin/lib/board.c b/arch/blackfin/lib/board.c index e3ee4cd..f8dade6 100644 --- a/arch/blackfin/lib/board.c +++ b/arch/blackfin/lib/board.c @@ -250,6 +250,10 @@ void board_init_f(ulong bootflag) bd->bi_memstart = CONFIG_SYS_SDRAM_BASE; bd->bi_memsize = CONFIG_SYS_MAX_RAM_SIZE;
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + /* Initialize */ serial_early_puts("IRQ init\n"); irq_init(); diff --git a/arch/m68k/include/asm/global_data.h b/arch/m68k/include/asm/global_data.h index 0ba2b43..ddd76f9 100644 --- a/arch/m68k/include/asm/global_data.h +++ b/arch/m68k/include/asm/global_data.h @@ -68,6 +68,7 @@ typedef struct global_data { #endif void **jt; /* Standalone app jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/m68k/lib/board.c b/arch/m68k/lib/board.c index 1526967..a420d21 100644 --- a/arch/m68k/lib/board.c +++ b/arch/m68k/lib/board.c @@ -227,6 +227,10 @@ board_init_f (ulong bootflag) /* Clear initial global data */ memset ((void *) gd, 0, sizeof (gd_t));
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) { hang (); diff --git a/arch/microblaze/include/asm/global_data.h b/arch/microblaze/include/asm/global_data.h index 6e8537c..4e340e6 100644 --- a/arch/microblaze/include/asm/global_data.h +++ b/arch/microblaze/include/asm/global_data.h @@ -47,6 +47,7 @@ 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. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/microblaze/lib/board.c b/arch/microblaze/lib/board.c index 9828b76..302a323 100644 --- a/arch/microblaze/lib/board.c +++ b/arch/microblaze/lib/board.c @@ -101,6 +101,11 @@ void board_init (void) asm ("nop"); /* FIXME gd is not initialize - wait */ memset ((void *)gd, 0, GENERATED_GBL_DATA_SIZE); memset ((void *)bd, 0, GENERATED_BD_INFO_SIZE); + + /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + gd->bd = bd; gd->baudrate = CONFIG_BAUDRATE; bd->bi_baudrate = CONFIG_BAUDRATE; diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h index f6cf9fe..9656fd6 100644 --- a/arch/mips/include/asm/global_data.h +++ b/arch/mips/include/asm/global_data.h @@ -61,6 +61,7 @@ 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. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/mips/lib/board.c b/arch/mips/lib/board.c index d998f0e..f40258c 100644 --- a/arch/mips/lib/board.c +++ b/arch/mips/lib/board.c @@ -160,6 +160,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) hang(); diff --git a/arch/nds32/include/asm/global_data.h b/arch/nds32/include/asm/global_data.h index de20a0a..313fecb 100644 --- a/arch/nds32/include/asm/global_data.h +++ b/arch/nds32/include/asm/global_data.h @@ -65,6 +65,7 @@ typedef struct global_data {
void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/nds32/lib/board.c b/arch/nds32/lib/board.c index 074aabf..34fff30 100644 --- a/arch/nds32/lib/board.c +++ b/arch/nds32/lib/board.c @@ -190,6 +190,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, GENERATED_GBL_DATA_SIZE);
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + gd->mon_len = (unsigned int)(&__bss_end__) - (unsigned int)(&_start);
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { diff --git a/arch/nios2/include/asm/global_data.h b/arch/nios2/include/asm/global_data.h index 4b86fbd..02f93d3 100644 --- a/arch/nios2/include/asm/global_data.h +++ b/arch/nios2/include/asm/global_data.h @@ -42,6 +42,7 @@ typedef struct global_data { #endif void **jt; /* Standalone app jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* flags */ diff --git a/arch/nios2/lib/board.c b/arch/nios2/lib/board.c index 65de26e..87e0559 100644 --- a/arch/nios2/lib/board.c +++ b/arch/nios2/lib/board.c @@ -97,6 +97,10 @@ void board_init (void)
memset( gd, 0, GENERATED_GBL_DATA_SIZE );
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + gd->bd = (bd_t *)(gd+1); /* At end of global data */ gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/openrisc/include/asm/global_data.h b/arch/openrisc/include/asm/global_data.h index 36de9d0..032b6b2 100644 --- a/arch/openrisc/include/asm/global_data.h +++ b/arch/openrisc/include/asm/global_data.h @@ -46,6 +46,7 @@ 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. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/openrisc/lib/board.c b/arch/openrisc/lib/board.c index 85aa189..2a92899 100644 --- a/arch/openrisc/lib/board.c +++ b/arch/openrisc/lib/board.c @@ -86,6 +86,10 @@ void board_init(void)
memset((void *)gd, 0, GENERATED_GBL_DATA_SIZE);
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + gd->bd = (bd_t *)(gd+1); /* At end of global data */ gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/powerpc/include/asm/global_data.h b/arch/powerpc/include/asm/global_data.h index 01f1d4a..0839d03 100644 --- a/arch/powerpc/include/asm/global_data.h +++ b/arch/powerpc/include/asm/global_data.h @@ -184,6 +184,7 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/powerpc/lib/board.c b/arch/powerpc/lib/board.c index 3f9af1d..ac88ae2 100644 --- a/arch/powerpc/lib/board.c +++ b/arch/powerpc/lib/board.c @@ -389,6 +389,10 @@ void board_init_f(ulong bootflag) memset((void *) gd, 0, sizeof(gd_t)); #endif
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) if ((*init_fnc_ptr) () != 0) hang(); diff --git a/arch/sandbox/include/asm/global_data.h b/arch/sandbox/include/asm/global_data.h index 8d47191..54342c0 100644 --- a/arch/sandbox/include/asm/global_data.h +++ b/arch/sandbox/include/asm/global_data.h @@ -47,6 +47,7 @@ typedef struct global_data { phys_size_t ram_size; /* RAM size */ void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/sandbox/lib/board.c b/arch/sandbox/lib/board.c index b7997e9..3d06cfc 100644 --- a/arch/sandbox/lib/board.c +++ b/arch/sandbox/lib/board.c @@ -156,6 +156,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) hang(); diff --git a/arch/sh/include/asm/global_data.h b/arch/sh/include/asm/global_data.h index 1b782fc..180f56e 100644 --- a/arch/sh/include/asm/global_data.h +++ b/arch/sh/include/asm/global_data.h @@ -42,6 +42,7 @@ 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. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */ diff --git a/arch/sparc/include/asm/global_data.h b/arch/sparc/include/asm/global_data.h index 613e2d8..82ed56f 100644 --- a/arch/sparc/include/asm/global_data.h +++ b/arch/sparc/include/asm/global_data.h @@ -76,6 +76,7 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/sparc/lib/board.c b/arch/sparc/lib/board.c index 519a4fb..86ee8db 100644 --- a/arch/sparc/lib/board.c +++ b/arch/sparc/lib/board.c @@ -179,6 +179,10 @@ void board_init_f(ulong bootflag) /* Clear initial global data */ memset((void *)gd, 0, sizeof(gd_t));
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + gd->bd = (bd_t *) (gd + 1); /* At end of global data */ gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 908a02c..171f85b 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -59,6 +59,7 @@ 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. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
static inline gd_t *get_fs_gd_ptr(void) diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index 5f0b62c..5ff4f42 100644 --- a/arch/x86/lib/board.c +++ b/arch/x86/lib/board.c @@ -220,6 +220,10 @@ void board_init_f(ulong boot_flags) { gd->flags = boot_flags;
+ /* Initialize early_malloc */ + DECLARE_EARLY_HEAP_ON_STACK; + early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE); + do_init_loop(init_sequence_f);
/* diff --git a/common/Makefile b/common/Makefile index 2a31c62..744beb8 100644 --- a/common/Makefile +++ b/common/Makefile @@ -188,6 +188,7 @@ COBJS-y += console.o COBJS-y += dlmalloc.o COBJS-y += memsize.o COBJS-y += stdio.o +COBJS-y += earlymalloc.o
COBJS := $(sort $(COBJS-y)) diff --git a/common/earlymalloc.c b/common/earlymalloc.c new file mode 100644 index 0000000..044b222 --- /dev/null +++ b/common/earlymalloc.c @@ -0,0 +1,91 @@ +/* + * (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 <earlymalloc.h> + +DECLARE_GLOBAL_DATA_PTR; + + +void early_heap_init(void *heap, size_t size) +{ + struct early_heap_header *h = heap; + + h->free_space_pointer = (void *)(roundup((phys_addr_t)heap + + sizeof(struct early_heap_header), + sizeof(phys_addr_t))); + h->free_bytes = size - roundup(sizeof(struct early_heap_header), + sizeof(phys_addr_t)); + h->next_early_heap = NULL; +} + +void *early_malloc(size_t size) +{ + phys_addr_t addr; + struct early_heap_header *h; + + /* Align size. */ + size = roundup(size, sizeof(phys_addr_t)); + + /* Choose early_heap with enough space. */ + h = gd->early_heap_first; + while ((h->free_bytes < size) && (h->next_early_heap != NULL)) + h = h->next_early_heap; + + if (h->free_bytes < size) { + debug("Early heap overflow. Heap %08lX, free %d, required %d.", + h, h->free_bytes, size); + return NULL; + } + + /* Choose block beginning address and mark next free space. */ + addr = h->free_space_pointer; + + h->free_space_pointer += size; + h->free_bytes -= size; + + return (void *)addr; +} + + +int early_malloc_isaddress(void *addr) +{ + if ((phys_addr_t)addr < (phys_addr_t)gd->early_heap_first) + return 0; + + if ((phys_addr_t)addr >= (phys_addr_t)gd->early_heap_first + + CONFIG_SYS_EARLY_HEAP_SIZE) + return 0; + + return 1; +} + +int early_malloc_finished(void) +{ + return gd->flags & GD_FLG_RELOC; +} + diff --git a/include/earlymalloc.h b/include/earlymalloc.h new file mode 100644 index 0000000..3b1fac2 --- /dev/null +++ b/include/earlymalloc.h @@ -0,0 +1,49 @@ +/* + * (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_EARLYMALLOC_H +#define __INCLUDE_EARLYMALLOC_H + +#include <linux/stddef.h> /* for size_t */ + +struct early_heap_header { + void *free_space_pointer; + size_t free_bytes; + void *next_early_heap; +}; + +void early_heap_init(void *heap, size_t size); +void *early_malloc(size_t size); +int early_malloc_isaddress(void *addr); +int early_malloc_finished(void); + +#ifndef CONFIG_SYS_EARLY_HEAP_SIZE +#define CONFIG_SYS_EARLY_HEAP_SIZE 256 +#endif /* CONFIG_SYS_EARLY_HEAP_SIZE */ + +#define DECLARE_EARLY_HEAP_ON_STACK char \ + __early_heap[CONFIG_SYS_EARLY_HEAP_SIZE]; \ + gd->early_heap_first = (void *)__early_heap + +#endif /* __INCLUDE_EARLYMALLOC_H */ +

Hi Tomas,
None of my example code is compile tested...
Regards,
Graeme
On Mon, Aug 27, 2012 at 10:42 PM, Tomas Hlavacek tmshlvck@gmail.com wrote:
Modular early_malloc for DM with support for more heaps and lightweight first heap on stack.
(Not intended for merging!)
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h index c3ff789..8563d49 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -84,6 +84,7 @@ 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
void *early_heap_first; /* early heap for early_malloc */
} gd_t;
Probably want to put an #ifdef CONFIG_SYS_EARLY_MALLOC around it. Also, it is a struct early_heap_header *
/* diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index 500e216..ad124c6 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -52,6 +52,7 @@ #include <fdtdec.h> #include <post.h> #include <logbuff.h> +#include <earlymalloc.h>
#ifdef CONFIG_BITBANGMII #include <miiphy.h> @@ -273,6 +274,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
/* Initialize early_malloc */
DECLARE_EARLY_HEAP_ON_STACK;
early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE);
I'm not a fan of burying the initialiser in a #define, and we already have a precedent of providing a hard-coded address for the chunk of memory (CONFIG_PRE_CON_BUF_ADDR)
diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index 5f0b62c..5ff4f42 100644 --- a/arch/x86/lib/board.c +++ b/arch/x86/lib/board.c @@ -220,6 +220,10 @@ void board_init_f(ulong boot_flags) { gd->flags = boot_flags;
/* Initialize early_malloc */
DECLARE_EARLY_HEAP_ON_STACK;
early_heap_init(gd->early_heap_first, CONFIG_SYS_EARLY_HEAP_SIZE);
do_init_loop(init_sequence_f); /*
early_heap_init() should be called via do_init_loop() - i.e. added to the top of the list and added in init_helpers.c
diff --git a/common/Makefile b/common/Makefile index 2a31c62..744beb8 100644 --- a/common/Makefile +++ b/common/Makefile @@ -188,6 +188,7 @@ COBJS-y += console.o COBJS-y += dlmalloc.o COBJS-y += memsize.o COBJS-y += stdio.o +COBJS-y += earlymalloc.o
Add the CONFIG_SYS_EARLY_MALLOC check here as well
COBJS := $(sort $(COBJS-y)) diff --git a/common/earlymalloc.c b/common/earlymalloc.c new file mode 100644 index 0000000..044b222 --- /dev/null +++ b/common/earlymalloc.c @@ -0,0 +1,91 @@ +/*
- (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 <earlymalloc.h>
+DECLARE_GLOBAL_DATA_PTR;
+void early_heap_init(void *heap, size_t size) +{
struct early_heap_header *h = heap;
h->free_space_pointer = (void *)(roundup((phys_addr_t)heap +
sizeof(struct early_heap_header),
sizeof(phys_addr_t)));
h->free_bytes = size - roundup(sizeof(struct early_heap_header),
sizeof(phys_addr_t));
h->next_early_heap = NULL;
+}
No need for this - see below for my prefered solution...
+void *early_malloc(size_t size) +{
phys_addr_t addr;
struct early_heap_header *h;
/* Align size. */
size = roundup(size, sizeof(phys_addr_t));
/* Choose early_heap with enough space. */
h = gd->early_heap_first;
while ((h->free_bytes < size) && (h->next_early_heap != NULL))
h = h->next_early_heap;
if (h->free_bytes < size) {
debug("Early heap overflow. Heap %08lX, free %d, required %d.",
h, h->free_bytes, size);
return NULL;
}
/* Choose block beginning address and mark next free space. */
addr = h->free_space_pointer;
h->free_space_pointer += size;
h->free_bytes -= size;
return (void *)addr;
+}
static struct early_heap_header *def_early_brk(size_t bytes) { struct early_heap_header *h;
if(gd->early_heap_first) return NULL;
/* The default implementation allocates all of the reserved space */ bytes = CONFIG_SYS_EARLY_HEAP_SIZE; gd->early_heap_first = bytes;
h = gd->early_heap_first;
h->free_space_pointer = (void *)(roundup((phys_addr_t)h + sizeof(struct early_heap_header), sizeof(phys_addr_t))); h->free_bytes = bytes - roundup(sizeof(struct early_heap_header), sizeof(phys_addr_t)); h->next_early_heap = NULL;
return h; } struct early_brk *early_brk(size_t bytes) __attribute__((weak, alias("def_early_brk")));
void *early_malloc(size_t size) { phys_addr_t addr; struct early_heap_header *h;
/* Align size. */ size = roundup(size, sizeof(phys_addr_t));
/* Find an early heap chunk with enough space. */ h = gd->early_heap_first; while (h && (h->free_bytes < size)) h = h->next_early_heap;
/* Initialise a new early heap chunk if required*/ if(!h) { h = early_brk(bytes);
if(!h) { debug("Out of early heap\n"); return NULL; } }
/* Choose block beginning address and mark next free space. */ addr = h->free_space_pointer;
h->free_space_pointer += size; h->free_bytes -= size;
return (void *)addr; }
+int early_malloc_isaddress(void *addr) +{
if ((phys_addr_t)addr < (phys_addr_t)gd->early_heap_first)
return 0;
if ((phys_addr_t)addr >= (phys_addr_t)gd->early_heap_first +
CONFIG_SYS_EARLY_HEAP_SIZE)
return 0;
return 1;
+}
I asked about this function before - it does not seem to serve any useful purpose. And even if it did, it does not scan through the chain of early malloc chunks
+int early_malloc_finished(void) +{
return gd->flags & GD_FLG_RELOC;
+}
Again, is this needed? It's not used yet, if it is needed, add it when it is and we can asses if this is the right approach then
diff --git a/include/earlymalloc.h b/include/earlymalloc.h new file mode 100644 index 0000000..3b1fac2 --- /dev/null +++ b/include/earlymalloc.h @@ -0,0 +1,49 @@ +/*
- (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_EARLYMALLOC_H +#define __INCLUDE_EARLYMALLOC_H
+#include <linux/stddef.h> /* for size_t */
+struct early_heap_header {
void *free_space_pointer;
size_t free_bytes;
void *next_early_heap;
+};
+void early_heap_init(void *heap, size_t size); +void *early_malloc(size_t size); +int early_malloc_isaddress(void *addr); +int early_malloc_finished(void);
+#ifndef CONFIG_SYS_EARLY_HEAP_SIZE +#define CONFIG_SYS_EARLY_HEAP_SIZE 256 +#endif /* CONFIG_SYS_EARLY_HEAP_SIZE */
+#define DECLARE_EARLY_HEAP_ON_STACK char \
__early_heap[CONFIG_SYS_EARLY_HEAP_SIZE]; \
gd->early_heap_first = (void *)__early_heap
+#endif /* __INCLUDE_EARLYMALLOC_H */
-- 1.7.10.4

Hi Tomas
static struct early_heap_header *def_early_brk(size_t bytes) { struct early_heap_header *h;
if(gd->early_heap_first) return NULL; /* The default implementation allocates all of the reserved space */ bytes = CONFIG_SYS_EARLY_HEAP_SIZE; gd->early_heap_first = bytes;
Oops
gd->early_heap_first = CONFIG_SYS_EARLY_HEAP_ADDR;
Regards,
Graeme

Hi Tomas,
Another small correction...
On Tue, Aug 28, 2012 at 9:02 AM, Graeme Russ graeme.russ@gmail.com wrote:
static struct early_heap_header *def_early_brk(size_t bytes) { struct early_heap_header *h;
if(gd->early_heap_first) return NULL; /* The default implementation allocates all of the reserved space */
if (bytes > (CONFIG_SYS_EARLY_HEAP_SIZE - roundup(sizeof(struct early_heap_header), sizeof(phys_addr_t)) return NULL;
bytes = CONFIG_SYS_EARLY_HEAP_SIZE; gd->early_heap_first = bytes; h = gd->early_heap_first; h->free_space_pointer = (void *)(roundup((phys_addr_t)h + sizeof(struct early_heap_header), sizeof(phys_addr_t))); h->free_bytes = bytes - roundup(sizeof(struct early_heap_header), sizeof(phys_addr_t)); h->next_early_heap = NULL; return h;
}
Regards,
Graeme

early_malloc for DM with support for more heaps and lightweight first heap on stack.
Adaptation layer for seamless calling of early_malloc or dlmalloc from DM based on init stage added (dmmalloc() and related functions).
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com --- arch/arm/include/asm/config.h | 3 + arch/arm/include/asm/global_data.h | 1 + arch/arm/lib/board.c | 7 ++ arch/avr32/include/asm/global_data.h | 1 + arch/avr32/lib/board.c | 6 ++ arch/blackfin/include/asm/global_data.h | 1 + arch/blackfin/lib/board.c | 7 ++ arch/m68k/include/asm/global_data.h | 1 + arch/m68k/lib/board.c | 7 ++ arch/microblaze/include/asm/global_data.h | 1 + arch/microblaze/lib/board.c | 8 ++ arch/mips/include/asm/global_data.h | 1 + arch/mips/lib/board.c | 7 ++ arch/nds32/include/asm/global_data.h | 1 + arch/nds32/lib/board.c | 6 ++ arch/nios2/include/asm/global_data.h | 1 + arch/nios2/lib/board.c | 6 ++ arch/openrisc/include/asm/global_data.h | 1 + arch/openrisc/lib/board.c | 6 ++ arch/powerpc/include/asm/global_data.h | 1 + arch/powerpc/lib/board.c | 6 ++ arch/sandbox/include/asm/global_data.h | 1 + arch/sandbox/lib/board.c | 6 ++ arch/sh/include/asm/global_data.h | 1 + arch/sh/lib/board.c | 6 ++ arch/sparc/include/asm/global_data.h | 1 + arch/sparc/lib/board.c | 6 ++ arch/x86/include/asm/global_data.h | 1 + arch/x86/lib/board.c | 14 ++++ common/Makefile | 1 + common/dmmalloc.c | 128 +++++++++++++++++++++++++++++ include/configs/zipitz2.h | 12 ++- include/dmmalloc.h | 51 ++++++++++++ 33 files changed, 306 insertions(+), 1 deletion(-) create mode 100644 common/dmmalloc.c create mode 100644 include/dmmalloc.h
diff --git a/arch/arm/include/asm/config.h b/arch/arm/include/asm/config.h index c60dba2..8e2f67b 100644 --- a/arch/arm/include/asm/config.h +++ b/arch/arm/include/asm/config.h @@ -23,4 +23,7 @@
#define CONFIG_LMB #define CONFIG_SYS_BOOT_RAMDISK_HIGH + +#define CONFIG_SYS_EARLY_MALLOC #endif + diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h index c3ff789..8563d49 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -84,6 +84,7 @@ 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 + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index 500e216..33e74da 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -52,6 +52,7 @@ #include <fdtdec.h> #include <post.h> #include <logbuff.h> +#include <dmmalloc.h>
#ifdef CONFIG_BITBANGMII #include <miiphy.h> @@ -273,6 +274,12 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+ +#ifdef CONFIG_SYS_EARLY_MALLOC + /* Initialize early_malloc */ + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->mon_len = _bss_end_ofs; #ifdef CONFIG_OF_EMBED /* Get a pointer to the FDT */ diff --git a/arch/avr32/include/asm/global_data.h b/arch/avr32/include/asm/global_data.h index 5c654bd..9ae7c5e 100644 --- a/arch/avr32/include/asm/global_data.h +++ b/arch/avr32/include/asm/global_data.h @@ -50,6 +50,7 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/avr32/lib/board.c b/arch/avr32/lib/board.c index 63fe297..6c97ef7 100644 --- a/arch/avr32/lib/board.c +++ b/arch/avr32/lib/board.c @@ -25,6 +25,7 @@ #include <stdio_dev.h> #include <version.h> #include <net.h> +#include <dmmalloc.h>
#ifdef CONFIG_BITBANGMII #include <miiphy.h> @@ -149,6 +150,11 @@ void board_init_f(ulong board_type) memset(&gd_data, 0, sizeof(gd_data)); gd = &gd_data;
+#ifdef CONFIG_SYS_EARLY_MALLOC + /* Initialize early_malloc */ + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + /* Perform initialization sequence */ board_early_init_f(); cpu_init(); diff --git a/arch/blackfin/include/asm/global_data.h b/arch/blackfin/include/asm/global_data.h index 67aa30f..33d3cec 100644 --- a/arch/blackfin/include/asm/global_data.h +++ b/arch/blackfin/include/asm/global_data.h @@ -59,6 +59,7 @@ typedef struct global_data {
void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/blackfin/lib/board.c b/arch/blackfin/lib/board.c index e3ee4cd..35257d7 100644 --- a/arch/blackfin/lib/board.c +++ b/arch/blackfin/lib/board.c @@ -24,6 +24,8 @@ #include <asm/mach-common/bits/mpu.h> #include <kgdb.h>
+#include <dmmalloc.h> + #ifdef CONFIG_CMD_NAND #include <nand.h> /* cannot even include nand.h if it isnt configured */ #endif @@ -250,6 +252,11 @@ void board_init_f(ulong bootflag) bd->bi_memstart = CONFIG_SYS_SDRAM_BASE; bd->bi_memsize = CONFIG_SYS_MAX_RAM_SIZE;
+#ifdef CONFIG_SYS_EARLY_MALLOC + /* Initialize early_malloc */ + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + /* Initialize */ serial_early_puts("IRQ init\n"); irq_init(); diff --git a/arch/m68k/include/asm/global_data.h b/arch/m68k/include/asm/global_data.h index 0ba2b43..ddd76f9 100644 --- a/arch/m68k/include/asm/global_data.h +++ b/arch/m68k/include/asm/global_data.h @@ -68,6 +68,7 @@ typedef struct global_data { #endif void **jt; /* Standalone app jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/m68k/lib/board.c b/arch/m68k/lib/board.c index 1526967..7ee7830 100644 --- a/arch/m68k/lib/board.c +++ b/arch/m68k/lib/board.c @@ -30,6 +30,8 @@ #include <malloc.h> #include <stdio_dev.h>
+#include <dmmalloc.h> + #include <asm/immap.h>
#if defined(CONFIG_CMD_IDE) @@ -227,6 +229,11 @@ board_init_f (ulong bootflag) /* Clear initial global data */ memset ((void *) gd, 0, sizeof (gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + /* Initialize early_malloc */ + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) { hang (); diff --git a/arch/microblaze/include/asm/global_data.h b/arch/microblaze/include/asm/global_data.h index 6e8537c..4e340e6 100644 --- a/arch/microblaze/include/asm/global_data.h +++ b/arch/microblaze/include/asm/global_data.h @@ -47,6 +47,7 @@ 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. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/microblaze/lib/board.c b/arch/microblaze/lib/board.c index 9828b76..a60e36f 100644 --- a/arch/microblaze/lib/board.c +++ b/arch/microblaze/lib/board.c @@ -33,6 +33,8 @@ #include <net.h> #include <asm/processor.h>
+#include <dmmalloc.h> + DECLARE_GLOBAL_DATA_PTR;
#ifdef CONFIG_SYS_GPIO_0 @@ -101,6 +103,12 @@ void board_init (void) asm ("nop"); /* FIXME gd is not initialize - wait */ memset ((void *)gd, 0, GENERATED_GBL_DATA_SIZE); memset ((void *)bd, 0, GENERATED_BD_INFO_SIZE); + +#ifdef CONFIG_SYS_EARLY_MALLOC + /* Initialize early_malloc */ + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = bd; gd->baudrate = CONFIG_BAUDRATE; bd->bi_baudrate = CONFIG_BAUDRATE; diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h index f6cf9fe..9656fd6 100644 --- a/arch/mips/include/asm/global_data.h +++ b/arch/mips/include/asm/global_data.h @@ -61,6 +61,7 @@ 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. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/mips/lib/board.c b/arch/mips/lib/board.c index d998f0e..d2349bf 100644 --- a/arch/mips/lib/board.c +++ b/arch/mips/lib/board.c @@ -32,6 +32,8 @@ #include <onenand_uboot.h> #include <spi.h>
+#include <dmmalloc.h> + #ifdef CONFIG_BITBANGMII #include <miiphy.h> #endif @@ -160,6 +162,11 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + /* Initialize early_malloc */ + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) hang(); diff --git a/arch/nds32/include/asm/global_data.h b/arch/nds32/include/asm/global_data.h index de20a0a..313fecb 100644 --- a/arch/nds32/include/asm/global_data.h +++ b/arch/nds32/include/asm/global_data.h @@ -65,6 +65,7 @@ typedef struct global_data {
void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/nds32/lib/board.c b/arch/nds32/lib/board.c index 074aabf..952fc1f 100644 --- a/arch/nds32/lib/board.c +++ b/arch/nds32/lib/board.c @@ -36,6 +36,7 @@ #include <nand.h> #include <onenand_uboot.h> #include <mmc.h> +#include <dmmalloc.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -190,6 +191,11 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, GENERATED_GBL_DATA_SIZE);
+#ifdef CONFIG_SYS_EARLY_MALLOC + /* Initialize early_malloc */ + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->mon_len = (unsigned int)(&__bss_end__) - (unsigned int)(&_start);
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { diff --git a/arch/nios2/include/asm/global_data.h b/arch/nios2/include/asm/global_data.h index 4b86fbd..02f93d3 100644 --- a/arch/nios2/include/asm/global_data.h +++ b/arch/nios2/include/asm/global_data.h @@ -42,6 +42,7 @@ typedef struct global_data { #endif void **jt; /* Standalone app jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* flags */ diff --git a/arch/nios2/lib/board.c b/arch/nios2/lib/board.c index 65de26e..8a65c2e 100644 --- a/arch/nios2/lib/board.c +++ b/arch/nios2/lib/board.c @@ -30,6 +30,7 @@ #include <malloc.h> #include <mmc.h> #include <net.h> +#include <dmmalloc.h> #ifdef CONFIG_STATUS_LED #include <status_led.h> #endif @@ -97,6 +98,11 @@ void board_init (void)
memset( gd, 0, GENERATED_GBL_DATA_SIZE );
+#ifdef CONFIG_SYS_EARLY_MALLOC + /* Initialize early_malloc */ + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = (bd_t *)(gd+1); /* At end of global data */ gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/openrisc/include/asm/global_data.h b/arch/openrisc/include/asm/global_data.h index 36de9d0..032b6b2 100644 --- a/arch/openrisc/include/asm/global_data.h +++ b/arch/openrisc/include/asm/global_data.h @@ -46,6 +46,7 @@ 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. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/openrisc/lib/board.c b/arch/openrisc/lib/board.c index 85aa189..30fca25 100644 --- a/arch/openrisc/lib/board.c +++ b/arch/openrisc/lib/board.c @@ -34,6 +34,7 @@ #include <malloc.h> #include <mmc.h> #include <net.h> +#include <dmmalloc.h> #ifdef CONFIG_STATUS_LED #include <status_led.h> #endif @@ -86,6 +87,11 @@ void board_init(void)
memset((void *)gd, 0, GENERATED_GBL_DATA_SIZE);
+#ifdef CONFIG_SYS_EARLY_MALLOC + /* Initialize early_malloc */ + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = (bd_t *)(gd+1); /* At end of global data */ gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/powerpc/include/asm/global_data.h b/arch/powerpc/include/asm/global_data.h index 01f1d4a..0839d03 100644 --- a/arch/powerpc/include/asm/global_data.h +++ b/arch/powerpc/include/asm/global_data.h @@ -184,6 +184,7 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/powerpc/lib/board.c b/arch/powerpc/lib/board.c index 3f9af1d..41ee9db 100644 --- a/arch/powerpc/lib/board.c +++ b/arch/powerpc/lib/board.c @@ -26,6 +26,7 @@ #include <command.h> #include <malloc.h> #include <stdio_dev.h> +#include <dmmalloc.h> #ifdef CONFIG_8xx #include <mpc8xx.h> #endif @@ -389,6 +390,11 @@ void board_init_f(ulong bootflag) memset((void *) gd, 0, sizeof(gd_t)); #endif
+#ifdef CONFIG_SYS_EARLY_MALLOC + /* Initialize early_malloc */ + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) if ((*init_fnc_ptr) () != 0) hang(); diff --git a/arch/sandbox/include/asm/global_data.h b/arch/sandbox/include/asm/global_data.h index 8d47191..54342c0 100644 --- a/arch/sandbox/include/asm/global_data.h +++ b/arch/sandbox/include/asm/global_data.h @@ -47,6 +47,7 @@ typedef struct global_data { phys_size_t ram_size; /* RAM size */ void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/sandbox/lib/board.c b/arch/sandbox/lib/board.c index b7997e9..055e493 100644 --- a/arch/sandbox/lib/board.c +++ b/arch/sandbox/lib/board.c @@ -44,6 +44,7 @@ #include <timestamp.h> #include <version.h> #include <serial.h> +#include <dmmalloc.h>
#include <os.h>
@@ -156,6 +157,11 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + /* Initialize early_malloc */ + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) hang(); diff --git a/arch/sh/include/asm/global_data.h b/arch/sh/include/asm/global_data.h index 1b782fc..180f56e 100644 --- a/arch/sh/include/asm/global_data.h +++ b/arch/sh/include/asm/global_data.h @@ -42,6 +42,7 @@ 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. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */ diff --git a/arch/sh/lib/board.c b/arch/sh/lib/board.c index d9c0c22..7d334f4 100644 --- a/arch/sh/lib/board.c +++ b/arch/sh/lib/board.c @@ -26,6 +26,7 @@ #include <watchdog.h> #include <net.h> #include <environment.h> +#include <dmmalloc.h>
#ifdef CONFIG_BITBANGMII #include <miiphy.h> @@ -160,6 +161,11 @@ void sh_generic_init(void)
memset(gd, 0, GENERATED_GBL_DATA_SIZE);
+#ifdef CONFIG_SYS_EARLY_MALLOC + /* Initialize early_malloc */ + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */
gd->bd = (bd_t *)(gd + 1); /* At end of global data */ diff --git a/arch/sparc/include/asm/global_data.h b/arch/sparc/include/asm/global_data.h index 613e2d8..82ed56f 100644 --- a/arch/sparc/include/asm/global_data.h +++ b/arch/sparc/include/asm/global_data.h @@ -76,6 +76,7 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
/* diff --git a/arch/sparc/lib/board.c b/arch/sparc/lib/board.c index 519a4fb..3421412 100644 --- a/arch/sparc/lib/board.c +++ b/arch/sparc/lib/board.c @@ -30,6 +30,7 @@ #include <malloc.h> #include <stdio_dev.h> #include <config.h> +#include <dmmalloc.h> #if defined(CONFIG_CMD_IDE) #include <ide.h> #endif @@ -179,6 +180,11 @@ void board_init_f(ulong bootflag) /* Clear initial global data */ memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + /* Initialize early_malloc */ + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = (bd_t *) (gd + 1); /* At end of global data */ gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 908a02c..171f85b 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -59,6 +59,7 @@ 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. */ + void *early_heap_first; /* early heap for early_malloc */ } gd_t;
static inline gd_t *get_fs_gd_ptr(void) diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index 5f0b62c..b609dbe 100644 --- a/arch/x86/lib/board.c +++ b/arch/x86/lib/board.c @@ -40,6 +40,8 @@ #include <asm/init_helpers.h> #include <asm/init_wrappers.h>
+#include <dmmalloc.h> + /* * Breath some life into the board... * @@ -85,6 +87,17 @@ typedef int (init_fnc_t) (void);
/* + * Initialize early heap (when enabled by config). + */ +static void early_malloc_init(void) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC + /* Initialize early_malloc */ + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ +} + +/* * init_sequence_f is the list of init functions which are run when U-Boot * is executing from Flash with a limited 'C' environment. The following * limitations must be considered when implementing an '_f' function: @@ -99,6 +112,7 @@ init_fnc_t *init_sequence_f[] = { cpu_init_f, board_early_init_f, env_init, + early_malloc_init, init_baudrate_f, serial_init, console_init_f, diff --git a/common/Makefile b/common/Makefile index 2a31c62..dfea4e8 100644 --- a/common/Makefile +++ b/common/Makefile @@ -188,6 +188,7 @@ COBJS-y += console.o COBJS-y += dlmalloc.o COBJS-y += memsize.o COBJS-y += stdio.o +COBJS-y += dmmalloc.o
COBJS := $(sort $(COBJS-y)) diff --git a/common/dmmalloc.c b/common/dmmalloc.c new file mode 100644 index 0000000..18f2d95 --- /dev/null +++ b/common/dmmalloc.c @@ -0,0 +1,128 @@ +/* + * (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> + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_SYS_EARLY_MALLOC +static struct early_heap_header *def_early_brk(size_t size) +{ + struct early_heap_header *h = + (struct early_heap_header *)CONFIG_SYS_EARLY_HEAP_ADDR; + + h->free_space_pointer = (void *)(roundup( + (phys_addr_t)CONFIG_SYS_EARLY_HEAP_ADDR + + sizeof(struct early_heap_header), + sizeof(phys_addr_t))); + h->free_bytes = size - roundup(sizeof(struct early_heap_header), + sizeof(phys_addr_t)); + h->next_early_heap = NULL; + + return h; +} + +struct early_heap_header *early_brk(size_t size) + __attribute__((weak, alias("def_early_brk"))); + + +void *early_malloc(size_t size) +{ + phys_addr_t addr; + struct early_heap_header *h; + + /* Align size. */ + size = roundup(size, sizeof(phys_addr_t)); + + /* Choose early_heap with enough space. */ + h = gd->early_heap_first; + while ((h->free_bytes < size) && (h->next_early_heap != NULL)) + h = h->next_early_heap; + + if (h->free_bytes < size) { + debug("Early heap overflow. Heap %p, free %d, required %d.", + h, h->free_bytes, size); + return NULL; + } + + /* Choose block beginning address and mark next free space. */ + addr = (phys_addr_t)h->free_space_pointer; + + h->free_space_pointer += size; + h->free_bytes -= size; + + return (void *)addr; +} + +static int is_early_malloc_active(void) +{ + if (gd->flags & GD_FLG_RELOC) + return 0; + + return 1; +} + +#endif /* CONFIG_SYS_EARLY_MALLOC */ + +void *dmmalloc(size_t size) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC + if (is_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 (is_early_malloc_active()) + return; +#endif /* CONFIG_SYS_EARLY_MALLOC */ + free(ptr); +} + +void *dmcalloc(size_t n, size_t elem_size) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC + if (is_early_malloc_active()) + return NULL; +#endif /* CONFIG_SYS_EARLY_MALLOC */ + return calloc(n, elem_size); +} + +void *dmrealloc(void *oldmem, size_t bytes) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC + if (is_early_malloc_active()) + return NULL; +#endif /* CONFIG_SYS_EARLY_MALLOC */ + return dmrealloc(oldmem, bytes); +} + diff --git a/include/configs/zipitz2.h b/include/configs/zipitz2.h index 26204af..5cd0dcb 100644 --- a/include/configs/zipitz2.h +++ b/include/configs/zipitz2.h @@ -176,8 +176,13 @@ unsigned char zipitz2_spi_read(void);
#define CONFIG_SYS_LOAD_ADDR CONFIG_SYS_DRAM_BASE
+#define CONFIG_SYS_EARLY_HEAP_ADDR (GENERATED_GBL_DATA_SIZE + \ + PHYS_SDRAM_1) +#define CONFIG_SYS_EARLY_HEAP_SIZE 256 + #define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1 -#define CONFIG_SYS_INIT_SP_ADDR (GENERATED_GBL_DATA_SIZE + PHYS_SDRAM_1 + 2048) +#define CONFIG_SYS_INIT_SP_ADDR (GENERATED_GBL_DATA_SIZE + \ + CONFIG_SYS_EARLY_HEAP_SIZE + PHYS_SDRAM_1 + 2048)
/* * NOR FLASH @@ -260,4 +265,9 @@ unsigned char zipitz2_spi_read(void); #define CONFIG_SYS_MCIO0_VAL 0x0001430f #define CONFIG_SYS_MCIO1_VAL 0x0001430f
+/* + * DM components + */ +#define CONFIG_SYS_EARLY_MALLOC + #endif /* __CONFIG_H */ diff --git a/include/dmmalloc.h b/include/dmmalloc.h new file mode 100644 index 0000000..01beea7 --- /dev/null +++ b/include/dmmalloc.h @@ -0,0 +1,51 @@ +/* + * (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 */ + +#if (!defined(CONFIG_SYS_EARLY_HEAP_ADDR)) || \ + (!defined(CONFIG_SYS_EARLY_HEAP_SIZE)) +#undef CONFIG_SYS_EARLY_MALLOC +#endif /* CONFIG_SYS_EARLY_HEAP_ADDR */ + +#ifdef CONFIG_SYS_EARLY_MALLOC +struct early_heap_header { + void *free_space_pointer; + size_t free_bytes; + void *next_early_heap; +}; + +struct early_heap_header *early_brk(size_t size); +void *early_malloc(size_t size); + +#endif /* CONFIG_SYS_EARLY_MALLOC */ + +void *dmmalloc(size_t size); +void dmfree(void *ptr); + +#endif /* __INCLUDE_DMMALLOC_H */ +

Dear Tomas Hlavacek,
early_malloc for DM with support for more heaps and lightweight first heap on stack.
Adaptation layer for seamless calling of early_malloc or dlmalloc from DM based on init stage added (dmmalloc() and related functions).
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com
It looks mostly OK, few comments
I'd say, pull out the modification of global data into separate patch and put it before this patch. That'd make review of the core code much easier.
[...]
+#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>
+DECLARE_GLOBAL_DATA_PTR;
+#ifdef CONFIG_SYS_EARLY_MALLOC +static struct early_heap_header *def_early_brk(size_t size) +{
- struct early_heap_header *h =
(struct early_heap_header *)CONFIG_SYS_EARLY_HEAP_ADDR;
- h->free_space_pointer = (void *)(roundup(
(phys_addr_t)CONFIG_SYS_EARLY_HEAP_ADDR +
sizeof(struct early_heap_header),
sizeof(phys_addr_t)));
- h->free_bytes = size - roundup(sizeof(struct early_heap_header),
sizeof(phys_addr_t));
- h->next_early_heap = NULL;
- return h;
+}
+struct early_heap_header *early_brk(size_t size)
- __attribute__((weak, alias("def_early_brk")));
what about using (it needs <linux/compiler.h>):
__weak struct early_heap_header *early_brk(size_t size) { ... body ... }
+void *early_malloc(size_t size) +{
- phys_addr_t addr;
- struct early_heap_header *h;
- /* Align size. */
- size = roundup(size, sizeof(phys_addr_t));
- /* Choose early_heap with enough space. */
- h = gd->early_heap_first;
- while ((h->free_bytes < size) && (h->next_early_heap != NULL))
h = h->next_early_heap;
- if (h->free_bytes < size) {
debug("Early heap overflow. Heap %p, free %d, required %d.",
h, h->free_bytes, size);
return NULL;
- }
- /* Choose block beginning address and mark next free space. */
- addr = (phys_addr_t)h->free_space_pointer;
- h->free_space_pointer += size;
- h->free_bytes -= size;
- return (void *)addr;
+}
+static int is_early_malloc_active(void) +{
- if (gd->flags & GD_FLG_RELOC)
return 0;
- return 1;
+}
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+void *dmmalloc(size_t size) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC
- if (is_early_malloc_active())
return early_malloc(size);
+#endif /* CONFIG_SYS_EARLY_MALLOC */
Or you can implement empty prototypes for these functions in case CONFIG_SYS ... isn't defined to punt this preprocessor bloat.
- return malloc(size);
+}
[...]
diff --git a/include/configs/zipitz2.h b/include/configs/zipitz2.h index 26204af..5cd0dcb 100644 --- a/include/configs/zipitz2.h +++ b/include/configs/zipitz2.h @@ -176,8 +176,13 @@ unsigned char zipitz2_spi_read(void);
#define CONFIG_SYS_LOAD_ADDR CONFIG_SYS_DRAM_BASE
+#define CONFIG_SYS_EARLY_HEAP_ADDR (GENERATED_GBL_DATA_SIZE + \
- PHYS_SDRAM_1)
+#define CONFIG_SYS_EARLY_HEAP_SIZE 256
1) Pull this file into separate patch and order it afterwards this patch. 2) You're putting your early thingie into SDRAM, which works on PXA (sadly) ... looking through the PXA init code, it needs cleanup, damn
... there's no real hint so far, just a rant.
#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1 -#define CONFIG_SYS_INIT_SP_ADDR (GENERATED_GBL_DATA_SIZE +
PHYS_SDRAM_1 +
- +#define CONFIG_SYS_INIT_SP_ADDR (GENERATED_GBL_DATA_SIZE
+ \
- CONFIG_SYS_EARLY_HEAP_SIZE + PHYS_SDRAM_1 + 2048)
/*
- NOR FLASH
@@ -260,4 +265,9 @@ unsigned char zipitz2_spi_read(void); #define CONFIG_SYS_MCIO0_VAL 0x0001430f #define CONFIG_SYS_MCIO1_VAL 0x0001430f
[...]

Hi Marek,
On Tue, Sep 18, 2012 at 8:57 PM, Marek Vasut marex@denx.de wrote:
Dear Tomas Hlavacek,
early_malloc for DM with support for more heaps and lightweight first heap on stack.
Adaptation layer for seamless calling of early_malloc or dlmalloc from DM based on init stage added (dmmalloc() and related functions).
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com
It looks mostly OK, few comments
I'd say, pull out the modification of global data into separate patch and put it before this patch. That'd make review of the core code much easier.
NAK - The addition of the global data member is intrinsic to the early malloc implmentaion. Keep them together
[...]
+#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>
+DECLARE_GLOBAL_DATA_PTR;
+#ifdef CONFIG_SYS_EARLY_MALLOC +static struct early_heap_header *def_early_brk(size_t size) +{
struct early_heap_header *h =
(struct early_heap_header *)CONFIG_SYS_EARLY_HEAP_ADDR;
h->free_space_pointer = (void *)(roundup(
(phys_addr_t)CONFIG_SYS_EARLY_HEAP_ADDR +
sizeof(struct early_heap_header),
sizeof(phys_addr_t)));
h->free_bytes = size - roundup(sizeof(struct early_heap_header),
sizeof(phys_addr_t));
h->next_early_heap = NULL;
return h;
+}
+struct early_heap_header *early_brk(size_t size)
__attribute__((weak, alias("def_early_brk")));
what about using (it needs <linux/compiler.h>):
__weak struct early_heap_header *early_brk(size_t size) { ... body ... }
We already have a lot of the former - I prefer not to add additional semantics (unless you want to do a wholesale search/replace ;))
+void *dmmalloc(size_t size) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC
if (is_early_malloc_active())
return early_malloc(size);
+#endif /* CONFIG_SYS_EARLY_MALLOC */
Or you can implement empty prototypes for these functions in case CONFIG_SYS ... isn't defined to punt this preprocessor bloat.
Agree
return malloc(size);
+}
[...]
diff --git a/include/configs/zipitz2.h b/include/configs/zipitz2.h index 26204af..5cd0dcb 100644 --- a/include/configs/zipitz2.h +++ b/include/configs/zipitz2.h @@ -176,8 +176,13 @@ unsigned char zipitz2_spi_read(void);
#define CONFIG_SYS_LOAD_ADDR CONFIG_SYS_DRAM_BASE
+#define CONFIG_SYS_EARLY_HEAP_ADDR (GENERATED_GBL_DATA_SIZE + \
PHYS_SDRAM_1)
+#define CONFIG_SYS_EARLY_HEAP_SIZE 256
- Pull this file into separate patch and order it afterwards this patch.
Already agreed :)
Regards,
Graeme

Dear Graeme Russ,
Hi Marek,
On Tue, Sep 18, 2012 at 8:57 PM, Marek Vasut marex@denx.de wrote:
Dear Tomas Hlavacek,
early_malloc for DM with support for more heaps and lightweight first heap on stack.
Adaptation layer for seamless calling of early_malloc or dlmalloc from DM based on init stage added (dmmalloc() and related functions).
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com
It looks mostly OK, few comments
I'd say, pull out the modification of global data into separate patch and put it before this patch. That'd make review of the core code much easier.
NAK - The addition of the global data member is intrinsic to the early malloc implmentaion. Keep them together
Very pleasant to review too, I almost didn't manage to find the core dmmalloc code in all that bloat.
[...]
+#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>
+DECLARE_GLOBAL_DATA_PTR;
+#ifdef CONFIG_SYS_EARLY_MALLOC +static struct early_heap_header *def_early_brk(size_t size) +{
struct early_heap_header *h =
(struct early_heap_header *)CONFIG_SYS_EARLY_HEAP_ADDR;
h->free_space_pointer = (void *)(roundup(
(phys_addr_t)CONFIG_SYS_EARLY_HEAP_ADDR +
sizeof(struct early_heap_header),
sizeof(phys_addr_t)));
h->free_bytes = size - roundup(sizeof(struct early_heap_header),
sizeof(phys_addr_t));
h->next_early_heap = NULL;
return h;
+}
+struct early_heap_header *early_brk(size_t size)
__attribute__((weak, alias("def_early_brk")));
what about using (it needs <linux/compiler.h>):
__weak struct early_heap_header *early_brk(size_t size) { ... body ... }
We already have a lot of the former - I prefer not to add additional semantics (unless you want to do a wholesale search/replace ;))
The former looks like shit and the later is more linux-friendly. I'd say stick with the later to avoid this insane __attribute__(()) construct.
+void *dmmalloc(size_t size) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC
if (is_early_malloc_active())
return early_malloc(size);
+#endif /* CONFIG_SYS_EARLY_MALLOC */
Or you can implement empty prototypes for these functions in case CONFIG_SYS ... isn't defined to punt this preprocessor bloat.
Agree
return malloc(size);
+}
[...]
diff --git a/include/configs/zipitz2.h b/include/configs/zipitz2.h index 26204af..5cd0dcb 100644 --- a/include/configs/zipitz2.h +++ b/include/configs/zipitz2.h @@ -176,8 +176,13 @@ unsigned char zipitz2_spi_read(void);
#define CONFIG_SYS_LOAD_ADDR CONFIG_SYS_DRAM_BASE
+#define CONFIG_SYS_EARLY_HEAP_ADDR (GENERATED_GBL_DATA_SIZE + \
PHYS_SDRAM_1)
+#define CONFIG_SYS_EARLY_HEAP_SIZE 256
- Pull this file into separate patch and order it afterwards this patch.
Already agreed :)
Regards,
Graeme
Best regards, Marek Vasut

Hi Marek,
On Wed, Sep 19, 2012 at 9:33 AM, Marek Vasut marex@denx.de wrote:
Dear Graeme Russ,
[snip]
+struct early_heap_header *early_brk(size_t size)
__attribute__((weak, alias("def_early_brk")));
what about using (it needs <linux/compiler.h>):
__weak struct early_heap_header *early_brk(size_t size) { ... body ... }
We already have a lot of the former - I prefer not to add additional semantics (unless you want to do a wholesale search/replace ;))
The former looks like shit and the later is more linux-friendly. I'd say stick with the later to avoid this insane __attribute__(()) construct.
I agree, but, consistently bad is worse than inconsistently bad :)
I'm look forward to reviewing a cleanup patch ;)
Regards,
Graeme

Dear Graeme Russ,
Hi Marek,
On Wed, Sep 19, 2012 at 9:33 AM, Marek Vasut marex@denx.de wrote:
Dear Graeme Russ,
[snip]
+struct early_heap_header *early_brk(size_t size)
__attribute__((weak, alias("def_early_brk")));
what about using (it needs <linux/compiler.h>):
__weak struct early_heap_header *early_brk(size_t size) { ... body ... }
We already have a lot of the former - I prefer not to add additional semantics (unless you want to do a wholesale search/replace ;))
The former looks like shit and the later is more linux-friendly. I'd say stick with the later to avoid this insane __attribute__(()) construct.
I agree, but, consistently bad is worse than inconsistently bad :)
To weed out the old crap, we need linux/compiler.h enabled across whole uboot ... it's in the todo.
I'm look forward to reviewing a cleanup patch ;)
Wait until I get it completely built. linux/compiler.h causes breakage on some ancient PPC crap.
Regards,
Graeme
Best regards, Marek Vasut

On Wed, Sep 19, 2012 at 09:29:04AM +1000, Graeme Russ wrote:
Hi Marek,
On Tue, Sep 18, 2012 at 8:57 PM, Marek Vasut marex@denx.de wrote:
Dear Tomas Hlavacek,
[snip]
+struct early_heap_header *early_brk(size_t size)
__attribute__((weak, alias("def_early_brk")));
what about using (it needs <linux/compiler.h>):
__weak struct early_heap_header *early_brk(size_t size) { ... body ... }
We already have a lot of the former - I prefer not to add additional semantics (unless you want to do a wholesale search/replace ;))
Migrating everyone but the real tricky uses (alias >=2 functions to one weak dummy) to the <linux/compiler.h> semantics is something on my TODO list from ages ago. So yes please, unless it's a complex case, find and use the __shortform that <linux/compiler.h> and company provide (and a git grep for your attribute when in doubt, sometimes it's in <linux/compiler-gcc.h or so).
And a general I know everyone should know but please, checkpatch.pl your work before posting. Getting everyone doing DM series patches to use patman might be a little bit more overhead (sorry!) but it'll help with a lot of the little things like formatting and some of the bigger things like changelog tracking. Don't have to switch but it might make your lives easier.

Hello all,
I have sent a new version. Although I tried to take into account all the opinions and comments I might have missed something.
On Wed, Sep 19, 2012 at 1:29 AM, Graeme Russ graeme.russ@gmail.com wrote:
I'd say, pull out the modification of global data into separate patch and put it before this patch. That'd make review of the core code much easier.
NAK - The addition of the global data member is intrinsic to the early malloc implmentaion. Keep them together
Yes, I think that in this case one does not make sense with the other. I kept them rather together.
+struct early_heap_header *early_brk(size_t size)
__attribute__((weak, alias("def_early_brk")));
what about using (it needs <linux/compiler.h>):
__weak struct early_heap_header *early_brk(size_t size) { ... body ... }
We already have a lot of the former - I prefer not to add additional semantics (unless you want to do a wholesale search/replace ;))
This time I used the shorter / newer variant. Hope this would be better.
Tomas

Hi Tomas
On Tue, Sep 18, 2012 at 5:13 PM, Tomas Hlavacek tmshlvck@gmail.com wrote:
early_malloc for DM with support for more heaps and lightweight first heap on stack.
Technically, you are not putting the first heap on the stack - you are sacrificing some early stack space to create the early heap
Adaptation layer for seamless calling of early_malloc or dlmalloc from DM based on init stage added (dmmalloc() and related functions).
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com
arch/arm/include/asm/config.h | 3 + arch/arm/include/asm/global_data.h | 1 + arch/arm/lib/board.c | 7 ++ arch/avr32/include/asm/global_data.h | 1 + arch/avr32/lib/board.c | 6 ++ arch/blackfin/include/asm/global_data.h | 1 + arch/blackfin/lib/board.c | 7 ++ arch/m68k/include/asm/global_data.h | 1 + arch/m68k/lib/board.c | 7 ++ arch/microblaze/include/asm/global_data.h | 1 + arch/microblaze/lib/board.c | 8 ++ arch/mips/include/asm/global_data.h | 1 + arch/mips/lib/board.c | 7 ++ arch/nds32/include/asm/global_data.h | 1 + arch/nds32/lib/board.c | 6 ++ arch/nios2/include/asm/global_data.h | 1 + arch/nios2/lib/board.c | 6 ++ arch/openrisc/include/asm/global_data.h | 1 + arch/openrisc/lib/board.c | 6 ++ arch/powerpc/include/asm/global_data.h | 1 + arch/powerpc/lib/board.c | 6 ++ arch/sandbox/include/asm/global_data.h | 1 + arch/sandbox/lib/board.c | 6 ++ arch/sh/include/asm/global_data.h | 1 + arch/sh/lib/board.c | 6 ++ arch/sparc/include/asm/global_data.h | 1 + arch/sparc/lib/board.c | 6 ++ arch/x86/include/asm/global_data.h | 1 + arch/x86/lib/board.c | 14 ++++ common/Makefile | 1 + common/dmmalloc.c | 128 +++++++++++++++++++++++++++++ include/configs/zipitz2.h | 12 ++-
WTF! - Move this out into another patch
include/dmmalloc.h | 51 ++++++++++++ 33 files changed, 306 insertions(+), 1 deletion(-) create mode 100644 common/dmmalloc.c create mode 100644 include/dmmalloc.h
diff --git a/arch/arm/include/asm/config.h b/arch/arm/include/asm/config.h index c60dba2..8e2f67b 100644 --- a/arch/arm/include/asm/config.h +++ b/arch/arm/include/asm/config.h @@ -23,4 +23,7 @@
#define CONFIG_LMB #define CONFIG_SYS_BOOT_RAMDISK_HIGH
+#define CONFIG_SYS_EARLY_MALLOC #endif
Why are you adding this define to ARM and nothing else? Shouldn't it be an all-in or none-in proposition?
(and why the stray eol white-space?)
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h index c3ff789..8563d49 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -84,6 +84,7 @@ 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
void *early_heap_first; /* early heap for early_malloc */
} gd_t;
early_heap_first is only used if CONFIG_SYS_EARLY_MALLOC is defined, so wrap a #ifdef around it. This will also help to detect unintended usage if CONFIG_SYS_EARLY_MALLOC is not defined.
/* diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index 500e216..33e74da 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -52,6 +52,7 @@ #include <fdtdec.h> #include <post.h> #include <logbuff.h> +#include <dmmalloc.h>
#ifdef CONFIG_BITBANGMII #include <miiphy.h> @@ -273,6 +274,12 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC
/* Initialize early_malloc */
gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE);
+#endif /* CONFIG_SYS_EARLY_MALLOC */
Did you checkpatch? You've added an additional blank line (for a total of two)
[snip]
diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index 5f0b62c..b609dbe 100644 --- a/arch/x86/lib/board.c +++ b/arch/x86/lib/board.c @@ -40,6 +40,8 @@ #include <asm/init_helpers.h> #include <asm/init_wrappers.h>
+#include <dmmalloc.h>
/*
- Breath some life into the board...
@@ -85,6 +87,17 @@ typedef int (init_fnc_t) (void);
/*
- Initialize early heap (when enabled by config).
- */
+static void early_malloc_init(void) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC
/* Initialize early_malloc */
gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE);
+#endif /* CONFIG_SYS_EARLY_MALLOC */ +}
+/*
- init_sequence_f is the list of init functions which are run when U-Boot
- is executing from Flash with a limited 'C' environment. The following
- limitations must be considered when implementing an '_f' function:
@@ -99,6 +112,7 @@ init_fnc_t *init_sequence_f[] = { cpu_init_f, board_early_init_f, env_init,
early_malloc_init,
Put the #ifdef here - gc_sections will clean up the unused function
init_baudrate_f, serial_init, console_init_f,
diff --git a/common/Makefile b/common/Makefile index 2a31c62..dfea4e8 100644 --- a/common/Makefile +++ b/common/Makefile @@ -188,6 +188,7 @@ COBJS-y += console.o COBJS-y += dlmalloc.o COBJS-y += memsize.o COBJS-y += stdio.o +COBJS-y += dmmalloc.o
COBJS-$(CONFIG_SYS_EARLY_MALLOC)
or
COBJS-$(CONFIG_SYS_DM)
If DM mandates early_malloc (which I think it will) then we need to tie the #defines together somehow
COBJS := $(sort $(COBJS-y)) diff --git a/common/dmmalloc.c b/common/dmmalloc.c new file mode 100644 index 0000000..18f2d95 --- /dev/null +++ b/common/dmmalloc.c @@ -0,0 +1,128 @@ +/*
- (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 */
Drop the comments - they are ugly
+#include <dmmalloc.h> +#include <malloc.h>
+DECLARE_GLOBAL_DATA_PTR;
+#ifdef CONFIG_SYS_EARLY_MALLOC +static struct early_heap_header *def_early_brk(size_t size) +{
struct early_heap_header *h =
(struct early_heap_header *)CONFIG_SYS_EARLY_HEAP_ADDR;
h->free_space_pointer = (void *)(roundup(
(phys_addr_t)CONFIG_SYS_EARLY_HEAP_ADDR +
sizeof(struct early_heap_header),
sizeof(phys_addr_t)));
h->free_bytes = size - roundup(sizeof(struct early_heap_header),
sizeof(phys_addr_t));
h->next_early_heap = NULL;
return h;
+}
+struct early_heap_header *early_brk(size_t size)
__attribute__((weak, alias("def_early_brk")));
+void *early_malloc(size_t size) +{
phys_addr_t addr;
struct early_heap_header *h;
/* Align size. */
size = roundup(size, sizeof(phys_addr_t));
/* Choose early_heap with enough space. */
h = gd->early_heap_first;
while ((h->free_bytes < size) && (h->next_early_heap != NULL))
h = h->next_early_heap;
if (h->free_bytes < size) {
You will get a NULL-pointer exception if no early heap has enough space
You also need to add some logic to allocate an additional early heap by calling early_brk. If that call fails (returns NULL) then bail out
debug("Early heap overflow. Heap %p, free %d, required %d.",
h, h->free_bytes, size);
return NULL;
}
/* Choose block beginning address and mark next free space. */
addr = (phys_addr_t)h->free_space_pointer;
h->free_space_pointer += size;
h->free_bytes -= size;
return (void *)addr;
+}
+static int is_early_malloc_active(void) +{
if (gd->flags & GD_FLG_RELOC)
return 0;
return 1;
Hmmm, return ((gd->flags & GD_FLG_RELOC) == GD_FLG_RELOC); ?
I also prefer the semantics of not having 'is_'. "if blah" reads better to me than "if is blah" - YMMV
+}
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+void *dmmalloc(size_t size) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC
if (is_early_malloc_active())
return early_malloc(size);
+#endif /* CONFIG_SYS_EARLY_MALLOC */
return malloc(size);
+}
The argument over dmmalloc() versus transparent malloc() is far from over IMNSHO, but for now, this will have to do :)
+void dmfree(void *ptr) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC
if (is_early_malloc_active())
return;
+#endif /* CONFIG_SYS_EARLY_MALLOC */
free(ptr);
+}
+void *dmcalloc(size_t n, size_t elem_size) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC
if (is_early_malloc_active())
return NULL;
+#endif /* CONFIG_SYS_EARLY_MALLOC */
return calloc(n, elem_size);
+}
+void *dmrealloc(void *oldmem, size_t bytes) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC
if (is_early_malloc_active())
return NULL;
+#endif /* CONFIG_SYS_EARLY_MALLOC */
return dmrealloc(oldmem, bytes);
+}
[snip]
Regards,
Graeme

early_malloc for DM with support for more heaps and lightweight first heap in the same memory as an early stack.
Adaptation layer for seamless calling of early_malloc or dlmalloc from DM based on init stage added (dmmalloc() and related functions).
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com --- arch/arm/include/asm/global_data.h | 3 + arch/arm/lib/board.c | 8 ++ arch/avr32/include/asm/global_data.h | 3 + arch/avr32/lib/board.c | 9 ++ arch/blackfin/include/asm/global_data.h | 3 + arch/blackfin/lib/board.c | 8 ++ arch/m68k/include/asm/global_data.h | 3 + arch/m68k/lib/board.c | 8 ++ arch/microblaze/include/asm/global_data.h | 3 + arch/microblaze/lib/board.c | 9 ++ arch/mips/include/asm/global_data.h | 3 + arch/mips/lib/board.c | 8 ++ arch/nds32/include/asm/global_data.h | 3 + arch/nds32/lib/board.c | 8 ++ arch/nios2/include/asm/global_data.h | 3 + arch/nios2/lib/board.c | 8 ++ arch/openrisc/include/asm/global_data.h | 3 + arch/openrisc/lib/board.c | 8 ++ arch/powerpc/include/asm/global_data.h | 3 + arch/powerpc/lib/board.c | 8 ++ arch/sandbox/include/asm/global_data.h | 3 + arch/sandbox/lib/board.c | 8 ++ arch/sh/include/asm/global_data.h | 3 + arch/sh/lib/board.c | 8 ++ arch/sparc/include/asm/global_data.h | 3 + arch/sparc/lib/board.c | 8 ++ arch/x86/include/asm/global_data.h | 3 + arch/x86/lib/board.c | 18 ++++ common/Makefile | 1 + common/dmmalloc.c | 140 +++++++++++++++++++++++++++++ include/dmmalloc.h | 56 ++++++++++++ 31 files changed, 363 insertions(+) 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 f8088fe..ef727b0 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -82,6 +82,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index f1951e8..2157a5d 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -53,6 +53,10 @@ #include <post.h> #include <logbuff.h>
+#ifdef CONFIG_SYS_DM +#include <dmmalloc.h> +#endif + #ifdef CONFIG_BITBANGMII #include <miiphy.h> #endif @@ -281,6 +285,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->mon_len = _bss_end_ofs; #ifdef CONFIG_OF_EMBED /* Get a pointer to the FDT */ diff --git a/arch/avr32/include/asm/global_data.h b/arch/avr32/include/asm/global_data.h index 7878bb1..0654a61 100644 --- a/arch/avr32/include/asm/global_data.h +++ b/arch/avr32/include/asm/global_data.h @@ -48,6 +48,9 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/avr32/lib/board.c b/arch/avr32/lib/board.c index d7a64b4..14ec278 100644 --- a/arch/avr32/lib/board.c +++ b/arch/avr32/lib/board.c @@ -42,6 +42,11 @@ #ifdef CONFIG_GENERIC_ATMEL_MCI #include <mmc.h> #endif + +#ifdef CONFIG_SYS_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
unsigned long monitor_flash_len; @@ -161,6 +166,10 @@ void board_init_f(ulong board_type) memset(&gd_data, 0, sizeof(gd_data)); gd = &gd_data;
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + /* Perform initialization sequence */ board_early_init_f(); cpu_init(); diff --git a/arch/blackfin/include/asm/global_data.h b/arch/blackfin/include/asm/global_data.h index 290a9e7..2ae395c 100644 --- a/arch/blackfin/include/asm/global_data.h +++ b/arch/blackfin/include/asm/global_data.h @@ -57,6 +57,9 @@ typedef struct global_data {
void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/blackfin/lib/board.c b/arch/blackfin/lib/board.c index c380d27..bb19bdd 100644 --- a/arch/blackfin/lib/board.c +++ b/arch/blackfin/lib/board.c @@ -37,6 +37,10 @@ int post_flag; #endif
+#ifdef CONFIG_SYS_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
__attribute__((always_inline)) @@ -267,6 +271,10 @@ void board_init_f(ulong bootflag) watchdog_init(); #endif
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + #ifdef DEBUG if (GENERATED_GBL_DATA_SIZE < sizeof(*gd)) hang(); diff --git a/arch/m68k/include/asm/global_data.h b/arch/m68k/include/asm/global_data.h index cd55b83..bd30435 100644 --- a/arch/m68k/include/asm/global_data.h +++ b/arch/m68k/include/asm/global_data.h @@ -66,6 +66,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/m68k/lib/board.c b/arch/m68k/lib/board.c index 65a8595..8815605 100644 --- a/arch/m68k/lib/board.c +++ b/arch/m68k/lib/board.c @@ -69,6 +69,10 @@
#include <nand.h>
+#ifdef CONFIG_SYS_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
static char *failed = "*** failed ***\n"; @@ -227,6 +231,10 @@ board_init_f (ulong bootflag) /* Clear initial global data */ memset ((void *) gd, 0, sizeof (gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) { hang (); diff --git a/arch/microblaze/include/asm/global_data.h b/arch/microblaze/include/asm/global_data.h index de3b8db..6f4066d 100644 --- a/arch/microblaze/include/asm/global_data.h +++ b/arch/microblaze/include/asm/global_data.h @@ -46,6 +46,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/microblaze/lib/board.c b/arch/microblaze/lib/board.c index 674b573..869a3ea 100644 --- a/arch/microblaze/lib/board.c +++ b/arch/microblaze/lib/board.c @@ -37,6 +37,10 @@ #include <asm/microblaze_intc.h> #include <fdtdec.h>
+#ifdef CONFIG_SYS_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
/* @@ -81,6 +85,11 @@ void board_init_f(ulong not_used) asm ("nop"); /* FIXME gd is not initialize - wait */ memset ((void *)gd, 0, GENERATED_GBL_DATA_SIZE); memset ((void *)bd, 0, GENERATED_BD_INFO_SIZE); + +#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = bd; gd->baudrate = CONFIG_BAUDRATE; bd->bi_baudrate = CONFIG_BAUDRATE; diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h index 6e2cdc7..ac24e3f 100644 --- a/arch/mips/include/asm/global_data.h +++ b/arch/mips/include/asm/global_data.h @@ -59,6 +59,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/mips/lib/board.c b/arch/mips/lib/board.c index 62d47a8..d9ae49f 100644 --- a/arch/mips/lib/board.c +++ b/arch/mips/lib/board.c @@ -36,6 +36,10 @@ #include <miiphy.h> #endif
+#ifdef CONFIG_SYS_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
ulong monitor_flash_len; @@ -153,6 +157,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) hang(); diff --git a/arch/nds32/include/asm/global_data.h b/arch/nds32/include/asm/global_data.h index 94bd4c2..d0e2606 100644 --- a/arch/nds32/include/asm/global_data.h +++ b/arch/nds32/include/asm/global_data.h @@ -63,6 +63,9 @@ typedef struct global_data {
void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/nds32/lib/board.c b/arch/nds32/lib/board.c index 2164a50..9c9be4e 100644 --- a/arch/nds32/lib/board.c +++ b/arch/nds32/lib/board.c @@ -37,6 +37,10 @@ #include <onenand_uboot.h> #include <mmc.h>
+#ifdef CONFIG_SYS_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
ulong monitor_flash_len; @@ -192,6 +196,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, GENERATED_GBL_DATA_SIZE);
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->mon_len = (unsigned int)(&__bss_end__) - (unsigned int)(&_start);
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { diff --git a/arch/nios2/include/asm/global_data.h b/arch/nios2/include/asm/global_data.h index 3b0d9e6..44373f4 100644 --- a/arch/nios2/include/asm/global_data.h +++ b/arch/nios2/include/asm/global_data.h @@ -42,6 +42,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/nios2/lib/board.c b/arch/nios2/lib/board.c index 1e495d4..96d3827 100644 --- a/arch/nios2/lib/board.c +++ b/arch/nios2/lib/board.c @@ -40,6 +40,10 @@ #include <nand.h> /* cannot even include nand.h if it isnt configured */ #endif
+#ifdef CONFIG_SYS_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
/* @@ -95,6 +99,10 @@ void board_init (void) /* compiler optimization barrier needed for GCC >= 3.4 */ __asm__ __volatile__("": : :"memory");
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = &bd_data; gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/openrisc/include/asm/global_data.h b/arch/openrisc/include/asm/global_data.h index 6a0c0cc..ec2220a 100644 --- a/arch/openrisc/include/asm/global_data.h +++ b/arch/openrisc/include/asm/global_data.h @@ -44,6 +44,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/openrisc/lib/board.c b/arch/openrisc/lib/board.c index 85aa189..527de09 100644 --- a/arch/openrisc/lib/board.c +++ b/arch/openrisc/lib/board.c @@ -44,6 +44,10 @@ #include <timestamp.h> #include <version.h>
+#ifdef CONFIG_SYS_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
/* @@ -86,6 +90,10 @@ void board_init(void)
memset((void *)gd, 0, GENERATED_GBL_DATA_SIZE);
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = (bd_t *)(gd+1); /* At end of global data */ gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/powerpc/include/asm/global_data.h b/arch/powerpc/include/asm/global_data.h index 5a5877f..38b63f9 100644 --- a/arch/powerpc/include/asm/global_data.h +++ b/arch/powerpc/include/asm/global_data.h @@ -182,6 +182,9 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/powerpc/lib/board.c b/arch/powerpc/lib/board.c index fea310e..dbf0520 100644 --- a/arch/powerpc/lib/board.c +++ b/arch/powerpc/lib/board.c @@ -87,6 +87,10 @@ #include <miiphy.h> #endif
+#ifdef CONFIG_SYS_DM +#include <dmmalloc.h> +#endif + #ifdef CONFIG_SYS_UPDATE_FLASH_SIZE extern int update_flash_size(int flash_size); #endif @@ -389,6 +393,10 @@ void board_init_f(ulong bootflag) memset((void *) gd, 0, sizeof(gd_t)); #endif
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) if ((*init_fnc_ptr) () != 0) hang(); diff --git a/arch/sandbox/include/asm/global_data.h b/arch/sandbox/include/asm/global_data.h index 581fd2f..00c7c10 100644 --- a/arch/sandbox/include/asm/global_data.h +++ b/arch/sandbox/include/asm/global_data.h @@ -46,6 +46,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/sandbox/lib/board.c b/arch/sandbox/lib/board.c index c173bf9..da4e3ea 100644 --- a/arch/sandbox/lib/board.c +++ b/arch/sandbox/lib/board.c @@ -47,6 +47,10 @@
#include <os.h>
+#ifdef CONFIG_SYS_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
static gd_t gd_mem; @@ -157,6 +161,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + #if defined(CONFIG_OF_EMBED) /* Get a pointer to the FDT */ gd->fdt_blob = _binary_dt_dtb_start; diff --git a/arch/sh/include/asm/global_data.h b/arch/sh/include/asm/global_data.h index 6e534ad..441fecd 100644 --- a/arch/sh/include/asm/global_data.h +++ b/arch/sh/include/asm/global_data.h @@ -42,6 +42,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/sh/lib/board.c b/arch/sh/lib/board.c index 34d7881..2cf94d3 100644 --- a/arch/sh/lib/board.c +++ b/arch/sh/lib/board.c @@ -32,6 +32,10 @@ #include <miiphy.h> #endif
+#ifdef CONFIG_SYS_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
extern int cpu_init(void); @@ -150,6 +154,10 @@ void sh_generic_init(void)
memset(gd, 0, GENERATED_GBL_DATA_SIZE);
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */
gd->bd = (bd_t *)(gd + 1); /* At end of global data */ diff --git a/arch/sparc/include/asm/global_data.h b/arch/sparc/include/asm/global_data.h index 93d3cc0..537e09a 100644 --- a/arch/sparc/include/asm/global_data.h +++ b/arch/sparc/include/asm/global_data.h @@ -74,6 +74,9 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/sparc/lib/board.c b/arch/sparc/lib/board.c index 6f33666..5a45d7c 100644 --- a/arch/sparc/lib/board.c +++ b/arch/sparc/lib/board.c @@ -53,6 +53,10 @@ #include <miiphy.h> #endif
+#ifdef CONFIG_SYS_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
/* Debug options @@ -178,6 +182,10 @@ void board_init_f(ulong bootflag) /* Clear initial global data */ memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = (bd_t *) (gd + 1); /* At end of global data */ gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 6d29c0b..920a805 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -57,6 +57,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
static inline gd_t *get_fs_gd_ptr(void) diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index 90cf7fc..e21c9af 100644 --- a/arch/x86/lib/board.c +++ b/arch/x86/lib/board.c @@ -40,6 +40,10 @@ #include <asm/init_helpers.h> #include <asm/init_wrappers.h>
+#ifdef CONFIG_SYS_DM +#include <dmmalloc.h> +#endif + /* * Breath some life into the board... * @@ -85,6 +89,17 @@ typedef int (init_fnc_t) (void);
/* + * Initialize early heap (when enabled by config). + */ +#ifdef CONFIG_SYS_EARLY_MALLOC +static void early_malloc_init(void) +{ + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +} +#endif /* CONFIG_SYS_EARLY_MALLOC */ + + +/* * init_sequence_f is the list of init functions which are run when U-Boot * is executing from Flash with a limited 'C' environment. The following * limitations must be considered when implementing an '_f' function: @@ -99,6 +114,9 @@ init_fnc_t *init_sequence_f[] = { cpu_init_f, board_early_init_f, env_init, +#ifdef CONFIG_SYS_EARLY_MALLOC + early_malloc_init, +#endif /* CONFIG_SYS_EARLY_MALLOC */ init_baudrate_f, serial_init, console_init_f, diff --git a/common/Makefile b/common/Makefile index 22e8a6f..e0bea58 100644 --- a/common/Makefile +++ b/common/Makefile @@ -201,6 +201,7 @@ COBJS-y += dlmalloc.o COBJS-y += image.o COBJS-y += memsize.o COBJS-y += stdio.o +COBJS-$(CONFIG_SYS_DM) += dmmalloc.o
COBJS := $(sort $(COBJS-y)) diff --git a/common/dmmalloc.c b/common/dmmalloc.c new file mode 100644 index 0000000..b5957f4 --- /dev/null +++ b/common/dmmalloc.c @@ -0,0 +1,140 @@ +/* + * (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 +__weak struct early_heap_header *early_brk(size_t size) +{ + struct early_heap_header *h = + (struct early_heap_header *)CONFIG_SYS_EARLY_HEAP_ADDR; + struct early_heap_header *ehp = gd->early_heap_first; + + while (ehp != NULL) { + if (ehp == h) + return NULL; + + ehp = ehp->next_early_heap; + } + + h->free_space_pointer = (void *)(roundup( + (phys_addr_t)CONFIG_SYS_EARLY_HEAP_ADDR + + sizeof(struct early_heap_header), + sizeof(phys_addr_t))); + h->free_bytes = size - roundup(sizeof(struct early_heap_header), + sizeof(phys_addr_t)); + h->next_early_heap = NULL; + + return h; +} + +void *early_malloc(size_t size) +{ + phys_addr_t addr; + struct early_heap_header *h; + + size = roundup(size, sizeof(phys_addr_t)); + + h = gd->early_heap_first; + while ((h->free_bytes < size) && (h->next_early_heap != NULL)) + h = h->next_early_heap; + + if (h->free_bytes < size) { + h->next_early_heap = early_brk(size); + if (h->next_early_heap == NULL) + debug("EH overflow. Can not early_brk. required %d B.", + size); + return NULL; + } + + addr = (phys_addr_t)h->free_space_pointer; + + h->free_space_pointer += size; + h->free_bytes -= size; + + return (void *)addr; +} + +static int early_malloc_active(void) +{ + if ((gd->flags & GD_FLG_RELOC) == GD_FLG_RELOC) + return 0; + + return 1; +} +#endif /* CONFIG_SYS_EARLY_MALLOC */ + +#ifdef CONFIG_SYS_EARLY_MALLOC +void *dmmalloc(size_t size) +{ + if (early_malloc_active()) + return early_malloc(size); + return malloc(size); +} +#else /* CONFIG_SYS_EARLY_MALLOC */ +#define dmmalloc malloc +#endif /* CONFIG_SYS_EARLY_MALLOC */ + +#ifdef CONFIG_SYS_EARLY_MALLOC +void dmfree(void *ptr) +{ + if (early_malloc_active()) + return; + free(ptr); +} +#else /* CONFIG_SYS_EARLY_MALLOC */ +#define dmfree free +#endif /* CONFIG_SYS_EARLY_MALLOC */ + +#ifdef CONFIG_SYS_EARLY_MALLOC +void *dmcalloc(size_t n, size_t elem_size) +{ + if (early_malloc_active()) + return NULL; + return calloc(n, elem_size); +} +#else /* CONFIG_SYS_EARLY_MALLOC */ +#define dmcalloc calloc +#endif /* CONFIG_SYS_EARLY_MALLOC */ + +#ifdef CONFIG_SYS_EARLY_MALLOC +void *dmrealloc(void *oldmem, size_t bytes) +{ + if (early_malloc_active()) + return NULL; + return dmrealloc(oldmem, bytes); +} +#else /* CONFIG_SYS_EARLY_MALLOC */ +#define dmrealloc realloc +#endif /* CONFIG_SYS_EARLY_MALLOC */ + diff --git a/include/dmmalloc.h b/include/dmmalloc.h new file mode 100644 index 0000000..726c6c9 --- /dev/null +++ b/include/dmmalloc.h @@ -0,0 +1,56 @@ +/* + * (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 */ + +#if (!defined(CONFIG_SYS_EARLY_HEAP_ADDR)) || \ + (!defined(CONFIG_SYS_EARLY_HEAP_SIZE)) +#undef CONFIG_SYS_EARLY_MALLOC +#endif /* CONFIG_SYS_EARLY_HEAP_ADDR */ + +#ifdef CONFIG_SYS_EARLY_MALLOC +struct early_heap_header { + void *free_space_pointer; + size_t free_bytes; + void *next_early_heap; +}; + +struct early_heap_header *early_brk(size_t size); +void *early_malloc(size_t size); + +#endif /* CONFIG_SYS_EARLY_MALLOC */ + +#ifdef CONFIG_SYS_DM +void *dmmalloc(size_t size); +void dmfree(void *ptr); +void *dmcalloc(size_t n, size_t elem_size); +void *dmrealloc(void *oldmem, size_t bytes); +#endif /* CONFIG_SYS_DM */ + + +#endif /* __INCLUDE_DMMALLOC_H */ +

Dear Tomas Hlavacek,
early_malloc for DM with support for more heaps and lightweight first heap in the same memory as an early stack.
Adaptation layer for seamless calling of early_malloc or dlmalloc from DM based on init stage added (dmmalloc() and related functions).
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com
[...]
31 files changed, 363 insertions(+) create mode 100644 common/dmmalloc.c create mode 100644 include/dmmalloc.h
What exactly changed in this version? Changelog is missing.
[...]
+static int early_malloc_active(void) +{
- if ((gd->flags & GD_FLG_RELOC) == GD_FLG_RELOC)
return 0;
Did you completely ignore the comments?
- return 1;
+} +#endif /* CONFIG_SYS_EARLY_MALLOC */
+#ifdef CONFIG_SYS_EARLY_MALLOC +void *dmmalloc(size_t size) +{
- if (early_malloc_active())
return early_malloc(size);
- return malloc(size);
+} +#else /* CONFIG_SYS_EARLY_MALLOC */ +#define dmmalloc malloc
How is this actually supposed to work?
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+#ifdef CONFIG_SYS_EARLY_MALLOC +void dmfree(void *ptr) +{
- if (early_malloc_active())
return;
- free(ptr);
+} +#else /* CONFIG_SYS_EARLY_MALLOC */ +#define dmfree free +#endif /* CONFIG_SYS_EARLY_MALLOC */
+#ifdef CONFIG_SYS_EARLY_MALLOC +void *dmcalloc(size_t n, size_t elem_size) +{
- if (early_malloc_active())
return NULL;
- return calloc(n, elem_size);
+} +#else /* CONFIG_SYS_EARLY_MALLOC */ +#define dmcalloc calloc +#endif /* CONFIG_SYS_EARLY_MALLOC */
+#ifdef CONFIG_SYS_EARLY_MALLOC +void *dmrealloc(void *oldmem, size_t bytes) +{
- if (early_malloc_active())
return NULL;
- return dmrealloc(oldmem, bytes);
+} +#else /* CONFIG_SYS_EARLY_MALLOC */ +#define dmrealloc realloc +#endif /* CONFIG_SYS_EARLY_MALLOC */
diff --git a/include/dmmalloc.h b/include/dmmalloc.h new file mode 100644 index 0000000..726c6c9 --- /dev/null +++ b/include/dmmalloc.h @@ -0,0 +1,56 @@ +/*
- (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 */
+#if (!defined(CONFIG_SYS_EARLY_HEAP_ADDR)) || \
- (!defined(CONFIG_SYS_EARLY_HEAP_SIZE))
+#undef CONFIG_SYS_EARLY_MALLOC +#endif /* CONFIG_SYS_EARLY_HEAP_ADDR */
+#ifdef CONFIG_SYS_EARLY_MALLOC +struct early_heap_header {
- void *free_space_pointer;
- size_t free_bytes;
- void *next_early_heap;
+};
+struct early_heap_header *early_brk(size_t size); +void *early_malloc(size_t size);
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+#ifdef CONFIG_SYS_DM
Isn't it CONFIG_DM ?
+void *dmmalloc(size_t size); +void dmfree(void *ptr); +void *dmcalloc(size_t n, size_t elem_size); +void *dmrealloc(void *oldmem, size_t bytes); +#endif /* CONFIG_SYS_DM */
+#endif /* __INCLUDE_DMMALLOC_H */

Hello Marek,
On Sat, Sep 22, 2012 at 2:28 AM, Marek Vasut marex@denx.de wrote:
Dear Tomas Hlavacek,
early_malloc for DM with support for more heaps and lightweight first heap in the same memory as an early stack.
Adaptation layer for seamless calling of early_malloc or dlmalloc from DM based on init stage added (dmmalloc() and related functions).
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com
[...]
31 files changed, 363 insertions(+) create mode 100644 common/dmmalloc.c create mode 100644 include/dmmalloc.h
What exactly changed in this version? Changelog is missing.
Preprocessor config-dependent (ifdef ... endif) blocks are different. early_brk call from early_malloc when the heaps are full. default early_brk checks existing heap for before setting.
[...]
+static int early_malloc_active(void) +{
if ((gd->flags & GD_FLG_RELOC) == GD_FLG_RELOC)
return 0;
Did you completely ignore the comments?
Yes, this is ugly and I did not notice the point of (your?) comment while reworking this tiny part again and again... Sorry.
return 1;
+} +#endif /* CONFIG_SYS_EARLY_MALLOC */
+#ifdef CONFIG_SYS_EARLY_MALLOC +void *dmmalloc(size_t size) +{
if (early_malloc_active())
return early_malloc(size);
return malloc(size);
+} +#else /* CONFIG_SYS_EARLY_MALLOC */ +#define dmmalloc malloc
How is this actually supposed to work?
Of course, this have to be in the header file dmmalloc.h. Just ignore the #else ... #endif part.
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+#ifdef CONFIG_SYS_EARLY_MALLOC +void dmfree(void *ptr) +{
if (early_malloc_active())
return;
free(ptr);
+} +#else /* CONFIG_SYS_EARLY_MALLOC */ +#define dmfree free +#endif /* CONFIG_SYS_EARLY_MALLOC */
+#ifdef CONFIG_SYS_EARLY_MALLOC +void *dmcalloc(size_t n, size_t elem_size) +{
if (early_malloc_active())
return NULL;
return calloc(n, elem_size);
+} +#else /* CONFIG_SYS_EARLY_MALLOC */ +#define dmcalloc calloc +#endif /* CONFIG_SYS_EARLY_MALLOC */
+#ifdef CONFIG_SYS_EARLY_MALLOC +void *dmrealloc(void *oldmem, size_t bytes) +{
if (early_malloc_active())
return NULL;
return dmrealloc(oldmem, bytes);
+} +#else /* CONFIG_SYS_EARLY_MALLOC */ +#define dmrealloc realloc +#endif /* CONFIG_SYS_EARLY_MALLOC */
diff --git a/include/dmmalloc.h b/include/dmmalloc.h new file mode 100644 index 0000000..726c6c9 --- /dev/null +++ b/include/dmmalloc.h @@ -0,0 +1,56 @@ +/*
- (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 */
+#if (!defined(CONFIG_SYS_EARLY_HEAP_ADDR)) || \
(!defined(CONFIG_SYS_EARLY_HEAP_SIZE))
+#undef CONFIG_SYS_EARLY_MALLOC +#endif /* CONFIG_SYS_EARLY_HEAP_ADDR */
+#ifdef CONFIG_SYS_EARLY_MALLOC +struct early_heap_header {
void *free_space_pointer;
size_t free_bytes;
void *next_early_heap;
+};
+struct early_heap_header *early_brk(size_t size); +void *early_malloc(size_t size);
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+#ifdef CONFIG_SYS_DM
Isn't it CONFIG_DM ?
I will change that. (Is it consistent with the naming convention? I mean: What the "_SYS_" exactly means?)
Tomas

Dear Tomas Hlavacek,
Hello Marek,
On Sat, Sep 22, 2012 at 2:28 AM, Marek Vasut marex@denx.de wrote:
Dear Tomas Hlavacek,
early_malloc for DM with support for more heaps and lightweight first heap in the same memory as an early stack.
Adaptation layer for seamless calling of early_malloc or dlmalloc from DM based on init stage added (dmmalloc() and related functions).
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com
[...]
31 files changed, 363 insertions(+) create mode 100644 common/dmmalloc.c create mode 100644 include/dmmalloc.h
What exactly changed in this version? Changelog is missing.
Preprocessor config-dependent (ifdef ... endif) blocks are different. early_brk call from early_malloc when the heaps are full. default early_brk checks existing heap for before setting.
[...]
+static int early_malloc_active(void) +{
if ((gd->flags & GD_FLG_RELOC) == GD_FLG_RELOC)
return 0;
Did you completely ignore the comments?
Yes, this is ugly and I did not notice the point of (your?) comment while reworking this tiny part again and again... Sorry.
I think it was GR.
return 1;
+} +#endif /* CONFIG_SYS_EARLY_MALLOC */
+#ifdef CONFIG_SYS_EARLY_MALLOC +void *dmmalloc(size_t size) +{
if (early_malloc_active())
return early_malloc(size);
return malloc(size);
+} +#else /* CONFIG_SYS_EARLY_MALLOC */ +#define dmmalloc malloc
How is this actually supposed to work?
Of course, this have to be in the header file dmmalloc.h. Just ignore the #else ... #endif part.
That won't work well either ... I'd say make the wrapper static inline for typechecking, no ?
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+#ifdef CONFIG_SYS_EARLY_MALLOC +void dmfree(void *ptr) +{
if (early_malloc_active())
return;
free(ptr);
+} +#else /* CONFIG_SYS_EARLY_MALLOC */ +#define dmfree free +#endif /* CONFIG_SYS_EARLY_MALLOC */
+#ifdef CONFIG_SYS_EARLY_MALLOC +void *dmcalloc(size_t n, size_t elem_size) +{
if (early_malloc_active())
return NULL;
return calloc(n, elem_size);
+} +#else /* CONFIG_SYS_EARLY_MALLOC */ +#define dmcalloc calloc +#endif /* CONFIG_SYS_EARLY_MALLOC */
+#ifdef CONFIG_SYS_EARLY_MALLOC +void *dmrealloc(void *oldmem, size_t bytes) +{
if (early_malloc_active())
return NULL;
return dmrealloc(oldmem, bytes);
+} +#else /* CONFIG_SYS_EARLY_MALLOC */ +#define dmrealloc realloc +#endif /* CONFIG_SYS_EARLY_MALLOC */
diff --git a/include/dmmalloc.h b/include/dmmalloc.h new file mode 100644 index 0000000..726c6c9 --- /dev/null +++ b/include/dmmalloc.h @@ -0,0 +1,56 @@ +/*
- (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 */
+#if (!defined(CONFIG_SYS_EARLY_HEAP_ADDR)) || \
(!defined(CONFIG_SYS_EARLY_HEAP_SIZE))
+#undef CONFIG_SYS_EARLY_MALLOC +#endif /* CONFIG_SYS_EARLY_HEAP_ADDR */
+#ifdef CONFIG_SYS_EARLY_MALLOC +struct early_heap_header {
void *free_space_pointer;
size_t free_bytes;
void *next_early_heap;
+};
+struct early_heap_header *early_brk(size_t size); +void *early_malloc(size_t size);
+#endif /* CONFIG_SYS_EARLY_MALLOC */
+#ifdef CONFIG_SYS_DM
Isn't it CONFIG_DM ?
I will change that. (Is it consistent with the naming convention? I mean: What the "_SYS_" exactly means?)
Tomas
Best regards, Marek Vasut

early_malloc for DM with support for more heaps and lightweight first heap in the same memory as an early stack.
Adaptation layer for seamless calling of early_malloc or dlmalloc from DM based on init stage added (dmmalloc() and related functions).
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com ---
Changelog since v5: dmmalloc() and all dm* functions has been moved to header, made static inline and preprocessor-dependent blocks are reworked. early_malloc_active() corrected and made not static. s/CONFIG_SYS_DM/CONFIG_DM/ applied.
arch/arm/include/asm/global_data.h | 3 + arch/arm/lib/board.c | 8 +++ arch/avr32/include/asm/global_data.h | 3 + arch/avr32/lib/board.c | 9 +++ arch/blackfin/include/asm/global_data.h | 3 + arch/blackfin/lib/board.c | 8 +++ arch/m68k/include/asm/global_data.h | 3 + arch/m68k/lib/board.c | 8 +++ arch/microblaze/include/asm/global_data.h | 3 + arch/microblaze/lib/board.c | 9 +++ arch/mips/include/asm/global_data.h | 3 + arch/mips/lib/board.c | 8 +++ arch/nds32/include/asm/global_data.h | 3 + arch/nds32/lib/board.c | 8 +++ arch/nios2/include/asm/global_data.h | 3 + arch/nios2/lib/board.c | 8 +++ arch/openrisc/include/asm/global_data.h | 3 + arch/openrisc/lib/board.c | 8 +++ arch/powerpc/include/asm/global_data.h | 3 + arch/powerpc/lib/board.c | 8 +++ arch/sandbox/include/asm/global_data.h | 3 + arch/sandbox/lib/board.c | 8 +++ arch/sh/include/asm/global_data.h | 3 + arch/sh/lib/board.c | 8 +++ arch/sparc/include/asm/global_data.h | 3 + arch/sparc/lib/board.c | 8 +++ arch/x86/include/asm/global_data.h | 3 + arch/x86/lib/board.c | 18 ++++++ common/Makefile | 1 + common/dmmalloc.c | 93 +++++++++++++++++++++++++++++ include/dmmalloc.h | 89 +++++++++++++++++++++++++++ 31 files changed, 349 insertions(+) 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 f8088fe..ef727b0 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -82,6 +82,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index f1951e8..f73d8b2 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -53,6 +53,10 @@ #include <post.h> #include <logbuff.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + #ifdef CONFIG_BITBANGMII #include <miiphy.h> #endif @@ -281,6 +285,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->mon_len = _bss_end_ofs; #ifdef CONFIG_OF_EMBED /* Get a pointer to the FDT */ diff --git a/arch/avr32/include/asm/global_data.h b/arch/avr32/include/asm/global_data.h index 7878bb1..0654a61 100644 --- a/arch/avr32/include/asm/global_data.h +++ b/arch/avr32/include/asm/global_data.h @@ -48,6 +48,9 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/avr32/lib/board.c b/arch/avr32/lib/board.c index d7a64b4..f1bd946 100644 --- a/arch/avr32/lib/board.c +++ b/arch/avr32/lib/board.c @@ -42,6 +42,11 @@ #ifdef CONFIG_GENERIC_ATMEL_MCI #include <mmc.h> #endif + +#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
unsigned long monitor_flash_len; @@ -161,6 +166,10 @@ void board_init_f(ulong board_type) memset(&gd_data, 0, sizeof(gd_data)); gd = &gd_data;
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + /* Perform initialization sequence */ board_early_init_f(); cpu_init(); diff --git a/arch/blackfin/include/asm/global_data.h b/arch/blackfin/include/asm/global_data.h index 290a9e7..2ae395c 100644 --- a/arch/blackfin/include/asm/global_data.h +++ b/arch/blackfin/include/asm/global_data.h @@ -57,6 +57,9 @@ typedef struct global_data {
void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/blackfin/lib/board.c b/arch/blackfin/lib/board.c index c380d27..96b7d76 100644 --- a/arch/blackfin/lib/board.c +++ b/arch/blackfin/lib/board.c @@ -37,6 +37,10 @@ int post_flag; #endif
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
__attribute__((always_inline)) @@ -267,6 +271,10 @@ void board_init_f(ulong bootflag) watchdog_init(); #endif
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + #ifdef DEBUG if (GENERATED_GBL_DATA_SIZE < sizeof(*gd)) hang(); diff --git a/arch/m68k/include/asm/global_data.h b/arch/m68k/include/asm/global_data.h index cd55b83..bd30435 100644 --- a/arch/m68k/include/asm/global_data.h +++ b/arch/m68k/include/asm/global_data.h @@ -66,6 +66,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/m68k/lib/board.c b/arch/m68k/lib/board.c index 65a8595..1b9312c 100644 --- a/arch/m68k/lib/board.c +++ b/arch/m68k/lib/board.c @@ -69,6 +69,10 @@
#include <nand.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
static char *failed = "*** failed ***\n"; @@ -227,6 +231,10 @@ board_init_f (ulong bootflag) /* Clear initial global data */ memset ((void *) gd, 0, sizeof (gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) { hang (); diff --git a/arch/microblaze/include/asm/global_data.h b/arch/microblaze/include/asm/global_data.h index de3b8db..6f4066d 100644 --- a/arch/microblaze/include/asm/global_data.h +++ b/arch/microblaze/include/asm/global_data.h @@ -46,6 +46,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/microblaze/lib/board.c b/arch/microblaze/lib/board.c index 674b573..eeb8441 100644 --- a/arch/microblaze/lib/board.c +++ b/arch/microblaze/lib/board.c @@ -37,6 +37,10 @@ #include <asm/microblaze_intc.h> #include <fdtdec.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
/* @@ -81,6 +85,11 @@ void board_init_f(ulong not_used) asm ("nop"); /* FIXME gd is not initialize - wait */ memset ((void *)gd, 0, GENERATED_GBL_DATA_SIZE); memset ((void *)bd, 0, GENERATED_BD_INFO_SIZE); + +#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = bd; gd->baudrate = CONFIG_BAUDRATE; bd->bi_baudrate = CONFIG_BAUDRATE; diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h index 6e2cdc7..ac24e3f 100644 --- a/arch/mips/include/asm/global_data.h +++ b/arch/mips/include/asm/global_data.h @@ -59,6 +59,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/mips/lib/board.c b/arch/mips/lib/board.c index 62d47a8..4657046 100644 --- a/arch/mips/lib/board.c +++ b/arch/mips/lib/board.c @@ -36,6 +36,10 @@ #include <miiphy.h> #endif
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
ulong monitor_flash_len; @@ -153,6 +157,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) hang(); diff --git a/arch/nds32/include/asm/global_data.h b/arch/nds32/include/asm/global_data.h index 94bd4c2..d0e2606 100644 --- a/arch/nds32/include/asm/global_data.h +++ b/arch/nds32/include/asm/global_data.h @@ -63,6 +63,9 @@ typedef struct global_data {
void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/nds32/lib/board.c b/arch/nds32/lib/board.c index 2164a50..97193b0 100644 --- a/arch/nds32/lib/board.c +++ b/arch/nds32/lib/board.c @@ -37,6 +37,10 @@ #include <onenand_uboot.h> #include <mmc.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
ulong monitor_flash_len; @@ -192,6 +196,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, GENERATED_GBL_DATA_SIZE);
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->mon_len = (unsigned int)(&__bss_end__) - (unsigned int)(&_start);
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { diff --git a/arch/nios2/include/asm/global_data.h b/arch/nios2/include/asm/global_data.h index 3b0d9e6..44373f4 100644 --- a/arch/nios2/include/asm/global_data.h +++ b/arch/nios2/include/asm/global_data.h @@ -42,6 +42,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/nios2/lib/board.c b/arch/nios2/lib/board.c index 1e495d4..866dc12 100644 --- a/arch/nios2/lib/board.c +++ b/arch/nios2/lib/board.c @@ -40,6 +40,10 @@ #include <nand.h> /* cannot even include nand.h if it isnt configured */ #endif
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
/* @@ -95,6 +99,10 @@ void board_init (void) /* compiler optimization barrier needed for GCC >= 3.4 */ __asm__ __volatile__("": : :"memory");
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = &bd_data; gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/openrisc/include/asm/global_data.h b/arch/openrisc/include/asm/global_data.h index 6a0c0cc..ec2220a 100644 --- a/arch/openrisc/include/asm/global_data.h +++ b/arch/openrisc/include/asm/global_data.h @@ -44,6 +44,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/openrisc/lib/board.c b/arch/openrisc/lib/board.c index 85aa189..f1199d6 100644 --- a/arch/openrisc/lib/board.c +++ b/arch/openrisc/lib/board.c @@ -44,6 +44,10 @@ #include <timestamp.h> #include <version.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
/* @@ -86,6 +90,10 @@ void board_init(void)
memset((void *)gd, 0, GENERATED_GBL_DATA_SIZE);
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = (bd_t *)(gd+1); /* At end of global data */ gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/powerpc/include/asm/global_data.h b/arch/powerpc/include/asm/global_data.h index 5a5877f..38b63f9 100644 --- a/arch/powerpc/include/asm/global_data.h +++ b/arch/powerpc/include/asm/global_data.h @@ -182,6 +182,9 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/powerpc/lib/board.c b/arch/powerpc/lib/board.c index fea310e..39af242 100644 --- a/arch/powerpc/lib/board.c +++ b/arch/powerpc/lib/board.c @@ -87,6 +87,10 @@ #include <miiphy.h> #endif
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + #ifdef CONFIG_SYS_UPDATE_FLASH_SIZE extern int update_flash_size(int flash_size); #endif @@ -389,6 +393,10 @@ void board_init_f(ulong bootflag) memset((void *) gd, 0, sizeof(gd_t)); #endif
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) if ((*init_fnc_ptr) () != 0) hang(); diff --git a/arch/sandbox/include/asm/global_data.h b/arch/sandbox/include/asm/global_data.h index 581fd2f..00c7c10 100644 --- a/arch/sandbox/include/asm/global_data.h +++ b/arch/sandbox/include/asm/global_data.h @@ -46,6 +46,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/sandbox/lib/board.c b/arch/sandbox/lib/board.c index c173bf9..d384481 100644 --- a/arch/sandbox/lib/board.c +++ b/arch/sandbox/lib/board.c @@ -47,6 +47,10 @@
#include <os.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
static gd_t gd_mem; @@ -157,6 +161,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + #if defined(CONFIG_OF_EMBED) /* Get a pointer to the FDT */ gd->fdt_blob = _binary_dt_dtb_start; diff --git a/arch/sh/include/asm/global_data.h b/arch/sh/include/asm/global_data.h index 6e534ad..441fecd 100644 --- a/arch/sh/include/asm/global_data.h +++ b/arch/sh/include/asm/global_data.h @@ -42,6 +42,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/sh/lib/board.c b/arch/sh/lib/board.c index 34d7881..eb04ed2 100644 --- a/arch/sh/lib/board.c +++ b/arch/sh/lib/board.c @@ -32,6 +32,10 @@ #include <miiphy.h> #endif
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
extern int cpu_init(void); @@ -150,6 +154,10 @@ void sh_generic_init(void)
memset(gd, 0, GENERATED_GBL_DATA_SIZE);
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */
gd->bd = (bd_t *)(gd + 1); /* At end of global data */ diff --git a/arch/sparc/include/asm/global_data.h b/arch/sparc/include/asm/global_data.h index 93d3cc0..537e09a 100644 --- a/arch/sparc/include/asm/global_data.h +++ b/arch/sparc/include/asm/global_data.h @@ -74,6 +74,9 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/sparc/lib/board.c b/arch/sparc/lib/board.c index 6f33666..2ced0a7 100644 --- a/arch/sparc/lib/board.c +++ b/arch/sparc/lib/board.c @@ -53,6 +53,10 @@ #include <miiphy.h> #endif
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
/* Debug options @@ -178,6 +182,10 @@ void board_init_f(ulong bootflag) /* Clear initial global data */ memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = (bd_t *) (gd + 1); /* At end of global data */ gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 6d29c0b..920a805 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -57,6 +57,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
static inline gd_t *get_fs_gd_ptr(void) diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index 90cf7fc..a670f9e 100644 --- a/arch/x86/lib/board.c +++ b/arch/x86/lib/board.c @@ -40,6 +40,10 @@ #include <asm/init_helpers.h> #include <asm/init_wrappers.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + /* * Breath some life into the board... * @@ -85,6 +89,17 @@ typedef int (init_fnc_t) (void);
/* + * Initialize early heap (when enabled by config). + */ +#ifdef CONFIG_SYS_EARLY_MALLOC +static void early_malloc_init(void) +{ + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +} +#endif /* CONFIG_SYS_EARLY_MALLOC */ + + +/* * init_sequence_f is the list of init functions which are run when U-Boot * is executing from Flash with a limited 'C' environment. The following * limitations must be considered when implementing an '_f' function: @@ -99,6 +114,9 @@ init_fnc_t *init_sequence_f[] = { cpu_init_f, board_early_init_f, env_init, +#ifdef CONFIG_SYS_EARLY_MALLOC + early_malloc_init, +#endif /* CONFIG_SYS_EARLY_MALLOC */ init_baudrate_f, serial_init, console_init_f, diff --git a/common/Makefile b/common/Makefile index 22e8a6f..5862d34 100644 --- a/common/Makefile +++ b/common/Makefile @@ -201,6 +201,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..3db0d7b --- /dev/null +++ b/common/dmmalloc.c @@ -0,0 +1,93 @@ +/* + * (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 +__weak struct early_heap_header *early_brk(size_t size) +{ + struct early_heap_header *h = + (struct early_heap_header *)CONFIG_SYS_EARLY_HEAP_ADDR; + struct early_heap_header *ehp = gd->early_heap_first; + + while (ehp != NULL) { + if (ehp == h) + return NULL; + + ehp = ehp->next_early_heap; + } + + h->free_space_pointer = (void *)(roundup( + (phys_addr_t)CONFIG_SYS_EARLY_HEAP_ADDR + + sizeof(struct early_heap_header), + sizeof(phys_addr_t))); + h->free_bytes = size - roundup(sizeof(struct early_heap_header), + sizeof(phys_addr_t)); + h->next_early_heap = NULL; + + return h; +} + +void *early_malloc(size_t size) +{ + phys_addr_t addr; + struct early_heap_header *h; + + size = roundup(size, sizeof(phys_addr_t)); + + h = gd->early_heap_first; + while ((h->free_bytes < size) && (h->next_early_heap != NULL)) + h = h->next_early_heap; + + if (h->free_bytes < size) { + h->next_early_heap = early_brk(size); + if (h->next_early_heap == NULL) + debug("EH overflow. Can not early_brk. required %d B.", + size); + return NULL; + } + + addr = (phys_addr_t)h->free_space_pointer; + + h->free_space_pointer += size; + h->free_bytes -= size; + + return (void *)addr; +} + +int early_malloc_active(void) +{ + return ((gd->flags & GD_FLG_RELOC) != GD_FLG_RELOC); +} + +#endif /* CONFIG_SYS_EARLY_MALLOC */ diff --git a/include/dmmalloc.h b/include/dmmalloc.h new file mode 100644 index 0000000..a5ce2ec --- /dev/null +++ b/include/dmmalloc.h @@ -0,0 +1,89 @@ +/* + * (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> + +#if (!defined(CONFIG_SYS_EARLY_HEAP_ADDR)) || \ + (!defined(CONFIG_SYS_EARLY_HEAP_SIZE)) +#undef CONFIG_SYS_EARLY_MALLOC +#endif /* CONFIG_SYS_EARLY_HEAP_ADDR */ + +#ifdef CONFIG_SYS_EARLY_MALLOC +struct early_heap_header { + void *free_space_pointer; + size_t free_bytes; + void *next_early_heap; +}; + +struct early_heap_header *early_brk(size_t size); +void *early_malloc(size_t size); +int early_malloc_active(void); + +#endif /* CONFIG_SYS_EARLY_MALLOC */ + +#ifdef CONFIG_DM + +static inline 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); +} + +static inline void dmfree(void *ptr) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC + if (early_malloc_active()) + return; +#endif /* CONFIG_SYS_EARLY_MALLOC */ + free(ptr); +} + +static inline void *dmcalloc(size_t n, size_t elem_size) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC + if (early_malloc_active()) + return NULL; +#endif /* CONFIG_SYS_EARLY_MALLOC */ + return calloc(n, elem_size); +} + +static inline void *dmrealloc(void *oldmem, size_t bytes) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC + if (early_malloc_active()) + return NULL; +#endif /* CONFIG_SYS_EARLY_MALLOC */ + return dmrealloc(oldmem, bytes); +} + +#endif /* CONFIG_DM */ +#endif /* __INCLUDE_DMMALLOC_H */ +

On Sep 23, 2012 8:09 AM, "Tomas Hlavacek" tmshlvck@gmail.com wrote:
early_malloc for DM with support for more heaps and lightweight first heap in the same memory as an early stack.
Adaptation layer for seamless calling of early_malloc or dlmalloc from DM based on init stage added (dmmalloc() and related functions).
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com
[snip]
+#ifdef CONFIG_SYS_EARLY_MALLOC +__weak struct early_heap_header *early_brk(size_t size) +{
struct early_heap_header *h =
(struct early_heap_header *)CONFIG_SYS_EARLY_HEAP_ADDR;
struct early_heap_header *ehp = gd->early_heap_first;
while (ehp != NULL) {
if (ehp == h)
return NULL;
ehp = ehp->next_early_heap;
}
if (g->early_heap_first == NULL) h = CONFIF_SYS_EARLY_HEAP_ADDR); else return NULL;
h->free_space_pointer = (void *)(roundup(
(phys_addr_t)CONFIG_SYS_EARLY_HEAP_ADDR +
sizeof(struct early_heap_header),
sizeof(phys_addr_t)));
h->free_bytes = size - roundup(sizeof(struct early_heap_header),
sizeof(phys_addr_t));
h->next_early_heap = NULL;
return h;
+}
Regards,
Graeme

Hello!
On Sun, Sep 23, 2012 at 3:06 PM, Graeme Russ graeme.russ@gmail.com wrote:
On Sep 23, 2012 8:09 AM, "Tomas Hlavacek" tmshlvck@gmail.com wrote:
early_malloc for DM with support for more heaps and lightweight first heap in the same memory as an early stack.
Adaptation layer for seamless calling of early_malloc or dlmalloc from DM based on init stage added (dmmalloc() and related functions).
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com
[snip]
+#ifdef CONFIG_SYS_EARLY_MALLOC +__weak struct early_heap_header *early_brk(size_t size) +{
struct early_heap_header *h =
(struct early_heap_header *)CONFIG_SYS_EARLY_HEAP_ADDR;
struct early_heap_header *ehp = gd->early_heap_first;
while (ehp != NULL) {
if (ehp == h)
return NULL;
ehp = ehp->next_early_heap;
}
if (g->early_heap_first == NULL) h = CONFIF_SYS_EARLY_HEAP_ADDR); else return NULL;
Yes, I was too paranoid. What about:
if (g->early_heap_first != NULL) return NULL;
h->free_space_pointer = (void *)(roundup(
(phys_addr_t)CONFIG_SYS_EARLY_HEAP_ADDR +
sizeof(struct early_heap_header),
sizeof(phys_addr_t)));
h->free_bytes = size - roundup(sizeof(struct early_heap_header),
sizeof(phys_addr_t));
h->next_early_heap = NULL;
return h;
+}
Tomas

early_malloc for DM with support for more heaps and lightweight first heap in the same memory as an early stack.
Adaptation layer for seamless calling of early_malloc or dlmalloc from DM based on init stage added (dmmalloc() and related functions).
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com --- Changelog since v5: dmmalloc() and all dm* functions has been moved to header, made static inline and preprocessor-dependent blocks are reworked. early_malloc_active() corrected and made not static. s/CONFIG_SYS_DM/CONFIG_DM/ applied.
Changelog sice v6: Check of first heap emptyness in early_brk() has been simplified.
arch/arm/include/asm/global_data.h | 3 + arch/arm/lib/board.c | 8 +++ arch/avr32/include/asm/global_data.h | 3 + arch/avr32/lib/board.c | 9 +++ arch/blackfin/include/asm/global_data.h | 3 + arch/blackfin/lib/board.c | 8 +++ arch/m68k/include/asm/global_data.h | 3 + arch/m68k/lib/board.c | 8 +++ arch/microblaze/include/asm/global_data.h | 3 + arch/microblaze/lib/board.c | 9 +++ arch/mips/include/asm/global_data.h | 3 + arch/mips/lib/board.c | 8 +++ arch/nds32/include/asm/global_data.h | 3 + arch/nds32/lib/board.c | 8 +++ arch/nios2/include/asm/global_data.h | 3 + arch/nios2/lib/board.c | 8 +++ arch/openrisc/include/asm/global_data.h | 3 + arch/openrisc/lib/board.c | 8 +++ arch/powerpc/include/asm/global_data.h | 3 + arch/powerpc/lib/board.c | 8 +++ arch/sandbox/include/asm/global_data.h | 3 + arch/sandbox/lib/board.c | 8 +++ arch/sh/include/asm/global_data.h | 3 + arch/sh/lib/board.c | 8 +++ arch/sparc/include/asm/global_data.h | 3 + arch/sparc/lib/board.c | 8 +++ arch/x86/include/asm/global_data.h | 3 + arch/x86/lib/board.c | 18 ++++++ common/Makefile | 1 + common/dmmalloc.c | 88 ++++++++++++++++++++++++++++ include/dmmalloc.h | 89 +++++++++++++++++++++++++++++ 31 files changed, 344 insertions(+) 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 f8088fe..ef727b0 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -82,6 +82,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index f1951e8..f73d8b2 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -53,6 +53,10 @@ #include <post.h> #include <logbuff.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + #ifdef CONFIG_BITBANGMII #include <miiphy.h> #endif @@ -281,6 +285,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->mon_len = _bss_end_ofs; #ifdef CONFIG_OF_EMBED /* Get a pointer to the FDT */ diff --git a/arch/avr32/include/asm/global_data.h b/arch/avr32/include/asm/global_data.h index 7878bb1..0654a61 100644 --- a/arch/avr32/include/asm/global_data.h +++ b/arch/avr32/include/asm/global_data.h @@ -48,6 +48,9 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/avr32/lib/board.c b/arch/avr32/lib/board.c index d7a64b4..f1bd946 100644 --- a/arch/avr32/lib/board.c +++ b/arch/avr32/lib/board.c @@ -42,6 +42,11 @@ #ifdef CONFIG_GENERIC_ATMEL_MCI #include <mmc.h> #endif + +#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
unsigned long monitor_flash_len; @@ -161,6 +166,10 @@ void board_init_f(ulong board_type) memset(&gd_data, 0, sizeof(gd_data)); gd = &gd_data;
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + /* Perform initialization sequence */ board_early_init_f(); cpu_init(); diff --git a/arch/blackfin/include/asm/global_data.h b/arch/blackfin/include/asm/global_data.h index 290a9e7..2ae395c 100644 --- a/arch/blackfin/include/asm/global_data.h +++ b/arch/blackfin/include/asm/global_data.h @@ -57,6 +57,9 @@ typedef struct global_data {
void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/blackfin/lib/board.c b/arch/blackfin/lib/board.c index c380d27..96b7d76 100644 --- a/arch/blackfin/lib/board.c +++ b/arch/blackfin/lib/board.c @@ -37,6 +37,10 @@ int post_flag; #endif
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
__attribute__((always_inline)) @@ -267,6 +271,10 @@ void board_init_f(ulong bootflag) watchdog_init(); #endif
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + #ifdef DEBUG if (GENERATED_GBL_DATA_SIZE < sizeof(*gd)) hang(); diff --git a/arch/m68k/include/asm/global_data.h b/arch/m68k/include/asm/global_data.h index cd55b83..bd30435 100644 --- a/arch/m68k/include/asm/global_data.h +++ b/arch/m68k/include/asm/global_data.h @@ -66,6 +66,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/m68k/lib/board.c b/arch/m68k/lib/board.c index 65a8595..1b9312c 100644 --- a/arch/m68k/lib/board.c +++ b/arch/m68k/lib/board.c @@ -69,6 +69,10 @@
#include <nand.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
static char *failed = "*** failed ***\n"; @@ -227,6 +231,10 @@ board_init_f (ulong bootflag) /* Clear initial global data */ memset ((void *) gd, 0, sizeof (gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) { hang (); diff --git a/arch/microblaze/include/asm/global_data.h b/arch/microblaze/include/asm/global_data.h index de3b8db..6f4066d 100644 --- a/arch/microblaze/include/asm/global_data.h +++ b/arch/microblaze/include/asm/global_data.h @@ -46,6 +46,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/microblaze/lib/board.c b/arch/microblaze/lib/board.c index 674b573..eeb8441 100644 --- a/arch/microblaze/lib/board.c +++ b/arch/microblaze/lib/board.c @@ -37,6 +37,10 @@ #include <asm/microblaze_intc.h> #include <fdtdec.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
/* @@ -81,6 +85,11 @@ void board_init_f(ulong not_used) asm ("nop"); /* FIXME gd is not initialize - wait */ memset ((void *)gd, 0, GENERATED_GBL_DATA_SIZE); memset ((void *)bd, 0, GENERATED_BD_INFO_SIZE); + +#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = bd; gd->baudrate = CONFIG_BAUDRATE; bd->bi_baudrate = CONFIG_BAUDRATE; diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h index 6e2cdc7..ac24e3f 100644 --- a/arch/mips/include/asm/global_data.h +++ b/arch/mips/include/asm/global_data.h @@ -59,6 +59,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/mips/lib/board.c b/arch/mips/lib/board.c index 62d47a8..4657046 100644 --- a/arch/mips/lib/board.c +++ b/arch/mips/lib/board.c @@ -36,6 +36,10 @@ #include <miiphy.h> #endif
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
ulong monitor_flash_len; @@ -153,6 +157,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) hang(); diff --git a/arch/nds32/include/asm/global_data.h b/arch/nds32/include/asm/global_data.h index 94bd4c2..d0e2606 100644 --- a/arch/nds32/include/asm/global_data.h +++ b/arch/nds32/include/asm/global_data.h @@ -63,6 +63,9 @@ typedef struct global_data {
void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/nds32/lib/board.c b/arch/nds32/lib/board.c index 2164a50..97193b0 100644 --- a/arch/nds32/lib/board.c +++ b/arch/nds32/lib/board.c @@ -37,6 +37,10 @@ #include <onenand_uboot.h> #include <mmc.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
ulong monitor_flash_len; @@ -192,6 +196,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, GENERATED_GBL_DATA_SIZE);
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->mon_len = (unsigned int)(&__bss_end__) - (unsigned int)(&_start);
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { diff --git a/arch/nios2/include/asm/global_data.h b/arch/nios2/include/asm/global_data.h index 3b0d9e6..44373f4 100644 --- a/arch/nios2/include/asm/global_data.h +++ b/arch/nios2/include/asm/global_data.h @@ -42,6 +42,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/nios2/lib/board.c b/arch/nios2/lib/board.c index 1e495d4..866dc12 100644 --- a/arch/nios2/lib/board.c +++ b/arch/nios2/lib/board.c @@ -40,6 +40,10 @@ #include <nand.h> /* cannot even include nand.h if it isnt configured */ #endif
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
/* @@ -95,6 +99,10 @@ void board_init (void) /* compiler optimization barrier needed for GCC >= 3.4 */ __asm__ __volatile__("": : :"memory");
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = &bd_data; gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/openrisc/include/asm/global_data.h b/arch/openrisc/include/asm/global_data.h index 6a0c0cc..ec2220a 100644 --- a/arch/openrisc/include/asm/global_data.h +++ b/arch/openrisc/include/asm/global_data.h @@ -44,6 +44,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/openrisc/lib/board.c b/arch/openrisc/lib/board.c index 85aa189..f1199d6 100644 --- a/arch/openrisc/lib/board.c +++ b/arch/openrisc/lib/board.c @@ -44,6 +44,10 @@ #include <timestamp.h> #include <version.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
/* @@ -86,6 +90,10 @@ void board_init(void)
memset((void *)gd, 0, GENERATED_GBL_DATA_SIZE);
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = (bd_t *)(gd+1); /* At end of global data */ gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/powerpc/include/asm/global_data.h b/arch/powerpc/include/asm/global_data.h index 5a5877f..38b63f9 100644 --- a/arch/powerpc/include/asm/global_data.h +++ b/arch/powerpc/include/asm/global_data.h @@ -182,6 +182,9 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/powerpc/lib/board.c b/arch/powerpc/lib/board.c index fea310e..39af242 100644 --- a/arch/powerpc/lib/board.c +++ b/arch/powerpc/lib/board.c @@ -87,6 +87,10 @@ #include <miiphy.h> #endif
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + #ifdef CONFIG_SYS_UPDATE_FLASH_SIZE extern int update_flash_size(int flash_size); #endif @@ -389,6 +393,10 @@ void board_init_f(ulong bootflag) memset((void *) gd, 0, sizeof(gd_t)); #endif
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) if ((*init_fnc_ptr) () != 0) hang(); diff --git a/arch/sandbox/include/asm/global_data.h b/arch/sandbox/include/asm/global_data.h index 581fd2f..00c7c10 100644 --- a/arch/sandbox/include/asm/global_data.h +++ b/arch/sandbox/include/asm/global_data.h @@ -46,6 +46,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/sandbox/lib/board.c b/arch/sandbox/lib/board.c index c173bf9..d384481 100644 --- a/arch/sandbox/lib/board.c +++ b/arch/sandbox/lib/board.c @@ -47,6 +47,10 @@
#include <os.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
static gd_t gd_mem; @@ -157,6 +161,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + #if defined(CONFIG_OF_EMBED) /* Get a pointer to the FDT */ gd->fdt_blob = _binary_dt_dtb_start; diff --git a/arch/sh/include/asm/global_data.h b/arch/sh/include/asm/global_data.h index 6e534ad..441fecd 100644 --- a/arch/sh/include/asm/global_data.h +++ b/arch/sh/include/asm/global_data.h @@ -42,6 +42,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/sh/lib/board.c b/arch/sh/lib/board.c index 34d7881..eb04ed2 100644 --- a/arch/sh/lib/board.c +++ b/arch/sh/lib/board.c @@ -32,6 +32,10 @@ #include <miiphy.h> #endif
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
extern int cpu_init(void); @@ -150,6 +154,10 @@ void sh_generic_init(void)
memset(gd, 0, GENERATED_GBL_DATA_SIZE);
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */
gd->bd = (bd_t *)(gd + 1); /* At end of global data */ diff --git a/arch/sparc/include/asm/global_data.h b/arch/sparc/include/asm/global_data.h index 93d3cc0..537e09a 100644 --- a/arch/sparc/include/asm/global_data.h +++ b/arch/sparc/include/asm/global_data.h @@ -74,6 +74,9 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/sparc/lib/board.c b/arch/sparc/lib/board.c index 6f33666..2ced0a7 100644 --- a/arch/sparc/lib/board.c +++ b/arch/sparc/lib/board.c @@ -53,6 +53,10 @@ #include <miiphy.h> #endif
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
/* Debug options @@ -178,6 +182,10 @@ void board_init_f(ulong bootflag) /* Clear initial global data */ memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = (bd_t *) (gd + 1); /* At end of global data */ gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 6d29c0b..920a805 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -57,6 +57,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
static inline gd_t *get_fs_gd_ptr(void) diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index 90cf7fc..a670f9e 100644 --- a/arch/x86/lib/board.c +++ b/arch/x86/lib/board.c @@ -40,6 +40,10 @@ #include <asm/init_helpers.h> #include <asm/init_wrappers.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + /* * Breath some life into the board... * @@ -85,6 +89,17 @@ typedef int (init_fnc_t) (void);
/* + * Initialize early heap (when enabled by config). + */ +#ifdef CONFIG_SYS_EARLY_MALLOC +static void early_malloc_init(void) +{ + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +} +#endif /* CONFIG_SYS_EARLY_MALLOC */ + + +/* * init_sequence_f is the list of init functions which are run when U-Boot * is executing from Flash with a limited 'C' environment. The following * limitations must be considered when implementing an '_f' function: @@ -99,6 +114,9 @@ init_fnc_t *init_sequence_f[] = { cpu_init_f, board_early_init_f, env_init, +#ifdef CONFIG_SYS_EARLY_MALLOC + early_malloc_init, +#endif /* CONFIG_SYS_EARLY_MALLOC */ init_baudrate_f, serial_init, console_init_f, diff --git a/common/Makefile b/common/Makefile index 22e8a6f..5862d34 100644 --- a/common/Makefile +++ b/common/Makefile @@ -201,6 +201,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..cde8800 --- /dev/null +++ b/common/dmmalloc.c @@ -0,0 +1,88 @@ +/* + * (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 +__weak struct early_heap_header *early_brk(size_t size) +{ + struct early_heap_header *h = + (struct early_heap_header *)CONFIG_SYS_EARLY_HEAP_ADDR; + + if (g->early_heap_first != NULL) + return NULL; + + h->free_space_pointer = (void *)(roundup( + (phys_addr_t)CONFIG_SYS_EARLY_HEAP_ADDR + + sizeof(struct early_heap_header), + sizeof(phys_addr_t))); + h->free_bytes = size - roundup(sizeof(struct early_heap_header), + sizeof(phys_addr_t)); + h->next_early_heap = NULL; + + return h; +} + +void *early_malloc(size_t size) +{ + phys_addr_t addr; + struct early_heap_header *h; + + size = roundup(size, sizeof(phys_addr_t)); + + h = gd->early_heap_first; + while ((h->free_bytes < size) && (h->next_early_heap != NULL)) + h = h->next_early_heap; + + if (h->free_bytes < size) { + h->next_early_heap = early_brk(size); + if (h->next_early_heap == NULL) + debug("EH overflow. Can not early_brk. required %d B.", + size); + return NULL; + } + + addr = (phys_addr_t)h->free_space_pointer; + + h->free_space_pointer += size; + h->free_bytes -= size; + + return (void *)addr; +} + +int early_malloc_active(void) +{ + return ((gd->flags & GD_FLG_RELOC) != GD_FLG_RELOC); +} + +#endif /* CONFIG_SYS_EARLY_MALLOC */ diff --git a/include/dmmalloc.h b/include/dmmalloc.h new file mode 100644 index 0000000..a5ce2ec --- /dev/null +++ b/include/dmmalloc.h @@ -0,0 +1,89 @@ +/* + * (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> + +#if (!defined(CONFIG_SYS_EARLY_HEAP_ADDR)) || \ + (!defined(CONFIG_SYS_EARLY_HEAP_SIZE)) +#undef CONFIG_SYS_EARLY_MALLOC +#endif /* CONFIG_SYS_EARLY_HEAP_ADDR */ + +#ifdef CONFIG_SYS_EARLY_MALLOC +struct early_heap_header { + void *free_space_pointer; + size_t free_bytes; + void *next_early_heap; +}; + +struct early_heap_header *early_brk(size_t size); +void *early_malloc(size_t size); +int early_malloc_active(void); + +#endif /* CONFIG_SYS_EARLY_MALLOC */ + +#ifdef CONFIG_DM + +static inline 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); +} + +static inline void dmfree(void *ptr) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC + if (early_malloc_active()) + return; +#endif /* CONFIG_SYS_EARLY_MALLOC */ + free(ptr); +} + +static inline void *dmcalloc(size_t n, size_t elem_size) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC + if (early_malloc_active()) + return NULL; +#endif /* CONFIG_SYS_EARLY_MALLOC */ + return calloc(n, elem_size); +} + +static inline void *dmrealloc(void *oldmem, size_t bytes) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC + if (early_malloc_active()) + return NULL; +#endif /* CONFIG_SYS_EARLY_MALLOC */ + return dmrealloc(oldmem, bytes); +} + +#endif /* CONFIG_DM */ +#endif /* __INCLUDE_DMMALLOC_H */ +

early_malloc for DM with support for more heaps and lightweight first heap in the same memory as an early stack.
Adaptation layer for seamless calling of early_malloc or dlmalloc from DM based on init stage added (dmmalloc() and related functions).
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com --- Changelog since v5: dmmalloc() and all dm* functions has been moved to header, made static inline and preprocessor-dependent blocks are reworked. early_malloc_active() corrected and made not static. s/CONFIG_SYS_DM/CONFIG_DM/ applied.
Changelog sice v6: Check of first heap emptyness in early_brk() has been simplified.
Changelog since v7: dmcalloc() implmentation added. Comments added to header.
arch/arm/include/asm/global_data.h | 3 + arch/arm/lib/board.c | 8 ++ arch/avr32/include/asm/global_data.h | 3 + arch/avr32/lib/board.c | 9 +++ arch/blackfin/include/asm/global_data.h | 3 + arch/blackfin/lib/board.c | 8 ++ arch/m68k/include/asm/global_data.h | 3 + arch/m68k/lib/board.c | 8 ++ arch/microblaze/include/asm/global_data.h | 3 + arch/microblaze/lib/board.c | 9 +++ arch/mips/include/asm/global_data.h | 3 + arch/mips/lib/board.c | 8 ++ arch/nds32/include/asm/global_data.h | 3 + arch/nds32/lib/board.c | 8 ++ arch/nios2/include/asm/global_data.h | 3 + arch/nios2/lib/board.c | 8 ++ arch/openrisc/include/asm/global_data.h | 3 + arch/openrisc/lib/board.c | 8 ++ arch/powerpc/include/asm/global_data.h | 3 + arch/powerpc/lib/board.c | 8 ++ arch/sandbox/include/asm/global_data.h | 3 + arch/sandbox/lib/board.c | 8 ++ arch/sh/include/asm/global_data.h | 3 + arch/sh/lib/board.c | 8 ++ arch/sparc/include/asm/global_data.h | 3 + arch/sparc/lib/board.c | 8 ++ arch/x86/include/asm/global_data.h | 3 + arch/x86/lib/board.c | 18 +++++ common/Makefile | 1 + common/dmmalloc.c | 88 ++++++++++++++++++++++ include/dmmalloc.h | 117 +++++++++++++++++++++++++++++ 31 files changed, 372 insertions(+) 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 f8088fe..ef727b0 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -82,6 +82,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index f1951e8..f73d8b2 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -53,6 +53,10 @@ #include <post.h> #include <logbuff.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + #ifdef CONFIG_BITBANGMII #include <miiphy.h> #endif @@ -281,6 +285,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->mon_len = _bss_end_ofs; #ifdef CONFIG_OF_EMBED /* Get a pointer to the FDT */ diff --git a/arch/avr32/include/asm/global_data.h b/arch/avr32/include/asm/global_data.h index 7878bb1..0654a61 100644 --- a/arch/avr32/include/asm/global_data.h +++ b/arch/avr32/include/asm/global_data.h @@ -48,6 +48,9 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/avr32/lib/board.c b/arch/avr32/lib/board.c index d7a64b4..f1bd946 100644 --- a/arch/avr32/lib/board.c +++ b/arch/avr32/lib/board.c @@ -42,6 +42,11 @@ #ifdef CONFIG_GENERIC_ATMEL_MCI #include <mmc.h> #endif + +#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
unsigned long monitor_flash_len; @@ -161,6 +166,10 @@ void board_init_f(ulong board_type) memset(&gd_data, 0, sizeof(gd_data)); gd = &gd_data;
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + /* Perform initialization sequence */ board_early_init_f(); cpu_init(); diff --git a/arch/blackfin/include/asm/global_data.h b/arch/blackfin/include/asm/global_data.h index 290a9e7..2ae395c 100644 --- a/arch/blackfin/include/asm/global_data.h +++ b/arch/blackfin/include/asm/global_data.h @@ -57,6 +57,9 @@ typedef struct global_data {
void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/blackfin/lib/board.c b/arch/blackfin/lib/board.c index c380d27..96b7d76 100644 --- a/arch/blackfin/lib/board.c +++ b/arch/blackfin/lib/board.c @@ -37,6 +37,10 @@ int post_flag; #endif
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
__attribute__((always_inline)) @@ -267,6 +271,10 @@ void board_init_f(ulong bootflag) watchdog_init(); #endif
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + #ifdef DEBUG if (GENERATED_GBL_DATA_SIZE < sizeof(*gd)) hang(); diff --git a/arch/m68k/include/asm/global_data.h b/arch/m68k/include/asm/global_data.h index cd55b83..bd30435 100644 --- a/arch/m68k/include/asm/global_data.h +++ b/arch/m68k/include/asm/global_data.h @@ -66,6 +66,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/m68k/lib/board.c b/arch/m68k/lib/board.c index 65a8595..1b9312c 100644 --- a/arch/m68k/lib/board.c +++ b/arch/m68k/lib/board.c @@ -69,6 +69,10 @@
#include <nand.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
static char *failed = "*** failed ***\n"; @@ -227,6 +231,10 @@ board_init_f (ulong bootflag) /* Clear initial global data */ memset ((void *) gd, 0, sizeof (gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) { hang (); diff --git a/arch/microblaze/include/asm/global_data.h b/arch/microblaze/include/asm/global_data.h index de3b8db..6f4066d 100644 --- a/arch/microblaze/include/asm/global_data.h +++ b/arch/microblaze/include/asm/global_data.h @@ -46,6 +46,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/microblaze/lib/board.c b/arch/microblaze/lib/board.c index 674b573..eeb8441 100644 --- a/arch/microblaze/lib/board.c +++ b/arch/microblaze/lib/board.c @@ -37,6 +37,10 @@ #include <asm/microblaze_intc.h> #include <fdtdec.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
/* @@ -81,6 +85,11 @@ void board_init_f(ulong not_used) asm ("nop"); /* FIXME gd is not initialize - wait */ memset ((void *)gd, 0, GENERATED_GBL_DATA_SIZE); memset ((void *)bd, 0, GENERATED_BD_INFO_SIZE); + +#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = bd; gd->baudrate = CONFIG_BAUDRATE; bd->bi_baudrate = CONFIG_BAUDRATE; diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h index 6e2cdc7..ac24e3f 100644 --- a/arch/mips/include/asm/global_data.h +++ b/arch/mips/include/asm/global_data.h @@ -59,6 +59,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/mips/lib/board.c b/arch/mips/lib/board.c index 62d47a8..4657046 100644 --- a/arch/mips/lib/board.c +++ b/arch/mips/lib/board.c @@ -36,6 +36,10 @@ #include <miiphy.h> #endif
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
ulong monitor_flash_len; @@ -153,6 +157,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) hang(); diff --git a/arch/nds32/include/asm/global_data.h b/arch/nds32/include/asm/global_data.h index 94bd4c2..d0e2606 100644 --- a/arch/nds32/include/asm/global_data.h +++ b/arch/nds32/include/asm/global_data.h @@ -63,6 +63,9 @@ typedef struct global_data {
void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/nds32/lib/board.c b/arch/nds32/lib/board.c index 2164a50..97193b0 100644 --- a/arch/nds32/lib/board.c +++ b/arch/nds32/lib/board.c @@ -37,6 +37,10 @@ #include <onenand_uboot.h> #include <mmc.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
ulong monitor_flash_len; @@ -192,6 +196,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, GENERATED_GBL_DATA_SIZE);
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->mon_len = (unsigned int)(&__bss_end__) - (unsigned int)(&_start);
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { diff --git a/arch/nios2/include/asm/global_data.h b/arch/nios2/include/asm/global_data.h index 3b0d9e6..44373f4 100644 --- a/arch/nios2/include/asm/global_data.h +++ b/arch/nios2/include/asm/global_data.h @@ -42,6 +42,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/nios2/lib/board.c b/arch/nios2/lib/board.c index 1e495d4..866dc12 100644 --- a/arch/nios2/lib/board.c +++ b/arch/nios2/lib/board.c @@ -40,6 +40,10 @@ #include <nand.h> /* cannot even include nand.h if it isnt configured */ #endif
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
/* @@ -95,6 +99,10 @@ void board_init (void) /* compiler optimization barrier needed for GCC >= 3.4 */ __asm__ __volatile__("": : :"memory");
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = &bd_data; gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/openrisc/include/asm/global_data.h b/arch/openrisc/include/asm/global_data.h index 6a0c0cc..ec2220a 100644 --- a/arch/openrisc/include/asm/global_data.h +++ b/arch/openrisc/include/asm/global_data.h @@ -44,6 +44,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/openrisc/lib/board.c b/arch/openrisc/lib/board.c index 85aa189..f1199d6 100644 --- a/arch/openrisc/lib/board.c +++ b/arch/openrisc/lib/board.c @@ -44,6 +44,10 @@ #include <timestamp.h> #include <version.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
/* @@ -86,6 +90,10 @@ void board_init(void)
memset((void *)gd, 0, GENERATED_GBL_DATA_SIZE);
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = (bd_t *)(gd+1); /* At end of global data */ gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/powerpc/include/asm/global_data.h b/arch/powerpc/include/asm/global_data.h index 5a5877f..38b63f9 100644 --- a/arch/powerpc/include/asm/global_data.h +++ b/arch/powerpc/include/asm/global_data.h @@ -182,6 +182,9 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/powerpc/lib/board.c b/arch/powerpc/lib/board.c index fea310e..39af242 100644 --- a/arch/powerpc/lib/board.c +++ b/arch/powerpc/lib/board.c @@ -87,6 +87,10 @@ #include <miiphy.h> #endif
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + #ifdef CONFIG_SYS_UPDATE_FLASH_SIZE extern int update_flash_size(int flash_size); #endif @@ -389,6 +393,10 @@ void board_init_f(ulong bootflag) memset((void *) gd, 0, sizeof(gd_t)); #endif
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) if ((*init_fnc_ptr) () != 0) hang(); diff --git a/arch/sandbox/include/asm/global_data.h b/arch/sandbox/include/asm/global_data.h index 581fd2f..00c7c10 100644 --- a/arch/sandbox/include/asm/global_data.h +++ b/arch/sandbox/include/asm/global_data.h @@ -46,6 +46,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/sandbox/lib/board.c b/arch/sandbox/lib/board.c index c173bf9..d384481 100644 --- a/arch/sandbox/lib/board.c +++ b/arch/sandbox/lib/board.c @@ -47,6 +47,10 @@
#include <os.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
static gd_t gd_mem; @@ -157,6 +161,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + #if defined(CONFIG_OF_EMBED) /* Get a pointer to the FDT */ gd->fdt_blob = _binary_dt_dtb_start; diff --git a/arch/sh/include/asm/global_data.h b/arch/sh/include/asm/global_data.h index 6e534ad..441fecd 100644 --- a/arch/sh/include/asm/global_data.h +++ b/arch/sh/include/asm/global_data.h @@ -42,6 +42,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/sh/lib/board.c b/arch/sh/lib/board.c index 34d7881..eb04ed2 100644 --- a/arch/sh/lib/board.c +++ b/arch/sh/lib/board.c @@ -32,6 +32,10 @@ #include <miiphy.h> #endif
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
extern int cpu_init(void); @@ -150,6 +154,10 @@ void sh_generic_init(void)
memset(gd, 0, GENERATED_GBL_DATA_SIZE);
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */
gd->bd = (bd_t *)(gd + 1); /* At end of global data */ diff --git a/arch/sparc/include/asm/global_data.h b/arch/sparc/include/asm/global_data.h index 93d3cc0..537e09a 100644 --- a/arch/sparc/include/asm/global_data.h +++ b/arch/sparc/include/asm/global_data.h @@ -74,6 +74,9 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/sparc/lib/board.c b/arch/sparc/lib/board.c index 6f33666..2ced0a7 100644 --- a/arch/sparc/lib/board.c +++ b/arch/sparc/lib/board.c @@ -53,6 +53,10 @@ #include <miiphy.h> #endif
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
/* Debug options @@ -178,6 +182,10 @@ void board_init_f(ulong bootflag) /* Clear initial global data */ memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +#endif /* CONFIG_SYS_EARLY_MALLOC */ + gd->bd = (bd_t *) (gd + 1); /* At end of global data */ gd->baudrate = CONFIG_BAUDRATE; gd->cpu_clk = CONFIG_SYS_CLK_FREQ; diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 6d29c0b..920a805 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -57,6 +57,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 + void *early_heap_first; /* heap for early_malloc */ +#endif } gd_t;
static inline gd_t *get_fs_gd_ptr(void) diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index 90cf7fc..a670f9e 100644 --- a/arch/x86/lib/board.c +++ b/arch/x86/lib/board.c @@ -40,6 +40,10 @@ #include <asm/init_helpers.h> #include <asm/init_wrappers.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif + /* * Breath some life into the board... * @@ -85,6 +89,17 @@ typedef int (init_fnc_t) (void);
/* + * Initialize early heap (when enabled by config). + */ +#ifdef CONFIG_SYS_EARLY_MALLOC +static void early_malloc_init(void) +{ + gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE); +} +#endif /* CONFIG_SYS_EARLY_MALLOC */ + + +/* * init_sequence_f is the list of init functions which are run when U-Boot * is executing from Flash with a limited 'C' environment. The following * limitations must be considered when implementing an '_f' function: @@ -99,6 +114,9 @@ init_fnc_t *init_sequence_f[] = { cpu_init_f, board_early_init_f, env_init, +#ifdef CONFIG_SYS_EARLY_MALLOC + early_malloc_init, +#endif /* CONFIG_SYS_EARLY_MALLOC */ init_baudrate_f, serial_init, console_init_f, diff --git a/common/Makefile b/common/Makefile index 22e8a6f..5862d34 100644 --- a/common/Makefile +++ b/common/Makefile @@ -201,6 +201,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..6dbb622 --- /dev/null +++ b/common/dmmalloc.c @@ -0,0 +1,88 @@ +/* + * (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 +__weak struct early_heap_header *early_brk(size_t size) +{ + struct early_heap_header *h = + (struct early_heap_header *)CONFIG_SYS_EARLY_HEAP_ADDR; + + if (gd->early_heap_first != NULL) + return NULL; + + h->free_space_pointer = (void *)(roundup( + (phys_addr_t)CONFIG_SYS_EARLY_HEAP_ADDR + + sizeof(struct early_heap_header), + sizeof(phys_addr_t))); + h->free_bytes = size - roundup(sizeof(struct early_heap_header), + sizeof(phys_addr_t)); + h->next_early_heap = NULL; + + return h; +} + +void *early_malloc(size_t size) +{ + phys_addr_t addr; + struct early_heap_header *h; + + size = roundup(size, sizeof(phys_addr_t)); + + h = gd->early_heap_first; + while ((h->free_bytes < size) && (h->next_early_heap != NULL)) + h = h->next_early_heap; + + if (h->free_bytes < size) { + h->next_early_heap = early_brk(size); + if (h->next_early_heap == NULL) + debug("EH overflow. Can not early_brk. required %d B.", + size); + return NULL; + } + + addr = (phys_addr_t)h->free_space_pointer; + + h->free_space_pointer += size; + h->free_bytes -= size; + + return (void *)addr; +} + +int early_malloc_active(void) +{ + return ((gd->flags & GD_FLG_RELOC) != GD_FLG_RELOC); +} + +#endif /* CONFIG_SYS_EARLY_MALLOC */ diff --git a/include/dmmalloc.h b/include/dmmalloc.h new file mode 100644 index 0000000..7bef0eb --- /dev/null +++ b/include/dmmalloc.h @@ -0,0 +1,117 @@ +/* + * (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> + +#if (!defined(CONFIG_SYS_EARLY_HEAP_ADDR)) || \ + (!defined(CONFIG_SYS_EARLY_HEAP_SIZE)) +#undef CONFIG_SYS_EARLY_MALLOC +#endif /* CONFIG_SYS_EARLY_HEAP_ADDR */ + +#ifdef CONFIG_SYS_EARLY_MALLOC +struct early_heap_header { + void *free_space_pointer; + size_t free_bytes; + void *next_early_heap; +}; + +/* + * Function to perfrom early break. This function can be platform dependent + * or board dependent but sensible default is provided. + * @size: size of the new early heap to be allocated and set up. + * Returns the new heap pointer. + */ +struct early_heap_header *early_brk(size_t size); + +/* + * malloc-like function operating on the early_heap(s). + */ +void *early_malloc(size_t size); + +/* + * Check whether the early mallocator is active. + */ +int early_malloc_active(void); + +#endif /* CONFIG_SYS_EARLY_MALLOC */ + +#ifdef CONFIG_DM + +/* + * DM versions of malloc* fuctions. In early init it calls early_malloc. + * It wraps around normal malloc* functions afterwards. + */ + +static inline 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); +} + +static inline void dmfree(void *ptr) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC + if (early_malloc_active()) + return; +#endif /* CONFIG_SYS_EARLY_MALLOC */ + free(ptr); +} + +static inline void *dmcalloc(size_t n, size_t elem_size) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC + char *addr; + int size = elem_size * n; + int i; + + if (early_malloc_active()) { + addr = early_malloc(size); + for (i=0; i<size; i++) + addr[i] = 0; + + return addr; + } +#endif /* CONFIG_SYS_EARLY_MALLOC */ + return calloc(n, elem_size); +} + +static inline void *dmrealloc(void *oldmem, size_t bytes) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC + if (early_malloc_active()) + return NULL; +#endif /* CONFIG_SYS_EARLY_MALLOC */ + return dmrealloc(oldmem, bytes); +} + +#endif /* CONFIG_DM */ +#endif /* __INCLUDE_DMMALLOC_H */ +

Dear Tomas Hlavacek,
In message 1348416940-20319-1-git-send-email-tmshlvck@gmail.com you wrote:
early_malloc for DM with support for more heaps and lightweight first heap in the same memory as an early stack.
Adaptation layer for seamless calling of early_malloc or dlmalloc from DM based on init stage added (dmmalloc() and related functions).
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com
Changelog since v5: dmmalloc() and all dm* functions has been moved to header, made static inline and preprocessor-dependent blocks are reworked. early_malloc_active() corrected and made not static. s/CONFIG_SYS_DM/CONFIG_DM/ applied.
Changelog sice v6: Check of first heap emptyness in early_brk() has been simplified.
Changelog since v7: dmcalloc() implmentation added. Comments added to header.
Your change log does not make much sense to me. It appears there has been some dmcalloc() implementation already in v5 (and eearlier?), as you write there you moved it into the header file. Now you add it again?
This changelog is intended to desccribe the difference between the patch versions, to allow a reviewer to recognize which comments you addressed, and where you decided otherwise.
Your log does not provide any such information.
Also, please re-read the recommendations for the commit message. "FOO added" is considered bad; please use something like "add FOO" instead (i. e. describe what this commit actually does).
Also, please make sure tu run ALL patches through checkpatch before submitting; your patch throws 4 errors that all need fixing.
Finally, you might want to consult a spell checker every now and then (see for example "implmentation", "perfrom", etc.).
Thanks.
Wolfgang Denk

Dear Wolfgang Denk,
On Sun, Sep 23, 2012 at 6:32 PM, Wolfgang Denk wd@denx.de wrote:
Changelog since v7: dmcalloc() implmentation added. Comments added to header.
Your change log does not make much sense to me. It appears there has been some dmcalloc() implementation already in v5 (and eearlier?), as you write there you moved it into the header file. Now you add it again?
Well no. The dmcalloc function returned always NULL in the early stage in the previous versions. The current version of dmcalloc simulates calloc also in the early_mallocator stage.
Also, please re-read the recommendations for the commit message. "FOO added" is considered bad; please use something like "add FOO" instead (i. e. describe what this commit actually does).
I will do that.
Tomas

On Sun, Sep 23, 2012 at 06:47:34PM +0200, Tomas Hlavacek wrote:
Dear Wolfgang Denk,
On Sun, Sep 23, 2012 at 6:32 PM, Wolfgang Denk wd@denx.de wrote:
Changelog since v7: dmcalloc() implmentation added. Comments added to header.
Your change log does not make much sense to me. It appears there has been some dmcalloc() implementation already in v5 (and eearlier?), as you write there you moved it into the header file. Now you add it again?
Well no. The dmcalloc function returned always NULL in the early stage in the previous versions. The current version of dmcalloc simulates calloc also in the early_mallocator stage.
Also, please re-read the recommendations for the commit message. "FOO added" is considered bad; please use something like "add FOO" instead (i. e. describe what this commit actually does).
I will do that.
I would strongly recommend and especially as the DM work moves on you try using patman to manage the series as it will help you to keep track of, and format properly, changelogs , run checkpatch and otherwise encourage you to have the other good habits that help us to focus on reviewing the changes themselves.

Dear Tomas Hlavacek,
[..]
- if (early_malloc_active()) {
addr = early_malloc(size);
for (i=0; i<size; i++)
addr[i] = 0;
memset() ?
return addr;
- }
+#endif /* CONFIG_SYS_EARLY_MALLOC */
- return calloc(n, elem_size);
+}
+static inline void *dmrealloc(void *oldmem, size_t bytes) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC
- if (early_malloc_active())
return NULL;
I wonder how should this be implemented ... maybe early_malloc + standard memcpy()
+#endif /* CONFIG_SYS_EARLY_MALLOC */
- return dmrealloc(oldmem, bytes);
+}
+#endif /* CONFIG_DM */ +#endif /* __INCLUDE_DMMALLOC_H */
Best regards, Marek Vasut

Hello Marek,
On Mon, Sep 24, 2012 at 1:11 AM, Marek Vasut marex@denx.de wrote:
Dear Tomas Hlavacek,
[..]
if (early_malloc_active()) {
addr = early_malloc(size);
for (i=0; i<size; i++)
addr[i] = 0;
memset() ?
Yes, sure. Thanks.
return addr;
}
+#endif /* CONFIG_SYS_EARLY_MALLOC */
return calloc(n, elem_size);
+}
+static inline void *dmrealloc(void *oldmem, size_t bytes) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC
if (early_malloc_active())
return NULL;
I wonder how should this be implemented ... maybe early_malloc + standard memcpy()
How do you want me to fix all the pointers to the memcpyied part of heap then? I think this will not work unless I make some reservations for eventual growth for each and every early_mallocated area. And I think this is not good idea at all for early_malloc.
I think there are two straight-forward possibilities: a) keep the empty implementation of dmrealloc() in early stage and avoid using it in code which might run in early stage, but retain the dm* version of the symbol. b) remove the dmrealloc() entirely which may have certain negative consequences, because it might be tempting to mix dmmalloc() and (non-dm*) realloc() calls which is obviously wrong.
Tomas

Dear Tomas Hlavacek,
[...]
+static inline void *dmrealloc(void *oldmem, size_t bytes) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC
if (early_malloc_active())
return NULL;
I wonder how should this be implemented ... maybe early_malloc + standard memcpy()
How do you want me to fix all the pointers to the memcpyied part of heap then? I think this will not work unless I make some reservations for eventual growth for each and every early_mallocated area. And I think this is not good idea at all for early_malloc.
What exactly would you need to fix ? It's only a matter of allocating new block, copying the existing data there and returning the pointer to the new block, no?
I think there are two straight-forward possibilities: a) keep the empty implementation of dmrealloc() in early stage and avoid using it in code which might run in early stage, but retain the dm* version of the symbol. b) remove the dmrealloc() entirely which may have certain negative consequences, because it might be tempting to mix dmmalloc() and (non-dm*) realloc() calls which is obviously wrong.
Tomas
Best regards, Marek Vasut

Hi Marek,
On Tue, Sep 25, 2012 at 12:19 AM, Marek Vasut marex@denx.de wrote:
Dear Tomas Hlavacek,
[...]
+static inline void *dmrealloc(void *oldmem, size_t bytes) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC
if (early_malloc_active())
return NULL;
I wonder how should this be implemented ... maybe early_malloc + standard memcpy()
How do you want me to fix all the pointers to the memcpyied part of heap then? I think this will not work unless I make some reservations for eventual growth for each and every early_mallocated area. And I think this is not good idea at all for early_malloc.
What exactly would you need to fix ? It's only a matter of allocating new block, copying the existing data there and returning the pointer to the new block, no?
I think there are two straight-forward possibilities: a) keep the empty implementation of dmrealloc() in early stage and avoid using it in code which might run in early stage, but retain the dm* version of the symbol. b) remove the dmrealloc() entirely which may have certain negative consequences, because it might be tempting to mix dmmalloc() and (non-dm*) realloc() calls which is obviously wrong.
From realloc man page:
"The realloc() function returns a pointer to the newly allocated memory, which is suitably aligned for any kind of variable and may be different from ptr, or NULL if the request fails. "
So all you need to do is allocate a new block and memcpy() the old data. Note also:
"If realloc() fails the original block is left untouched; it is not freed or moved."
"If the new size is larger than the old size, the added memory will not be initialized"
"If ptr is NULL, then the call is equivalent to malloc(size)"
"if size is equal to zero, and ptr is not NULL, then the call is equivalent to free(ptr)"
"If the area pointed to was moved, a free(ptr) is done."
The last two are NOPs for early heap as we have no way to track free'd blocks
Keep in mind that 'real' realloc() has access to information providing the size of the source block of allocated memory, so it can do a memcpy using (at least a good guess of) the size of the source block. In the early heap case, we do not have that data, so we would need to memcpy the entire size of the destination block - this will likely bring in garbage (no problem as we there is nothing in the spec to forbid that) and _might_ have some interesting boundary conditions (what happens if we memcpy past the end of an early heap block into ga-ga land?)
Regards,
Graeme

Hello Graeme!
On Tue, Sep 25, 2012 at 2:37 AM, Graeme Russ graeme.russ@gmail.com wrote:
Hi Marek,
[...]
The last two are NOPs for early heap as we have no way to track free'd blocks
Keep in mind that 'real' realloc() has access to information providing the size of the source block of allocated memory, so it can do a memcpy using (at least a good guess of) the size of the source block. In the early heap case, we do not have that data, so we would need to memcpy the entire size of the destination block - this will likely bring in garbage (no problem as we there is nothing in the spec to forbid that) and _might_ have some interesting boundary conditions (what happens if we memcpy past the end of an early heap block into ga-ga land?)
I was thinking about such simple implementation:
static inline void *dmrealloc(void *oldaddr, size_t bytes) { #ifdef CONFIG_SYS_EARLY_MALLOC char *addr; if (early_malloc_active()) { addr = dmalloc(bytes); memcpy(addr, oldaddr, bytes); return addr; } #endif /* CONFIG_SYS_EARLY_MALLOC */ return dmrealloc(oldmem, bytes); }
But then the fun comes: I can not distinguish the case when you have 100 B char *x allocated and you called dmrealloc(x, 99). And I can hit some boundaries as
But yes, we can have such a stupid implementation. Or I can use early_malloc frame header which would contain magic (to detect wrong dmrealloc calls on arbitrary pointer) and size, so I would be able to do free and realloc. Then I would need new free-space enumeration mechanism to reuse free space (let's say that I can create a linked list of free headers), so the frame header is going to be 12 B total. Or we can have no implementation of dmrealloc at all.
Tomas

Hi Thomas,
On Sep 25, 2012 6:43 PM, "Tomas Hlavacek" tmshlvck@gmail.com wrote:
Hello Graeme!
On Tue, Sep 25, 2012 at 2:37 AM, Graeme Russ graeme.russ@gmail.com
wrote:
Hi Marek,
[...]
The last two are NOPs for early heap as we have no way to track free'd
blocks
Keep in mind that 'real' realloc() has access to information providing the size of the source block of allocated memory, so it can do a memcpy using (at least a good guess of) the size of the source block. In the early heap case, we do not have that data, so we would need to memcpy the entire size of the destination block - this will likely bring in garbage (no problem as we there is nothing in the spec to forbid that) and _might_ have some interesting boundary conditions (what happens if we memcpy past the end of an early heap block into ga-ga land?)
I was thinking about such simple implementation:
static inline void *dmrealloc(void *oldaddr, size_t bytes) { #ifdef CONFIG_SYS_EARLY_MALLOC char *addr; if (early_malloc_active()) { addr = dmalloc(bytes); memcpy(addr, oldaddr, bytes); return addr; } #endif /* CONFIG_SYS_EARLY_MALLOC */ return dmrealloc(oldmem, bytes); }
But then the fun comes: I can not distinguish the case when you have 100 B char *x allocated and you called dmrealloc(x, 99). And I can hit some boundaries as
But yes, we can have such a stupid implementation. Or I can use early_malloc frame header which would contain magic (to detect wrong dmrealloc calls on arbitrary pointer) and size, so I would be able to do free and realloc. Then I would need new free-space enumeration mechanism to reuse free space (let's say that I can create a linked list of free headers), so the frame header is going to be 12 B total. Or we can have no implementation of dmrealloc at all.
We should implement each of malloc(), free(), calloc(), and realloc().
Don't worry about reclaiming and reusing space with a proper free() implementation. Remember, all memory allocated on the early heap must be relocated anyway.
Maybe if you add a size_t value immediately before the allocated space which stores the block size. So:
size_t *bytes_ptr = ptr; bytes_ptr--; size_t bytes = *bytes_ptr;
gives you the block size
Regards,
Graeme

Hi Tomas
On Tue, Sep 25, 2012 at 7:09 PM, Graeme Russ graeme.russ@gmail.com wrote:
We should implement each of malloc(), free(), calloc(), and realloc().
Don't worry about reclaiming and reusing space with a proper free() implementation. Remember, all memory allocated on the early heap must be relocated anyway.
Maybe if you add a size_t value immediately before the allocated space which stores the block size. So:
size_t *bytes_ptr = ptr; bytes_ptr--; size_t bytes = *bytes_ptr;
gives you the block size
I've been thinking about this a bit more, and for the sake of 4 bytes, this additional 'size' member could be quite handy: - We effectively end up with a linked-list of allocated blocks - free() could set the high bit to tag the block as 'de-allocated' - When a block is relocated into the permanent heap, free() should be called on the source (early heap) block - We can call a 'cleanup' function after early heap is no longer needed and check that every block has the high bit set - We can re-use blocks by scanning for a tagged block with the same size (usefull for drivers that allocate temporary buffers which are always the same size) - If there are no early heaps with enough space for a given malloc operation, but there is a tagged block that is larger than the requested size, we can split tagged blocks
Remebering back to when I suggested a list of relocation helpers (one for each allocated block), I think we can implement that as an additional field in the block header (stretching the header to 8 bytes). This can come later.
Regards,
Graeme

Hello Graeme,
On Wed, Sep 26, 2012 at 1:04 AM, Graeme Russ graeme.russ@gmail.com wrote:
Hi Tomas
On Tue, Sep 25, 2012 at 7:09 PM, Graeme Russ graeme.russ@gmail.com wrote:
We should implement each of malloc(), free(), calloc(), and realloc().
Don't worry about reclaiming and reusing space with a proper free() implementation. Remember, all memory allocated on the early heap must be relocated anyway.
Maybe if you add a size_t value immediately before the allocated space which stores the block size. So:
size_t *bytes_ptr = ptr; bytes_ptr--; size_t bytes = *bytes_ptr;
gives you the block size
I've been thinking about this a bit more, and for the sake of 4 bytes, this additional 'size' member could be quite handy:
- We effectively end up with a linked-list of allocated blocks
Yes, this makes sense. Knowing size of allocated blocks enables the early_malloc to do the whole set of malloc* functions.
Do you think it would be also useful to have a basic check that the pointer passed to new early_free() and/or early_realloc() is valid? I mean check that the pointer really points at the start of the block and there is a valid header preceding the block. We can have a magic number in the header for example. Or I can store a list of allocated blocks as a variable-sized array in the early_heap_header.
- free() could set the high bit to tag the block as 'de-allocated'
Well, we would end up with malloc doing:
1) scan through all heaps to find best fit into previously free()-ed block 2) scan through all heaps to find enough free space using the heap header 3) call early_brk to obtain more space
Data structures would be:
The scanning two different header types for free space seems to me being a bit redundant. What do you think about replacing point (2) and using block headers instead of free space pointer in the heap header and just split the block when there is not exact size match. I mean:
1) scan through all heaps to find best fit block 2) scan through all heaps to find greater block and split it 3) call early_brk to obtain more space
Data structures would be:
struct early_heap_header { int heap_size; phys_addr_t reloc_addr_old; }
struct early_block_header { int magic; int size; }
The brand new early_heap right after it's creation would consist of a early_heap_header followed by a early_block_header with the free bit set to true.
- When a block is relocated into the permanent heap, free() should be called on the source (early heap) block
Well, that time we would have only a copy of the early_heap on certain platforms. Assuming that first we set off drivers and DM using early_heap(s), then we would copy each early_heap to some computed address and jump to board_init_r. In board_init_r we would access the early_heap copy via translation function using the address offset (early_heap_copy - early_heap_copy->reloc_addr_old).
To do the early_free correctly in this mid-relocation state I would have to allow early_* code to operate during this period. It is not that hard to do, but maybe it is conceptually wrong because it means operating early_malloc/realloc/free code on a copy of it's own data after relocation.
- We can call a 'cleanup' function after early heap is no longer needed and check that every block has the high bit set
Yes, it would help. When each block has to be free()-ed or relocated and then free()-ed, it could help find memory leaks during early init.
- We can re-use blocks by scanning for a tagged block with the same size (usefull for drivers that allocate temporary buffers which are always the same size)
- If there are no early heaps with enough space for a given malloc operation, but there is a tagged block that is larger than the requested size, we can split tagged blocks
Remebering back to when I suggested a list of relocation helpers (one for each allocated block), I think we can implement that as an additional field in the block header (stretching the header to 8 bytes). This can come later.
Do you mean we should place a pointer pointing at a relocation function into each block header? I think it would end up in situation like: Somebody is allocating a tree for example, he would set the helper function into the root element and NULL pointers to other nodes, because it makes more sense to relocate tree recursively from the root.
Tomas

Hi Tomas,
On Wed, Sep 26, 2012 at 8:16 PM, Tomas Hlavacek tmshlvck@gmail.com wrote:
Hello Graeme,
On Wed, Sep 26, 2012 at 1:04 AM, Graeme Russ graeme.russ@gmail.com wrote:
Hi Tomas
On Tue, Sep 25, 2012 at 7:09 PM, Graeme Russ graeme.russ@gmail.com wrote:
We should implement each of malloc(), free(), calloc(), and realloc().
Don't worry about reclaiming and reusing space with a proper free() implementation. Remember, all memory allocated on the early heap must be relocated anyway.
Maybe if you add a size_t value immediately before the allocated space which stores the block size. So:
size_t *bytes_ptr = ptr; bytes_ptr--; size_t bytes = *bytes_ptr;
gives you the block size
I've been thinking about this a bit more, and for the sake of 4 bytes, this additional 'size' member could be quite handy:
- We effectively end up with a linked-list of allocated blocks
Yes, this makes sense. Knowing size of allocated blocks enables the early_malloc to do the whole set of malloc* functions.
Do you think it would be also useful to have a basic check that the pointer passed to new early_free() and/or early_realloc() is valid? I mean check that the pointer really points at the start of the block and there is a valid header preceding the block. We can have a magic number in the header for example. Or I can store a list of allocated blocks as a variable-sized array in the early_heap_header.
The goal of early_malloc is to be lightweight and fast, not bullet-proof.
- free() could set the high bit to tag the block as 'de-allocated'
Well, we would end up with malloc doing:
- scan through all heaps to find best fit into previously free()-ed block
- scan through all heaps to find enough free space using the heap header
- call early_brk to obtain more space
Data structures would be:
The scanning two different header types for free space seems to me being a bit redundant. What do you think about replacing point (2) and using block headers instead of free space pointer in the heap header and just split the block when there is not exact size match. I mean:
- scan through all heaps to find best fit block
- scan through all heaps to find greater block and split it
- call early_brk to obtain more space
Data structures would be:
struct early_heap_header { int heap_size; phys_addr_t reloc_addr_old; }
Hmm, what is reloc_addr_old all about?
struct early_block_header { int magic; int size; }
NAK on the magic - waste of space
The brand new early_heap right after it's creation would consist of a early_heap_header followed by a early_block_header with the free bit set to true.
Hmm, I think you may be on to something:
struct early_heap_header { struct early_heap_header *next_heap; };
struch early_block { size_t size; unsigned char *data; }
We could reserve the upper, say, 8 bits of size as flags. This leaves 24 bits as usable 'size' value (if anyone needs to allocate a 16M chunck of memory early then we have a problem)
So the early heap starts out with an early_heap_header and an early_block with size set to the size of the early heap (minus headers) with the 'free' and 'last block' flags set. The first call to early_malloc() would: - Split the block - Set the size to the appropriate value - Clear the 'free' and 'last block' flags - Create a new early_block after the allocated space - Set the size of the new block to the size of the remaining space - Set the 'free' and 'last block' flags of the new block
When calling early_malloc(), search through the list. If you find a free block of exactly the right size, use it. If not, then while you are scanning, keep a reference to the smallest free block larger than the requested size. That leave a decision: - Do we always split the first 'smallest free block', or; - Do we always split the last block?
If there are no free blocks that can be split, call early_brk()
- When a block is relocated into the permanent heap, free() should be called on the source (early heap) block
Well, that time we would have only a copy of the early_heap on certain platforms. Assuming that first we set off drivers and DM using early_heap(s), then we would copy each early_heap to some computed address and jump to board_init_r. In board_init_r we would access the early_heap copy via translation function using the address offset (early_heap_copy - early_heap_copy->reloc_addr_old).
Me == 100% lost :)
Looks like you are still clinging onto the double-copy. If so, I'm still not convinced.
To do the early_free correctly in this mid-relocation state I would have to allow early_* code to operate during this period. It is not that hard to do, but maybe it is conceptually wrong because it means operating early_malloc/realloc/free code on a copy of it's own data after relocation.
Me == 110% lost :(
- We can call a 'cleanup' function after early heap is no longer needed and check that every block has the high bit set
Yes, it would help. When each block has to be free()-ed or relocated and then free()-ed, it could help find memory leaks during early init.
That's the idea - find poorly written drivers that assumed they would never be initialised pre-relocation and don't handle relocation correctly.
- We can re-use blocks by scanning for a tagged block with the same size (usefull for drivers that allocate temporary buffers which are always the same size)
- If there are no early heaps with enough space for a given malloc operation, but there is a tagged block that is larger than the requested size, we can split tagged blocks
Remebering back to when I suggested a list of relocation helpers (one for each allocated block), I think we can implement that as an additional field in the block header (stretching the header to 8 bytes). This can come later.
Do you mean we should place a pointer pointing at a relocation function into each block header? I think it would end up in situation like: Somebody is allocating a tree for example, he would set the helper function into the root element and NULL pointers to other nodes, because it makes more sense to relocate tree recursively from the root.
Exactly - One of the flags could be 'no relocate' or some such
Regards,
Graeme

Hi Tomas,
On Mon, Sep 24, 2012 at 2:15 AM, Tomas Hlavacek tmshlvck@gmail.com wrote:
early_malloc for DM with support for more heaps and lightweight first heap in the same memory as an early stack.
Adaptation layer for seamless calling of early_malloc or dlmalloc from DM based on init stage added (dmmalloc() and related functions).
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com
Changelog since v5: dmmalloc() and all dm* functions has been moved to header, made static inline and preprocessor-dependent blocks are reworked. early_malloc_active() corrected and made not static. s/CONFIG_SYS_DM/CONFIG_DM/ applied.
Changelog sice v6: Check of first heap emptyness in early_brk() has been simplified.
Changelog since v7: dmcalloc() implmentation added. Comments added to header.
arch/arm/include/asm/global_data.h | 3 + arch/arm/lib/board.c | 8 ++ arch/avr32/include/asm/global_data.h | 3 + arch/avr32/lib/board.c | 9 +++ arch/blackfin/include/asm/global_data.h | 3 + arch/blackfin/lib/board.c | 8 ++ arch/m68k/include/asm/global_data.h | 3 + arch/m68k/lib/board.c | 8 ++ arch/microblaze/include/asm/global_data.h | 3 + arch/microblaze/lib/board.c | 9 +++ arch/mips/include/asm/global_data.h | 3 + arch/mips/lib/board.c | 8 ++ arch/nds32/include/asm/global_data.h | 3 + arch/nds32/lib/board.c | 8 ++ arch/nios2/include/asm/global_data.h | 3 + arch/nios2/lib/board.c | 8 ++ arch/openrisc/include/asm/global_data.h | 3 + arch/openrisc/lib/board.c | 8 ++ arch/powerpc/include/asm/global_data.h | 3 + arch/powerpc/lib/board.c | 8 ++ arch/sandbox/include/asm/global_data.h | 3 + arch/sandbox/lib/board.c | 8 ++ arch/sh/include/asm/global_data.h | 3 + arch/sh/lib/board.c | 8 ++ arch/sparc/include/asm/global_data.h | 3 + arch/sparc/lib/board.c | 8 ++ arch/x86/include/asm/global_data.h | 3 + arch/x86/lib/board.c | 18 +++++ common/Makefile | 1 + common/dmmalloc.c | 88 ++++++++++++++++++++++ include/dmmalloc.h | 117 +++++++++++++++++++++++++++++ 31 files changed, 372 insertions(+) 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 f8088fe..ef727b0 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -82,6 +82,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
void *early_heap_first; /* heap for early_malloc */
+#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index f1951e8..f73d8b2 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -53,6 +53,10 @@ #include <post.h> #include <logbuff.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif
#ifdef CONFIG_BITBANGMII #include <miiphy.h> #endif @@ -281,6 +285,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC
gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE);
+#endif /* CONFIG_SYS_EARLY_MALLOC */
I just realised that all these initialisers can be dumped - early_brk() will be called when early_malloc() is first called
[snip]
diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index 90cf7fc..a670f9e 100644 --- a/arch/x86/lib/board.c +++ b/arch/x86/lib/board.c @@ -40,6 +40,10 @@ #include <asm/init_helpers.h> #include <asm/init_wrappers.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif
/*
- Breath some life into the board...
@@ -85,6 +89,17 @@ typedef int (init_fnc_t) (void);
/*
- Initialize early heap (when enabled by config).
- */
+#ifdef CONFIG_SYS_EARLY_MALLOC +static void early_malloc_init(void) +{
gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE);
+} +#endif /* CONFIG_SYS_EARLY_MALLOC */
So this uglyness goes
+/*
- init_sequence_f is the list of init functions which are run when U-Boot
- is executing from Flash with a limited 'C' environment. The following
- limitations must be considered when implementing an '_f' function:
@@ -99,6 +114,9 @@ init_fnc_t *init_sequence_f[] = { cpu_init_f, board_early_init_f, env_init, +#ifdef CONFIG_SYS_EARLY_MALLOC
early_malloc_init,
+#endif /* CONFIG_SYS_EARLY_MALLOC */
And this one as well
COBJS := $(sort $(COBJS-y)) diff --git a/common/dmmalloc.c b/common/dmmalloc.c new file mode 100644 index 0000000..6dbb622 --- /dev/null +++ b/common/dmmalloc.c @@ -0,0 +1,88 @@ +/*
- (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 +__weak struct early_heap_header *early_brk(size_t size) +{
struct early_heap_header *h =
(struct early_heap_header *)CONFIG_SYS_EARLY_HEAP_ADDR;
if (gd->early_heap_first != NULL)
return NULL;
if (gd->early_heap_first != NULL) { debug("Early Heap: Failed to allocate %d byte block of early heap.\n", size); return NULL; }
h->free_space_pointer = (void *)(roundup(
(phys_addr_t)CONFIG_SYS_EARLY_HEAP_ADDR +
sizeof(struct early_heap_header),
sizeof(phys_addr_t)));
h->free_bytes = size - roundup(sizeof(struct early_heap_header),
sizeof(phys_addr_t));
h->next_early_heap = NULL;
return h;
+}
+void *early_malloc(size_t size) +{
phys_addr_t addr;
struct early_heap_header *h;
size = roundup(size, sizeof(phys_addr_t));
h = gd->early_heap_first;
while ((h->free_bytes < size) && (h->next_early_heap != NULL))
h = h->next_early_heap;
if (h->free_bytes < size) {
h->next_early_heap = early_brk(size);
if (h->next_early_heap == NULL)
debug("EH overflow. Can not early_brk. required %d B.",
size);
return NULL;
Missing brace and not using the newly allocated block
}
addr = (phys_addr_t)h->free_space_pointer;
h->free_space_pointer += size;
h->free_bytes -= size;
return (void *)addr;
+}
This is still NULL pointer exception prone, for example calling dmmalloc() before the initialisation function in board.c is called.
void *early_malloc(size_t size) { phys_addr_t addr; struct early_heap_header *h;
size = roundup(size, sizeof(phys_addr_t));
/* Initialise first block of early heap (if not already done) */ if (!gd->early_heap_first) { gd->early_heap_first = early_brk(size);
if (!gd->early_heap_first) return NULL; }
/* Find an early heap block with enough free space */ h = gd->early_heap_first;
while ((h->free_bytes < size) && (h->next_early_heap != NULL)) h = h->next_early_heap;
/* Initialise another block of early heap if neccessary */ if (h->free_bytes < size) { h->next_early_heap = early_brk(size);
if (!h->next_early_heap) return NULL;
/* Use the newly allocated block */ h = h->next_early_heap; }
addr = (phys_addr_t)h->free_space_pointer;
h->free_space_pointer += size; h->free_bytes -= size;
return (void *)addr; }
Regards,
Graeme

Hi Graeme!
On Mon, Sep 24, 2012 at 2:00 AM, Graeme Russ graeme.russ@gmail.com wrote:
Hi Tomas,
On Mon, Sep 24, 2012 at 2:15 AM, Tomas Hlavacek tmshlvck@gmail.com wrote:
early_malloc for DM with support for more heaps and lightweight first heap in the same memory as an early stack.
Adaptation layer for seamless calling of early_malloc or dlmalloc from DM based on init stage added (dmmalloc() and related functions).
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com
Changelog since v5: dmmalloc() and all dm* functions has been moved to header, made static inline and preprocessor-dependent blocks are reworked. early_malloc_active() corrected and made not static. s/CONFIG_SYS_DM/CONFIG_DM/ applied.
Changelog sice v6: Check of first heap emptyness in early_brk() has been simplified.
Changelog since v7: dmcalloc() implmentation added. Comments added to header.
arch/arm/include/asm/global_data.h | 3 + arch/arm/lib/board.c | 8 ++ arch/avr32/include/asm/global_data.h | 3 + arch/avr32/lib/board.c | 9 +++ arch/blackfin/include/asm/global_data.h | 3 + arch/blackfin/lib/board.c | 8 ++ arch/m68k/include/asm/global_data.h | 3 + arch/m68k/lib/board.c | 8 ++ arch/microblaze/include/asm/global_data.h | 3 + arch/microblaze/lib/board.c | 9 +++ arch/mips/include/asm/global_data.h | 3 + arch/mips/lib/board.c | 8 ++ arch/nds32/include/asm/global_data.h | 3 + arch/nds32/lib/board.c | 8 ++ arch/nios2/include/asm/global_data.h | 3 + arch/nios2/lib/board.c | 8 ++ arch/openrisc/include/asm/global_data.h | 3 + arch/openrisc/lib/board.c | 8 ++ arch/powerpc/include/asm/global_data.h | 3 + arch/powerpc/lib/board.c | 8 ++ arch/sandbox/include/asm/global_data.h | 3 + arch/sandbox/lib/board.c | 8 ++ arch/sh/include/asm/global_data.h | 3 + arch/sh/lib/board.c | 8 ++ arch/sparc/include/asm/global_data.h | 3 + arch/sparc/lib/board.c | 8 ++ arch/x86/include/asm/global_data.h | 3 + arch/x86/lib/board.c | 18 +++++ common/Makefile | 1 + common/dmmalloc.c | 88 ++++++++++++++++++++++ include/dmmalloc.h | 117 +++++++++++++++++++++++++++++ 31 files changed, 372 insertions(+) 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 f8088fe..ef727b0 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -82,6 +82,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
void *early_heap_first; /* heap for early_malloc */
+#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index f1951e8..f73d8b2 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -53,6 +53,10 @@ #include <post.h> #include <logbuff.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif
#ifdef CONFIG_BITBANGMII #include <miiphy.h> #endif @@ -281,6 +285,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC
gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE);
+#endif /* CONFIG_SYS_EARLY_MALLOC */
I just realised that all these initialisers can be dumped - early_brk() will be called when early_malloc() is first called
Yes, but how can I determine the size of the new heap which the early_brk gives out? When I have CONFIG_SYS_EARLY_HEAP_SIZE macro in board configuration I can ignore the size passed to the "default" early_brk and return the full-sized heap as configuration says (when the requested size is lower than configured heap size and NULL otherwise). But what if somebody implements at some point a dynamic early_brk capable of returning multiple heaps? Should I safely assume that the future dynamic early_brk would give out multiples of page size or so?
All other comments understood and agreed.
Thanks, Tomas

Hi Thomas,
On Mon, Sep 24, 2012 at 10:35 AM, Tomas Hlavacek tmshlvck@gmail.com wrote:
Hi Graeme!
On Mon, Sep 24, 2012 at 2:00 AM, Graeme Russ graeme.russ@gmail.com wrote:
Hi Tomas,
On Mon, Sep 24, 2012 at 2:15 AM, Tomas Hlavacek tmshlvck@gmail.com wrote:
early_malloc for DM with support for more heaps and lightweight first heap in the same memory as an early stack.
Adaptation layer for seamless calling of early_malloc or dlmalloc from DM based on init stage added (dmmalloc() and related functions).
Signed-off-by: Tomas Hlavacek tmshlvck@gmail.com
Changelog since v5: dmmalloc() and all dm* functions has been moved to header, made static inline and preprocessor-dependent blocks are reworked. early_malloc_active() corrected and made not static. s/CONFIG_SYS_DM/CONFIG_DM/ applied.
Changelog sice v6: Check of first heap emptyness in early_brk() has been simplified.
Changelog since v7: dmcalloc() implmentation added. Comments added to header.
arch/arm/include/asm/global_data.h | 3 + arch/arm/lib/board.c | 8 ++ arch/avr32/include/asm/global_data.h | 3 + arch/avr32/lib/board.c | 9 +++ arch/blackfin/include/asm/global_data.h | 3 + arch/blackfin/lib/board.c | 8 ++ arch/m68k/include/asm/global_data.h | 3 + arch/m68k/lib/board.c | 8 ++ arch/microblaze/include/asm/global_data.h | 3 + arch/microblaze/lib/board.c | 9 +++ arch/mips/include/asm/global_data.h | 3 + arch/mips/lib/board.c | 8 ++ arch/nds32/include/asm/global_data.h | 3 + arch/nds32/lib/board.c | 8 ++ arch/nios2/include/asm/global_data.h | 3 + arch/nios2/lib/board.c | 8 ++ arch/openrisc/include/asm/global_data.h | 3 + arch/openrisc/lib/board.c | 8 ++ arch/powerpc/include/asm/global_data.h | 3 + arch/powerpc/lib/board.c | 8 ++ arch/sandbox/include/asm/global_data.h | 3 + arch/sandbox/lib/board.c | 8 ++ arch/sh/include/asm/global_data.h | 3 + arch/sh/lib/board.c | 8 ++ arch/sparc/include/asm/global_data.h | 3 + arch/sparc/lib/board.c | 8 ++ arch/x86/include/asm/global_data.h | 3 + arch/x86/lib/board.c | 18 +++++ common/Makefile | 1 + common/dmmalloc.c | 88 ++++++++++++++++++++++ include/dmmalloc.h | 117 +++++++++++++++++++++++++++++ 31 files changed, 372 insertions(+) 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 f8088fe..ef727b0 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -82,6 +82,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
void *early_heap_first; /* heap for early_malloc */
+#endif } gd_t;
#include <asm-generic/global_data_flags.h> diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index f1951e8..f73d8b2 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -53,6 +53,10 @@ #include <post.h> #include <logbuff.h>
+#ifdef CONFIG_DM +#include <dmmalloc.h> +#endif
#ifdef CONFIG_BITBANGMII #include <miiphy.h> #endif @@ -281,6 +285,10 @@ void board_init_f(ulong bootflag)
memset((void *)gd, 0, sizeof(gd_t));
+#ifdef CONFIG_SYS_EARLY_MALLOC
gd->early_heap_first = early_brk(CONFIG_SYS_EARLY_HEAP_SIZE);
+#endif /* CONFIG_SYS_EARLY_MALLOC */
I just realised that all these initialisers can be dumped - early_brk() will be called when early_malloc() is first called
Yes, but how can I determine the size of the new heap which the early_brk gives out? When I have CONFIG_SYS_EARLY_HEAP_SIZE macro in board configuration I can ignore the size passed to the "default" early_brk and return the full-sized heap as configuration says (when the requested size is lower than configured heap size and NULL
default early_brk() should always use CONFIG_SYS_EARLY_HEAP_SIZE
otherwise). But what if somebody implements at some point a dynamic early_brk capable of returning multiple heaps? Should I safely assume that the future dynamic early_brk would give out multiples of page size or so?
Very good point. I would assume early_brk() will always return the largest possible chunk of memory it can. These sizes might be specified as multiple #defines in the board config or may be dynamically determined via hardware probing. Either way, that is a problem for the implementer to deal with :)
Regards,
Graeme

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 v9: - Rework early_malloc to keep track of allocated block size. - Add early_free and dmfree functions. - Rework dmrealloc. - Add kerneldoc comments to dmmalloc.h.
Changes in v8: - Add dmcalloc() implmentation. - 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 | 3 + arch/avr32/include/asm/global_data.h | 3 + arch/blackfin/include/asm/global_data.h | 3 + arch/m68k/include/asm/global_data.h | 3 + arch/microblaze/include/asm/global_data.h | 3 + arch/mips/include/asm/global_data.h | 3 + arch/nds32/include/asm/global_data.h | 3 + arch/nios2/include/asm/global_data.h | 3 + arch/openrisc/include/asm/global_data.h | 3 + arch/powerpc/include/asm/global_data.h | 3 + arch/sandbox/include/asm/global_data.h | 3 + arch/sh/include/asm/global_data.h | 3 + arch/sparc/include/asm/global_data.h | 3 + arch/x86/include/asm/global_data.h | 3 + common/Makefile | 1 + common/dmmalloc.c | 188 ++++++++++++++++++++++++++++ include/dmmalloc.h | 194 +++++++++++++++++++++++++++++ 17 files changed, 425 insertions(+) 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..9045829 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -82,6 +82,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 + void *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..f18f480 100644 --- a/arch/avr32/include/asm/global_data.h +++ b/arch/avr32/include/asm/global_data.h @@ -48,6 +48,9 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *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..0725d55 100644 --- a/arch/blackfin/include/asm/global_data.h +++ b/arch/blackfin/include/asm/global_data.h @@ -57,6 +57,9 @@ typedef struct global_data {
void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *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..ab73499 100644 --- a/arch/m68k/include/asm/global_data.h +++ b/arch/m68k/include/asm/global_data.h @@ -66,6 +66,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 + void *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..f991e5d 100644 --- a/arch/microblaze/include/asm/global_data.h +++ b/arch/microblaze/include/asm/global_data.h @@ -46,6 +46,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 + void *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..8167d39 100644 --- a/arch/mips/include/asm/global_data.h +++ b/arch/mips/include/asm/global_data.h @@ -59,6 +59,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 + void *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..f7480e9 100644 --- a/arch/nds32/include/asm/global_data.h +++ b/arch/nds32/include/asm/global_data.h @@ -63,6 +63,9 @@ typedef struct global_data {
void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *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..8881e31 100644 --- a/arch/nios2/include/asm/global_data.h +++ b/arch/nios2/include/asm/global_data.h @@ -42,6 +42,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 + void *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..6ed6a15 100644 --- a/arch/openrisc/include/asm/global_data.h +++ b/arch/openrisc/include/asm/global_data.h @@ -44,6 +44,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 + void *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..f8d440b 100644 --- a/arch/powerpc/include/asm/global_data.h +++ b/arch/powerpc/include/asm/global_data.h @@ -182,6 +182,9 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *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..6ee20e2 100644 --- a/arch/sandbox/include/asm/global_data.h +++ b/arch/sandbox/include/asm/global_data.h @@ -46,6 +46,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 + void *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..6e0ae54 100644 --- a/arch/sh/include/asm/global_data.h +++ b/arch/sh/include/asm/global_data.h @@ -42,6 +42,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 + void *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..9be8f27 100644 --- a/arch/sparc/include/asm/global_data.h +++ b/arch/sparc/include/asm/global_data.h @@ -74,6 +74,9 @@ typedef struct global_data { #endif void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_SYS_EARLY_MALLOC + void *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..60384a5 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -57,6 +57,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 + void *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..41589dd --- /dev/null +++ b/common/dmmalloc.c @@ -0,0 +1,188 @@ +/* + * (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 +__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); +} + +int early_malloc_active(void) +{ + return ((gd->flags & GD_FLG_RELOC) != GD_FLG_RELOC); +} + +void early_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"); +} + +#endif /* CONFIG_SYS_EARLY_MALLOC */ + diff --git a/include/dmmalloc.h b/include/dmmalloc.h new file mode 100644 index 0000000..a241e19 --- /dev/null +++ b/include/dmmalloc.h @@ -0,0 +1,194 @@ +/* + * (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> + +#if (!defined(CONFIG_SYS_EARLY_HEAP_ADDR)) || \ + (!defined(CONFIG_SYS_EARLY_HEAP_SIZE)) +#undef CONFIG_SYS_EARLY_MALLOC +#endif /* CONFIG_SYS_EARLY_HEAP_ADDR */ + +#ifdef CONFIG_SYS_EARLY_MALLOC +struct early_heap_header { + size_t size; + void *early_heap_next; +}; + +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) + +/** + * 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_active() - indicate if the early mallocator is active + * + * Function returns true when the early_malloc and early_free are used and + * false otherwise. + */ +int early_malloc_active(void); + +/** + * early_heap_dump() - print blocks contained in an early_heap + * @h: Address of the early heap. + */ +void early_heap_dump(struct early_heap_header *h); + +#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. + */ +static inline 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); +} + +/** + * dmfree() - free working seamlessly in early as well as in RAM stages + * @ptr: Pointer to the allocated block to be released. + */ +static inline void dmfree(void *ptr) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC + if (early_malloc_active()) { + early_free(ptr); + return; + } +#endif /* CONFIG_SYS_EARLY_MALLOC */ + free(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. + */ +static inline 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); +} + +/** + * 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. + */ +static inline void *dmrealloc(void *oldaddr, size_t bytes) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC + char *addr; + struct early_block_header *h; + if (early_malloc_active()) { + 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); +} + +#endif /* CONFIG_DM */ +#endif /* __INCLUDE_DMMALLOC_H */ +

Hi Tomas,
Overall impression - Very nice indeed :)
A couple of nit-picks (some of which may be wrong on my part) and one lingering question around the switch over from early to late heap...
On Thu, Oct 25, 2012 at 10:49 AM, Tomas Hlavacek tmshlvck@gmail.com 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 v9: - Rework early_malloc to keep track of allocated block size. - Add early_free and dmfree functions. - Rework dmrealloc. - Add kerneldoc comments to dmmalloc.h.
Changes in v8: - Add dmcalloc() implmentation. - 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 | 3 + arch/avr32/include/asm/global_data.h | 3 + arch/blackfin/include/asm/global_data.h | 3 + arch/m68k/include/asm/global_data.h | 3 + arch/microblaze/include/asm/global_data.h | 3 + arch/mips/include/asm/global_data.h | 3 + arch/nds32/include/asm/global_data.h | 3 + arch/nios2/include/asm/global_data.h | 3 + arch/openrisc/include/asm/global_data.h | 3 + arch/powerpc/include/asm/global_data.h | 3 + arch/sandbox/include/asm/global_data.h | 3 + arch/sh/include/asm/global_data.h | 3 + arch/sparc/include/asm/global_data.h | 3 + arch/x86/include/asm/global_data.h | 3 + common/Makefile | 1 + common/dmmalloc.c | 188 ++++++++++++++++++++++++++++ include/dmmalloc.h | 194 +++++++++++++++++++++++++++++ 17 files changed, 425 insertions(+) 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..9045829 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -82,6 +82,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
void *early_heap; /* heap for early_malloc */
+#endif
Why not early_heap_header *early_heap; ?
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-$(CONFIG_SYS_EARLY_MALLOC) += dmmalloc.o ?
COBJS := $(sort $(COBJS-y)) diff --git a/common/dmmalloc.c b/common/dmmalloc.c new file mode 100644 index 0000000..41589dd --- /dev/null +++ b/common/dmmalloc.c @@ -0,0 +1,188 @@ +/*
- (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
If you use COBJS-$(CONFIG_SYS_EARLY_MALLOC) += dmmalloc.o in the Makefile, you can drop this #ifdef
+__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);
Hmmm, does this really work? I would have thought:
b = (struct early_block_header *)(h + sizeof(struct early_heap_header));
but I could be mistaken
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);
+}
+int early_malloc_active(void) +{
return ((gd->flags & GD_FLG_RELOC) != GD_FLG_RELOC);
+}
I think we need another flag - GD_FLG_RELOC gets set before the permanent heap is initialised, so there is a window of opportunity where things may break
+void early_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");
+}
Nice touch, but could we just iterate through all ealry heap chunks starting from gd->early_heap?
+#endif /* CONFIG_SYS_EARLY_MALLOC */
diff --git a/include/dmmalloc.h b/include/dmmalloc.h new file mode 100644 index 0000000..a241e19 --- /dev/null +++ b/include/dmmalloc.h @@ -0,0 +1,194 @@ +/*
- (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>
+#if (!defined(CONFIG_SYS_EARLY_HEAP_ADDR)) || \
(!defined(CONFIG_SYS_EARLY_HEAP_SIZE))
+#undef CONFIG_SYS_EARLY_MALLOC +#endif /* CONFIG_SYS_EARLY_HEAP_ADDR */
If a board implements early_brk() using non-fixed a address and/or size then this is going to cause trouble
+#ifdef CONFIG_SYS_EARLY_MALLOC
I see no need for the #ifdef
+struct early_heap_header {
size_t size;
void *early_heap_next;
+};
+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)
Again, not sure if this is correct. I would have thought:
(struct early_block_header *)(addr - sizeof(struct early_block_header)
And again, not sure if I'm right
+#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)
Hmmm, I'm not sure what the general policy is about where to put 'stuff' that is only used by the implementation and does not 'need' to be made publically available. i.e. I don't know if these #defines and the early_block_header struct belong here or in the .c file...
+/**
- 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_active() - indicate if the early mallocator is active
- Function returns true when the early_malloc and early_free are used and
- false otherwise.
- */
+int early_malloc_active(void);
+/**
- early_heap_dump() - print blocks contained in an early_heap
- @h: Address of the early heap.
- */
+void early_heap_dump(struct early_heap_header *h);
+#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.
- */
I don't think these _need_ to be inline functions - The compiler should be smart enough no (non-)inline them as appropriate.
+/**
- 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.
- */
+static inline 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);
+}
+/**
- dmfree() - free working seamlessly in early as well as in RAM stages
- @ptr: Pointer to the allocated block to be released.
- */
+static inline void dmfree(void *ptr) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC
if (early_malloc_active()) {
early_free(ptr);
return;
}
+#endif /* CONFIG_SYS_EARLY_MALLOC */
free(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.
- */
+static inline 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);
+}
+/**
- 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.
- */
+static inline void *dmrealloc(void *oldaddr, size_t bytes) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC
char *addr;
struct early_block_header *h;
if (early_malloc_active()) {
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);
+}
Hmmm, we have a very intersting corner case to deal with. What if we use dmrealloc() to move allocated data from the early malloc pool to the final malloc pool?
At some point, we need to assume the developer is only ever going to pass early malloc'd memory to dmrealloc()
The other option is to use the gd->flags...
Define two flags - something like:
GD_FLG_HEAP_INIT -> Final heap has been initialised GD_FLG_EH_DONE -> free(), realloc() refer to final heap
(I don't like the names, I'm just not up to thinking of anything better)
This way we can use dmalloc() prior to the heap being initialised and then set GD_FLG_HEAP_INIT. Once GD_FLG_HEAP_INIT has been set, do a bunch of dmrealloc() calls to essentially move the data into the permanent heap (of course pointers int the structures need to be fixed up by the drivers) and finally set GD_FLG_EH_DONE (and call early_heap_dump)
One problem I see is what happens of you call malloc() and free() on the same block between the setting of GD_FLG_HEAP_INIT and GD_FLG_EH_DONE? The code will try to reference the block as if it is in the early heap, but it won't be.
One solution is, on detection of GD_FLG_HEAP_INIT being set, dmfree() and dmrealloc() could search the early heap chunks instead of just assuming that the referenced block is in the early heap (if GD_FLG_HEAP_INIT has not been set, it will be safe to assume the memory is on the early heap)
+#endif /* CONFIG_DM */ +#endif /* __INCLUDE_DMMALLOC_H */
-- 1.7.10.4
Regards,
Graeme

Hello Graeme,
On Thu, Oct 25, 2012 at 3:40 AM, Graeme Russ graeme.russ@gmail.com wrote:
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h index 2b9af93..9045829 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -82,6 +82,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
void *early_heap; /* heap for early_malloc */
+#endif
Why not early_heap_header *early_heap; ?
It might be.
Actually it is a good point because I am using 3 different ways of dealing with addresses: 1) struct early_heap header * or struct early_block_header * - I am using this when I want to access members of the stucture or compute address past the structure (which is where the heap or block starts); 2) phys_addr_t - which is plain integer and I use this for simple computations when I do not want to worry about pointer arithmetic; 3) void * when I have just plain address, especially when I want to pass an addres among logical parts of the mallocator or outside. This may a bit controversial and perhaps I should replace it by specific strucutre pointers internally.
I am unable to decide: Should I remove struct early_heap_header from dmmalloc.h making it publicly unavailable or should I rather change the void * to struct early_heap_header * in the GD structure? What do you think is better?
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-$(CONFIG_SYS_EARLY_MALLOC) += dmmalloc.o ?
Oh yes, now it is redundant to #ifdef CONFIG_SYS_EARLY_MALLOC inside the dmmalloc.c file. I had a plan to extend the dmmalloc.c file by relocation routines and then it would make sense. But I will shufle the code a bit in the v10 anyway and we will see if the #ifdefs can still be reduced.
+#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
If you use COBJS-$(CONFIG_SYS_EARLY_MALLOC) += dmmalloc.o in the Makefile, you can drop this #ifdef
Yes, that is redundant now.
+__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);
Hmmm, does this really work? I would have thought:
b = (struct early_block_header *)(h + sizeof(struct early_heap_header));
but I could be mistaken
It seems that it works as it is (at least I wrote bunch of tests and I inspected resulting heaps and it was all right). I believe that since h is a pointer to the struct early_heap_header then pointer arithmetic is in effect and h+1 actually means "next element in the array of struct early_heap_header". Which is the address past the header that equals beginning of the heap data block. (?)
+int early_malloc_active(void) +{
return ((gd->flags & GD_FLG_RELOC) != GD_FLG_RELOC);
+}
I think we need another flag - GD_FLG_RELOC gets set before the permanent heap is initialised, so there is a window of opportunity where things may break
Well, as I wrote in the commit message - this is only a temporary implementation. I suppose I am going to change this when we have more coarse initialization flags wired into DM (which I believe we are going to have it anyway). So now I am just working around "forward dependency" here.
+void early_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");
+}
Nice touch, but could we just iterate through all ealry heap chunks starting from gd->early_heap?
Or I can have two functions. One heap specific and one for all heaps. I think both might be useful when somebody needs to debug early_malloc or memory usage etc. in the early stage. Thanks.
+#ifndef __INCLUDE_DMMALLOC_H +#define __INCLUDE_DMMALLOC_H
+#include <config.h> +#include <linux/stddef.h> /* for size_t */ +#include <malloc.h>
+#if (!defined(CONFIG_SYS_EARLY_HEAP_ADDR)) || \
(!defined(CONFIG_SYS_EARLY_HEAP_SIZE))
+#undef CONFIG_SYS_EARLY_MALLOC +#endif /* CONFIG_SYS_EARLY_HEAP_ADDR */
If a board implements early_brk() using non-fixed a address and/or size then this is going to cause trouble
Right, I will drop this.
+#ifdef CONFIG_SYS_EARLY_MALLOC
I see no need for the #ifdef
+struct early_heap_header {
size_t size;
void *early_heap_next;
+};
+struct early_block_header {
size_t size;
+};
+#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)
Hmmm, I'm not sure what the general policy is about where to put 'stuff' that is only used by the implementation and does not 'need' to be made publically available. i.e. I don't know if these #defines and the early_block_header struct belong here or in the .c file...
You are right, I will put it to the .c.
+/**
- 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_active() - indicate if the early mallocator is active
- Function returns true when the early_malloc and early_free are used and
- false otherwise.
- */
+int early_malloc_active(void);
+/**
- early_heap_dump() - print blocks contained in an early_heap
- @h: Address of the early heap.
- */
+void early_heap_dump(struct early_heap_header *h);
+#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.
- */
I don't think these _need_ to be inline functions - The compiler should be smart enough no (non-)inline them as appropriate.
Yes. Now I am thinking about pulling all this into the .c file and making the functions non-static. Actually, this "static inline" evolved from really simple "if(...) early_malloc() else malloc()", but now it is not always straight-forward and even more future extensions are expected to these functions due to relocation-related code.
+/**
- 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.
- */
+static inline 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);
+}
+/**
- dmfree() - free working seamlessly in early as well as in RAM stages
- @ptr: Pointer to the allocated block to be released.
- */
+static inline void dmfree(void *ptr) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC
if (early_malloc_active()) {
early_free(ptr);
return;
}
+#endif /* CONFIG_SYS_EARLY_MALLOC */
free(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.
- */
+static inline 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);
+}
+/**
- 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.
- */
+static inline void *dmrealloc(void *oldaddr, size_t bytes) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC
char *addr;
struct early_block_header *h;
if (early_malloc_active()) {
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);
+}
Hmmm, we have a very intersting corner case to deal with. What if we use dmrealloc() to move allocated data from the early malloc pool to the final malloc pool?
At some point, we need to assume the developer is only ever going to pass early malloc'd memory to dmrealloc()
Good point! The current code would do the job assuming that the early_malloc can still access the proper early_heap (or a copy, but in that case some additional magic is needed) and the real malloc is already initialized.
As you can see I am still sticking with the double-copy method. It is maybe due to lack of insight. But the discussion here was not absolutely conclusive last time. I have even some experimental code (not ready for submitting at all) for double copy method but I would prefer to discuss it separately when the early_malloc() is done.
The other option is to use the gd->flags...
Define two flags - something like:
GD_FLG_HEAP_INIT -> Final heap has been initialised GD_FLG_EH_DONE -> free(), realloc() refer to final heap
(I don't like the names, I'm just not up to thinking of anything better)
This way we can use dmalloc() prior to the heap being initialised and then set GD_FLG_HEAP_INIT. Once GD_FLG_HEAP_INIT has been set, do a bunch of dmrealloc() calls to essentially move the data into the permanent heap (of course pointers int the structures need to be fixed up by the drivers) and finally set GD_FLG_EH_DONE (and call early_heap_dump)
One problem I see is what happens of you call malloc() and free() on the same block between the setting of GD_FLG_HEAP_INIT and GD_FLG_EH_DONE? The code will try to reference the block as if it is in the early heap, but it won't be.
One solution is, on detection of GD_FLG_HEAP_INIT being set, dmfree() and dmrealloc() could search the early heap chunks instead of just assuming that the referenced block is in the early heap (if GD_FLG_HEAP_INIT has not been set, it will be safe to assume the memory is on the early heap)
Sure we will have that flags. But I think we can use them as well for switching from DM driver instance list to tree for example. Or other way around: I can use DM flags for early_malloc. Therefore I would like to synchronize with DM cores for PCI and another low-level things which are certainly going to start in early stage. It would be best to use the same flags and switch on/off early_malloc based on DM internal state.
Best regards, Tomas

Hi Tomas,
On Fri, Oct 26, 2012 at 6:16 AM, Tomas Hlavacek tmshlvck@gmail.com wrote:
Hello Graeme,
On Thu, Oct 25, 2012 at 3:40 AM, Graeme Russ graeme.russ@gmail.com wrote:
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h index 2b9af93..9045829 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -82,6 +82,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
void *early_heap; /* heap for early_malloc */
+#endif
Why not early_heap_header *early_heap; ?
It might be.
Actually it is a good point because I am using 3 different ways of dealing with addresses: 1) struct early_heap header * or struct early_block_header * - I am using this when I want to access members of the stucture or compute address past the structure (which is where the heap or block starts); 2) phys_addr_t - which is plain integer and I use this for simple computations when I do not want to worry about pointer arithmetic; 3) void * when I have just plain address, especially when I want to pass an addres among logical parts of the mallocator or outside. This may a bit controversial and perhaps I should replace it by specific strucutre pointers internally.
I am unable to decide: Should I remove struct early_heap_header from dmmalloc.h making it publicly unavailable or should I rather change the void * to struct early_heap_header * in the GD structure? What do you think is better?
I think struct early_heap_header * in the GD structure is the better way to go as that is exactly what it is.
[snip]
h = (struct early_heap_header *)CONFIG_SYS_EARLY_HEAP_ADDR;
b = (struct early_block_header *)(h + 1);
Hmmm, does this really work? I would have thought:
b = (struct early_block_header *)(h + sizeof(struct early_heap_header));
but I could be mistaken
It seems that it works as it is (at least I wrote bunch of tests and I inspected resulting heaps and it was all right). I believe that since h is a pointer to the struct early_heap_header then pointer arithmetic is in effect and h+1 actually means "next element in the array of struct early_heap_header". Which is the address past the header that equals beginning of the heap data block. (?)
As I said, I could be mistaken - it appears I am :)
+int early_malloc_active(void) +{
return ((gd->flags & GD_FLG_RELOC) != GD_FLG_RELOC);
+}
I think we need another flag - GD_FLG_RELOC gets set before the permanent heap is initialised, so there is a window of opportunity where things may break
Well, as I wrote in the commit message - this is only a temporary implementation. I suppose I am going to change this when we have more coarse initialization flags wired into DM (which I believe we are going to have it anyway). So now I am just working around "forward dependency" here.
+void early_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");
+}
Nice touch, but could we just iterate through all ealry heap chunks starting from gd->early_heap?
Or I can have two functions. One heap specific and one for all heaps. I think both might be useful when somebody needs to debug early_malloc or memory usage etc. in the early stage. Thanks.
True, just adding another function which iterates through the heaps and calls this function would be fine.
[snip]
+static inline void *dmrealloc(void *oldaddr, size_t bytes) +{ +#ifdef CONFIG_SYS_EARLY_MALLOC
char *addr;
struct early_block_header *h;
if (early_malloc_active()) {
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);
+}
Hmmm, we have a very intersting corner case to deal with. What if we use dmrealloc() to move allocated data from the early malloc pool to the final malloc pool?
At some point, we need to assume the developer is only ever going to pass early malloc'd memory to dmrealloc()
Good point! The current code would do the job assuming that the early_malloc can still access the proper early_heap (or a copy, but in that case some additional magic is needed) and the real malloc is already initialized.
As you can see I am still sticking with the double-copy method. It is maybe due to lack of insight. But the discussion here was not absolutely conclusive last time. I have even some experimental code (not ready for submitting at all) for double copy method but I would prefer to discuss it separately when the early_malloc() is done.
Well the double-copy approach to reallocating early-malloc'd memory and how dmrealloc() is implemented are tightly coupled.
I understand the reason for the double copy is performance related (getting into a position to enable cache as early as possible), but I wonder how much will really be gained. It seems to me that the only performance gain will be for the execution of the driver 'relocation fixup' code wich, I assume, would not really consume that many CPU cycles.
There is a point where code simplicity outweighs performance gains.
The other option is to use the gd->flags...
Define two flags - something like:
GD_FLG_HEAP_INIT -> Final heap has been initialised GD_FLG_EH_DONE -> free(), realloc() refer to final heap
(I don't like the names, I'm just not up to thinking of anything better)
This way we can use dmalloc() prior to the heap being initialised and then set GD_FLG_HEAP_INIT. Once GD_FLG_HEAP_INIT has been set, do a bunch of dmrealloc() calls to essentially move the data into the permanent heap (of course pointers int the structures need to be fixed up by the drivers) and finally set GD_FLG_EH_DONE (and call early_heap_dump)
One problem I see is what happens of you call malloc() and free() on the same block between the setting of GD_FLG_HEAP_INIT and GD_FLG_EH_DONE? The code will try to reference the block as if it is in the early heap, but it won't be.
One solution is, on detection of GD_FLG_HEAP_INIT being set, dmfree() and dmrealloc() could search the early heap chunks instead of just assuming that the referenced block is in the early heap (if GD_FLG_HEAP_INIT has not been set, it will be safe to assume the memory is on the early heap)
Sure we will have that flags. But I think we can use them as well for switching from DM driver instance list to tree for example. Or other way around: I can use DM flags for early_malloc. Therefore I would like to synchronize with DM cores for PCI and another low-level things which are certainly going to start in early stage. It would be best to use the same flags and switch on/off early_malloc based on DM internal state.
Ah, I see where more performance gains are to be made by switching on cache earlier - During the reallocation phase, you are switching from the list based structure (fast for the small number of pre-SDRAM drivers) into the final tree based structure.
I'm looking at this early malloc code from a much more generic point of view - I think there are use-cases outside the driver model, so I don't see a need (rather the opposite) to tie early malloc to the driver model
Regards,
Graeme

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 */ +

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,

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!

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!
participants (7)
-
Graeme Russ
-
Marek Vasut
-
Marek Vasut
-
Mateusz Zalega
-
Tom Rini
-
Tomas Hlavacek
-
Wolfgang Denk