Skip to content

Commit 7aecb03

Browse files
wentongwuandrewboie
authored andcommitted
arch: arm: switching stack pointer with assembly code
With -O0 optimizion, gcc compiler doesn't inline "static inline" marked function. So when function call return from function set_and_switch_to_psp which is to switch sp from MSP to PSP, the ending "mov sp, r7" instruction will overwrite the just updated sp value(PSP) with the beginning stack pointer(should be MSP) stored in r7 register, so the switch doesn't happen. And it causes unpredictable problems in the initialization process, the backward analysis for this problem can be found on Github issue #15794. Fixes: #15794. Signed-off-by: Wentong Wu <[email protected]>
1 parent a2fa8e9 commit 7aecb03

File tree

2 files changed

+37
-48
lines changed

2 files changed

+37
-48
lines changed

arch/arm/core/cortex_m/prep_c.c

-47
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
#include <linker/linker-defs.h>
2323
#include <kernel_internal.h>
2424
#include <arch/arm/cortex_m/cmsis.h>
25-
#include <cortex_m/stack.h>
2625

2726
#if defined(__GNUC__)
2827
/*
@@ -37,44 +36,6 @@
3736

3837
#include <string.h>
3938

40-
static inline void switch_sp_to_psp(void)
41-
{
42-
__set_CONTROL(__get_CONTROL() | CONTROL_SPSEL_Msk);
43-
/*
44-
* When changing the stack pointer, software must use an ISB instruction
45-
* immediately after the MSR instruction. This ensures that instructions
46-
* after the ISB instruction execute using the new stack pointer.
47-
*/
48-
__ISB();
49-
}
50-
51-
static inline void set_and_switch_to_psp(void)
52-
{
53-
u32_t process_sp;
54-
55-
process_sp = (u32_t)&_interrupt_stack + CONFIG_ISR_STACK_SIZE;
56-
__set_PSP(process_sp);
57-
switch_sp_to_psp();
58-
}
59-
60-
void lock_interrupts(void)
61-
{
62-
#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
63-
__disable_irq();
64-
#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
65-
__set_BASEPRI(_EXC_IRQ_DEFAULT_PRIO);
66-
#else
67-
#error Unknown ARM architecture
68-
#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */
69-
}
70-
71-
#ifdef CONFIG_INIT_STACKS
72-
static inline void init_stacks(void)
73-
{
74-
memset(&_interrupt_stack, 0xAA, CONFIG_ISR_STACK_SIZE);
75-
}
76-
#endif
77-
7839
#ifdef CONFIG_CPU_CORTEX_M_HAS_VTOR
7940

8041
#ifdef CONFIG_XIP
@@ -191,14 +152,6 @@ extern void z_IntLibInit(void);
191152
#endif
192153
void _PrepC(void)
193154
{
194-
#ifdef CONFIG_INIT_STACKS
195-
init_stacks();
196-
#endif
197-
/*
198-
* Set PSP and use it to boot without using MSP, so that it
199-
* gets set to _interrupt_stack during initialization.
200-
*/
201-
set_and_switch_to_psp();
202155
relocate_vector_table();
203156
enable_floating_point();
204157
z_bss_zero();

arch/arm/core/cortex_m/reset.S

+37-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
_ASM_FILE_PROLOGUE
2020

2121
GTEXT(__reset)
22+
GTEXT(memset)
23+
GDATA(_interrupt_stack)
2224
#if defined(CONFIG_PLATFORM_SPECIFIC_INIT)
2325
GTEXT(_PlatformInit)
2426
#endif
@@ -61,12 +63,46 @@ SECTION_SUBSEC_FUNC(TEXT,_reset_section,__start)
6163
#endif
6264

6365
/* lock interrupts: will get unlocked when switch to main task */
64-
bl lock_interrupts
66+
#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
67+
cpsid i
68+
#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
69+
movs.n r0, #_EXC_IRQ_DEFAULT_PRIO
70+
msr BASEPRI, r0
71+
#else
72+
#error Unknown ARM architecture
73+
#endif
74+
6575
#ifdef CONFIG_WDOG_INIT
6676
/* board-specific watchdog initialization is necessary */
6777
bl _WdogInit
6878
#endif
6979

80+
#ifdef CONFIG_INIT_STACKS
81+
ldr r0, =_interrupt_stack
82+
ldr r1, =0xaa
83+
ldr r2, =CONFIG_ISR_STACK_SIZE
84+
bl memset
85+
#endif
86+
87+
/*
88+
* Set PSP and use it to boot without using MSP, so that it
89+
* gets set to _interrupt_stack during initialization.
90+
*/
91+
ldr r0, =_interrupt_stack
92+
ldr r1, =CONFIG_ISR_STACK_SIZE
93+
adds r0, r0, r1
94+
msr PSP, r0
95+
mrs r0, CONTROL
96+
movs r1, #2
97+
orrs r0, r1 /* CONTROL_SPSEL_Msk */
98+
msr CONTROL, r0
99+
/*
100+
* When changing the stack pointer, software must use an ISB instruction
101+
* immediately after the MSR instruction. This ensures that instructions
102+
* after the ISB instruction execute using the new stack pointer.
103+
*/
104+
isb
105+
70106
/*
71107
* 'bl' jumps the furthest of the branch instructions that are
72108
* supported on all platforms. So it is used when jumping to _PrepC

0 commit comments

Comments
 (0)