[U-Boot] [PATCH v2 0/6] spl: full-featured heap cleanups

Some platforms cannot use simple malloc even in very early stages, e.g. when using FAT before DRAM is available. Such platforms currently often use non-Kconfig defines to initialize full malloc and rely on simple heap before that.
This series makes some adjustments to ensure SPL behaves the same with simple or full malloc: when CONFIG_SPL_SYS_MALLOC_F_LEN is != 0, both heap types can be used (by changing CONFIG_SPL_SYS_MALLOC_SIMPLE), without manually supplying an address range for the full heap.
Changes in v2: - make CONFIG_SPL_CLEAR_BSS_F depend on ARM for now - add CONFIG_SPL_CLEAR_BSS_F implementation for arm64 also - use if() instead of #if - adapt documentation to using CONFIG_SPL_SYS_MALLOC_F_LEN for full-featured heap as well - ensure SPL_CLEAR_BSS_F is set when using SYS_MALLOC_F_LEN for full featured heap (or else, the heap status stored in bss will be overwritten between board_init_f and board_init_r) - fixed summary ("stack" -> "heap") - enable CONFIG_SPL_CLEAR_BSS_F for socfpga_arria10 using full malloc early in SPL
Simon Goldschmidt (6): spl: add Kconfig option to clear bss early spl: arm: implement SPL_CLEAR_BSS_F dlmalloc: fix malloc range at end of ram dlmalloc: be compatible to tiny printf spl: support using full malloc with SYS_MALLOC_F_LEN arm: socfpga: a10: move SPL heap size to Kconfig
Kconfig | 24 ++++++++++++++-------- README | 15 ++++++++++---- arch/arm/lib/crt0.S | 22 +++++++++++++++++++++ arch/arm/lib/crt0_64.S | 14 +++++++++++++ common/dlmalloc.c | 6 +++++- common/spl/Kconfig | 12 +++++++++++ common/spl/spl.c | 10 ++++++++-- configs/socfpga_arria10_defconfig | 2 ++ drivers/core/Kconfig | 33 +++++++++++++++---------------- include/configs/socfpga_common.h | 14 ------------- 10 files changed, 106 insertions(+), 46 deletions(-)

This introduces a new Kconfig option SPL_CLEAR_BSS_F. If enabled, it clears the bss before calling board_init_f() instead of clearing it before calling board_init_r().
This also ensures that variables placed in BSS can be shared between board_init_f() and board_init_r() in SPL.
Make the new option depend on ARM for now until more implementations follow.
Signed-off-by: Simon Goldschmidt simon.k.r.goldschmidt@gmail.com ---
Changes in v2: - make CONFIG_SPL_CLEAR_BSS_F depend on ARM for now
common/spl/Kconfig | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 206c24076d..6a4270516a 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -156,6 +156,18 @@ config SPL_STACK_R_MALLOC_SIMPLE_LEN to give board_init_r() a larger heap then the initial heap in SRAM which is limited to SYS_MALLOC_F_LEN bytes.
+config SPL_CLEAR_BSS_F + bool "Clear BSS section before calling board_init_f" + depends on ARM + help + The BSS section is initialized to zero. In SPL, this is normally done + before calling board_init_r(). + For platforms using BSS in board_init_f() already, enable this to + clear the BSS section before calling board_init_f() instead of + clearing it before calling board_init_r(). This also ensures that + variables placed in BSS can be shared between board_init_f() and + board_init_r(). + config SPL_SEPARATE_BSS bool "BSS section is in a different memory region from text" help

