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.

SVC/SWI assembly code but in HALCOGEN

Other Parts Discussed in Thread: HALCOGEN

I believe that the assembly code provided by HALCOGEN for FreeRTOS in os_portasm.{asm,s} is incorrect.  In particular, while some SVC vectors clobber r0, the entry/exit code in vPortSWI does not save r0.  Recall that r0 is not a banked register, and unlike ARMv7-M, it is not automatically stacked by the hardware on exception entry, either.

The TI compiler does not seem to be affected, since it does not seem to be saving anything in r0 (only v1) in the relevant code section.  However, the GCC toolchain does use r0.  When optimization is enabled, the HALCOGEN-provided port of FreeRTOS fails to run.

  • Hi Jonathan,

    I have forwarded your post to our Halcogen team so they can address your concerns.

  • Hi Jonathan,

    I think you are right, this is a bug.

    Some of the SWI handlers do make use of the R0 register, thus it has to be preserved.

    • The following function does preserve R0
      • swiPortYield (in macro portSAVE_CONTEXT)
    • The following functions do corrupt R0
      • swiRaisePrivilege
      • swiPortEnterCritical
      • swiPortExitCritical
      • swiPortTaskUsesFPU
      • swiPortDisableInterrupts
      • swiPortEnableInterrupts

    So the majority for the functions called from the SWI handler do corrupt R0.

    • The following two functions can be reworked to use R12 instead (R12 is already stacked in vPortSWI):
      • swiPortDisableInterrupts
      • swiPortEnableInterrupts
    • The following functions do need code to preserve R0:
      • swiPortTaskUsesFPU
      • swiRaisePrivilege
      • swiPortEnterCritical
      • swiPortExitCritical

    I filed a bug for this against HALCoGen version 04.04.00: SDOCM00117282

    Best Regards,
    Christian

  • Thank you for escalating this issue to your internal bug tracker.  What is the official notification mechanism for you to report to us when you have fixed this in an official release?

    In my code, I just saved all of the call-clobbered registers in accordance with the AAPCS.

  • Jonathan,

    As I'm not sure how to set up tickets in the bug tracker for external access you won't be able to see this.
    However, I will receive notifications on status changes and I will try to post this here.
    But for now it should be fine to save and restore R0-R3, R12 and LR as you wrote.

    Best Regards,
    Christian
  • Jonathan,

    I received the notification from the system that this bug was fixed, the fix will be in v4.05.00:

    Implemented Stream/Label REL_04_05_00_EA1
    Branch Fixed In master
    Resolution updated the API to backup and restore r0

    Best Regards,
    Christian

  • Looks like the bug isn't quite fixed.  Now you've got a mismatched push and pop in some circumstances.  I hit this issue when enabling OS timers and just running the Blinky sample code.  Here's the main:

    int main(void) {
    /* USER CODE BEGIN (3) */

    /* Set high end timer GIO port hetPort pin direction to all output */
    gioSetDirection(hetPORT1, 0xFFFFFFFF);

    /* Create Task 1 */
    if (xTaskCreate(vTask1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1,
    &xTask1Handle) != pdTRUE) {
    /* Task could not be created */
    while (1)
    ;
    }

    /* Start Scheduler */
    vTaskStartScheduler();    <<<<< CRASH IN THIS CALL HERE >>>>>>

    /* Run forever */
    while (1)
    ;
    /* USER CODE END */
    }

    Here's the problem I see when debugging through os_portasm.s:

    @ SWI Handler, interface to Protected Mode Functions
    
            .weak vPortSWI
            .type vPortSWI, %function
            
    vPortSWI:
            stmfd   sp!, {r12,lr}                      <---- 1. push r12, lr onto the stack 
            mrs     r12, spsr
            ands    r12, r12, #0x20
            ldrbne  r12, [lr, #-2]
            ldrbeq  r12, [lr, #-4]
            ldr     r14,  table
            ldr     r12, [r14, r12, lsl #2]            <---- 2. Jump to swiPortExitCritical
            blx     r12                                <---- 5. Return Here
            ldmfd   sp!, {r12,pc}^                     <---- 6. Pop from mismatched stack and throw invalid instruction
    
    table:
            .word   jumpTable
    
    jumpTable:
            .word   swiPortYield                 @ 0 - vPortYield
            .word   swiRaisePrivilege            @ 1 - Raise Priviledge
            .word   swiPortEnterCritical         @ 2 - vPortEnterCritical
            .word   swiPortExitCritical          @ 3 - vPortExitCritical
            .word   swiPortTaskUsesFPU           @ 4 - vPortTaskUsesFPU
            .word   swiPortDisableInterrupts     @ 5 - vPortDisableInterrupts
            .word   swiPortEnableInterrupts      @ 6 - vPortEnableInterrupts




    /*-------------------------------------------------------------------------------*/
    @ swiPortExitCritical
            
    swiPortExitCritical:
            stmfd   sp!, {r0}                            <---- 3. Enter here and push R0 onto the stack
            ldr     r0, ulCriticalNestingConst
            ldr     r12, [r0]
            cmp     r12, #0
            bxeq    r14
            subs    r12, r12, #1
            str     r12, [r0]
            bxne    r14                                  <---- 4. return here (without the pop)
            mrs     r0, SPSR
            bic     r0, r0, #0x80
            msr     SPSR_c, r0
            ldmfd   sp!, {r0}
            bx      r14
            
    /*-------------------------------------------------------------------------------*/
     
  • My temporary fix is to update swiPortExitCritical to the following code:

    /*-------------------------------------------------------------------------------*/
    @ swiPortExitCritical

    swiPortExitCritical:
    stmfd sp!, {r0}
    ldr r0, ulCriticalNestingConst
    ldr r12, [r0]
    cmp r12, #0
    ldmfdeq sp!, {r0}
    bxeq r14
    subs r12, r12, #1
    str r12, [r0]
    ldmfdne sp!, {r0}
    bxne r14
    mrs r0, SPSR
    bic r0, r0, #0x80
    msr SPSR_c, r0
    ldmfd sp!, {r0}
    bx r14

    /*-------------------------------------------------------------------------------*/
  • I agree, TI's fix for this is incomplete.  IMO, the far simpler way to address this is to save r0 at vPortSWI, rather than capture all of the cases where it needs to be popped off with the multiple return sequences in swiPortExitCritical.

  • They asked me to open another thread for this. In the other thread, they confirmed the bug and noted that the fix will be in the next HALCoGen release. I briefly scanned the rest of the file to see if more were missed. I didn't find any other cases in the few minutes I spent. But certainly saving and restoring r0 in vPortSWI would reduce the amount of code, increase confidence, and eliminate the other un-found instances of this.