5

When jumping from a bootloader to the application we usually update the stack pointer to the application stack pointer and then update the program counter to Reset_Handler of application.

void jump_to_application(void)
{
    /* Function pointer to the address of the user application. */
    fnc_ptr_for_app jump_to_app;
    jump_to_app = (fnc_ptr_for_app)(*(volatile uint32_t*) (FLASH_APP_START_ADDRESS+4u));
    __CRC_CLK_DISABLE();
    HAL_DeInit();

    /* Change the main stack pointer. */
    __set_MSP(*(volatile uint32_t*)FLASH_APP_START_ADDRESS);

    jump_to_app();
}

Reset_Handler's first line of code is below, which initializes the stack pointer to its own stack pointer value

Reset_Handler:
ldr   sp, =_estack    /* Atollic update: set stack pointer */

/* Copy the data segment initializers from flash to SRAM */
movs    r1, #0
b   LoopCopyDataInit

But still it's recommended to update the stack pointer with application's one.

Why is it needed, what are the side effects if we jump without updating it

0xAB1E
  • 721
  • 10
  • 27
  • not all of the cortex-ms have the dual stack pointer implemented. the implementation is not what you think its kind of a PITA. And, no, you dont need to do this. If you are a bootloader launching an application with no expectation of coming back the application can completely control the stack/processor so no need to do much of anything. If an RTOS and not a bootloader, okay then you do need to mess with the stack pointer for the application so that its stack doesnt affect the RTOS nor other applications. – old_timer Dec 23 '19 at 18:41
  • the side effect is the code may be easier to write/manage. – old_timer Dec 23 '19 at 18:42
  • fair enough if using the HAL or some other library then you need to conform to the rules of that library just like if under a bootloader or RTOS that expects to stay resident or get a return. – old_timer Dec 23 '19 at 18:43
  • and why are you using a bootloader on this device, not that you cant nor folks dont, but what is the bootloader doing for you with the in circuit programming options available. – old_timer Dec 23 '19 at 18:45
  • @old_timer bootloader is needed to do a FOTA (firmware over the air) update. Application will be writing the new fw into a temporary location and then reset itself, bootloader will then overwrite the actual application area with the new firmware. – 0xAB1E Dec 24 '19 at 03:37
  • fair enough, do you have a need to save/set the stack pointer before jumping, if not then you dont. – old_timer Dec 24 '19 at 05:52

1 Answers1

7

In ARM Cortex-M, the initial stack pointer is stored in the first 4 bytes of the vector table, and the initial program counter in the second 4 bytes. On reset, the hardware loads the SP and PC from these 8 bytes. This allows for example, Cortex-M start-up code to be written in C rather than assembler.

Your bootloader simulates this reset behaviour, by de-initialising the hardware to its reset state, and loading the SP and PC from the application's vector table. This allows the application to start as if it had started from reset without relying on any initialisation or set-up by the bootloader.

The bootloader is compiled and linked separately from the application and must be capable of loading any application code with the appropriate start address. As such the bootloader has no means of determining or enforcing that any a application code loaded will will set the stack pointer because it might reasonably assume that the hardware has set it already. Also in this case it is entirely possible that _estack != *(volatile uint32_t*)FLASH_APP_START_ADDRESS) in any case.

One observation on your bootloader is that it does not however set the vector table to that of the application, which is potentially dangerous - if the start-up code enables interrupts without first setting the vector table, it may cause a bootloader interrupt handler to be invoked erroneously. It would be safer to have:

// Switch vector table
SCB->VTOR = APPLICATION_START_ADDR ;

before jump_to_app(). Or if you choose to use the HAL:

NVIC_SetVectorTable( NVIC_VectTab_FLASH, APPLICATION_START_ADDR ) ;
Michael Petch
  • 46,082
  • 8
  • 107
  • 198
Clifford
  • 88,407
  • 13
  • 85
  • 165
  • Let me reiterate what i understand from this, if the application startup is doing the stack pointer update, then there is no need to set the stack pointer from the bootloader, but it's a good to have since it will not be assuming anything regarding the application. Please correct if my understanding is wrong. And thanks a lot for suggesting the vector table update, will go through the application startup and make sure it's handled in proper way. If application is enabling interrupt only after updating the reset vector, then is it a good to have in the bootloader or is it a must have. – 0xAB1E Dec 23 '19 at 17:00
  • @AbleEldhose : I would not put it like that - not incorrect, but wrong emphasis. The bootloader has no knowledge of what the application code might do, so has no real choice in the matter. To suggest "_no need to set the stack pointer from the bootloader_" is dangerous - rather the bootloader might work without that for _some_ applications that happen to set the SP. On Cortex-M it is quite likely that the application will not because of the normal reset behaviour. – Clifford Dec 23 '19 at 17:17