4040#include "dfu.h"
4141#include "pack.h"
4242
43+ // Whether the bootloader will leave via reset, or direct jump to the application.
44+ #ifndef MBOOT_LEAVE_BOOTLOADER_VIA_RESET
45+ #define MBOOT_LEAVE_BOOTLOADER_VIA_RESET (1)
46+ #endif
47+
4348// This option selects whether to use explicit polling or IRQs for USB events.
4449// In some test cases polling mode can run slightly faster, but it uses more power.
4550// Polling mode will also cause failures with the mass-erase command because USB
@@ -1329,6 +1334,45 @@ static int get_reset_mode(void) {
13291334 return reset_mode ;
13301335}
13311336
1337+ NORETURN static __attribute__((naked )) void branch_to_application (uint32_t r0 , uint32_t bl_addr ) {
1338+ __asm volatile (
1339+ "ldr r2, [r1, #0]\n" // get address of stack pointer
1340+ "msr msp, r2\n" // set stack pointer
1341+ "ldr r2, [r1, #4]\n" // get address of destination
1342+ "bx r2\n" // branch to application
1343+ );
1344+ MP_UNREACHABLE ;
1345+ }
1346+
1347+ static void try_enter_application (int reset_mode ) {
1348+ uint32_t msp = * (volatile uint32_t * )APPLICATION_ADDR ;
1349+ if ((msp & APP_VALIDITY_BITS ) != 0 ) {
1350+ // Application is invalid.
1351+ return ;
1352+ }
1353+
1354+ // undo our DFU settings
1355+ // TODO probably should disable all IRQ sources first
1356+ #if defined(MBOOT_BOARD_CLEANUP )
1357+ MBOOT_BOARD_CLEANUP (reset_mode );
1358+ #endif
1359+ #if USE_CACHE && defined(STM32F7 )
1360+ SCB_DisableICache ();
1361+ SCB_DisableDCache ();
1362+ #endif
1363+
1364+ // Jump to the application.
1365+ branch_to_application (reset_mode , APPLICATION_ADDR );
1366+ }
1367+
1368+ static void leave_bootloader (void ) {
1369+ #if !MBOOT_LEAVE_BOOTLOADER_VIA_RESET
1370+ // Try to enter the application via a jump, if it's valid.
1371+ try_enter_application (BOARDCTRL_RESET_MODE_BOOTLOADER );
1372+ #endif
1373+ NVIC_SystemReset ();
1374+ }
1375+
13321376static void do_reset (void ) {
13331377 led_state_all (0 );
13341378 mp_hal_delay_ms (50 );
@@ -1337,7 +1381,7 @@ static void do_reset(void) {
13371381 i2c_slave_shutdown (MBOOT_I2Cx , I2Cx_EV_IRQn );
13381382 #endif
13391383 mp_hal_delay_ms (50 );
1340- NVIC_SystemReset ();
1384+ leave_bootloader ();
13411385}
13421386
13431387extern PCD_HandleTypeDef pcd_fs_handle ;
@@ -1402,17 +1446,11 @@ void stm32_main(int initial_r0) {
14021446 }
14031447
14041448 int reset_mode = get_reset_mode ();
1405- uint32_t msp = * (volatile uint32_t * )APPLICATION_ADDR ;
1406- if (reset_mode != BOARDCTRL_RESET_MODE_BOOTLOADER && (msp & APP_VALIDITY_BITS ) == 0 ) {
1407- // not DFU mode so jump to application, passing through reset_mode
1408- // undo our DFU settings
1409- // TODO probably should disable all IRQ sources first
1410- #if USE_CACHE && defined(STM32F7 )
1411- SCB_DisableICache ();
1412- SCB_DisableDCache ();
1413- #endif
1414- __set_MSP (msp );
1415- ((void (* )(uint32_t )) * ((volatile uint32_t * )(APPLICATION_ADDR + 4 )))(reset_mode );
1449+ if (reset_mode != BOARDCTRL_RESET_MODE_BOOTLOADER ) {
1450+ // Bootloader mode was not selected so try to enter the application,
1451+ // passing through the reset_mode. This will return if the application
1452+ // is invalid.
1453+ try_enter_application (reset_mode );
14161454 }
14171455
14181456enter_bootloader :
@@ -1461,7 +1499,7 @@ void stm32_main(int initial_r0) {
14611499 }
14621500 // Always reset because the application is expecting to resume
14631501 led_state_all (0 );
1464- NVIC_SystemReset ();
1502+ leave_bootloader ();
14651503 }
14661504 #endif
14671505
0 commit comments