diff --git a/firmware/asm/arm/thread.c b/firmware/asm/arm/thread.c index 30df56e0d9..e6f180f4ec 100644 --- a/firmware/asm/arm/thread.c +++ b/firmware/asm/arm/thread.c @@ -61,7 +61,12 @@ static void __attribute__((naked)) USED_ATTR start_thread(void) static inline void store_context(void* addr) { asm volatile( +#if defined(CPU_ARM_MICRO) && ARCH_VERSION >= 7 + "stmia %0, { r4-r11, lr } \n" + "str sp, [%0, #36] \n" +#else "stmia %0, { r4-r11, sp, lr } \n" +#endif : : "r" (addr) ); } @@ -85,7 +90,13 @@ static inline void load_context(const void* addr) "ldmiane %0, { r0, pc } \n" #endif +#if defined(CPU_ARM_MICRO) && ARCH_VERSION >= 7 + "mov r0, %0 \n" + "ldmia r0, { r4-r11, lr } \n" + "ldr sp, [r0, #36] \n" +#else "ldmia %0, { r4-r11, sp, lr } \n" /* Load regs r4 to r14 from context */ +#endif END_ARM_ASM_SYNTAX_UNIFIED : : "r" (addr) : "r0" /* only! */ ); diff --git a/firmware/asm/arm/thread.h b/firmware/asm/arm/thread.h index 533a088979..1cfc3741da 100644 --- a/firmware/asm/arm/thread.h +++ b/firmware/asm/arm/thread.h @@ -21,6 +21,20 @@ #include "config.h" +#if defined(CPU_ARM_MICRO) && ARCH_VERSION >= 7 +/* + * Cortex-M cannot load/store SP with ldm/stm so we need to store it + * separately. This makes it slightly more efficient to store SP last + * so as not to split the register list. + */ +struct regs +{ + uint32_t r[8]; /* 0-28 - Registers r4-r11 */ + uint32_t lr; /* 32 - r14 (lr) */ + uint32_t sp; /* 36 - Stack pointer (r13) */ + uint32_t start; /* 40 - Thread start address, or NULL when started */ +}; +#else struct regs { uint32_t r[8]; /* 0-28 - Registers r4-r11 */ @@ -28,6 +42,7 @@ struct regs uint32_t lr; /* 36 - r14 (lr) */ uint32_t start; /* 40 - Thread start address, or NULL when started */ }; +#endif #if (CONFIG_PLATFORM & PLATFORM_HOSTED) #include