This implements the new option to clear BSS early in SPL for standard arm and arm64 crt0.
BSS is cleared before calling board_init_f() and thus not cleared before calling board_init_r() as it is not relocated in SPL.
Signed-off-by: Simon Goldschmidt simon.k.r.goldschmidt@gmail.com ---
Changes in v2: - add CONFIG_SPL_CLEAR_BSS_F implementation for arm64 also
arch/arm/lib/crt0.S | 22 ++++++++++++++++++++++ arch/arm/lib/crt0_64.S | 14 ++++++++++++++ 2 files changed, 36 insertions(+)
diff --git a/arch/arm/lib/crt0.S b/arch/arm/lib/crt0.S index fe312db690..b06e54e144 100644 --- a/arch/arm/lib/crt0.S +++ b/arch/arm/lib/crt0.S @@ -80,6 +80,26 @@ ENTRY(_main) mov r9, r0 bl board_init_f_init_reserve
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_CLEAR_BSS_F) + ldr r0, =__bss_start + +#ifdef CONFIG_USE_ARCH_MEMSET + ldr r3, =__bss_end + mov r1, #0x00000000 /* prepare zero to clear BSS */ + + subs r2, r3, r0 /* r2 = memset len */ + bl memset +#else + ldr r1, =__bss_end + mov r2, #0x00000000 /* prepare zero to clear BSS */ + +clbss_l:cmp r0, r1 /* while not at end of BSS */ + strlo r2, [r0] /* clear 32-bit BSS word */ + addlo r0, r0, #4 /* move to next */ + blo clbss_l +#endif +#endif + mov r0, #0 bl board_init_f
@@ -124,6 +144,7 @@ here: movne sp, r0 movne r9, r0 # endif +#if !defined(CONFIG_SPL_BUILD) || !defined(CONFIG_SPL_CLEAR_BSS_F) ldr r0, =__bss_start /* this is auto-relocated! */
#ifdef CONFIG_USE_ARCH_MEMSET @@ -141,6 +162,7 @@ clbss_l:cmp r0, r1 /* while not at end of BSS */ addlo r0, r0, #4 /* move to next */ blo clbss_l #endif +#endif
#if ! defined(CONFIG_SPL_BUILD) bl coloured_LED_init diff --git a/arch/arm/lib/crt0_64.S b/arch/arm/lib/crt0_64.S index d6b632aa87..82f643f737 100644 --- a/arch/arm/lib/crt0_64.S +++ b/arch/arm/lib/crt0_64.S @@ -86,6 +86,18 @@ ENTRY(_main) mov x18, x0 bl board_init_f_init_reserve
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_CLEAR_BSS_F) +/* + * Clear BSS section + */ + ldr x0, =__bss_start + ldr x1, =__bss_end +clear_loop: + str xzr, [x0], #8 + cmp x0, x1 + b.lo clear_loop +#endif + mov x0, #0 bl board_init_f
@@ -136,6 +148,7 @@ relocation_return: mov sp, x0 #endif
+#if !defined(CONFIG_SPL_BUILD) || !defined(CONFIG_SPL_CLEAR_BSS_F) /* * Clear BSS section */ @@ -145,6 +158,7 @@ clear_loop: str xzr, [x0], #8 cmp x0, x1 b.lo clear_loop +#endif
/* call board_init_r(gd_t *id, ulong dest_addr) */ mov x0, x18 /* gd_t */

If the malloc range passed to mem_malloc_init() is at the end of address range and 'start + size' overflows to 0, following allocations fail as mem_malloc_end is zero (which looks like uninitialized).
Fix this by subtracting 1 of 'start + size' overflows to zero.
Signed-off-by: Simon Goldschmidt simon.k.r.goldschmidt@gmail.com ---
Changes in v2: None
common/dlmalloc.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/common/dlmalloc.c b/common/dlmalloc.c index edaad299bb..51d3bd671a 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -603,6 +603,10 @@ void mem_malloc_init(ulong start, ulong size) mem_malloc_start = start; mem_malloc_end = start + size; mem_malloc_brk = start; + if (start && size && !mem_malloc_end) { + /* overflow: malloc area is at end of address range */ + mem_malloc_end--; + }
debug("using memory %#lx-%#lx for malloc()\n", mem_malloc_start, mem_malloc_end);

