Jump to FreeRTOS program from Bootloader

Hello everyone!

I have a big issue with my project.

I have a Bootloader program, that is located in the 0x00 position on my board. I’m using the TMB507LS3137 kit. When I tested my Bootloader program recording different programs at 0x20020 location (without RTOS), it worked fine.

When I tried to record a FreeRTOS program in the 0x20020 location, nothing happened. It didn’t work, it stuck when it tried to create a task.

The issue is when the FreeRTOS program enters the following line:

#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
QueueHandle_t MPU_xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType )
{
QueueHandle_t xReturn;
BaseType_t xRunningPrivileged = prvRaisePrivilege();
xReturn = xQueueGenericCreate( uxQueueLength, uxItemSize, ucQueueType );
portRESET_PRIVILEGE( xRunningPrivileged );
return xReturn;
}
#endif

I think that it doesn’t find the prvRaisePrivilege(); function (it’s defined as an extern BaseType_t prvRaisePrivilege( void ); ) (In fact, I cannot find this function). But if I try to run the FreeRTOS program only at location 0x000, the program works well.

It looks like the program jumps to another location at the beginning of the program, to find this function.

How can I solve this issue? Maybe I need an extra change to can run the FreeRTOS program in another memory location? I double-checked my Bootloader and my FreeRTOS program and I didn’t find any issue. I contacted Texas support, and they suggested that it might be a FreeRTOS issue when the program tries to jump to another memory location.

Thanks in advance.

Fede

Assuming your question is about TMS570. Are you using the FreeRTOS portable files from portable/CCS/ARM_Cortex-R4? Seems not if your portable files support the MPU. Are you using code generated by HALCoGen? (If you search the forum for HALCoGen and TMS570 there are a few helpful threads.)

Did you ensure that your compiler generates reloctable code, or will the linker assume offsets always from 0?

Hello jefftenneym, thank you for your help. Yes, I generated the code with HalCoGen. I asked in TMS forums, but they cannot solve this issue yet. I searched about related issues, but I don’t find anything with Bootloader + FreeRTOS in another memory location. They suggested that maybe in FreeRTOS forum I will be able to find the solution for this.

I only changed the sys_link.cmd for my FreeRTOS code to work at the 0x20020 location. If I reverted the changes, the code works (but at the beginning of the memory location).

  • With these lines the code works at the beginning of the memory location:

    VECTORS (X) : origin=0x00000000 length=0x00000020
    KERNEL (RX) : origin=0x00000020 length=0x00008000
    FLASH0 (RX) : origin=0x00008020 length=0x00177FE0
    FLASH1 (RX) : origin=0x00180000 length=0x00180000
    STACKS (RW) : origin=0x08000000 length=0x00000800
    KRAM (RW) : origin=0x08000800 length=0x00000800
    RAM (RW) : origin=(0x08000800+0x00000800) length=(0x0003F800 - 0x00000800)

  • With these lines, FreeRTOS will record from location 0x00020020, but it gets stuck when the code tries to create the tasks.

    VECTORS (X) : origin=0x00020020 length=0x00000020
    FLASH_CODE (RX) : origin=0x00020040 length=0x008000-0x40 fill=0xFFFFFFFF
    FLASH0 (RX) : origin=0x00028000 length=0x0014FFC0
    FLASH1 (RX) : origin=0x00180000 length=0x00180000
    STACKS (RW) : origin=0x08000000 length=0x00000800
    KRAM (RW) : origin=0x08000800 length=0x00000800
    RAM (RW) : origin=(0x08000800+0x00000800) length=(0x0003F800 - 0x00000800)

Is there I can do to fix it? Should I change anything else in the FreeRTOS code to make it work in another memory location?

Thank you !!

Hello RAc! Thank you for your reply.

Yes I’m sure about it. I checked the memory browser, and the FreeRTOS code is recorded at the 0x20020 location. I cannot attach a photo or video (sorry for that), but I checked it.

The jump is done well (if I do a while(1) with a Led turn ON/OFF, I notice that the jump works) But the problem is when the program tries to create the tasks. It doesn’t seem to find the instruction.

