This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

SWI exception handling

Other Parts Discussed in Thread: SYSBIOS

I was porting the I2C_eeprom_armL137 QuickStart example to a SYS/BIOS project (6.41.0.26).  In init_OMAPL137 there's  a _call_swi(ARM_PRIV_MODE_KEY); function call. This causes the SWI exception as expected, then while it's processing the exception, an illegal instruction exception is taken on this instruction:         mrc     p15, #0, r12, c6, c0, #2 ; read IFAR into r12 in the assembler function ti_sysbios_family_arm_exc_Exception_excHandlerAsm__I.  From there the CPU is in an infinite loop, as the         mrc     p15, #0, r12, c6, c0, #2 ; read IFAR into r12 instruction is also a part of the illegal instruction handling.  What gives?!?!  This just can't be right.... Is there some initialization I must be missing???

Thanks.

Steve

  • Steve,

    Do you know what that _call_swi() does?  My guess is its probably related to this.

    But aside from that, I think you might want to plug your own SWI exception handler and override the default BIOS one.
    I don't think the default BIOS one is going to do the right thing for you.

    Judah

  • Do you know what that _call_swi() does?  My guess is its probably related to this.


    It's TI-provided code, so you should be telling me what it does... But here's the full context:

        // Intrinsic Function; Gain 'supervisor' privileges
        _call_swi(ARM_PRIV_MODE_KEY);

    But aside from that, I think you might want to plug your own SWI exception handler and override the default BIOS one.
    I don't think the default BIOS one is going to do the right thing for you.

    How to do that?

    But I really don't think that's going to help as this is general-purpose exception handling code from TI and I'm getting an illegal instruction exception while executing it. Any help on that???

    Steve

     

  • This is a known exception handler issue in the version of BIOS you're using.

    If you upgrade to BIOS 6.42.01.20 or newer that problem has been fixed.

    You will still need to plug in your own SWI handler so you don't end up in BIOS' exception handler when you invoke a SWI.

    This can be done by configuring Hwi.swiFunc to point to your SWI handler:

     var Hwi = xdc.useModule('ti.sysbios.family.arm.da830.Hwi');

     Hwi.swiFunc = "&mySwiFunc";

    Alan

  • If you upgrade to BIOS 6.42.01.20 or newer that problem has been fixed.

    Switching BIOS versions has exposed another problem I've had in the past.  When I single-step this:

        _call_swi(ARM_PRIV_MODE_KEY);

    I start trying to execute code at 0x8 instead of 0xffff0008. I've worked around this in my non-BIOS project by putting this at my entrypoint:

        ; Set VINITH to force interrupt vectors to be at ffff0000
        MRC        p15, #0, R0, c1, c0, #0        ; read CP15 register1
        ORR        R0, R0, #0x2000                ; turn on the Vbit (VINITHIGH)
        MCR        p15, #0, R0, c1, c0, #0        ; write back the CP15 register1

    What's the entrypoint I should use for SYS/BIOS?   File and assembly function?

  • The best I found was

    ti_sysbios_family_arm_exc_Exception_initCore0__I

    in

    C:\ti\bios_6_45_01_29\packages\ti\sysbios\family\arm\exc\Exception_asm.asm

    but there's gotta be a better spot... Looking for c_int00, but can't find it.

  • I followed the above and my SWI function is getting called OK. The function that's calling _call_swi() is not returning, however. It just loops at the end forever. I took that attached screenshot to capture... the register R14 looks OK *before* the _call_swi(), but not after. Any suggestion?5340.Document.rtf

  • I moved the magic three instructions to the very beginning of main() and thus avoid having to change OS code:

        // ; Set VINITH to force interrupt vectors to be at ffff0000
        asm(" MRC        p15, #0, R0, c1, c0, #0        ;"); // read CP15 register1
        asm(" ORR        R0, R0, #0x2000                ;"); // turn on the Vbit (VINITHIGH)
        asm(" MCR        p15, #0, R0, c1, c0, #0        ;"); // write back the CP15 register1

    And it still works...


    So... I'm left with two questions on this thread:

    1. WHY do I need to do the above? I'm running on an OMAPL137EVM and nowhere do I purposely set VINITH=0...
    2. Why does the function calling _call_swi not return?

  • Is the R13_SVC stack pointer pointing to a valid memory buffer? This is the stack pointer used while executing the SWI handler. BIOS does not initialize this register.

    What does the return code in the SWI handler look like? Below are the recommendations from ARM:

    Returning from SWI and Undefined Instruction handlers

    The SWI and Undefined Instruction exceptions are generated by the instruction itself, so the PC is not updated when the exception is taken. The processor stores (PC–4) in lr_ mode. This makes lr_mode point to the next instruction to be executed. Restoring the PC from the link register with:

        MOVS        pc, lr
    

    returns control from the handler.

    The handler entry and exit code to stack the return address and pop it on return is:

        STMFD        sp!,{reglist,lr}
        ;...
        LDMFD        sp!,{reglist,pc}^
    

    For exceptions that occur in Thumb state, the handler return instruction (MOVS pc,lr) changes the PC to the address of the next instruction to execute. This is at (PC–2), so the value stored by the processor in lr_mode is (PC–2).

    Alan

  • Is the R13_SVC stack pointer pointing to a valid memory buffer?

    No - I'm linked to c300..., so all RAM location should start with c3.

    What does the return code in the SWI handler look like?

    The SWI handler is void. What do you mean???

  • You can't plug a normal 'C' function in as your SWI handler. Some assembly code wrapper must be invoked that pushes the scratch registers first, then calls your C code, then pops the scratch registers and then returns-with-state-change.

    The ARM recommendation should be used:

    STMFD sp!,{reglist,lr}
    call your C code here.
    LDMFD sp!,{reglist,pc}^

    But first, you must initialize the SVC_R13 register so that the above STM and LDM instructions are pushing and popping from valid memory.

    Alan
  • You can't plug a normal 'C' function in as your SWI handler.

    This made me think I could:

    This can be done by configuring Hwi.swiFunc to point to your SWI handler:

     var Hwi = xdc.useModule('ti.sysbios.family.arm.da830.Hwi');

     Hwi.swiFunc = "&mySwiFunc";

    Can you point me to some example that does what you suggest?

    Thanks.

    Steve

  • Developing a SWI handler may take a little studying on your part. Other than allowing the user to plug the SWI vector with their custom SWI handler, no other support is given for this in BIOS.

    I googled "example ARM SWI handler". This came up:

    SWI_Handler
    STMFD sp!,{r0-r12,lr} ; Store registers.
    LDR r0,[lr,#-4] ; Calculate address of
    ; SWI instruction and
    ; load it into r0.
    BIC r0,r0,#0xff000000 ; Mask off top 8 bits of
    ; instruction to give SWI number.
    ;
    ; Use value in r0 to determine which SWI routine to execute.
    ;
    BL C_SWI_Handler ; Call C routine to handle the SWI

    LDMFD sp!, {r0-r12,pc}^ ; Restore registers and return.

    void C_SWI_handler (unsigned number)
    {
    switch (number) {
    case 0 : /* SWI number 0 code */
    break;
    case 1 : /* SWI number 1 code */
    break;
    case x:
    break;
    default : /* Unknown SWI - report error */
    }
    }

    Alan
  • I did some Googling, too, and my takeaway was to declare my interrupt handler "interrupt" and the compiler would take care of it from there... Almost, but the handler returns to the SWI instruction, not the instruction after it.  So... this just keeps getting invoked repeatedly:

     _call_swi(ARM_PRIV_MODE_KEY);


    Seems the adjustment by 4 at the end of my handler isn't really needed in this case:

    c300a3e8:   E25EF004 SUBS          PC, R14, #0x4

    I'd like to keep this in 'C' if at all possible.  Any suggestions?

  • Also... any feedback on this earlier question?

    1. WHY do I need to do the above? I'm running on an OMAPL137EVM and nowhere do I purposely set VINITH=0...

    Thanks.

    Steve

  • The TI Compiler manual (section 5.10.15) suggests that adding:

    #pragma INTERRUPT mySwiFunc, SWI

    just ahead of the definition of mySwiFunc() will cause the SWI-specific wrapper to be generated around your C function.

    I don't think you should have to manually set VINITH. BIOS also assumes that the vector table is up at 0xffff0000. Do you have a GEL file that might be setting this register prior to loading your application?

    Alan
  • The TI Compiler manual (section 5.10.15) suggests that adding:

    #pragma INTERRUPT mySwiFunc, SWI

    just ahead of the definition of mySwiFunc() will cause the SWI-specific wrapper to be generated around your C function.


    That's it!

    I don't think you should have to manually set VINITH. BIOS also assumes that the vector table is up at 0xffff0000. Do you have a GEL file that might be setting this register prior to loading your application?

    Not on purpose - I'm using the GEL files from Spectrum Digital w/small mods for RAM timing. Looked through and ... nothing. Is it even possible to mod that bit from a GEL file?  Other ideas?

    Steve

  • I found a reference to a "vinithi pin" here:

    groups.google.com/.../

    Is there a jumper on your board to pull this pin high?

    Alan
  • Is there a jumper on your board to pull this pin high?


    Nope - I'm using the OMAPL137 EVM from Spectrum Digital...

  • Is there a jumper on your board to pull this pin high?


    Nope - I'm using the OMAPL137 EVM from Spectrum Digital...

    Any other suggestions???

  • I moved this to the device forum. They know the hardware on the boards better.

    Todd