This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

SVCall returning to 0xdeadbeee

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

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    2001FFD4
    sp    2001FFB0
    excrt FFFFFFF1
    psr   20000003
    hfsr  40000000
    cfsr  00000000
    mmfar E000ED34
    bfar  E000ED38
    shcsr 00000080
    s.r0  00000000
    s.r1  0000000A
    s.r2  20000A3C
    s.r3  00000000
    s.r12 20000B48
    s.lr  FFFFFFF9
    s.pc  00000240
    s.psr 0100020B

    Bit 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

    __asm__( "svc #0\n" );

    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