Convert debug output from '%#lx' to '0x%lx' to be compatible with tiny printf used in SPL.
Signed-off-by: Simon Goldschmidt simon.k.r.goldschmidt@gmail.com ---
Changes in v2: None
common/dlmalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/common/dlmalloc.c b/common/dlmalloc.c index 51d3bd671a..af6f43dcc9 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -608,7 +608,7 @@ void mem_malloc_init(ulong start, ulong size) mem_malloc_end--; }
- debug("using memory %#lx-%#lx for malloc()\n", mem_malloc_start, + debug("using memory 0x%lx-0x%lx for malloc()\n", mem_malloc_start, mem_malloc_end); #ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT memset((void *)mem_malloc_start, 0x0, size);

Some platforms (like socfpga A10) need a big hep before SDRAM is available (e.g. because FAT is used). For such platforms, simple_malloc is often not a good option as it does not support freeing memory. These platforms often use the non-Kconfig defines CONFIG_SYS_SPL_MALLOC_START (and its SIZE).
This patch allows enabling CONFIG_SPL_SYS_MALLOC_F_LEN while leaving CONFIG_SPL_SYS_MALLOC_SIMPLE disabled. In this case, the full malloc heap is made available as early as the simple_malloc heap would be normally.
This way, platforms can drop the non-Kconfig options to set up the full heap and rely on the same automatically calculated heap allocation used for simple heap.
Signed-off-by: Simon Goldschmidt simon.k.r.goldschmidt@gmail.com ---
Changes in v2: - use if() instead of #if - adapt documentation to using CONFIG_SPL_SYS_MALLOC_F_LEN for full-featured heap as well - ensure SPL_CLEAR_BSS_F is set when using SYS_MALLOC_F_LEN for full featured heap (or else, the heap status stored in bss will be overwritten between board_init_f and board_init_r)
Kconfig | 24 ++++++++++++++++-------- README | 15 +++++++++++---- common/spl/spl.c | 10 ++++++++-- drivers/core/Kconfig | 33 ++++++++++++++++----------------- 4 files changed, 51 insertions(+), 31 deletions(-)
diff --git a/Kconfig b/Kconfig index 305b265ed7..e4165692d1 100644 --- a/Kconfig +++ b/Kconfig @@ -155,22 +155,30 @@ config SYS_MALLOC_LEN config SPL_SYS_MALLOC_F_LEN hex "Size of malloc() pool in SPL before relocation" depends on SYS_MALLOC_F + depends on SPL_SYS_MALLOC_SIMPLE || SPL_CLEAR_BSS_F default SYS_MALLOC_F_LEN help - Before relocation, memory is very limited on many platforms. Still, - we can provide a small malloc() pool if needed. Driver model in - particular needs this to operate, so that it can allocate the - initial serial device and any others that are needed. + Before relocation (before calling board_init_r, that is), memory is + very limited on many platforms. Still, we can provide a small + malloc() pool if needed. Driver model in particular needs this to + operate, so that it can allocate the initial serial device and any + others that are needed. + This option controls the size of this initial malloc() pool by + default.
config TPL_SYS_MALLOC_F_LEN hex "Size of malloc() pool in TPL before relocation" depends on SYS_MALLOC_F + depends on TPL_SYS_MALLOC_SIMPLE || SPL_CLEAR_BSS_F default SYS_MALLOC_F_LEN help - Before relocation, memory is very limited on many platforms. Still, - we can provide a small malloc() pool if needed. Driver model in - particular needs this to operate, so that it can allocate the - initial serial device and any others that are needed. + Before relocation (before calling board_init_r, that is), memory is + very limited on many platforms. Still, we can provide a small + malloc() pool if needed. Driver model in particular needs this to + operate, so that it can allocate the initial serial device and any + others that are needed. + This option controls the size of this initial malloc() pool by + default.
menuconfig EXPERT bool "Configure standard U-Boot features (expert users)" diff --git a/README b/README index 6525b81e3f..abe2e22a3c 100644 --- a/README +++ b/README @@ -2477,13 +2477,19 @@ FIT uImage format: CONFIG_SPL_STACK.
CONFIG_SYS_SPL_MALLOC_START - Starting address of the malloc pool used in SPL. + This is one way of providing the starting address of the malloc + pool used in SPL. If CONFIG_SPL_SYS_MALLOC_SIMPLE isn't set, + the full-featured heap will be used and it will allocate its + memory from the initial stack if CONFIG_SPL_SYS_MALLOC_F_LEN is + != 0. If you need it to use a dedicated area, use this option + to set an absolute address for the initial heap. When this option is set the full malloc is used in SPL and it is set up by spl_init() and before that, the simple malloc() - can be used if CONFIG_SYS_MALLOC_F is defined. + can still be used if CONFIG_SPL_SYS_MALLOC_F_LEN is defined.
CONFIG_SYS_SPL_MALLOC_SIZE - The size of the malloc pool used in SPL. + The size of the malloc pool used in SPL if + CONFIG_SYS_SPL_MALLOC_START is set.
CONFIG_SPL_OS_BOOT Enable booting directly to an OS from SPL. @@ -2758,7 +2764,8 @@ Configuration Settings: - CONFIG_SYS_MALLOC_SIMPLE Provides a simple and small malloc() and calloc() for those boards which do not use the full malloc in SPL (which is - enabled with CONFIG_SYS_SPL_MALLOC_START). + enabled by default with CONFIG_SYS_SPL_MALLOC_START or + CONFIG_SPL_SYS_MALLOC_F_LEN).
- CONFIG_SYS_NONCACHED_MEMORY: Size of non-cached memory area. This area of memory will be diff --git a/common/spl/spl.c b/common/spl/spl.c index 88d4b8a9bf..dec06c6e07 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -383,8 +383,14 @@ static int spl_common_init(bool setup_malloc) #ifdef CONFIG_MALLOC_F_ADDR gd->malloc_base = CONFIG_MALLOC_F_ADDR; #endif - gd->malloc_limit = CONFIG_VAL(SYS_MALLOC_F_LEN); - gd->malloc_ptr = 0; + if (CONFIG_IS_ENABLED(SYS_MALLOC_SIMPLE)) { + gd->malloc_limit = CONFIG_VAL(SYS_MALLOC_F_LEN); + gd->malloc_ptr = 0; + } else { + mem_malloc_init(gd->malloc_base, + CONFIG_VAL(SYS_MALLOC_F_LEN)); + gd->flags |= GD_FLG_FULL_MALLOC_INIT; + } } #endif ret = bootstage_init(true); diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index ddf2fb3fb8..297c19383f 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -12,28 +12,27 @@ config SPL_DM bool "Enable Driver Model for SPL" depends on DM && SPL help - Enable driver model in SPL. You will need to provide a - suitable malloc() implementation. If you are not using the - full malloc() enabled by CONFIG_SYS_SPL_MALLOC_START, - consider using CONFIG_SYS_MALLOC_SIMPLE. In that case you - must provide CONFIG_SPL_SYS_MALLOC_F_LEN to set the size. - In most cases driver model will only allocate a few uclasses - and devices in SPL, so 1KB should be enable. See - CONFIG_SPL_SYS_MALLOC_F_LEN for more details on how to enable it. + Enable driver model in SPL. You will need to provide a suitable + malloc() implementation. In most cases driver model will only + allocate a few uclasses and devices in SPL wihout freeing them, so + 1KB should be enough. + If full malloc() (default if CONFIG_SYS_SPL_MALLOC_START or + CONFIG_SPL_SYS_MALLOC_F_LEN are set) is too big for your board, + consider using CONFIG_SPL_SYS_MALLOC_SIMPLE (see help of that option + or CONFIG_SPL_SYS_MALLOC_F_LEN for more info).
config TPL_DM bool "Enable Driver Model for TPL" depends on DM && TPL help - Enable driver model in TPL. You will need to provide a - suitable malloc() implementation. If you are not using the - full malloc() enabled by CONFIG_SYS_SPL_MALLOC_START, - consider using CONFIG_SYS_MALLOC_SIMPLE. In that case you - must provide CONFIG_SPL_SYS_MALLOC_F_LEN to set the size. - In most cases driver model will only allocate a few uclasses - and devices in SPL, so 1KB should be enough. See - CONFIG_SPL_SYS_MALLOC_F_LEN for more details on how to enable it. - Disable this for very small implementations. + Enable driver model in TPL. You will need to provide a suitable + malloc() implementation. In most cases driver model will only + allocate a few uclasses and devices in TPL wihout freeing them, so + 1KB should be enough. + If full malloc() (default if CONFIG_SYS_SPL_MALLOC_START or + CONFIG_TPL_SYS_MALLOC_F_LEN are set) is too big for your board, + consider using CONFIG_TPL_SYS_MALLOC_SIMPLE (see help of that option + or CONFIG_TPL_SYS_MALLOC_F_LEN for more info).
config DM_WARN bool "Enable warnings in driver model"

