Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cortex-m-rt/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

- Add a new `reset-interrupt-state` feature to disable and clear interrupts
inherited from a bootloader before application startup.

## [v0.7.6]

- Mark `pre_init` as deprecated
Expand Down
1 change: 1 addition & 0 deletions cortex-m-rt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ required-features = ["device"]

[features]
device = []
reset-interrupt-state = []
set-sp = []
set-vtor = []
set-msplim = []
Expand Down
2 changes: 2 additions & 0 deletions cortex-m-rt/ci/script.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ main() {
cargo rustc --target "$TARGET" --example minimal --features "zero-init-ram,${needed_features}" --release -- $linker
cargo rustc --target "$TARGET" --example minimal --features "set-vtor,${needed_features}" -- $linker
cargo rustc --target "$TARGET" --example minimal --features "set-vtor,${needed_features}" --release -- $linker
cargo rustc --target "$TARGET" --example minimal --features "reset-interrupt-state,${needed_features}" -- $linker
cargo rustc --target "$TARGET" --example minimal --features "reset-interrupt-state,${needed_features}" --release -- $linker
done
fi

Expand Down
62 changes: 62 additions & 0 deletions cortex-m-rt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,14 @@
//! conjunction with crates generated using `svd2rust`. Those peripheral access crates, or PACs,
//! will populate the missing part of the vector table when their `"rt"` feature is enabled.
//!
//! ## `reset-interrupt-state`
//!
//! If this feature is enabled, the reset handler disables all configurable interrupts before any
//! other startup code runs. It then stops and clears SysTick, clears pending PendSV, and disables
//! and clears all device specific interrupts. This is useful when a bootloader jumps to the
//! application without first disabling its interrupts. If the bootloader also leaves its vector
//! table active, enable the `set-vtor` feature as well.
//!
//! ## `set-sp`
//!
//! If this feature is enabled, the stack pointer (SP) is initialised in the reset handler to the
Expand Down Expand Up @@ -556,6 +564,11 @@ cfg_global_asm! {
".cfi_startproc
Reset:",

// If enabled, mask all configurable interrupts before any other startup code runs. This
// prevents interrupts left enabled by a bootloader from using the bootloader's vector table.
#[cfg(feature = "reset-interrupt-state")]
"cpsid i",

// If enabled, initialise the SP. This is normally initialised by the CPU itself or by a
// bootloader, but some debuggers fail to set it when resetting the target, leading to
// stack corruptions.
Expand All @@ -580,6 +593,55 @@ cfg_global_asm! {
"ldr r0, =_stack_end
msr MSPLIM, r0",

// If enabled, stop and clear SysTick, clear pending SysTick and PendSV exceptions, and disable
// and clear every implemented device specific interrupt. Global interrupts remain masked until
// the interrupt state is reset.
#[cfg(feature = "reset-interrupt-state")]
"ldr r0, =0xe000e010
movs r1, #0
str r1, [r0]
str r1, [r0, #4]
str r1, [r0, #8]
ldr r0, =0xe000ed04
ldr r1, =0x0a000000
str r1, [r0]",

// ARMv6-M has at most 32 device specific interrupts and does not provide ICTR.
#[cfg(all(feature = "reset-interrupt-state", armv6m))]
"ldr r0, =0xe000e180
ldr r1, =0xe000e280
movs r2, #0
mvns r2, r2
str r2, [r0]
str r2, [r1]",

// On other architectures ICTR contains the number of implemented groups of 32 interrupts,
// minus one. Disable and clear each group through NVIC.ICER and NVIC.ICPR respectively.
#[cfg(all(feature = "reset-interrupt-state", not(armv6m)))]
"ldr r0, =0xe000e004
ldr r0, [r0]
lsls r0, r0, #28
lsrs r0, r0, #28
adds r0, #1
ldr r1, =0xe000e180
ldr r2, =0xe000e280
movs r3, #0
mvns r3, r3
0:
str r3, [r1]
str r3, [r2]
adds r1, #4
adds r2, #4
subs r0, #1
bne 0b",

// All inherited core interrupt enables and pending state have been cleared, so restore the
// global interrupt state expected after a hardware reset before continuing startup.
#[cfg(feature = "reset-interrupt-state")]
"dsb
isb
cpsie i",

// Run user pre-init code which must be executed immediately after startup, before the
// potentially time-consuming memory initialisation takes place.
// Example use cases include disabling default watchdogs or enabling RAM.
Expand Down