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:
parent
296a234ddb
commit
7f4c294e5c
5 changed files with 46 additions and 6 deletions
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue