Skip to content

Commit 1c51d5f

Browse files
stuijkeith-packard
authored andcommitted
picocrt/arm: For non M-class Arm cores set distinct banked SPs
Currently in the Arm crt0.c, we set all the banked SPs to the same address. So if we would change to a different mode from the default supervisor (SVC) mode, we would set the SP back to the original value of the SVC SP, and stomp over the existing values. This patch sets up different addresses for the different modes at the top of the stack, with the main SVC stack defined at the bottom of these, which then grows towards the heap like before. The stacks are all set to the very small value of 16 bytes. Enough to be able to debug picolibc test startup code, which currently isn't expected to switch mode in normal operation.
1 parent 8657cbf commit 1c51d5f

File tree

1 file changed

+38
-13
lines changed

1 file changed

+38
-13
lines changed

picocrt/machine/arm/crt0.c

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -188,28 +188,43 @@ extern char __stack[];
188188
#define I_BIT (1 << 7)
189189
#define F_BIT (1 << 6)
190190

191-
#define SET_MODE(mode) \
191+
#define SHADOW_STACK_SIZE 0x10
192+
#define STACK_IRQ (__stack - SHADOW_STACK_SIZE * 0)
193+
#define STACK_ABT (__stack - SHADOW_STACK_SIZE * 1)
194+
#define STACK_UND (__stack - SHADOW_STACK_SIZE * 2)
195+
#define STACK_FIQ (__stack - SHADOW_STACK_SIZE * 3)
196+
#define STACK_SYS (__stack - SHADOW_STACK_SIZE * 4)
197+
#define STACK_SVC (__stack - SHADOW_STACK_SIZE * 5)
198+
199+
#define SET_MODE(mode) \
192200
__asm__("mov r0, %0\nmsr cpsr_c, r0" :: "I" (mode | I_BIT | F_BIT) : "r0"); \
193201

194-
#define SET_SP(mode) \
195-
SET_MODE(mode); \
196-
__asm__("mov sp, %0" : : "r" (__stack))
202+
#define SET_SP(mode, address) \
203+
SET_MODE(mode); \
204+
__asm__("mov sp, %0" : : "r" (address))
197205

198206
#define SET_SPS() \
199-
SET_SP(MODE_IRQ); \
200-
SET_SP(MODE_ABT); \
201-
SET_SP(MODE_UND); \
202-
SET_SP(MODE_FIQ); \
203-
SET_SP(MODE_SYS); \
207+
SET_SP(MODE_IRQ, STACK_IRQ); \
208+
SET_SP(MODE_ABT, STACK_ABT); \
209+
SET_SP(MODE_UND, STACK_UND); \
210+
SET_SP(MODE_FIQ, STACK_FIQ); \
211+
SET_SP(MODE_SYS, STACK_SYS); \
204212
SET_MODE(MODE_SVC);
205213

206214
#if __ARM_ARCH_ISA_THUMB == 1
207215
static __noinline __attribute__((target("arm"))) void
208216
_set_stacks(void)
209217
{
218+
#ifdef __GNUC__
219+
#pragma GCC diagnostic push
220+
#pragma GCC diagnostic ignored "-Warray-bounds"
221+
#endif /* __GNUC__ */
210222
SET_SPS();
223+
#ifdef __GNUC__
224+
#pragma GCC diagnostic pop
225+
#endif /* __GNUC__ */
211226
}
212-
#endif
227+
#endif /*__ARM_ARCH_ISA_THUMB == 1 */
213228

214229
/*
215230
* Regular ARM has an 8-entry exception vector and starts without SP
@@ -306,11 +321,21 @@ _start(void)
306321
/* Generate a reference to __vector_table so we get one loaded */
307322
__asm__(".equ __my_vector_table, __vector_table");
308323

309-
__asm__("mov sp, %0" : : "r" (__stack));
324+
#ifdef __GNUC__
325+
#pragma GCC diagnostic push
326+
#pragma GCC diagnostic ignored "-Warray-bounds"
327+
#endif /* __GNUC__ */
328+
__asm__("mov sp, %0" : : "r" (STACK_SVC));
329+
310330
#if __ARM_ARCH_ISA_THUMB != 1
311331
SET_SPS();
312-
#endif
313-
/* Branch to C code */
332+
#endif /* __ARM_ARCH_ISA_THUMB != 1 */
333+
334+
#ifdef __GNUC__
335+
#pragma GCC diagnostic pop
336+
#endif /* __GNUC__ */
337+
338+
/* Branch to C code */
314339
__asm__("b _cstart");
315340
}
316341

0 commit comments

Comments
 (0)