diff options
author | Albert ARIBAUD | 2015-11-25 17:56:32 +0100 |
---|---|---|
committer | Tom Rini | 2016-01-13 21:05:17 -0500 |
commit | ecc306639e83c9019a5093b77a48685ea40eedc2 (patch) | |
tree | 7785c9d7358ccd22ddabe52489aae8a8c7035ffe /common/init | |
parent | 20d08f59fa7cdde0da1eb7aca7915c91dbdeaf51 (diff) |
Fix board init code to respect the C runtime environment
board_init_f_mem() alters the C runtime environment's
stack it is actually already using. This is not a valid
behaviour within a C runtime environment.
Split board_init_f_mem into C functions which do not alter
their own stack and always behave properly with respect to
their C runtime environment.
Signed-off-by: Albert ARIBAUD <albert.u.boot@aribaud.net>
Acked-by: Thomas Chou <thomas@wytron.com.tw>
Diffstat (limited to 'common/init')
-rw-r--r-- | common/init/board_init.c | 109 |
1 files changed, 99 insertions, 10 deletions
diff --git a/common/init/board_init.c b/common/init/board_init.c index 1c6126d8ce5..e649e078b9c 100644 --- a/common/init/board_init.c +++ b/common/init/board_init.c @@ -29,31 +29,120 @@ __weak void arch_setup_gd(struct global_data *gd_ptr) } #endif /* !CONFIG_X86 */ -ulong board_init_f_mem(ulong top) +/* + * 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 */ +#if defined(CONFIG_SYS_MALLOC_F) + top -= CONFIG_SYS_MALLOC_F_LEN; +#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; #ifndef _USE_MEMCPY int *ptr; #endif - /* Leave space for the stack we are running with now */ - top -= 0x40; + /* + * clear GD entirely and set it up. + * Use gd_ptr, as gd may not be properly set yet. + */ - top -= sizeof(struct global_data); - top = ALIGN(top, 16); - gd_ptr = (struct global_data *)top; + gd_ptr = (struct global_data *)base; + /* zero the area */ #ifdef _USE_MEMCPY memset(gd_ptr, '\0', sizeof(*gd)); #else for (ptr = (int *)gd_ptr; ptr < (int *)(gd_ptr + 1); ) *ptr++ = 0; #endif + /* set GD unless architecture did it already */ +#ifndef CONFIG_X86 arch_setup_gd(gd_ptr); +#endif + /* 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 defined(CONFIG_SYS_MALLOC_F) - top -= CONFIG_SYS_MALLOC_F_LEN; - gd->malloc_base = top; + /* go down one 'early malloc arena' */ + gd->malloc_base = base; + /* next alloc will be higher by one 'early malloc arena' size */ + base += CONFIG_SYS_MALLOC_F_LEN; #endif - - return top; } |