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

Graeme Russ graeme.russ at gmail.com
Tue Aug 28 01:02:32 CEST 2012


Hi Tomas,

None of my example code is compile tested...

Regards,

Graeme

On Mon, Aug 27, 2012 at 10:42 PM, Tomas Hlavacek <tmshlvck at 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 at 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 at 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
>


More information about the U-Boot mailing list