Instead of fixing the SPL heap to 64 KiB in the board config header via CONFIG_SYS_SPL_MALLOC_SIZE, let's just use CONFIG_SPL_SYS_MALLOC_F_LEN in the defconfig.
This also has the advantage that it removes sub-mach specific ifdefs in socfpga_common.h.
Signed-off-by: Simon Goldschmidt simon.k.r.goldschmidt@gmail.com ---
Changes in v2: - fixed summary ("stack" -> "heap") - enable CONFIG_SPL_CLEAR_BSS_F for socfpga_arria10 using full malloc early in SPL
configs/socfpga_arria10_defconfig | 2 ++ include/configs/socfpga_common.h | 14 -------------- 2 files changed, 2 insertions(+), 14 deletions(-)
diff --git a/configs/socfpga_arria10_defconfig b/configs/socfpga_arria10_defconfig index f321a0ac3b..094232e847 100644 --- a/configs/socfpga_arria10_defconfig +++ b/configs/socfpga_arria10_defconfig @@ -2,6 +2,7 @@ CONFIG_ARM=y CONFIG_ARCH_SOCFPGA=y CONFIG_SYS_TEXT_BASE=0x01000040 CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_SPL_SYS_MALLOC_F_LEN=0x10000 CONFIG_TARGET_SOCFPGA_ARRIA10_SOCDK=y CONFIG_SPL=y CONFIG_IDENT_STRING="socfpga_arria10" @@ -13,6 +14,7 @@ CONFIG_BOOTARGS="console=ttyS0,115200" CONFIG_DEFAULT_FDT_FILE="socfpga_arria10_socdk_sdmmc.dtb" CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_BOUNCE_BUFFER=y +CONFIG_SPL_CLEAR_BSS_F=y CONFIG_SPL_FPGA_SUPPORT=y CONFIG_SPL_SPI_LOAD=y CONFIG_CMD_ASKENV=y diff --git a/include/configs/socfpga_common.h b/include/configs/socfpga_common.h index 191204b27b..b33a228b5e 100644 --- a/include/configs/socfpga_common.h +++ b/include/configs/socfpga_common.h @@ -253,16 +253,6 @@ unsigned int cm_get_qspi_controller_clk_hz(void); #define CONFIG_SPL_MAX_SIZE CONFIG_SYS_INIT_RAM_SIZE #endif
-#if defined(CONFIG_TARGET_SOCFPGA_ARRIA10) -/* SPL memory allocation configuration, this is for FAT implementation */ -#ifndef CONFIG_SYS_SPL_MALLOC_START -#define CONFIG_SYS_SPL_MALLOC_SIZE 0x00010000 -#define CONFIG_SYS_SPL_MALLOC_START (CONFIG_SYS_INIT_RAM_SIZE - \ - CONFIG_SYS_SPL_MALLOC_SIZE + \ - CONFIG_SYS_INIT_RAM_ADDR) -#endif -#endif - /* SPL SDMMC boot support */ #ifdef CONFIG_SPL_MMC_SUPPORT #if defined(CONFIG_SPL_FS_FAT) || defined(CONFIG_SPL_FS_EXT4) @@ -296,11 +286,7 @@ unsigned int cm_get_qspi_controller_clk_hz(void); /* * Stack setup */ -#if defined(CONFIG_TARGET_SOCFPGA_GEN5) #define CONFIG_SPL_STACK CONFIG_SYS_INIT_SP_ADDR -#elif defined(CONFIG_TARGET_SOCFPGA_ARRIA10) -#define CONFIG_SPL_STACK CONFIG_SYS_SPL_MALLOC_START -#endif
/* Extra Environment */ #ifndef CONFIG_SPL_BUILD
participants (1)
-
Simon Goldschmidt