99#include "memfault/core/compiler.h"
1010
1111#if MEMFAULT_COMPILER_ARM_V7_A_R
12-
13- //! Only ARMv7-R is officially supported, notify the user if compiling for
14- //! ARMv7-A
15- #if defined(__ARM_ARCH_7A__ )
16- #pragma message \
17- "ARMv7-A is not officially supported yet by Memfault. Please contact
[email protected] with questions!"
18- #endif
19-
2012 #include "memfault/components.h"
2113 #include "memfault/panics/arch/arm/v7_a_r.h"
2214 #include "memfault/panics/coredump_impl.h"
@@ -43,27 +35,6 @@ extern void MEMFAULT_EXC_HANDLER_PREFETCH_ABORT(void);
4335
4436static eMemfaultRebootReason s_crash_reason = kMfltRebootReason_Unknown ;
4537
46- //! These are the regs pushed by the exception wrapper, which are transcribed
47- //! into 'struct MfltRegState' for the coredump.
48- MEMFAULT_PACKED_STRUCT ExceptionPushedRegs {
49- uint32_t r0 ;
50- uint32_t r1 ;
51- uint32_t r2 ;
52- uint32_t r3 ;
53- uint32_t r4 ;
54- uint32_t r5 ;
55- uint32_t r6 ;
56- uint32_t r7 ;
57- uint32_t r8 ;
58- uint32_t r9 ;
59- uint32_t r10 ;
60- uint32_t r11 ;
61- uint32_t r12 ;
62- uint32_t sp ; // R13
63- uint32_t lr ; // R14
64- uint32_t cpsr ;
65- };
66-
6738const sMfltCoredumpRegion * memfault_coredump_get_arch_regions (size_t * num_regions ) {
6839 * num_regions = 0 ;
6940 return NULL ;
@@ -247,6 +218,17 @@ MEMFAULT_USED void memfault_fault_handler(const sMfltRegState *regs, eMemfaultRe
247218 // We push callee r0-r12, lr, pc, and cpsr onto the stack, then pass the stack
248219 // pointer to the C memfault_fault_handler.
249220 //
221+ // Note that r0-r7 are shared across all execution modes, and r8-r12 are
222+ // shared in all modes except for FIQ.
223+ //
224+ // We need to ensure that we enter SYS MODE rather than USER MODE, so we
225+ // perform a check and mask if the fault occurred in USER mode.
226+ //
227+ // In order to preserve the layout of `MfltRegState` and ensure that we don't
228+ // clobber any registers, pushing to the stack to the stack is done out of
229+ // order, moving the stack pointer around manually to ensure ordering is
230+ // consistent.
231+ //
250232 // Here's a worked example of the position the registers are saved on the stack:
251233 //
252234 // sp = 128 <- starting example stack pointer value
@@ -256,16 +238,10 @@ MEMFAULT_USED void memfault_fault_handler(const sMfltRegState *regs, eMemfaultRe
256238 // cpsr @ 124
257239 // pc @ 120
258240 //
259- // // Now push user mode r8-r12, sp, lr, by first switching to user mode
260- // lr @ 116
261- // sp @ 112
262- // r12 @ 108
263- // r11 @ 104
264- // r10 @ 100
265- // r9 @ 96
266- // r8 @ 92
241+ // // Now, create a hole for the user mode registers.
242+ // sp -> 92
267243 //
268- // // Now switch back to exception mode, save r0-r7 to the stack
244+ // // Now push r0-r7 to the stack
269245 // r7 @ 88
270246 // r6 @ 84
271247 // r5 @ 80
@@ -274,43 +250,39 @@ MEMFAULT_USED void memfault_fault_handler(const sMfltRegState *regs, eMemfaultRe
274250 // r2 @ 68
275251 // r1 @ 64
276252 // r0 @ 60 <- this is the struct address we pass to memfault_fault_handler
277-
253+ //
254+ // // Now enter user mode, with r2 address @ 120 (the hole we made earlier)
255+ // // Now push user mode r8-r12, sp, lr, using r2 as the stack pointer
256+ // lr @ 116
257+ // sp @ 112
258+ // r12 @ 108
259+ // r11 @ 104
260+ // r10 @ 100
261+ // r9 @ 96
262+ // r8 @ 92
263+ //
264+ // // Now switch back to exception mode, set up args in r0 & r1, and call the
265+ // // fault handler.
278266 #define MEMFAULT_FAULT_HANDLING_ASM (_mode_string , _reason ) \
279- __asm volatile( /* assemble in ARM mode so we can copy sp with a stm instruction */ \
280- ".arm \n" /* save callee pc (exception handler adjusted lr) + spsr (callee \
281- cpsr) of the current mode */ \
282- "srsdb sp!, #" _mode_string \
283- " \n" /* push user mode regs at point of fault, including sp + lr */ \
284- "mov r8, r1 \n" \
285- "mov r1, sp \n" /* Save SPSR and mask mode bits */ \
286- "mrs r9, spsr \n" \
287- "and r9, #0x1f \n" /* Check each applicable mode and set current mode on a \
288- match */ \
289- "cmp r9, #" CPU_MODE_IRQ_STR " \n" \
290- "bne fiq_mode_%= \n" \
291- "cps #" CPU_MODE_IRQ_STR " \n" \
292- "b store_regs_%= \n" \
293- "fiq_mode_%=: \n" \
294- "cmp r9, #" CPU_MODE_FIQ_STR " \n" \
295- "bne supervisor_mode_%= \n" \
296- "cps #" CPU_MODE_FIQ_STR " \n" \
297- "b store_regs_%= \n" \
298- "supervisor_mode_%=: \n" \
299- "cmp r9, #" CPU_MODE_SUPERVISOR_STR " \n" \
300- "bne system_mode_%= \n" \
301- "cps #" CPU_MODE_SUPERVISOR_STR " \n" \
302- "b store_regs_%= \n" /* Fall back to system mode if no match */ \
303- "system_mode_%=: \n" \
304- "cps #" CPU_MODE_SYSTEM_STR " \n" \
305- "store_regs_%=: \n" \
306- "stmfd r1!, {r8-r12, sp, lr} \n" \
307- "cps #" _mode_string " \n" /* save active registers in exception frame */ \
308- "mov sp, r1 \n" \
309- "mov r1, r8 \n" \
310- "stmfd sp!, {r0-r7} \n" /* load the pushed frame and reason into r0+r1 for \
311- the handler args */ \
312- "mov r0, sp \n" \
313- "ldr r1, =%c0 \n" \
267+ __asm volatile(".arm \n" /* assemble in ARM mode so we can copy sp with a stm instruction */ \
268+ \
269+ "srsdb sp!, #" _mode_string " \n" /* Push PC + CPSR of previous mode */ \
270+ "sub sp, sp, #28 \n" /* Want r0-r7 after r8 - r14, make space */ \
271+ "stmfd sp!, {r0-r7} \n" /* Push r0-r7, shared amongst all modes */ \
272+ "add r2, sp, #60 \n" /* r2 for previous mode to push r8-r14 */ \
273+ \
274+ "mrs r3, cpsr \n" /* r3: CPSR to return to exception mode */ \
275+ "mrs r4, spsr \n" /* Get the previous mode CPSR */ \
276+ "tst r4, #0xf \n" /* Set Z Flag if in USR mode */ \
277+ "orreq r4, r4, #0xf \n" /* r4: Previous mode changed to SYS if was USR */ \
278+ \
279+ "msr CPSR_c, r4 \n" /* Enter the previous mode */ \
280+ "stmfd r2!, {r8-r12, sp, lr} \n" /* Push all banked registers */ \
281+ \
282+ "msr CPSR_cxsf, r3 \n" /* Back to our exception mode */ \
283+ \
284+ "mov r0, sp \n" /* arg0 = sp */ \
285+ "ldr r1, =%c0 \n" /* arg1 = reason */ \
314286 "b memfault_fault_handler \n" \
315287 : \
316288 : "i "((uint16_t )_reason ))
0 commit comments