spl: implement stack usage check

This implements a stack usage check in SPL.

Many boards start up SPL to run code + data from one common, rather small
SRAM. To implement a sophisticated SPL binary size limit on such boards,
the stack size (as well as malloc size and global data size) must be
subtracted from this SRAM size.

However, to do that properly, the stack size first needs to be known.

This patch adds a new Kconfig option:
- SPL_SYS_REPORT_STACK_F_USAGE: memset(0xaa) the whole area of the stack
  very early and check stack usage based on this constant later before the
  stack is switched to DRAM

Initializing the stack and checking it is implemented in weak functions,
in case a board does not use the stack as saved in gd->start_addr_sp.

Signed-off-by: Simon Goldschmidt <simon.k.r.goldschmidt@gmail.com>
This commit is contained in:
Simon Goldschmidt 2019-07-16 22:30:36 +02:00 committed by Tom Rini
parent af325e9597
commit d8c0332031
3 changed files with 64 additions and 0 deletions

View File

@ -18,6 +18,23 @@ __weak void arch_setup_gd(struct global_data *gd_ptr)
}
#endif /* !CONFIG_X86 && !CONFIG_ARM */
/**
* 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
@ -126,6 +143,9 @@ void board_init_f_init_reserve(ulong base)
/* next alloc will be higher by one 'early malloc arena' size */
base += CONFIG_VAL(SYS_MALLOC_F_LEN);
#endif
if (CONFIG_IS_ENABLED(SYS_REPORT_STACK_F_USAGE))
board_init_f_init_stack_protection();
}
/*

View File

@ -62,6 +62,25 @@ config SPL_SIZE_LIMIT_PROVIDE_STACK
of SRAM available for SPL when the stack required before reolcation
uses this SRAM, too.
config SPL_SYS_STACK_F_CHECK_BYTE
hex
default 0xaa
help
Constant used to check the stack
config SPL_SYS_REPORT_STACK_F_USAGE
depends on SPL_SIZE_LIMIT_PROVIDE_STACK != 0
bool "Check and report stack usage in SPL before relocation"
help
If this option is enabled, the initial SPL stack is filled with 0xaa
very early, up to the size configured with
SPL_SIZE_LIMIT_PROVIDE_STACK.
Later when SPL is done using this initial stack and switches to a
stack in DRAM, the actually used size of this initial stack is
reported by examining the memory and searching for the lowest
occurrence of non 0xaa bytes.
This default implementation works for stacks growing down only.
menu "PowerPC SPL Boot options"
depends on PPC && (SUPPORT_SPL && !SPL_FRAMEWORK)

View File

@ -709,6 +709,28 @@ void preloader_console_init(void)
}
#endif
/**
* This function is called before the stack is changed from initial stack to
* relocated stack. It tries to dump the stack size used
*/
__weak void spl_relocate_stack_check(void)
{
#if CONFIG_IS_ENABLED(SYS_REPORT_STACK_F_USAGE)
ulong init_sp = gd->start_addr_sp;
ulong stack_bottom = init_sp - CONFIG_VAL(SIZE_LIMIT_PROVIDE_STACK);
u8 *ptr = (u8 *)stack_bottom;
ulong i;
for (i = 0; i < CONFIG_VAL(SIZE_LIMIT_PROVIDE_STACK); i++) {
if (*ptr != CONFIG_VAL(SYS_STACK_F_CHECK_BYTE))
break;
ptr++;
}
printf("SPL initial stack usage: %lu bytes\n",
CONFIG_VAL(SIZE_LIMIT_PROVIDE_STACK) - i);
#endif
}
/**
* spl_relocate_stack_gd() - Relocate stack ready for board_init_r() execution
*
@ -733,6 +755,9 @@ ulong spl_relocate_stack_gd(void)
gd_t *new_gd;
ulong ptr = CONFIG_SPL_STACK_R_ADDR;
if (CONFIG_IS_ENABLED(SYS_REPORT_STACK_F_USAGE))
spl_relocate_stack_check();
#if defined(CONFIG_SPL_SYS_MALLOC_SIMPLE) && CONFIG_VAL(SYS_MALLOC_F_LEN)
if (CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN) {
debug("SPL malloc() before relocation used 0x%lx bytes (%ld KB)\n",