aboutsummaryrefslogtreecommitdiff
path: root/cortex-m-rt
diff options
context:
space:
mode:
Diffstat (limited to 'cortex-m-rt')
-rw-r--r--cortex-m-rt/CHANGELOG.md14
-rw-r--r--cortex-m-rt/Cargo.toml7
-rw-r--r--cortex-m-rt/README.md2
-rw-r--r--cortex-m-rt/asm.S113
-rwxr-xr-xcortex-m-rt/assemble.sh33
-rw-r--r--cortex-m-rt/bin/thumbv6m-none-eabi.abin2738 -> 0 bytes
-rw-r--r--cortex-m-rt/bin/thumbv7em-none-eabi.abin2746 -> 0 bytes
-rw-r--r--cortex-m-rt/bin/thumbv7em-none-eabihf.abin2778 -> 0 bytes
-rw-r--r--cortex-m-rt/bin/thumbv7m-none-eabi.abin2746 -> 0 bytes
-rw-r--r--cortex-m-rt/bin/thumbv8m.base-none-eabi.abin2742 -> 0 bytes
-rw-r--r--cortex-m-rt/bin/thumbv8m.main-none-eabi.abin2750 -> 0 bytes
-rw-r--r--cortex-m-rt/bin/thumbv8m.main-none-eabihf.abin2782 -> 0 bytes
-rw-r--r--cortex-m-rt/build.rs15
-rwxr-xr-xcortex-m-rt/check-blobs.sh21
-rwxr-xr-xcortex-m-rt/ci/script.sh32
-rw-r--r--cortex-m-rt/examples/qemu.rs30
-rw-r--r--cortex-m-rt/link.x.in8
-rw-r--r--cortex-m-rt/macros/Cargo.toml3
-rw-r--r--cortex-m-rt/src/lib.rs213
-rw-r--r--cortex-m-rt/tests/compile-fail/non-static-resource.rs4
20 files changed, 235 insertions, 260 deletions
diff --git a/cortex-m-rt/CHANGELOG.md b/cortex-m-rt/CHANGELOG.md
index c66b5c0..0ee0510 100644
--- a/cortex-m-rt/CHANGELOG.md
+++ b/cortex-m-rt/CHANGELOG.md
@@ -7,11 +7,22 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
+## [v0.7.2]
+
+- MSRV is now Rust 1.59.
+- Moved precompiled assembly blobs to `global_asm!`, requiring Rust 1.59.
+- Add new `set_vtor` and `set-sp` features to conditionally set the VTOR and SP
+ registers at device reset ([#423]).
+- Allow (unstable) `naked` attribute on interrupt handlers and `pre_init`.
+
## Fixes
- Fix `cortex_m_rt::exception` macro no longer being usable fully-qualified ([#414])
+- Fix veneer limit position in linker script ([#434]).
[#414]: https://github.com/rust-embedded/cortex-m/issues/414
+[#423]: https://github.com/rust-embedded/cortex-m/issues/423
+[#434]: https://github.com/rust-embedded/cortex-m/issues/434
## Notes
@@ -591,7 +602,8 @@ section size addr
Initial release
-[Unreleased]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.7.1...HEAD
+[Unreleased]: https://github.com/rust-embedded/cortex-m/compare/c-m-rt-v0.7.2...HEAD
+[v0.7.2]: https://github.com/rust-embedded/cortex-m/compare/c-m-rt-v0.7.1...c-m-rt-v0.7.2
[v0.7.1]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.7.0...v0.7.1
[v0.7.0]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.11...v0.7.0
[v0.6.15]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.14...v0.6.15
diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml
index 5289057..e6ea8c8 100644
--- a/cortex-m-rt/Cargo.toml
+++ b/cortex-m-rt/Cargo.toml
@@ -12,10 +12,11 @@ license = "MIT OR Apache-2.0"
name = "cortex-m-rt"
readme = "README.md"
repository = "https://github.com/rust-embedded/cortex-m"
-version = "0.7.1"
+version = "0.7.2"
autoexamples = true
links = "cortex-m-rt" # Prevent multiple versions of cortex-m-rt being linked
-edition = "2018"
+edition = "2021"
+rust-version = "1.59"
[dependencies]
cortex-m-rt-macros = { path = "macros", version = "=0.7.0" }
@@ -42,6 +43,8 @@ required-features = ["device"]
[features]
device = []
+set-sp = []
+set-vtor = []
[package.metadata.docs.rs]
features = ["device"]
diff --git a/cortex-m-rt/README.md b/cortex-m-rt/README.md
index 34b0f17..b62dbb5 100644
--- a/cortex-m-rt/README.md
+++ b/cortex-m-rt/README.md
@@ -11,7 +11,7 @@ This project is developed and maintained by the [Cortex-M team][team].
# Minimum Supported Rust Version (MSRV)
-This crate is guaranteed to compile on stable Rust 1.42.0 and up. It *might*
+This crate is guaranteed to compile on stable Rust 1.59.0 and up. It *might*
compile with older versions but that may change in any new patch release.
# License
diff --git a/cortex-m-rt/asm.S b/cortex-m-rt/asm.S
deleted file mode 100644
index 0d078b3..0000000
--- a/cortex-m-rt/asm.S
+++ /dev/null
@@ -1,113 +0,0 @@
- .cfi_sections .debug_frame
-
- # Notes for function attributes:
- # .type and .thumb_func are _both_ required, otherwise the Thumb mode bit
- # will not be set and an invalid vector table is generated.
- # LLD requires that section flags are set explicitly.
-
- .section .HardFaultTrampoline, "ax"
- .global HardFaultTrampoline
- .type HardFaultTrampoline,%function
- .thumb_func
- .cfi_startproc
- # HardFault exceptions are bounced through this trampoline which grabs the
- # stack pointer at the time of the exception and passes it to the user's
- # HardFault handler in r0.
-HardFaultTrampoline:
- # Depending on the stack mode in EXC_RETURN, fetch stack pointer from
- # PSP or MSP.
- mov r0, lr
- mov r1, #4
- tst r0, r1
- bne 0f
- mrs r0, MSP
- b HardFault
-0:
- mrs r0, PSP
- b HardFault
- .cfi_endproc
- .size HardFaultTrampoline, . - HardFaultTrampoline
-
- .section .Reset, "ax"
- .global Reset
- .type Reset,%function
- .thumb_func
- .cfi_startproc
- # Main entry point after reset. This jumps to the user __pre_init function,
- # which cannot be called from Rust code without invoking UB, then
- # initialises RAM. If the target has an FPU, it is enabled. Finally, jumps
- # to the user main function.
-Reset:
- # ARMv6-M does not initialise LR, but many tools expect it to be 0xFFFF_FFFF
- # when reaching the first call frame, so we set it at startup.
- # ARMv7-M and above initialise LR to 0xFFFF_FFFF at reset.
- ldr r4,=0xffffffff
- mov lr,r4
-
- # 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.
- bl __pre_init
-
- # Restore LR after calling __pre_init (r4 is preserved by subroutines).
- mov lr,r4
-
- # Initialise .bss memory. `__sbss` and `__ebss` come from the linker script.
- ldr r0,=__sbss
- ldr r1,=__ebss
- mov r2,#0
-0:
- cmp r1, r0
- beq 1f
- stm r0!, {r2}
- b 0b
-1:
-
- # Initialise .data memory. `__sdata`, `__sidata`, and `__edata` come from the
- # linker script. Copy from r2 into r0 until r0 reaches r1.
- ldr r0,=__sdata
- ldr r1,=__edata
- ldr r2,=__sidata
-2:
- cmp r1, r0
- beq 3f
- # load 1 word from r2 to r3, inc r2
- ldm r2!, {r3}
- # store 1 word from r3 to r0, inc r0
- stm r0!, {r3}
- b 2b
-3:
-
-#ifdef HAS_FPU
- # Conditionally enable the FPU.
- # Address of SCB.CPACR.
- ldr r0, =0xE000ED88
- # Enable access to CP10 and CP11 from both privileged and unprivileged mode.
- ldr r1, =(0b1111 << 20)
- # RMW.
- ldr r2, [r0]
- orr r2, r2, r1
- str r2, [r0]
- # Barrier is required on some processors.
- dsb
- isb
-#endif
-
-4:
- # Preserve `lr` and emit debuginfo that lets external tools restore it.
- # This fixes unwinding past the `Reset` handler.
- # See https://sourceware.org/binutils/docs/as/CFI-directives.html for an
- # explanation of the directives.
-.cfi_def_cfa sp, 0
- push {lr}
-.cfi_offset lr, 0
-
- # Jump to user main function. We use bl for the extended range, but the
- # user main function may not return.
- bl main
-
- # Trap on return.
- udf
-
- .cfi_endproc
- .size Reset, . - Reset
diff --git a/cortex-m-rt/assemble.sh b/cortex-m-rt/assemble.sh
deleted file mode 100755
index 9b1f15c..0000000
--- a/cortex-m-rt/assemble.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/env bash
-
-set -euxo pipefail
-
-# cflags taken from cc 1.0.22
-
-crate=cortex-m-rt
-
-# remove existing blobs because otherwise this will append object files to the old blobs
-rm -f bin/*.a
-
-arm-none-eabi-gcc -g -c -march=armv6s-m asm.S -o bin/$crate.o
-ar crs bin/thumbv6m-none-eabi.a bin/$crate.o
-
-arm-none-eabi-gcc -g -c -march=armv7-m asm.S -o bin/$crate.o
-ar crs bin/thumbv7m-none-eabi.a bin/$crate.o
-
-arm-none-eabi-gcc -g -c -march=armv7e-m asm.S -o bin/$crate.o
-ar crs bin/thumbv7em-none-eabi.a bin/$crate.o
-
-arm-none-eabi-gcc -g -c -march=armv7e-m asm.S -DHAS_FPU -o bin/$crate.o
-ar crs bin/thumbv7em-none-eabihf.a bin/$crate.o
-
-arm-none-eabi-gcc -g -c -march=armv8-m.base asm.S -o bin/$crate.o
-ar crs bin/thumbv8m.base-none-eabi.a bin/$crate.o
-
-arm-none-eabi-gcc -g -c -march=armv8-m.main asm.S -o bin/$crate.o
-ar crs bin/thumbv8m.main-none-eabi.a bin/$crate.o
-
-arm-none-eabi-gcc -g -c -march=armv8-m.main -DHAS_FPU asm.S -o bin/$crate.o
-ar crs bin/thumbv8m.main-none-eabihf.a bin/$crate.o
-
-rm bin/$crate.o
diff --git a/cortex-m-rt/bin/thumbv6m-none-eabi.a b/cortex-m-rt/bin/thumbv6m-none-eabi.a
deleted file mode 100644
index c145cc6..0000000
--- a/cortex-m-rt/bin/thumbv6m-none-eabi.a
+++ /dev/null
Binary files differ
diff --git a/cortex-m-rt/bin/thumbv7em-none-eabi.a b/cortex-m-rt/bin/thumbv7em-none-eabi.a
deleted file mode 100644
index 2d6b6a1..0000000
--- a/cortex-m-rt/bin/thumbv7em-none-eabi.a
+++ /dev/null
Binary files differ
diff --git a/cortex-m-rt/bin/thumbv7em-none-eabihf.a b/cortex-m-rt/bin/thumbv7em-none-eabihf.a
deleted file mode 100644
index aa765ea..0000000
--- a/cortex-m-rt/bin/thumbv7em-none-eabihf.a
+++ /dev/null
Binary files differ
diff --git a/cortex-m-rt/bin/thumbv7m-none-eabi.a b/cortex-m-rt/bin/thumbv7m-none-eabi.a
deleted file mode 100644
index 3d1783c..0000000
--- a/cortex-m-rt/bin/thumbv7m-none-eabi.a
+++ /dev/null
Binary files differ
diff --git a/cortex-m-rt/bin/thumbv8m.base-none-eabi.a b/cortex-m-rt/bin/thumbv8m.base-none-eabi.a
deleted file mode 100644
index a9fb434..0000000
--- a/cortex-m-rt/bin/thumbv8m.base-none-eabi.a
+++ /dev/null
Binary files differ
diff --git a/cortex-m-rt/bin/thumbv8m.main-none-eabi.a b/cortex-m-rt/bin/thumbv8m.main-none-eabi.a
deleted file mode 100644
index 40a5c51..0000000
--- a/cortex-m-rt/bin/thumbv8m.main-none-eabi.a
+++ /dev/null
Binary files differ
diff --git a/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a b/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a
deleted file mode 100644
index 6c523af..0000000
--- a/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a
+++ /dev/null
Binary files differ
diff --git a/cortex-m-rt/build.rs b/cortex-m-rt/build.rs
index 96a8560..2b65cdf 100644
--- a/cortex-m-rt/build.rs
+++ b/cortex-m-rt/build.rs
@@ -1,4 +1,4 @@
-use std::fs::{self, File};
+use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::{env, ffi::OsStr};
@@ -16,15 +16,6 @@ fn main() {
.map_or(target.clone(), |stem| stem.to_str().unwrap().to_string());
}
- let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
-
- if target.starts_with("thumbv") {
- let lib_path = format!("bin/{}.a", target);
- fs::copy(&lib_path, out_dir.join("libcortex-m-rt.a")).unwrap();
- println!("cargo:rustc-link-lib=static=cortex-m-rt");
- println!("cargo:rerun-if-changed={}", lib_path);
- }
-
// Put the linker script somewhere the linker can find it
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
let link_x = include_bytes!("link.x.in");
@@ -69,6 +60,10 @@ INCLUDE device.x"#
240
};
+ if target.ends_with("-eabihf") {
+ println!("cargo:rustc-cfg=has_fpu");
+ }
+
// checking the size of the interrupts portion of the vector table is sub-architecture dependent
writeln!(
f,
diff --git a/cortex-m-rt/check-blobs.sh b/cortex-m-rt/check-blobs.sh
deleted file mode 100755
index 166b4a4..0000000
--- a/cortex-m-rt/check-blobs.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env bash
-
-# Checks that the blobs are up to date with the committed assembly files
-
-set -euxo pipefail
-
-for lib in bin/*.a; do
- filename=$(basename "$lib")
- arm-none-eabi-objdump -Cd "$lib" > "bin/${filename%.a}.before"
-done
-
-./assemble.sh
-
-for lib in bin/*.a; do
- filename=$(basename "$lib")
- arm-none-eabi-objdump -Cd "$lib" > "bin/${filename%.a}.after"
-done
-
-for cksum in bin/*.after; do
- diff -u "$cksum" "${cksum%.after}.before"
-done
diff --git a/cortex-m-rt/ci/script.sh b/cortex-m-rt/ci/script.sh
index 08ff863..2941e48 100755
--- a/cortex-m-rt/ci/script.sh
+++ b/cortex-m-rt/ci/script.sh
@@ -7,10 +7,13 @@ main() {
cargo check --target "$TARGET" --features device
+ # A `critical_section` implementation is always needed.
+ needed_features=cortex-m/critical-section-single-core
+
if [ "$TARGET" = x86_64-unknown-linux-gnu ] && [ "$TRAVIS_RUST_VERSION" = stable ]; then
( cd macros && cargo check && cargo test )
- cargo test --features device --test compiletest
+ cargo test --features "device,${needed_features}" --test compiletest
fi
local examples=(
@@ -43,20 +46,25 @@ main() {
if [ "$TARGET" != x86_64-unknown-linux-gnu ]; then
# Only test on stable and nightly, not MSRV.
if [ "$TRAVIS_RUST_VERSION" = stable ] || [ "$TRAVIS_RUST_VERSION" = nightly ]; then
- RUSTDOCFLAGS="-Cpanic=abort" cargo test --doc
+ RUSTDOCFLAGS="-Cpanic=abort" cargo test --features "${needed_features}" --doc
fi
for linker in "${linkers[@]}"; do
for ex in "${examples[@]}"; do
- cargo rustc --target "$TARGET" --example "$ex" -- $linker
- cargo rustc --target "$TARGET" --example "$ex" --release -- $linker
+ cargo rustc --target "$TARGET" --example "$ex" --features "${needed_features}" -- $linker
+ cargo rustc --target "$TARGET" --example "$ex" --features "${needed_features}" --release -- $linker
done
for ex in "${fail_examples[@]}"; do
- ! cargo rustc --target "$TARGET" --example "$ex" -- $linker
- ! cargo rustc --target "$TARGET" --example "$ex" --release -- $linker
+ ! cargo rustc --target "$TARGET" --example "$ex" --features "${needed_features}" -- $linker
+ ! cargo rustc --target "$TARGET" --example "$ex" --features "${needed_features}" --release -- $linker
done
- cargo rustc --target "$TARGET" --example device --features device -- $linker
- cargo rustc --target "$TARGET" --example device --features device --release -- $linker
+ cargo rustc --target "$TARGET" --example device --features "device,${needed_features}" -- $linker
+ cargo rustc --target "$TARGET" --example device --features "device,${needed_features}" --release -- $linker
+
+ cargo rustc --target "$TARGET" --example minimal --features "set-sp,${needed_features}" -- $linker
+ cargo rustc --target "$TARGET" --example minimal --features "set-sp,${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
done
fi
@@ -64,17 +72,13 @@ main() {
thumbv6m-none-eabi|thumbv7m-none-eabi)
for linker in "${linkers[@]}"; do
env RUSTFLAGS="$linker -C link-arg=-Tlink.x" cargo run \
- --target "$TARGET" --example qemu | grep "x = 42"
+ --target "$TARGET" --features "${needed_features}" --example qemu | grep "x = 42"
env RUSTFLAGS="$linker -C link-arg=-Tlink.x" cargo run \
- --target "$TARGET" --example qemu --release | grep "x = 42"
+ --target "$TARGET" --features "${needed_features}" --example qemu --release | grep "x = 42"
done
;;
esac
-
- if [ "$TARGET" = x86_64-unknown-linux-gnu ]; then
- ./check-blobs.sh
- fi
}
main
diff --git a/cortex-m-rt/examples/qemu.rs b/cortex-m-rt/examples/qemu.rs
index e903404..a8ffd20 100644
--- a/cortex-m-rt/examples/qemu.rs
+++ b/cortex-m-rt/examples/qemu.rs
@@ -1,28 +1,24 @@
-// #![feature(stdsimd)]
#![no_main]
#![no_std]
-extern crate cortex_m;
-extern crate cortex_m_rt as rt;
-extern crate cortex_m_semihosting as semihosting;
+use core::fmt::Write;
-extern crate panic_halt;
-
-use cortex_m::asm;
-use rt::entry;
-
-#[entry]
+#[cortex_m_rt::entry]
fn main() -> ! {
- use core::fmt::Write;
let x = 42;
loop {
- asm::nop();
-
- // write something through semihosting interface
- let mut hstdout = semihosting::hio::hstdout().unwrap();
+ let mut hstdout = cortex_m_semihosting::hio::hstdout().unwrap();
write!(hstdout, "x = {}\n", x).unwrap();
- // exit from qemu
- semihosting::debug::exit(semihosting::debug::EXIT_SUCCESS);
+ cortex_m_semihosting::debug::exit(cortex_m_semihosting::debug::EXIT_SUCCESS);
+ }
+}
+
+// Define a panic handler that uses semihosting to exit immediately,
+// so that any panics cause qemu to quit instead of hang.
+#[panic_handler]
+fn panic(_: &core::panic::PanicInfo) -> ! {
+ loop {
+ cortex_m_semihosting::debug::exit(cortex_m_semihosting::debug::EXIT_FAILURE);
}
}
diff --git a/cortex-m-rt/link.x.in b/cortex-m-rt/link.x.in
index 92004b7..4461646 100644
--- a/cortex-m-rt/link.x.in
+++ b/cortex-m-rt/link.x.in
@@ -66,6 +66,8 @@ SECTIONS
/* ### Vector table */
.vector_table ORIGIN(FLASH) :
{
+ __vector_table = .;
+
/* Initial Stack Pointer (SP) value */
LONG(_stack_start);
@@ -142,8 +144,12 @@ SECTIONS
__veneer_base = .;
*(.gnu.sgstubs*)
. = ALIGN(32);
- __veneer_limit = .;
} > FLASH
+ /* Place `__veneer_limit` outside the `.gnu.sgstubs` section because veneers are
+ * always inserted last in the section, which would otherwise be _after_ the `__veneer_limit` symbol.
+ */
+ . = ALIGN(32);
+ __veneer_limit = .;
/* ### .bss */
.bss (NOLOAD) : ALIGN(4)
diff --git a/cortex-m-rt/macros/Cargo.toml b/cortex-m-rt/macros/Cargo.toml
index c73ebc1..e95cc7d 100644
--- a/cortex-m-rt/macros/Cargo.toml
+++ b/cortex-m-rt/macros/Cargo.toml
@@ -8,7 +8,8 @@ license = "MIT OR Apache-2.0"
name = "cortex-m-rt-macros"
repository = "https://github.com/rust-embedded/cortex-m"
version = "0.7.0"
-edition = "2018"
+edition = "2021"
+rust-version = "1.59"
[lib]
proc-macro = true
diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs
index 752d3d7..6e6bf7e 100644
--- a/cortex-m-rt/src/lib.rs
+++ b/cortex-m-rt/src/lib.rs
@@ -34,14 +34,14 @@
//!
//! This crate expects the user, or some other crate, to provide the memory layout of the target
//! device via a linker script named `memory.x`. This section covers the contents of `memory.x`
-//! The `memory.x` file is used by during linking by the `link.x` script provided by this crate.
+//! The `memory.x` file is used during linking by the `link.x` script provided by this crate.
//!
//! ### `MEMORY`
//!
//! The linker script must specify the memory available in the device as, at least, two `MEMORY`
//! regions: one named `FLASH` and one named `RAM`. The `.text` and `.rodata` sections of the
//! program will be placed in the `FLASH` region, whereas the `.bss` and `.data` sections, as well
-//! as the heap,will be placed in the `RAM` region.
+//! as the heap, will be placed in the `RAM` region.
//!
//! ```text
//! /* Linker script for the STM32F103C8T6 */
@@ -158,6 +158,19 @@
//! conjunction with crates generated using `svd2rust`. Those *device crates* will populate the
//! missing part of the vector table when their `"rt"` feature is enabled.
//!
+//! ## `set-sp`
+//!
+//! If this feature is enabled, the stack pointer (SP) is initialised in the reset handler to the
+//! `_stack_start` value from the linker script. This is not usually required, but some debuggers
+//! do not initialise SP when performing a soft reset, which can lead to stack corruption.
+//!
+//! ## `set-vtor`
+//!
+//! If this feature is enabled, the vector table offset register (VTOR) is initialised in the reset
+//! handler to the start of the vector table defined in the linker script. This is not usually
+//! required, but some bootloaders do not set VTOR before jumping to application code, leading to
+//! your main function executing but interrupt handlers not being used.
+//!
//! # Inspection
//!
//! This section covers how to inspect a binary that builds on top of `cortex-m-rt`.
@@ -309,14 +322,10 @@
//!
//! We want to provide a default handler for all the interrupts while still letting the user
//! individually override each interrupt handler. In C projects, this is usually accomplished using
-//! weak aliases declared in external assembly files. In Rust, we could achieve something similar
-//! using `global_asm!`, but that's an unstable feature.
-//!
-//! A solution that doesn't require `global_asm!` or external assembly files is to use the `PROVIDE`
-//! command in a linker script to create the weak aliases. This is the approach that `cortex-m-rt`
-//! uses; when the `"device"` feature is enabled `cortex-m-rt`'s linker script (`link.x`) depends on
-//! a linker script named `device.x`. The crate that provides `__INTERRUPTS` must also provide this
-//! file.
+//! weak aliases declared in external assembly files. We use a similar solution via the `PROVIDE`
+//! command in the linker script: when the `"device"` feature is enabled, `cortex-m-rt`'s linker
+//! script (`link.x`) includes a linker script named `device.x`, which must be provided by
+//! whichever crate provides `__INTERRUPTS`.
//!
//! For our running example the `device.x` linker script looks like this:
//!
@@ -330,8 +339,8 @@
//! that the core exceptions use unless overridden.
//!
//! Because this linker script is provided by a dependency of the final application the dependency
-//! must contain build script that puts `device.x` somewhere the linker can find. An example of such
-//! build script is shown below:
+//! must contain a build script that puts `device.x` somewhere the linker can find. An example of
+//! such build script is shown below:
//!
//! ```ignore
//! use std::env;
@@ -418,7 +427,7 @@
//!
//! # Minimum Supported Rust Version (MSRV)
//!
-//! The MSRV of this release is Rust 1.42.0.
+//! The MSRV of this release is Rust 1.59.0.
// # Developer notes
//
@@ -430,16 +439,152 @@
extern crate cortex_m_rt_macros as macros;
+#[cfg(cortex_m)]
+use core::arch::global_asm;
use core::fmt;
-use core::sync::atomic::{self, Ordering};
+
+// HardFault exceptions are bounced through this trampoline which grabs the stack pointer at
+// the time of the exception and passes it to the user's HardFault handler in r0.
+// Depending on the stack mode in EXC_RETURN, fetches stack from either MSP or PSP.
+#[cfg(cortex_m)]
+global_asm!(
+ ".cfi_sections .debug_frame
+ .section .HardFaultTrampoline, \"ax\"
+ .global HardFaultTrampline
+ .type HardFaultTrampline,%function
+ .thumb_func
+ .cfi_startproc
+ HardFaultTrampoline:",
+ "mov r0, lr
+ movs r1, #4
+ tst r0, r1
+ bne 0f
+ mrs r0, MSP
+ b HardFault
+ 0:
+ mrs r0, PSP
+ b HardFault",
+ ".cfi_endproc
+ .size HardFaultTrampoline, . - HardFaultTrampoline",
+);
+
+/// Parse cfg attributes inside a global_asm call.
+#[cfg(cortex_m)]
+macro_rules! cfg_global_asm {
+ {@inner, [$($x:tt)*], } => {
+ global_asm!{$($x)*}
+ };
+ (@inner, [$($x:tt)*], #[cfg($meta:meta)] $asm:literal, $($rest:tt)*) => {
+ #[cfg($meta)]
+ cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
+ #[cfg(not($meta))]
+ cfg_global_asm!{@inner, [$($x)*], $($rest)*}
+ };
+ {@inner, [$($x:tt)*], $asm:literal, $($rest:tt)*} => {
+ cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
+ };
+ {$($asms:tt)*} => {
+ cfg_global_asm!{@inner, [], $($asms)*}
+ };
+}
+
+// This reset vector is the initial entry point after a system reset.
+// Calls an optional user-provided __pre_init and then initialises RAM.
+// If the target has an FPU, it is enabled.
+// Finally jumps to the user main function.
+#[cfg(cortex_m)]
+cfg_global_asm! {
+ ".cfi_sections .debug_frame
+ .section .Reset, \"ax\"
+ .global Reset
+ .type Reset,%function
+ .thumb_func",
+ ".cfi_startproc
+ Reset:",
+
+ // Ensure LR is loaded with 0xFFFF_FFFF at startup to help debuggers find the first call frame.
+ // On ARMv6-M LR is not initialised at all, while other platforms should initialise it.
+ "movs r4, #0
+ mvns r4, r4
+ mov lr, r4",
+
+ // 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.
+ #[cfg(feature = "set-sp")]
+ "ldr r0, =_stack_start
+ msr msp, r0",
+
+ // If enabled, initialise VTOR to the start of the vector table. This is normally initialised
+ // by a bootloader when the non-reset value is required, but some bootloaders do not set it,
+ // leading to frustrating issues where everything seems to work but interrupts are never
+ // handled. The VTOR register is optional on ARMv6-M, but when not present is RAZ,WI and
+ // therefore safe to write to.
+ #[cfg(feature = "set-vtor")]
+ "ldr r0, =0xe000ed08
+ ldr r1, =__vector_table
+ str r1, [r0]",
+
+ // 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.
+ // Reload LR after returning from pre-init (r4 is preserved by subroutines).
+ "bl __pre_init
+ mov lr, r4",
+
+ // Initialise .bss memory. `__sbss` and `__ebss` come from the linker script.
+ "ldr r0, =__sbss
+ ldr r1, =__ebss
+ movs r2, #0
+ 0:
+ cmp r1, r0
+ beq 1f
+ stm r0!, {{r2}}
+ b 0b
+ 1:",
+
+ // Initialise .data memory. `__sdata`, `__sidata`, and `__edata` come from the linker script.
+ "ldr r0, =__sdata
+ ldr r1, =__edata
+ ldr r2, =__sidata
+ 2:
+ cmp r1, r0
+ beq 3f
+ ldm r2!, {{r3}}
+ stm r0!, {{r3}}
+ b 2b
+ 3:",
+
+ // Potentially enable an FPU.
+ // SCB.CPACR is 0xE000_ED88.
+ // We enable access to CP10 and CP11 from priviliged and unprivileged mode.
+ #[cfg(has_fpu)]
+ "ldr r0, =0xE000ED88
+ ldr r1, =(0b1111 << 20)
+ ldr r2, [r0]
+ orr r2, r2, r1
+ str r2, [r0]
+ dsb
+ isb",
+
+ // Push `lr` to the stack for debuggers, to prevent them unwinding past Reset.
+ // See https://sourceware.org/binutils/docs/as/CFI-directives.html.
+ ".cfi_def_cfa sp, 0
+ push {{lr}}
+ .cfi_offset lr, 0",
+
+ // Jump to user main function.
+ // `bl` is used for the extended range, but the user main function should not return,
+ // so trap on any unexpected return.
+ "bl main
+ udf #0",
+
+ ".cfi_endproc
+ .size Reset, . - Reset",
+}
/// Attribute to declare an interrupt (AKA device-specific exception) handler
///
-/// **IMPORTANT**: If you are using Rust 1.30 this attribute must be used on reachable items (i.e.
-/// there must be no private modules between the item and the root of the crate); if the item is in
-/// the root of the crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31
-/// and newer releases.
-///
/// **NOTE**: This attribute is exposed by `cortex-m-rt` only when the `device` feature is enabled.
/// However, that export is not meant to be used directly -- using it will result in a compilation
/// error. You should instead use the device crate (usually generated using `svd2rust`) re-export of
@@ -506,11 +651,6 @@ pub use macros::interrupt;
/// Attribute to declare the entry point of the program
///
-/// **IMPORTANT**: This attribute must appear exactly *once* in the dependency graph. Also, if you
-/// are using Rust 1.30 the attribute must be used on a reachable item (i.e. there must be no
-/// private modules between the item and the root of the crate); if the item is in the root of the
-/// crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 and newer releases.
-///
/// The specified function will be called by the reset handler *after* RAM has been initialized. In
/// the case of the `thumbv7em-none-eabihf` target the FPU will also be enabled before the function
/// is called.
@@ -565,11 +705,6 @@ pub use macros::entry;
/// Attribute to declare an exception handler
///
-/// **IMPORTANT**: If you are using Rust 1.30 this attribute must be used on reachable items (i.e.
-/// there must be no private modules between the item and the root of the crate); if the item is in
-/// the root of the crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31
-/// and newer releases.
-///
/// # Syntax
///
/// ```
@@ -681,11 +816,7 @@ pub use macros::exception;
/// Attribute to mark which function will be called at the beginning of the reset handler.
///
-/// **IMPORTANT**: This attribute can appear at most *once* in the dependency graph. Also, if you
-/// are using Rust 1.30 the attribute must be used on a reachable item (i.e. there must be no
-/// private modules between the item and the root of the crate); if the item is in the root of the
-/// crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 and newer
-/// releases.
+/// **IMPORTANT**: This attribute can appear at most *once* in the dependency graph.
///
/// The function must have the signature of `unsafe fn()`.
///
@@ -920,21 +1051,15 @@ pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = Reset;
#[cfg_attr(cortex_m, link_section = ".HardFault.default")]
#[no_mangle]
pub unsafe extern "C" fn HardFault_(ef: &ExceptionFrame) -> ! {
- loop {
- // add some side effect to prevent this from turning into a UDF instruction
- // see rust-lang/rust#28728 for details
- atomic::compiler_fence(Ordering::SeqCst);
- }
+ #[allow(clippy::empty_loop)]
+ loop {}
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn DefaultHandler_() -> ! {
- loop {
- // add some side effect to prevent this from turning into a UDF instruction
- // see rust-lang/rust#28728 for details
- atomic::compiler_fence(Ordering::SeqCst);
- }
+ #[allow(clippy::empty_loop)]
+ loop {}
}
#[doc(hidden)]
diff --git a/cortex-m-rt/tests/compile-fail/non-static-resource.rs b/cortex-m-rt/tests/compile-fail/non-static-resource.rs
index a603728..95f314b 100644
--- a/cortex-m-rt/tests/compile-fail/non-static-resource.rs
+++ b/cortex-m-rt/tests/compile-fail/non-static-resource.rs
@@ -21,7 +21,7 @@ fn SVCall() {
static mut STAT: u8 = 0;
let _stat: &'static mut u8 = STAT;
- //~^ ERROR lifetime of reference outlives lifetime of borrowed content
+ //~^ ERROR lifetime may not live long enough
}
#[interrupt]
@@ -29,7 +29,7 @@ fn UART0() {
static mut STAT: u8 = 0;
let _stat: &'static mut u8 = STAT;
- //~^ ERROR lifetime of reference outlives lifetime of borrowed content
+ //~^ ERROR lifetime may not live long enough
}
#[entry]