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.

MSPM0G3519: Arm-based microcontrollers forum

Part Number: MSPM0G3519

Tool/software:

Hi guys, I am working with mspm0g3519 controller. I have designed custom bootloader based taking reference from Customer secure Code.  I have one doubt. why is it recommended to use optimization level 2 or above when running customer secure code? why this code not work with optimization level 0?  even when I try to run example code (from SDK Boot image manager) that is customer secure code with its example application code. It will only work with -O2 and not working with -O0. 

  • Hi,

    Could you describe the behavior you are observing?

    -Matthew

  • Hi, 

    I have taken customer secure code and sample example from sdk. with optimization level 2 code works fine. means customer secure code perfect jump to sample code. but when i changed optimization level to 0 (-O0) that time customer secure code does not jump to application code. does optimization level affect jump logic code in customer secure code?  this is code snippet from customer secure code. 

    static void start_app(uint32_t *vector_table)
    {
        /* The following code resets the SP to the value specified in the
         * provided vector table, and then the Reset Handler is invoked.
         *
         * Per ARM Cortex specification:
         *
         *           ARM Cortex VTOR
         *
         *
         *   Offset             Vector
         *
         * 0x00000000  ++++++++++++++++++++++++++
         *             |    Initial SP value    |
         * 0x00000004  ++++++++++++++++++++++++++
         *             |         Reset          |
         * 0x00000008  ++++++++++++++++++++++++++
         *             |          NMI           |
         *             ++++++++++++++++++++++++++
         *             |           .            |
         *             |           .            |
         *             |           .            |
         *
         * */
    
        /* Reset the SP with the value stored at vector_table[0] */
        __asm volatile(
            "LDR R3,[%[vectab],#0x0] \n"
            "MOV SP, R3       \n" ::[vectab] "r"(vector_table));
    
        /* Set the Reset Vector to the new vector table (Will be reset to 0x000) */
        SCB->VTOR = (uint32_t) vector_table;
    
        /* Jump to the Reset Handler address at vector_table[1] */
    
        ((void (*)(void))(*(vector_table + 1)))();
    }
  • Have you seen such behavior? does CSC teste with optimization level below 2?

  • What else is happening with the setup? Could you explain if there is anything else running that could affect the behavior?

    Can you do a diff on the map to see what is different between O2 and O0?

  • code goes into hardfault. i have checked assembly file for both optimization. 

    Optimization level 2. (code work fine)
    0x00001810  4818      ldr     r0, [pc, #0x60]      ; Load immediate address (string/format) into r0
    0x00001812  211F      movs    r1, #0x1f            ; r1 = 0x1F
    0x00001814  02CD      lsls    r5, r1, #0xb         ; r5 = 0x1F << 11 (vector table address base)
    0x00001816  4629      mov     r1, r5               ; Move r5 → r1 (bit_printf arg)
    
    0x0000181C  682B      ldr     r3, [r5]             ; r3 = *(r5) (new stack pointer)
    0x0000181E  469D      mov     r13, r3              ; Set SP = *(r5)
    
    0x00001820  4815      ldr     r0, [pc, #0x54]      ; Load address (VTOR reg addr) into r0
    0x00001822  6005      str     r5, [r0]             ; Write new vector table base to VTOR
    0x00001824  CD06      ldm     r5!, {r1, r2}        ; Load r1=*(r5), r2=*(r5+4), then r5+=8
    0x00001826  4815      ldr     r0, [pc, #0x54]      ; Reload VTOR addr into r0
    0x00001828  3D08      subs    r5, #8               ; Restore r5 back (undo ldm increment)
    0x0000182E  4811      ldr     r0, [pc, #0x44]      ; Load another format string address
    0x00001830  4629      mov     r1, r5               ; r1 = r5
    
    0x00001836  6868      ldr     r0, [r5, #4]         ; r0 = *(r5+4) (reset handler address)
    0x00001838  4780      blx     r0                   ; Jump to application reset handler
    
    0x0000183A  4620      mov     r0, r4               ; r0 = r4 (not used, dead code)
    0x0000183C  F000FC8E  bl      DL_Common_delayCycles; Delay (dead code after jump)
    
    
    
    Optimization level 0 (not jump to aaplication code)
    0x00001AD8  B580      push    {r7, r14}            ; Save frame pointer and LR
    0x00001ADA  B082      sub     r13, #8              ; Allocate 8 bytes stack
    
    0x00001ADC  9001      str     r0, [r13, #4]        ; Save argument (app base addr) to stack
    0x00001ADE  E7FF      b       #0x1ae0              ; Jump to next instruction (compiler artifact)
    0x00001AE0  9901      ldr     r1, [r13, #4]        ; r1 = saved arg
    0x00001AE2  480E      ldr     r0, [pc, #0x38]      ; Load format string addr
    0x00001AE8  E7FF      b       #0x1aea              ; Compiler artifact
    0x00001AEA  9801      ldr     r0, [r13, #4]        ; r0 = app base addr
    0x00001AEC  6803      ldr     r3, [r0]             ; r3 = *(app base) (stack pointer value)
    0x00001AEE  469D      mov     r13, r3              ; Set SP = *(app base)
    0x00001AF0  9801      ldr     r0, [r13, #4]        ; r0 = *(app base+4) (reset handler)
    0x00001AF2  490B      ldr     r1, [pc, #0x2c]      ; r1 = VTOR address
    0x00001AF4  6008      str     r0, [r1]             ; Write new vector table base
    0x00001AF6  E7FF      b       #0x1af8              ; Compiler artifact
    0x00001AF8  9801      ldr     r0, [r13, #4]        ; r0 = app base
    0x00001AFA  6801      ldr     r1, [r0]             ; r1 = *(app base) (stack pointer value)
    0x00001AFC  6842      ldr     r2, [r0, #4]         ; r2 = *(app base+4) (reset handler addr)
    0x00001AFE  4809      ldr     r0, [pc, #0x24]      ; Load format string addr
    0x00001B04  E7FF      b       #0x1b06              ; Compiler artifact
    0x00001B06  E7FF      b       #0x1b08              ; Compiler artifact
    0x00001B08  9901      ldr     r1, [r13, #4]        ; r1 = app base addr
    0x00001B0A  4804      ldr     r0, [pc, #0x10]      ; Load format string addr
    0x00001B10  E7FF      b       #0x1b12              ; Compiler artifact
    0x00001B12  9801      ldr     r0, [r13, #4]        ; r0 = app base addr
    0x00001B14  6840      ldr     r0, [r0, #4]         ; r0 = *(app base+4) (reset handler addr)
    
    0x00001B16  4780      blx     r0                   ; Jump to application reset handler
    0x00001B18  B002      add     r13, #8              ; restore stack after jump
    0x00001B1A  BD80      pop     {r7, pc}             ; Restore registers and return

  • If it is possible, try at your end. with available example code to get better exposure. is this actual issue with those example codes or am i missing something? 

  • It really does look like the C code is loading SP much too early; with -O0 it subsequently references a (dangling) stack variable but with -O2 it doesn't. (Even with -O2 I would say it "works by accident".)

    I'm not sure this is a compiler bug per se, since it has no way of knowing about SP (is there a "clobber" option in __asm()?).

    I haven't found this code in boot_manager/customer_secure_code. Can you give us a hint where it is?

    [Edit: Ah, I found it in customer_secure_code.c.]

  • Thanks, it's in customer_secure_code.c.

    I think you've identified the problem, but I don't know what TI's plan is.

    Is the "-O2" workaround OK for your purposes?

    Alternatively: One fairly simple change might be to copy the vector_table variable to a local "static" (.bss rather than stack) variable, and use that in the rest of the function.  The .bss won't move around so much.

    [Edit: For good measure, declare the new variable "volatile" so the optimizer doesn't get any "improper" ideas.]

  • We are working internally to see what could be happening here

  • Personally, I would do the load-SP and the call in a single __asm() statement, but I'm not in a position to actually try it. My suggestion seemed more likely to work the first time.

  • Hi,

    You're right -- This hard fault occurs because the start_app function is attempting to access a value on the stack after the stack pointer has been moved in -O0.

    We recommend using -O2 or higher for this example. -O0 can work if the entire function is written is assembly, but we kept it more readable by writing in C.

    It is possible to declare the vector table volatile static, but that would cost memory, and cycles.

    -Matthew

  • hi Bruce, i have tried to load sp and then call but board rebooting again and againe into bootloader code whic i placed into flash start(0x00000000) , it seems like code jump to bootloader again . 

        __asm volatile(
             "LDR R3, [%[vectab], #0x0] \n" // Load initial SP value
             "MSR MSP, R3                \n" // Set MSP to initial SP value
             "LDR R3, [%[vectab], #0x4] \n" // Load Reset_Handler address
             "BX R3                      \n" // Branch to Reset_Handler
             :: [vectab] "r" (vector_table)
         );
  • I want code to run with O0 level for my purpose. can you more idea why this code malfunctioned with -O0 level?

  • Did you remove the other __asm i.e. the one that sets SP? That's where things start to go wrong.

    Specifically: In the -O0 case, Line 37 of your assembly listing sets SP to the application's stack, but then line 38 (and then line 42) go back to fetch the value of vector_table off the (old) stack, which is gone.

    For the -O2 case, line 8 sets the SP, but by then all the locals [OK, there's only one of them] are already in registers, so it doesn't need to go back to the stack copies [good thing since there aren't any]. The optimizer is not guaranteed to do this, but it usually does.

    In theory, you could move the __asm that sets SP to be the last thing before the call, but the call could still reference the stack (line 42). The trick I was suggesting was intended to prevent the generated code from referencing the stack by telling it to look elsewhere. It's a bit clunky but it's normal C. [I expect this code is executed about once/year, so 4 bytes and a few extra clocks won't matter.]

    That said, I don't see anything obvious in your __asm except

    (a) you're using R3 without declaring it as a (dummy) output argument -- it's possible the compiler allocated R3 for [vectab] and

    (b) I would have used "MOV SP,R3" rather than MSR but that's mostly so I wouldn't have to dig through the Cortex-M0 documents to remember whether I want MSP or PSP.

    [Edit: Minor clarification.]

  • Specifically, something like [untested]:

    static void start_app(uint32_t *vector_table)
    {
        static uint32_t * volatile bss_vector_ptr; // So it doesn't move
        bss_vector_ptr = vector_table;
        
        /* Set the Reset Vector to the new vector table (Will be reset to 0x000) */
        SCB->VTOR = (uint32_t) bss_vector_ptr;
    
        /* Reset the SP with the value stored at vector_table[0] */
        __asm volatile(
            "LDR R3,[%[vectab],#0x0] \n"
            "MOV SP, R3       \n" ::[vectab] "r"(bss_vector_ptr));
    
        /* Jump to the Reset Handler address at vector_table[1] */
    
        ((void (*)(void))(*(bss_vector_ptr + 1)))();
    }

    [Edit: Fixed goof]

    [Edit: Tested]

  • Alternatively:

    void
    start_app(uint32_t *vector_table)
    {
        SCB->VTOR = (uint32_t) vector_table;
        __asm volatile(
           "MOV SP,%[newSP]  \n"
           "BLX %[newPC]     \n"
                :
                :[newSP] "r" (vector_table[0]), [newPC] "r" (vector_table[1])
                :
           );
        return;
    }