stm32: Enter bootloader via a system reset.
Entering a bootloader (ST system bootloader, or custom mboot) from software by directly branching to it is not reliable, and the reliability of it working can depend on the peripherals that were enabled by the application code. It's also not possible to branch to a bootloader if the WDT is enabled (unless the bootloader has specific provisions to feed the WDT). This patch changes the way a bootloader is entered from software by first doing a complete system reset, then branching to the desired bootloader early on in the start-up process. The top two words of RAM (of the stack) are reserved to store flags indicating that the bootloader should be entered after a reset.
This commit is contained in:
parent
205c6d0dc9
commit
04c7cdb668
|
@ -92,6 +92,7 @@ CFLAGS += -fsingle-precision-constant -Wdouble-promotion
|
|||
endif
|
||||
|
||||
LDFLAGS = -nostdlib -L $(LD_DIR) $(addprefix -T,$(LD_FILES)) -Map=$(@:.elf=.map) --cref
|
||||
LDFLAGS += --defsym=_estack_reserve=8
|
||||
LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
|
||||
|
||||
# Remove uncalled code from the final image.
|
||||
|
|
|
@ -31,7 +31,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 16K;
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -30,7 +30,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 24K;
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -29,7 +29,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 32K; /* tunable */
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -16,7 +16,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 6K; /* tunable */
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -18,7 +18,7 @@ _minimum_heap_size = 16K; /* tunable */
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 16K;
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -18,7 +18,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 16K; /* tunable */
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -19,7 +19,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 16K; /* tunable */
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -18,7 +18,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 16K; /* tunable */
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -21,7 +21,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 16K; /* tunable */
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -21,7 +21,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 16K; /* tunable */
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -19,7 +19,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 16K; /* tunable */
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -20,7 +20,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 16K; /* tunable */
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -17,7 +17,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 32K; /* tunable */
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -19,7 +19,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 16K; /* tunable */
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -20,7 +20,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 32K; /* tunable */
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -19,7 +19,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 32K; /* tunable */
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -19,7 +19,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 16K; /* tunable */
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -17,7 +17,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 6K; /* tunable */
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -20,7 +20,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 16K; /* tunable */
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -20,7 +20,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve;
|
||||
_sstack = _estack - 16K; /* tunable */
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -20,7 +20,7 @@ _minimum_heap_size = 16K;
|
|||
|
||||
/* Define the stack. The stack is full descending so begins just above last byte
|
||||
of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) + LENGTH(SRAM2);
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM) + LENGTH(SRAM2) - _estack_reserve;
|
||||
_sstack = _estack - 206K; /* tunable */
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
|
||||
#include "systick.h"
|
||||
#include "pendsv.h"
|
||||
#include "powerctrl.h"
|
||||
#include "pybthread.h"
|
||||
#include "gccollect.h"
|
||||
#include "factoryreset.h"
|
||||
|
@ -368,6 +369,9 @@ STATIC uint update_reset_mode(uint reset_mode) {
|
|||
#endif
|
||||
|
||||
void stm32_main(uint32_t reset_mode) {
|
||||
// Check if bootloader should be entered instead of main application
|
||||
powerctrl_check_enter_bootloader();
|
||||
|
||||
// Enable caches and prefetch buffers
|
||||
|
||||
#if defined(STM32F4)
|
||||
|
|
|
@ -237,7 +237,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id);
|
|||
|
||||
// Resets the pyboard in a manner similar to pushing the external RESET button.
|
||||
STATIC mp_obj_t machine_reset(void) {
|
||||
NVIC_SystemReset();
|
||||
powerctrl_mcu_reset();
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);
|
||||
|
@ -248,15 +248,6 @@ STATIC mp_obj_t machine_soft_reset(void) {
|
|||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset);
|
||||
|
||||
__attribute__((naked)) void branch_to_bootloader(uint32_t r0, uint32_t addr) {
|
||||
__asm volatile (
|
||||
"ldr r2, [r1, #0]\n" // get address of stack pointer
|
||||
"msr msp, r2\n" // get stack pointer
|
||||
"ldr r2, [r1, #4]\n" // get address of destination
|
||||
"bx r2\n" // branch to bootloader
|
||||
);
|
||||
}
|
||||
|
||||
// Activate the bootloader without BOOT* pins.
|
||||
STATIC NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) {
|
||||
#if MICROPY_HW_ENABLE_USB
|
||||
|
@ -266,24 +257,10 @@ STATIC NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args)
|
|||
storage_flush();
|
||||
#endif
|
||||
|
||||
#if __DCACHE_PRESENT == 1
|
||||
// Flush and disable caches before turning off peripherals (eg SDRAM)
|
||||
SCB_DisableICache();
|
||||
SCB_DisableDCache();
|
||||
#endif
|
||||
|
||||
HAL_RCC_DeInit();
|
||||
HAL_DeInit();
|
||||
|
||||
#if (__MPU_PRESENT == 1)
|
||||
// MPU must be disabled for bootloader to function correctly
|
||||
HAL_MPU_Disable();
|
||||
#endif
|
||||
|
||||
#if MICROPY_HW_USES_BOOTLOADER
|
||||
if (n_args == 0 || !mp_obj_is_true(args[0])) {
|
||||
// By default, with no args given, we enter the custom bootloader (mboot)
|
||||
branch_to_bootloader(0x70ad0000, 0x08000000);
|
||||
powerctrl_enter_bootloader(0x70ad0000, 0x08000000);
|
||||
}
|
||||
|
||||
if (n_args == 1 && mp_obj_is_str_or_bytes(args[0])) {
|
||||
|
@ -292,15 +269,14 @@ STATIC NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args)
|
|||
const char *data = mp_obj_str_get_data(args[0], &len);
|
||||
void *mboot_region = (void*)*((volatile uint32_t*)0x08000000);
|
||||
memmove(mboot_region, data, len);
|
||||
branch_to_bootloader(0x70ad0080, 0x08000000);
|
||||
powerctrl_enter_bootloader(0x70ad0080, 0x08000000);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(STM32F7) || defined(STM32H7)
|
||||
branch_to_bootloader(0, 0x1ff00000);
|
||||
powerctrl_enter_bootloader(0, 0x1ff00000);
|
||||
#else
|
||||
__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
|
||||
branch_to_bootloader(0, 0x00000000);
|
||||
powerctrl_enter_bootloader(0, 0x00000000);
|
||||
#endif
|
||||
|
||||
while (1);
|
||||
|
|
|
@ -30,6 +30,60 @@
|
|||
#include "rtc.h"
|
||||
#include "genhdr/pllfreqtable.h"
|
||||
|
||||
#if defined(STM32H7)
|
||||
#define RCC_SR RSR
|
||||
#define RCC_SR_SFTRSTF RCC_RSR_SFTRSTF
|
||||
#define RCC_SR_RMVF RCC_RSR_RMVF
|
||||
#else
|
||||
#define RCC_SR CSR
|
||||
#define RCC_SR_SFTRSTF RCC_CSR_SFTRSTF
|
||||
#define RCC_SR_RMVF RCC_CSR_RMVF
|
||||
#endif
|
||||
|
||||
// Location in RAM of bootloader state (just after the top of the stack)
|
||||
extern uint32_t _estack[];
|
||||
#define BL_STATE ((uint32_t*)&_estack)
|
||||
|
||||
NORETURN void powerctrl_mcu_reset(void) {
|
||||
BL_STATE[1] = 1; // invalidate bootloader address
|
||||
#if __DCACHE_PRESENT == 1
|
||||
SCB_CleanDCache();
|
||||
#endif
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
NORETURN void powerctrl_enter_bootloader(uint32_t r0, uint32_t bl_addr) {
|
||||
BL_STATE[0] = r0;
|
||||
BL_STATE[1] = bl_addr;
|
||||
#if __DCACHE_PRESENT == 1
|
||||
SCB_CleanDCache();
|
||||
#endif
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
static __attribute__((naked)) void branch_to_bootloader(uint32_t r0, uint32_t bl_addr) {
|
||||
__asm volatile (
|
||||
"ldr r2, [r1, #0]\n" // get address of stack pointer
|
||||
"msr msp, r2\n" // get stack pointer
|
||||
"ldr r2, [r1, #4]\n" // get address of destination
|
||||
"bx r2\n" // branch to bootloader
|
||||
);
|
||||
}
|
||||
|
||||
void powerctrl_check_enter_bootloader(void) {
|
||||
uint32_t bl_addr = BL_STATE[1];
|
||||
BL_STATE[1] = 1; // invalidate bootloader address
|
||||
if ((bl_addr & 0xfff) == 0 && (RCC->RCC_SR & RCC_SR_SFTRSTF)) {
|
||||
// Reset by NVIC_SystemReset with bootloader data set -> branch to bootloader
|
||||
RCC->RCC_SR = RCC_SR_RMVF;
|
||||
#if defined(STM32F0) || defined(STM32F4) || defined(STM32L4)
|
||||
__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
|
||||
#endif
|
||||
uint32_t r0 = BL_STATE[0];
|
||||
branch_to_bootloader(r0, bl_addr);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(STM32F0)
|
||||
|
||||
// Assumes that PLL is used as the SYSCLK source
|
||||
|
|
|
@ -28,6 +28,10 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
NORETURN void powerctrl_mcu_reset(void);
|
||||
NORETURN void powerctrl_enter_bootloader(uint32_t r0, uint32_t bl_addr);
|
||||
void powerctrl_check_enter_bootloader(void);
|
||||
|
||||
int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk_mhz, bool need_pllsai);
|
||||
int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t apb2);
|
||||
void powerctrl_enter_stop_mode(void);
|
||||
|
|
|
@ -72,6 +72,7 @@
|
|||
#include "stm32_it.h"
|
||||
#include "pendsv.h"
|
||||
#include "irq.h"
|
||||
#include "powerctrl.h"
|
||||
#include "pybthread.h"
|
||||
#include "gccollect.h"
|
||||
#include "extint.h"
|
||||
|
@ -144,7 +145,7 @@ int pyb_hard_fault_debug = 0;
|
|||
|
||||
void HardFault_C_Handler(ExceptionRegisters_t *regs) {
|
||||
if (!pyb_hard_fault_debug) {
|
||||
NVIC_SystemReset();
|
||||
powerctrl_mcu_reset();
|
||||
}
|
||||
|
||||
#if MICROPY_HW_ENABLE_USB
|
||||
|
|
Loading…
Reference in New Issue