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.

Parents
  • 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.
            );
    }

Reply
  • 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.
            );
    }

Children
No Data
Related