arm: use interrupt stack during early init

The ARM Cortex-M early boot was using a custom stack at the end of the
SRAM instead of the interrupt stack. This works as long as no static
data that needs a known initial value occupies that stack space. This
has probably not been an issue because the .noinit section is at the
very end of the image, but it was still wrong to use that region of
memory for that initial stack.

To be able to use the interrupt stack during early boot, the stack has
to be released before an interrupt can happen. Since ARM Cortex-M uses
PendSV as a very low priority exception for context switching, if a
device driver installs and enables an interrupt during the PRE_KERNEL
initialization points, an interrupt could take precedence over PendSV
while the initial dummy thread has not yet been context switched of and
thus released the interrupt stack. To address this, rather than using
_Swap() and thus triggering PendSV, the initialization logic switches to
the main stack and branches to _main() directly instead.

Fixes ZEP-1309

Change-Id: If0b62cc66470b45b601e63826b5b3306e6a25ae9
Signed-off-by: Benjamin Walsh <benjamin.walsh@windriver.com>
This commit is contained in:
Benjamin Walsh 2016-11-20 11:08:53 -05:00 committed by Anas Nashif
commit 7f4c294e5c
5 changed files with 46 additions and 6 deletions

View file

@ -28,6 +28,7 @@ config CPU_CORTEX_M
# Omit prompt to signify "hidden" option
default n
select CPU_CORTEX
select ARCH_HAS_CUSTOM_SWAP_TO_MAIN
help
This option signifies the use of a CPU of the Cortex-M family.

View file

@ -33,6 +33,7 @@
_ASM_FILE_PROLOGUE
GTEXT(__reset)
GDATA(_interrupt_stack)
/**
*
@ -81,7 +82,8 @@ SECTION_SUBSEC_FUNC(TEXT,_reset_section,__start)
* Set PSP and use it to boot without using MSP, so that it
* gets set to _interrupt_stack during nanoInit().
*/
ldr r0, =__CORTEXM_BOOT_PSP
ldr r0, =_interrupt_stack
adds r0, r0, CONFIG_ISR_STACK_SIZE
msr PSP, r0
movs.n r0, #2 /* switch to using PSP (bit1 of CONTROL reg) */
msr CONTROL, r0

View file

@ -43,7 +43,7 @@ SECTION_SUBSEC_FUNC(exc_vector_table,_vector_table_section,_vector_table)
SECTION_SUBSEC_FUNC(exc_vector_table,_vector_table_section,__start)
#endif
.word __CORTEXM_BOOT_MSP
.word 0 /* no need for a stack, the kernel sets one up before running C */
.word __reset
.word __nmi

View file

@ -42,10 +42,6 @@ extern "C" {
#include <sections.h>
#include <misc/util.h>
/* location of MSP and PSP upon boot: at the end of SRAM */
.equ __CORTEXM_BOOT_MSP, (CONFIG_SRAM_BASE_ADDRESS + KB(CONFIG_SRAM_SIZE) - 8)
.equ __CORTEXM_BOOT_PSP, (__CORTEXM_BOOT_MSP - 0x100)
GTEXT(__start)
GTEXT(_vector_table)

View file

@ -47,6 +47,47 @@ static ALWAYS_INLINE void nanoArchInit(void)
_CpuIdleInit();
}
static ALWAYS_INLINE void
_arch_switch_to_main_thread(char *main_stack, size_t main_stack_size,
_thread_entry_t _main)
{
/* get high address of the stack, i.e. its start (stack grows down) */
char *start_of_main_stack;
start_of_main_stack = main_stack + main_stack_size;
start_of_main_stack = (void *)STACK_ROUND_DOWN(start_of_main_stack);
_current = (void *)main_stack;
__asm__ __volatile__(
/* move to main() thread stack */
"msr PSP, %0 \t\n"
/* unlock interrupts */
#ifdef CONFIG_CPU_CORTEX_M0_M0PLUS
"cpsie i \t\n"
#else
"movs %%r1, #0 \n\t"
"msr BASEPRI, %%r1 \n\t"
#endif
/* branch to _thread_entry(_main, 0, 0, 0) */
"mov %%r0, %1 \n\t"
"bx %2 \t\n"
/* never gets here */
:
: "r"(start_of_main_stack),
"r"(_main), "r"(_thread_entry)
: "r0", "r1", "sp"
);
CODE_UNREACHABLE;
}
static ALWAYS_INLINE void
_set_thread_return_value(struct k_thread *thread, unsigned int value)
{