Skip to content

Commit 6639e28

Browse files
committed
stm32/mboot: Add MBOOT_LEAVE_BOOTLOADER_VIA_RESET option.
It is enabled by default to get the standard behaviour of doing a reset after it is finished, but can be disabled by a board to jump straight to the application (likely the board needs to use MBOOT_BOARD_CLEANUP to make this work). The application is passed a reset mode of BOARDCTRL_RESET_MODE_BOOTLOADER if the bootloader was active and entered via a jump. Signed-off-by: Damien George <damien@micropython.org>
1 parent 9ee116c commit 6639e28

File tree

1 file changed

+51
-13
lines changed

1 file changed

+51
-13
lines changed

ports/stm32/mboot/main.c

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@
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+
13321376
static 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

13431387
extern 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

14181456
enter_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

Comments
 (0)