Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Can't jump to a custom app location using nrf_bootloader_app_start with SDK V15

With SDK V14.2, I was able to specify internal flash address argument into nrf_bootloader_app_start(uint32_t start_addr) and was able to boot into the address. With SDK V15, the argument option is removed and the jump address is fixed to MBR_SIZE within the nrf_bootloader_app_start(void) function. I tried modifying the start address within nrf_bootloader_app_start but I was not able to boot into the custom app location.

  • i have the exact same question. Can someone from nordic answer on WHY the change was made?

    ------------------------------------------------------------------------------------------------------------------------------------------------

    Update: I copied the code from SDK14.1 and I am now able to jump to any RAM and flash address on nrf52840.

    void start_app(cb_uint32 startAddress)
    {
        nrf_dfu_mbr_init_sd();

        // Disable and clear interrupts
        NVIC->ICER[0] = 0xFFFFFFFF;
        NVIC->ICPR[0] = 0xFFFFFFFF;
        NVIC->ICER[1] = 0xFFFFFFFF;
        NVIC->ICPR[1] = 0xFFFFFFFF;
        sd_softdevice_vector_table_base_set(startAddress);
        nrf_bootloader_app_start_impl(startAddress);
    }

    void __attribute__((noinline)) nrf_bootloader_app_start_impl(uint32_t start_addr)
    {
        __ASM volatile(
            "ldr   r0, [%0]\t\n"            // Get App initial MSP for bootloader.
            "msr   msp, r0\t\n"             // Set the main stack pointer to the applications MSP.
            "ldr   r0, [%0, #0x04]\t\n"     // Load Reset handler into R0.

            "movs  r4, #0xFF\t\n"           // Move ones to R4.
            "sxtb  r4, r4\t\n"              // Sign extend R4 to obtain 0xFFFFFFFF instead of 0xFF.

            "mrs   r5, IPSR\t\n"            // Load IPSR to R5 to check for handler or thread mode.
            "cmp   r5, #0x00\t\n"           // Compare, if 0 then we are in thread mode and can continue to reset handler of bootloader.
            "bne   isr_abort\t\n"           // If not zero we need to exit current ISR and jump to reset handler of bootloader.

            "mrs   r1, control\t\n"         // Get CONTROL register value
            "movs  r2, #0x02\t\n"           // load 2 to r2
            "bic   r1, r2\t\n"              // clear value of CONTROL->SPSEL - > make sure MSP will be used
            "msr   control, r1\t\n"         // set the stack pointer to MSP

            "mov   lr, r4\t\n"              // Clear the link register and set to ones to ensure no return.
            "bx    r0\t\n"                  // Branch to reset handler of bootloader.

            "isr_abort:  \t\n"

            "mov   r5, r4\t\n"              // Fill with ones before jumping to reset handling. Will be popped as LR when exiting ISR. Ensures no return to application.
            "mov   r6, r0\t\n"              // Move address of reset handler to R6. Will be popped as PC when exiting ISR. Ensures the reset handler will be executed when exist ISR.
            "movs  r7, #0x21\t\n"           // Move MSB reset value of xPSR to R7. Will be popped as xPSR when exiting ISR. xPSR is 0x21000000 thus MSB is 0x21.
            "rev   r7, r7\t\n"              // Reverse byte order to put 0x21 as MSB.
            "push  {r4-r7}\t\n"             // Push everything to new stack to allow interrupt handler to fetch it on exiting the ISR.

            "movs  r4, #0x00\t\n"           // Fill with zeros before jumping to reset handling. We be popped as R0 when exiting ISR (Cleaning up of the registers).
            "movs  r5, #0x00\t\n"           // Fill with zeros before jumping to reset handling. We be popped as R1 when exiting ISR (Cleaning up of the registers).
            "movs  r6, #0x00\t\n"           // Fill with zeros before jumping to reset handling. We be popped as R2 when exiting ISR (Cleaning up of the registers).
            "movs  r7, #0x00\t\n"           // Fill with zeros before jumping to reset handling. We be popped as R3 when exiting ISR (Cleaning up of the registers).
            "push  {r4-r7}\t\n"             // Push zeros (R4-R7) to stack to prepare for exiting the interrupt routine.

            "movs  r0, #0xF9\t\n"           // Move the execution return command into register, 0xFFFFFFF9.
            "sxtb  r0, r0\t\n"              // Sign extend R0 to obtain 0xFFFFFFF9 instead of 0xF9.
            "bx    r0\t\n"                  // No return - Handler mode will be exited. Stack will be popped and execution will continue in reset handler initializing other application.
            ".align\t\n"
            :: "r" (start_addr)             // Argument list for the gcc assembly. start_addr is %0.
            : "r0", "r4", "r5", "r6", "r7" // List of register maintained manually.
            );
    }

  • Note that 's solution doesn't work if there is no SoftDevice present.

    The reason it was removed was that in SDK 15, we also support having no SoftDevice present, so this function would have needed to accomodate that new configuration. Removing the start address argument allowed us to not implement something we didn't need for our own examples.

    The DFU we provide only allows placing apps 1) at 0x1000 (after the 'MBR'), or 2) after the SoftDevice if there is a SoftDevice present. The start address in both cases can be 0x1000, so we hard-coded it.

    Implementing this functionality for the general case is surprisingly tedious and has tricky caveats, but if you know what you need for your specific case, it's quite doable.

    Below is an untested mockup. Use _with_sd if the app needs the SD, and likewise, use _without_sd if the app doesn't need the SD. This might not compile out of the box (because of dependencies), and might not run together with old MBRs. Note that I changed the app_start_impl call to use app_start_final from SDK 15 instead. It should do the same thing, and also give you the memory protection present in 15. Note also that using the _with_sd call in otherwise SD-independent bootloaders (i.e. UART or USB) makes them SD-dependent and brickable by an update that removes the SD. Add the BLE_STACK_SUPPORT_REQD define to prevent this.

    void start_app_with_sd(cb_uint32 startAddress)
    {
        nrf_dfu_mbr_init_sd();
    
        // Disable and clear interrupts
        NVIC->ICER[0] = 0xFFFFFFFF;
        NVIC->ICPR[0] = 0xFFFFFFFF;
        NVIC->ICER[1] = 0xFFFFFFFF;
        NVIC->ICPR[1] = 0xFFFFFFFF;
    
        sd_softdevice_vector_table_base_set(startAddress);
        nrf_dfu_mbr_irq_forward_address_set(MBR_SIZE);
        nrf_bootloader_app_start_final(startAddress);
    }
    
    void start_app_without_sd(cb_uint32 startAddress)
    {
        NVIC->ICER[0] = 0xFFFFFFFF;
        NVIC->ICPR[0] = 0xFFFFFFFF;
        NVIC->ICER[1] = 0xFFFFFFFF;
        NVIC->ICPR[1] = 0xFFFFFFFF;
    
        nrf_dfu_mbr_irq_forward_address_set(startAddress);
        nrf_bootloader_app_start_final(startAddress);
    }
    
    // nrf_dfu_mbr.c:
    // Replace this
    uint32_t nrf_dfu_mbr_irq_forward_address_set(void)
    {
        uint32_t ret_val = NRF_ERROR_INVALID_PARAM;
        uint32_t address = MBR_SIZE;
        ...
        
    // With this
    uint32_t nrf_dfu_mbr_irq_forward_address_set(uint32_t address)
    {
        uint32_t ret_val = NRF_ERROR_INVALID_PARAM;
        ...

  • Hello

    i have a question to the appstart.

    I have the application "secure bootloader ble s140" and there is the function "nrf_bootloader_app_start();" This should call my application, right?

    This application must be at which address?

    I have also the s140 flashed which is there from 0x00001000 - 0x00025E7C and the bl app from 0x000F8000 - 0x000FDA94.

    If i define the flash_start 0x00026000 which is behind the sd it could be called from the bl app, right and how ?

    I just quoted this because its confusing that it's said that anyway the app will start at 0x1000 but in my case after i flashed the sd with nrfgo studio this is at 0x1000 ?!

    The DFU we provide only allows placing apps 1) at 0x1000 (after the 'MBR'), or 2) after the SoftDevice if there is a SoftDevice present. The start address in both cases can be 0x1000, so we hard-coded it.

    Thanks in advance.

    twittich

  • The reason the start address is 0x1000 in both cases is that, when the SoftDevice is present, the BL will boot the SoftDevice instead of the app. The SoftDevice will in turn boot the app, if the app is located right after the SoftDevice (rounded up to the nearest flash page boundary). In all cases, the bootloader boots whatever is located at 0x1000.

    So, in your case when you call nrf_bootloader_app_start(), it will boot the SD, and the SD will boot the app at 0x26000.

  • Just to complement the thematic:

    First the mbr will boot and jump to the sd which starts at 0x1000 and the sd will jumb after its end to the next flash page in case of s140 it will be 0x26000.

    I have the application "secure bootloader ble s140" and there is the function "nrf_bootloader_app_start();" This should call my application, right?

    And i explained it a little vaguely.

    My plan was/is that the app "secure ble" will jump to another application. The problem to jump between different apps is already solved.

    I'm still hanging on the boot into ble secure...

    The procedure should be as follows.

    Flash the sd which includes the mbr which jumps to the sd and after the sd i want to start the ble app, but this is standard at

    bl app from 0x000F8000 - 0x000FDA94.

    i think i have to make a small app which only jumps there or change the flash start address of the ble app, but for this the support said to read first some stuff about memory layout and the ble app and so on what i'm doing in parallel.

Related