I have been investigating signal handling in NuttX for SEGV/BUS/… for armv7-m. I have got some PoC code written (for a backlevel NuttX) that, while I’m in the interrupt handler, will schedule a signal handler. However, when it returns from the interrupt in exception_common and the next instruction is executed:
exception_common
343 bx r14 /* And return */ (gdb) p $r14 $1 = 0xfffffffd (gdb) stepi up_sigdeliver () at armv7-m/up_sigdeliver.c:74 74 struct tcb_s *rtcb = this_task(); (gdb) bt #0 up_sigdeliver () at armv7-m/up_sigdeliver.c:74 #1 <signal handler called>
I get a hardfault with a cfault of 0x1 (instruction access violation) and an hfault of 0x40000000 (“FORCED”):
[ 9.439000] [12] up_hardfault: IRQ: 3 regs: 0xc0327078 [ 9.439000] [12] up_hardfault: BASEPRI: 00000080 PRIMASK: 00000000 IPSR: 00000003 CONTROL: 00000001 [ 9.439000] [12] up_hardfault: CFAULTS: 00000001 HFAULTS: 40000000 DFAULTS: 0000000b BFAULTADDR: 00000000 AFAULTS: 00000000
The registers at the time of the fault:
lr 0xfffffff9 0xfffffff9 pc 0x8161ef0 0x8161ef0 <up_sigdeliver> xPSR 0x1000000 0x1000000 fpscr 0x80000010 0x80000010 msp 0xc03275e8 0xc03275e8 psp 0xc03276b8 0xc03276b8 primask 0x0 0x0 basepri 0x80 0x80 faultmask 0x0 0x0 control 0x3 0x3
In the interrupt handler I thought I was clearing/acknowledging the interrupt in the correct way in up_memfault:
up_memfault
uint32_t cfsr = getreg32(NVIC_CFAULTS); /* NVIC_CFAULTS = 0xe000ed28 */ uint32_t *mfsr = (uintptr_t) NVIC_CFAULTS; : *mfsr |= cfsr; /* Acknowledge interrupt */
I have looked through the ARM-7M Architecture Reference but I can’t work out what the proper way of exiting the memfault handler is (assuming this is the root cause of the problem).