Skip to main content
Gordon Madden
Associate III
July 19, 2017
Solved

How to jump to another execution region defined by a scatter file?

  • July 19, 2017
  • 1 reply
  • 2743 views
Posted on July 19, 2017 at 17:58

I have successfully built a firmware upgrade app using C# and the bootloader in the STM32F4 To make it more robust, I am adding a scatter file based on CliveOne's recommendation:

I'd generally recommend having a boot loader at the base of memory (0x08000000, 16KB for the STM32 F2/F4), and then never erase that. Then place the app code above that, and have the boot loader validate the app code before jumping to it. This protects you if the power fails during an update, and makes things far more robust.

The 417 will startup at 0x08000000, calculate a checksum on the installed firmware, and then if it matches will continue on to a normal startup (unless an upgrade has been indicated, and then it will do that).

My question is: How to make the jump from the first executable region (0x08000000-0x08003FFF) where the checksum function is, to the normally-running app starting at 0x08004000?

Here is my code for getting into the bootloader:

; NORMAL UPGRADE STARTUP

LDR R0, =0x2001FFF0 ; Load address of WORD placed in SRAM from MAIN.C

LDR R1, =0xDEADBEEF ; Load same value stored above to a register

LDR R2, [R0, #0] ; Read the current value stored at 0x2001FFF0

STR R0, [R0, #0] ; Erase the value store in SRAM (next restart will

be normal) [stores address as value for R0]

CMP R2, R1 ; If values match (DEADBEEF), jump to bootloader,

otherwise continue startup

BEQ Reboot_Loader ; Jump to Reboot Loader below

; INTERRUPTED UPGRADE

LDR R0, =0x2001FFA0 ; Load address of WORD placed in SRAM from MAIN.C,

; indicates that the bootloader was previously active

; This word will be overwritten after the upgrade is completed.

LDR R1, =0xCAFEBABE ; Load same value stored at above address to a register

LDR R2, [R0, #0] ; Read what is stored at 0x2001FFA0

CMP R2, R1 ; If values match (CAFEBABE), jump to bootloader,

otherwise continue startup

BEQ Reboot_Loader ; Jump to Reboot Loader below

; Normal startup path

LDR R0, =SystemInit

BLX R0

LDR R0, =__main

BX R0

ENDP

;...

; Vector into System Loader

; Sets up board for bootloader mode

Reboot_Loader PROC

EXPORT Reboot_Loader

LDR R0, =0x40023844 ; RCC_APB2ENR

LDR R1, =0x00004000 ; ENABLE SYSCFG CLOCK

STR R1, [R0, #0]

LDR R0, =0x40013800 ; SYSCFG_MEMRMP

LDR R1, =0x00000001 ; MAP ROM AT ZERO

STR R1, [R0, #0]

LDR R0, =0x1FFF0000 ; ROM BASE

LDR SP,[R0, #0] ; SP @ +0

LDR R0,[R0, #4] ; PC @ +4

BX R0

ENDP

SystemReset PROC

EXPORT SystemReset

ldr r1, =0xE000ED0C ; NVIC Application Interrupt and Controller

ldr r0, =0x05FA0004 ; Magic

str r0, [r1, #0] ; Reset

b .

ENDP

Do I have to do another system reset or is there a way to jump into the firmware on completion of the checksum. When doing an upgrade, I use the GO command to leave the bootloader and start executing code.

Thank you!

#armlink #linker #execution-region #jump-memory #robust #firmware-upgrade #scatter-file

Note: this post was migrated and contained many threaded conversations, some content may be missing.
    This topic has been closed for replies.
    Best answer by Tesla DeLorean
    Posted on July 19, 2017 at 18:54

    If you build the app with it's vector table based at 0x08004000, code like this will suffice

    JumpApp     PROC

                    EXPORT  JumpApp

                    LDR     R0, =0x08004000 ; APP BASE

                    LDR     SP,[R0, #0]     ; SP @ +0

                    LDR     R0,[R0, #4]     ; PC @ +4

                    BX      R0

                    ENDP

    Look at some of the IAP examples. In C you can use function pointers, think qsort()

    Make sure code in app's SystemInit() sets the vector table, via SCB->VTOR = 0x08004000

    1 reply

    Tesla DeLorean
    Tesla DeLoreanBest answer
    Guru
    July 19, 2017
    Posted on July 19, 2017 at 18:54

    If you build the app with it's vector table based at 0x08004000, code like this will suffice

    JumpApp     PROC

                    EXPORT  JumpApp

                    LDR     R0, =0x08004000 ; APP BASE

                    LDR     SP,[R0, #0]     ; SP @ +0

                    LDR     R0,[R0, #4]     ; PC @ +4

                    BX      R0

                    ENDP

    Look at some of the IAP examples. In C you can use function pointers, think qsort()

    Make sure code in app's SystemInit() sets the vector table, via SCB->VTOR = 0x08004000

    Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
    Gordon Madden
    Associate III
    July 20, 2017
    Posted on July 20, 2017 at 22:09

    Thanks, Clive!

    Now I essentially have two programs, the first of which I will not be upgrading. If the first program is running a checksum on the second (firmware), how can I get access to the checksum value? During testing, I have been putting the checksum value into the first program, but I will not be able to do that when running upgrades. When the firmware is upgraded, I will be able to include a value for the checksum for the new firmware, but how can I get the first program to have access to that constant?

    I tried to extern it, but they are two separate programs, not just separate .c files. I can't extern the checksum and then not define it.

    Is there a way to store the value somewhere (register or memory) so that the first program can pick it up to do the comparison?

    Thanks!

    Tesla DeLorean
    Guru
    July 21, 2017
    Posted on July 21, 2017 at 00:08

    I'd sign the image. You could use one of the empty vectors to encode the size and then append a checksum or crc on the end. Here I'd take the output from the linker, in either .HEX, .BIN or .ELF, process the image and sign it. The loader pulls the size, and for a crc it should divide through itself resulting in a remainder of zero.

    Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..