DIY bootloader for nRF5340

I'm writing my own lightweight bootloader for nRF5340 (which may or may not turn out to be a good idea).  I have something similar that I'm using successfully on nRF52832 based on a minimal Zephyr application.

The bootloader doesn't use TF-M so it has a single flash partition, however the application has both secure and non-secure code.  By inspection the vector table is in the non-secure partition.

This is what I do in the bootloader to start up the application:

__STATIC_INLINE void jump_to_addr(uint32_t new_msp, uint32_t new_lr, uint32_t addr) 
{
	__ASM volatile("MSR MSP, %[arg]" : : [arg] "r" (new_msp));
	__ASM volatile("MOV LR,  %[arg]" : : [arg] "r" (new_lr) : "lr");
	__ASM volatile("BX       %[arg]" : : [arg] "r" (addr));
}

__STATIC_INLINE void app_start(uint32_t vector_table_addr)
{
    struct arm_vector_table *vt = (void *)vector_table_addr;
	printk("Inspect vector table at %08x\n", vector_table_addr);

	//const uint32_t current_isr_num = (__get_IPSR() & IPSR_ISR_Msk);
	const uint32_t new_msp         = vt->msp;     // The app's Stack Pointer is found as the first word of the vector table.
	const uint32_t reset_handler   = vt->reset;   // The app's Reset Handler is found as the second word of the vector table.
	const uint32_t new_lr          = 0xFFFFFFFF;

	printk("Stack pointer %08x\n", new_msp);
	printk("Reset vector %08x\n", reset_handler);

    irq_lock();

	__set_CONTROL(0x00000000);     // Set CONTROL to its reset value 0.
	__set_PRIMASK(0x00000000);     // Set PRIMASK to its reset value 0.
	__set_BASEPRI(0x00000000);     // Set BASEPRI to its reset value 0.
	__set_FAULTMASK(0x00000000);   // Set FAULTMASK to its reset value 0.

	jump_to_addr(new_msp, new_lr, reset_handler);   // Jump directly to the App's Reset Handler.
}

I'm investigating this by programming the bootloader code first and then running a debug session with the application code.  I can see from the RTT output that the bootloader starts up and attempts to run the application, but it doesn't hit a breakpoint in the application's Reset_Handler(); instead it seems to jump immediately into k_sys_fatal_error_handler with reason 25.

Debugging the bootloader code I see that jump_to_addr appears to have the correct parameters, and switching to disassembly mode I see that the application's Reset_Handler() is invoked and at least the first few instructions are executed.

Can you see what I'm going wrong?

Related