BaseType_t xRunningPrivileged = prvRaisePrivilege();

Thanks for your help.

This is probably the issue. On CR4 the vectors are at 0x00000000 (or optionally at 0xFFFF0000). For the system to work with application vectors at 0x00020020, you will need your bootloader’s handlers to “re-vector” to the application’s handlers.

I don’t have your port code in front of me (because it is not provided by FreeRTOS), but I assume that the prvRaisePrivilege() function uses the SVC instruction to generate a software interrupt, which in turn requires your application vectors to be working properly.

Thanks very much for your help.

Yes, I changed the vector table on my Bootloader to:

.sect ".intvecs"
.arm

;-------------------------------------------------------------------------------
; import reference for interrupt routines

.ref _c_int00
.ref _dabort
.ref phantomInterrupt
.def resetEntry

;-------------------------------------------------------------------------------
; interrupt vectors

resetEntry
b _c_int00
undefEntry
b #0x20020 ;undefEntry
svcEntry
b #0x20020 ;svcEntry
prefetchEntry
b #0x20020 ;prefetchEntry
b _dabort
b #0x20020 ;phantomInterrupt
ldr pc,[pc,#-0x1b0]
ldr pc,[pc,#-0x1b0]

I cannot change the _dabort, because if not the program doesn’t compile.

In my Application (with RTOS) I have the following code lines:

.sect ".intvecs"
.arm

;-------------------------------------------------------------------------------
; import reference for interrupt routines

.ref _c_int00
.ref vPortSWI
.ref _dabort
.ref phantomInterrupt
.def resetEntry

;-------------------------------------------------------------------------------
; interrupt vectors

resetEntry
b _c_int00
undefEntry
b undefEntry
b vPortSWI
prefetchEntry
b prefetchEntry
b _dabort
b phantomInterrupt
ldr pc,[pc,#-0x1b0]
ldr pc,[pc,#-0x1b0]

Is there a way to solve it?

Let me know if you need anything more.

Thank you very much.

Looks like you have the right idea to use your bootloader’s vector table to pass control to the application’s vector table. I’ve made some corrections in the addresses below:

This would be for the bootloader vector table:

;-------------------------------------------------------------------------------
; interrupt vectors

resetEntry:
    b    _c_int00        ; Reset
    b    #0x20024        ; Undefined instruction
    b    #0x20028        ; Software interrupt (SWI / SVC)
    b    #0x2002C        ; Abort (prefetch)
    b    _dabort         ; Abort (data)
    b    #0x20034        ; phantomInterrupt
    ldr  pc,[pc,#-0x1b0] ; IRQ
    ldr  pc,[pc,#-0x1b0] ; FIRQ

Your application vector table seems to be correct already (barring some formatting issues probably caused by the forum software).

Hello jefftenney,

I think that we are near to fix the issue !

I changed the Bootloader vector table, and now I have another bug. When the code tried to create the tasks, jump to location 0x04 (said Break at address “0x4” with no debug information available, or out of the program code.), and then enter the _dabort (from the RTOS Application vector table), and end up jumping to location 0x20048090 (strange, I checked and it’s the final address of the Application).

But well, I think that the issue is related to the vector tables.

I copied my Assembly code (You can see that in the 0x4 location, there is information, It’s the Bootloader program).

00000000: EA001F03 b #0x7c14
00000004: EA008009 b #0x20030
00000008: EA00800A b #0x20038
0000000c: EA00800B b xTaskCreateRestricted
00000010: EA002171 b #0x85dc
00000014: EA00800D b #0x20050
00000018: E51FF1B0 ldr pc, [pc, #-0x1b0]
0000001c: E51FF1B0 ldr pc, [pc, #-0x1b0]
00000020: E24DD008 sub r13, r13, #8
00000024: E58D0000 str r0, [r13]
00000028: E28DD008 add r13, r13, #8
0000002c: E12FFF1E bx lr
00000030: E92D4008 push {r3, r14}
00000034: E59F0FBC ldr r0, [pc, #0xfbc]
00000038: E3A0C006 mov r12, #6
0000003c: E580C000 str r12, [r0]
00000040: E59FCFB4 ldr r12, [pc, #0xfb4]
00000044: E59CC000 ldr r12, [r12]
00000048: E31C0C01 tst r12, #0x100
0000004c: 0AFFFFFB beq #0x40
00000050: E59FCFA4 ldr r12, [pc, #0xfa4]
00000054: E59CC000 ldr r12, [r12]
00000058: E31C0001 tst r12, #1
0000005c: 0A000002 beq #0x6c
00000060: E3A00001 mov r0, #1
00000064: EBFFFFED bl #0x20
00000068: EA000040 b #0x170
0000006c: E59FCF8C ldr r12, [pc, #0xf8c]
00000070: E59CC000 ldr r12, [r12]
00000074: E31C0102 tst r12, #0x80000000
00000078: 0A000002 beq #0x88
0000007c: E3A00002 mov r0, #2
00000080: EBFFFFE6 bl #0x20
00000084: EA000039 b #0x170
00000088: E59F0F68 ldr r0, [pc, #0xf68]
0000008c: E3A0C009 mov r12, #9
00000090: E580C000 str r12, [r0]
00000094: E59FCF5C ldr r12, [pc, #0xf5c]
00000098: E59CC000 ldr r12, [r12]
0000009c: E35C0000 cmp r12, #0
000000a0: 0A000003 beq #0xb4

Let me know if you need anything else. Thank you very much for your help. I have been dealing with this issue for some time.

I was going through the implementation of my FreeRTOS program alone (I recorded it at location 0x00), and then I did a step-by-step to find where the code goes when it tries to create the tasks.

And when it tries to create the tasks, the code goes to: b vPortSWI

This line is in sys_intvecs.asm in my application code. And this line is not in my Bootloader program.
On my App I have:

; interrupt vectors

resetEntry
        b   _c_int00
undefEntry
        b   undefEntry
        **b   vPortSWI**
prefetchEntry
        b   prefetchEntry
        b   _dabort
        b   phantomInterrupt
        ldr pc,[pc,#-0x1b0]
        ldr pc,[pc,#-0x1b0]

And on my Bootloader I have:

; interrupt vectors

resetEntry
        b   _c_int00
undefEntry
        b   #0x20024 ;undefEntry
svcEntry
        b   #0x20028 ;svcEntry
prefetchEntry
        b   #0x2002C ;prefetchEntry
        b   _dabort
        b   #0x20034 ;phantomInterrupt
        ldr pc,[pc,#-0x1b0]
        ldr pc,[pc,#-0x1b0]

How could I change my Bootloader vector, to create the vPortSWI? Thank you very much !

(Small hint: enclose code blocks by 3 tildes ‘~’ or backticks ‘`’ and use the ‘</> Preformatted text’ button for intra line text for better formatting.)

1 Like

Another correction for you – the branch #immediate syntax apparently expects the offset, not the target address, even though the disassembly you posted shows the #immediate syntax as a target address. Can you try this in your bootloader:

;-------------------------------------------------------------------------------
; interrupt vectors

resetEntry:
    b    _c_int00        ; Reset
    b    #0x20018        ; Undefined instruction
    b    #0x20018        ; Software interrupt (SWI / SVC)
    b    #0x20018        ; Abort (prefetch)
    b    _dabort         ; Abort (data)
    b    #0x20018        ; phantomInterrupt
    ldr  pc,[pc,#-0x1b0] ; IRQ
    ldr  pc,[pc,#-0x1b0] ; FIRQ

The theory being the offset is always 0x20020 to the same position in the application vector table. And the PC always has instr+8 to begin with.

3 Likes

Hello Jeff,

Thank you very much !!! I tried your suggestions, and now IT’S WORKING !!

Now I can jump from the Bootloader to the Application program.

I have been dealing with this issue for a long time, so thank you very much for your help.

I am very grateful for this with you :smiley:

3 Likes

So glad you could finally get past this issue. Bootloaders can make things tricky.

1 Like

Hello jefftenney!!

Sorry for my delay haha but I had another doubt about this topic.

Is it possible that my board has 2 programmes with FreeRTOS in different locations? I mean, as it is now, I would like to add another program with FreeRTOS in the x10020 position, for example. Would that be possible?

Thanks in advance!

Fede.

Without having read all messages in this post, I would say: of course you can include two programs with FreeRTOS. As long as:

  • The CPU has enough flash
  • The CPU either runs program-1 or program-2

The network-aware bootloaders that I made are also FreeRTOS applications. They download an image and when all is correct, they will reboot and execute the application.

There might be one problem: the interrupt tables. Some platforms have 2 predefined flash locations where a jump table is expected. Other platforms are more flexible.

Would you be able to put all the functionality you need into one application? Then, when your application starts, it could decide which functionality to provide, and then start only those tasks. That solution is probably better than having two completely separate applications.

For two completely separate applications, you would need to add a SVC handler to your bootloader. That SVC handler would be written as a naked C function (or written in assembly) and would transfer control to the “active” application’s SVC handler. This is a fairly advanced technique. You would also need to let your bootloader handle the other three special interrupts (undefined instruction, prefetch abort, and phantom interrupt).

Hey @FedeUnsam,
So I noticed a few things while reading through your post. With your issue of prvRaisePrivilege taking you to 0x0, I don’t think this is related to your interrupt vector problem? I’m fairly certain that this function is an extern that is used in the os_mpu_wrappers.c file that HALCoGen generates, but I don’t believe it is correctly implemented in the port, if at all, which would be why you can’t seem to find it. I believe that the port that HALCoGen generates should have an SVC that raises the privilege level of the caller? If not I believe the code to do so would look like this:

    <BRANCH FROM SVC HANDLER>
    /* Move CPSR into R12 */
    MRS     R12, SPSR
    /* USER_MODE is 0x10, so clear other bits. Now R0 will only
     * be 0 if the caller to this function was in user mode
    */
    ANDS    R0, R12, #0x0F
    /* Set the MODE bits to SYS_MODE */
    ORREQ   R12, R12, #SYS_MODE
    /* Assign the new value to SPSR */
    MSREQ   SPSR_cxsf, R12

Additionally I wouldn’t recommend the approach being taken with the re-direction of your interrupt vectors. These should instead just perform the jump to the necessary function. What you could do, if you need to account for SVCs inside of your bootloader, would be to create a landing point function that can determine if you were in an SVC from the FreeRTOS-Kernel or from your bootloader. This could then look something like:

;-------------------------------------------------------------------------------
; interrupt vectors

resetEntry
        b   _c_int00
undefEntry
        b   undefEntry
        b   SVC_Landing_point
prefetchEntry
        b   prefetchEntry
        b   _dabort
        b   phantomInterrupt
        ldr pc,[pc,#-0x1b0]
        ldr pc,[pc,#-0x1b0]

Paired with a handler that would look like this:

.def    SVC_Landing_point
.asmfunc
SVC_Landing_point
    ; Push R0 for scratch space
    PUSH    {R0}
    
    ; DETERMINE IF FREERTOS IS RUNNING YOU COULD DO THIS BY SETTING A VALUE WHEN LEAVING YOUR BOOTLOADER
    ; Load the address of the variable set by the bootloader when it "exits" to FreeRTOS
    LDR     R11, =leftBootLoader
    ; Load the actual value of it
    LDR     R11, [R11]
    ; Check if the application has left the bootloader
    TST     R11, 0x0
    ; Can restore the pushed R0 here - won't change the mode comparison bits
    POP     {R0}
    ; If the variable is zero perform the bootloader's SVC
    BNE     <FreeRTOS SVC Handler>      
    ; If the variable is zero then go to the bootloader's SVC
    BEQ     <Bootloader SVC Handler>

This would allow you to split up the work done between these handlers based upon if you are running FreeRTOS or still in your bootloader. If your bootloader doesn’t need to perform SVCs you could instead just directly map this jump to the Port’s SVC handler name.

Where I believe that if these are being compiled as two separate applications with two different linker scripts adding in an extern to the function name would cause it to be compiled to 0x0 if a definition isn’t provided? Where you COULD potentially load the function names and check if they are null to determine if you are in the bootloader or not as well? But even if that works I don’t know if I’d recommend that approach