Hi,
I am developing for an ARM Cortex-M7 core (NXP iMIMXRT1062 chip), which is a Thumb only processor. I am using MCUXpressoIDE 11.1 which is based on Eclipse.
I have a problem returning from SVCall. When free running, it usually ends up at address 0xdeadbeee (0xdeadbeef with last bit removed), or can be caught in the HardFault_Handler. When I step through using a debugger (GDB) it appears to work correctly.
in excep.S
SVC_Handler: // This call follows the ARM Architecture Procedure Calling Standard (AAPCS) // which pushes the following onto the stack from the calling function. // {r0-r3}, r12, LR, PC, xPSR // The LR currently set is the EXC_RETURN value which will cause the stack to // be unwound and the registers set to the initial values. .syntax unified // stack contains r0, r1, r2, r3 which are used as function arguments // Check whether we are using PSP or MSP (Handler mode always uses MSP) TST LR, #4 // Test EXC_RETURN to see which stack is expected. ITE EQ MOVEQ r1, sp // MSP in use MRSNE r1, psp // PSP in use LDR r3, [r1, #0x18] // excavate pc from stack // No need to check Thumb state LDRH r0, [r3,#-2] // Yes: Load halfword and... BIC r0, r0, #0xFF00 // ...extract comment field STMFD sp!, {LR} // push LR onto stack before call BL SVC_Handler_C // Call main part of handler LDMIA sp!, {LR} // retrieve LR from stack // Put r0 (return value) into stack as return value from this function. stm sp, {r0} // Set PC to LR (which contains EXC_RETURN value), which will unwind the // stack and restore the registers BX LR .syntax divided.endfunc
in excep_handlers.h
/** @brief Enumeration of operations performed by SVC. * The operation IDs need to fit into a uint8_t. */typedef enum{ C4_SVC_Reserved, C4_SVC_PRINT, C4_SVC_ADD, C4_SVC_USER,}C4_SVC_Op_t;
in excep_handlers.c
void *SVC_Handler_C(uint8_t SVC_type, void **args){ switch (SVC_type) { case C4_SVC_PRINT: printf((char *)*args, (int) *(args+1)); break; case C4_SVC_ADD: return (void *)((int)*args + (int)*(args+1)); break; case C4_SVC_USER: break; default: { pointer expt_frm_ptr = 0; // Get PSP - should this test whether to get PSP or MSP asm volatile ("MRS %0, psp" : "=r" (expt_frm_ptr) ); expt_frm_dump(expt_frm_ptr); // C4_PRINT_ERR_STRING is safe here as the exception handler is already executing in privileged // state so does not need to use the exception call mechanism. C4_PRINT_ERR_STRING("Unhandled option in %s(%d)\n", __PRETTY_FUNCTION__, SVC_type); while(1) {} } } return NULL;}
It is called like this:
int a1 = 3;int a2 = 5;int res = 0;asm("MOV r0, %1\n\tMOV r1, %2\n\tSVC %3\n\tMOV %0, r0\n\t":"=r"(res): \ "r"(a1), "r"(a2), "I" (C4_SVC_ADD));
The value of LR is 0xFFFF_FFF1 which is the expectd value of EXC_RETURN
0xFFFF_FFF1
EXC_RETURN
What am I doing wrong in the return?
thanks
Dan
I am not following all of your logic, but one thing jumped out at me was that you expected, and got, an LR of 0xfffffff1. That would suggest you were in handler mode at time of the SVC call. I have always seen SVC as the way an RTOS implements the thread mode (aka user space) to handler mode (aka kernel space) trap. If you were truly in handler mode at time of SVC call, you were either in an ISR or in a system exception. I think both are not good places to call SVC from.
One more point. Should
MOVEQ r1, sp
not be
MRSEQ r1, msp
?
Thanks for your replies tobermory.
Changing to your MRS will definitely be more explicit about what is happening.
As far as the LR = 0xFFFF_FFF1, I thought that the nested SVC calls was permitted - not necessarily a good idea.
I am finding it very strange that I can step through the code, but not step over it.
How do you mean step through code but not over?
I don't think nested SVC are permitted. I know you can't call SVC from a fault handler. SVC from non Hard Fault Handler (memmanage, bus and usage) will result in a Hard Fault. If in HFH at time of SVC, I think you end up in lock up.
To confim that nested SVC calls will fault:
main() {
__asm__( "svc #0\n" );
}
void SVC_Handler(void) {
__asm__( "svc #1\n" );
produces this fault dump on my SiliconLabs EFM32GG dev board, which is a Cortex M3:
r7 2001FFD4sp 2001FFB0excrt FFFFFFF1psr 20000003hfsr 40000000cfsr 00000000mmfar E000ED34bfar E000ED38shcsr 00000080s.r0 00000000s.r1 0000000As.r2 20000A3Cs.r3 00000000s.r12 20000B48s.lr FFFFFFF9s.pc 00000240s.psr 0100020BBit 30 of the Hard Fault Status Register is set, telling us (I think) that the nested SVC call was escalated to a HardFault. We know a Hard Fault is active since PSR[8:0] == 3. Note how excrt[3:0] == 1, confirming we were in handler mode at time of fault, due to the outer SVC call being active (stacked PSR[8..0] == B backing this up, SVC is exception num 11 == 0xB).
Hi tobermory,
thanks for your replies.
I am using NXP MCUXpresso, which is based on Eclipse, to debug. By step through the code, I mean that if I am debugging and am stopped just before the line
If I use the "step over" button, then I get the fault expressed.
If I use the "step into" button, then I can step through the handler code line by line (either in C or in assembly language). In fact, I can use the "step return" button directly after entering the SVC_Handler and the code will run as expected.
Thanks also for your test. I had been assuming that since an exception could return to Handler mode (LR = 0xFFFF_FFF1) as well as to thread mode (0xFFFF_FFF9 or 0xFFFF_FFFD) that this permitted nested calls.
dan