mirror of
https://github.com/u-boot/u-boot.git
synced 2024-12-02 00:53:29 +08:00
5004901efb
In case the MALLOC_F_ADDR is set to non-zero value, the early malloc area is not going to be placed just below stack top, but elsewhere. Do not reserve MALLOC_F bytes in this case, as that wastes stack space and may even cause insufficient stack space in SPL. This functionality is particularly useful on i.MX8M, where the insufficient stack space can be triggered. Signed-off-by: Marek Vasut <marex@denx.de> Cc: Albert ARIBAUD <albert.u.boot@aribaud.net> Cc: Fabio Estevam <festevam@denx.de> Cc: Peng Fan <peng.fan@nxp.com> Cc: Simon Glass <sjg@chromium.org> Cc: Stefano Babic <sbabic@denx.de> Cc: Thomas Chou <thomas@wytron.com.tw> Cc: Tom Rini <trini@konsulko.com>
177 lines
5.2 KiB
C
177 lines
5.2 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Code shared between SPL and U-Boot proper
|
|
*
|
|
* Copyright (c) 2015 Google, Inc
|
|
* Written by Simon Glass <sjg@chromium.org>
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <bootstage.h>
|
|
#include <init.h>
|
|
#include <asm/global_data.h>
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
/* Unfortunately x86 or ARM can't compile this code as gd cannot be assigned */
|
|
#if !defined(CONFIG_X86) && !defined(CONFIG_ARM)
|
|
__weak void arch_setup_gd(struct global_data *gd_ptr)
|
|
{
|
|
gd = gd_ptr;
|
|
}
|
|
#endif /* !CONFIG_X86 && !CONFIG_ARM */
|
|
|
|
/**
|
|
* This function is called from board_init_f_init_reserve to set up
|
|
* gd->start_addr_sp for stack protection if not already set otherwise
|
|
*/
|
|
__weak void board_init_f_init_stack_protection_addr(ulong base)
|
|
{
|
|
#if CONFIG_IS_ENABLED(SYS_REPORT_STACK_F_USAGE)
|
|
/* set up stack pointer for stack usage if not set yet */
|
|
if (!gd->start_addr_sp)
|
|
gd->start_addr_sp = base;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* This function is called after the position of the initial stack is
|
|
* determined in gd->start_addr_sp. Boards can override it to set up
|
|
* stack-checking markers.
|
|
*/
|
|
__weak void board_init_f_init_stack_protection(void)
|
|
{
|
|
#if CONFIG_IS_ENABLED(SYS_REPORT_STACK_F_USAGE)
|
|
ulong stack_bottom = gd->start_addr_sp -
|
|
CONFIG_VAL(SIZE_LIMIT_PROVIDE_STACK);
|
|
|
|
/* substact some safety margin (0x20) since stack is in use here */
|
|
memset((void *)stack_bottom, CONFIG_VAL(SYS_STACK_F_CHECK_BYTE),
|
|
CONFIG_VAL(SIZE_LIMIT_PROVIDE_STACK) - 0x20);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Allocate reserved space for use as 'globals' from 'top' address and
|
|
* return 'bottom' address of allocated space
|
|
*
|
|
* Notes:
|
|
*
|
|
* Actual reservation cannot be done from within this function as
|
|
* it requires altering the C stack pointer, so this will be done by
|
|
* the caller upon return from this function.
|
|
*
|
|
* IMPORTANT:
|
|
*
|
|
* Alignment constraints may differ for each 'chunk' allocated. For now:
|
|
*
|
|
* - GD is aligned down on a 16-byte boundary
|
|
*
|
|
* - the early malloc arena is not aligned, therefore it follows the stack
|
|
* alignment constraint of the architecture for which we are bulding.
|
|
*
|
|
* - GD is allocated last, so that the return value of this functions is
|
|
* both the bottom of the reserved area and the address of GD, should
|
|
* the calling context need it.
|
|
*/
|
|
|
|
ulong board_init_f_alloc_reserve(ulong top)
|
|
{
|
|
/* Reserve early malloc arena */
|
|
#ifndef CONFIG_MALLOC_F_ADDR
|
|
#if CONFIG_VAL(SYS_MALLOC_F_LEN)
|
|
top -= CONFIG_VAL(SYS_MALLOC_F_LEN);
|
|
#endif
|
|
#endif
|
|
/* LAST : reserve GD (rounded up to a multiple of 16 bytes) */
|
|
top = rounddown(top-sizeof(struct global_data), 16);
|
|
|
|
return top;
|
|
}
|
|
|
|
/*
|
|
* Initialize reserved space (which has been safely allocated on the C
|
|
* stack from the C runtime environment handling code).
|
|
*
|
|
* Notes:
|
|
*
|
|
* Actual reservation was done by the caller; the locations from base
|
|
* to base+size-1 (where 'size' is the value returned by the allocation
|
|
* function above) can be accessed freely without risk of corrupting the
|
|
* C runtime environment.
|
|
*
|
|
* IMPORTANT:
|
|
*
|
|
* Upon return from the allocation function above, on some architectures
|
|
* the caller will set gd to the lowest reserved location. Therefore, in
|
|
* this initialization function, the global data MUST be placed at base.
|
|
*
|
|
* ALSO IMPORTANT:
|
|
*
|
|
* On some architectures, gd will already be good when entering this
|
|
* function. On others, it will only be good once arch_setup_gd() returns.
|
|
* Therefore, global data accesses must be done:
|
|
*
|
|
* - through gd_ptr if before the call to arch_setup_gd();
|
|
*
|
|
* - through gd once arch_setup_gd() has been called.
|
|
*
|
|
* Do not use 'gd->' until arch_setup_gd() has been called!
|
|
*
|
|
* IMPORTANT TOO:
|
|
*
|
|
* Initialization for each "chunk" (GD, early malloc arena...) ends with
|
|
* an incrementation line of the form 'base += <some size>'. The last of
|
|
* these incrementations seems useless, as base will not be used any
|
|
* more after this incrementation; but if/when a new "chunk" is appended,
|
|
* this increment will be essential as it will give base right value for
|
|
* this new chunk (which will have to end with its own incrementation
|
|
* statement). Besides, the compiler's optimizer will silently detect
|
|
* and remove the last base incrementation, therefore leaving that last
|
|
* (seemingly useless) incrementation causes no code increase.
|
|
*/
|
|
|
|
void board_init_f_init_reserve(ulong base)
|
|
{
|
|
struct global_data *gd_ptr;
|
|
|
|
/*
|
|
* clear GD entirely and set it up.
|
|
* Use gd_ptr, as gd may not be properly set yet.
|
|
*/
|
|
|
|
gd_ptr = (struct global_data *)base;
|
|
/* zero the area */
|
|
memset(gd_ptr, '\0', sizeof(*gd));
|
|
/* set GD unless architecture did it already */
|
|
#if !defined(CONFIG_ARM)
|
|
arch_setup_gd(gd_ptr);
|
|
#endif
|
|
|
|
if (CONFIG_IS_ENABLED(SYS_REPORT_STACK_F_USAGE))
|
|
board_init_f_init_stack_protection_addr(base);
|
|
|
|
/* next alloc will be higher by one GD plus 16-byte alignment */
|
|
base += roundup(sizeof(struct global_data), 16);
|
|
|
|
/*
|
|
* record early malloc arena start.
|
|
* Use gd as it is now properly set for all architectures.
|
|
*/
|
|
|
|
#if CONFIG_VAL(SYS_MALLOC_F_LEN)
|
|
/* go down one 'early malloc arena' */
|
|
gd->malloc_base = base;
|
|
#endif
|
|
|
|
if (CONFIG_IS_ENABLED(SYS_REPORT_STACK_F_USAGE))
|
|
board_init_f_init_stack_protection();
|
|
}
|
|
|
|
#if CONFIG_IS_ENABLED(SHOW_BOOT_PROGRESS)
|
|
/*
|
|
* Board-specific Platform code can reimplement show_boot_progress () if needed
|
|
*/
|
|
__weak void show_boot_progress(int val) {}
|
|
#endif
|