I have a function that generates an UsageFault exception for test:
intUsageFault_Trigger_UnalignedAccess(void){ int r = 0; volatile unsigned int* p;
/* Not word aligned address */ p = (unsigned int*)0x20000002;
/* Load word from unaligned address raises exception */ r = *p;
return r;}
When the program jumps to UsageFault_Handler(), I extract the SP and then I call a C routine to print some debug info - Pmd_Fault_Handler()
voidUsageFault_Handler(void){ __asm__("TST LR, #4; "); __asm__("ITE EQ; "); __asm__("MRSEQ R0, MSP; "); __asm__("MRSNE R0, PSP; "); __asm__("MOV R1, LR; "); __asm__("b Pmd_Fault_Handler ");
//......
__asm__("BX LR ");
}
voidPmd_Fault_Handler (uint32_t* pSP, int32_t exc){ regsss[0] = pSP[0]; regsss[1] = pSP[1]; regsss[2] = pSP[2]; regsss[3] = pSP[3]; regsss[4] = pSP[4]; regsss[5] = pSP[5]; regsss[6] = pSP[6]; regsss[7] = pSP[7];
.....
return;
PROBLEM: When returning from Pmd_Fault_Handler(), the program jump again to the beginning of this function instead of returning to UsageFault_Handler()
The overall scope for me is to return from UsageFault_Handler() in a controlled manner and to continue execution from the next instruction from the caller of UsageFault_Trigger_UnalignedAccess(), but I cannot reach this - __asm__("BX LR "); - to be able to return from exception.
Thanks!
You are calling the Branch instruction (mnemonic "B") in the code below.
__asm__("b Pmd_Fault_Handler ");
According to what you want, Branch with Link (BL or BLX) should be used, instead of B (see the doc below for BL and BLX).
Arm A-profile A32/T32 Instruction Set Architecture
Otherwise, the Return Link isn't stored to the Link Register (LR) when branching to Pmd_Fault_Handler .
Kind regards,
Toshi
Thanks Toshi!
Using BL, indeed, will return my code into UsageFault_Handler(), after execution of Pmd_Fault_Handler()
When jumping to UsageFault_Handler() I have LR set to 0xFFFF.FFF9, but after I will return from Pmd_Fault_Handler() into UsageFault_Handler(), I see the LR is pointing to some executable code.
Should it work if I'll save the LR before jumping to Pmd_Fault_Handler() into some global variable (using asm), restore it back and then executing BX LR to return from exception?
Dan
Update:
static volatile uint32_t lr_exc = 0;
voidUsageFault_Handler(void){
//...................
__asm__("LDR R3, =lr_exc "); __asm__("STR R1, [R3]"); // Store LR code into lr_exc __asm__("bl Pmd_Fault_Handler "); // do some user processing __asm__("LDR R3, =lr_exc "); __asm__("LDR R4, [R3] "); __asm__("MOV LR, R4; ");
__asm__("bx LR "); // LR is restored with 0xFFFF.FFF9 from global "lr_exc", but it is jumping to the same UsageFault_Handler() instead of returning to the function that generated the exception
I think you need your UsageFault_Handler to be marked 'naked', so that the compiler doesn't add any 'prolog' at the start of the routine. By default, a prolog of 'push r7, lr' will be added, and I think that will mess up your call stack.
I have done some work on fault handling on cortex-m, see here
https://github.com/tobermory/faultHandling-cortex-m
Stuart