diff options
Diffstat (limited to 'cortex-m-rt')
-rw-r--r-- | cortex-m-rt/CHANGELOG.md | 14 | ||||
-rw-r--r-- | cortex-m-rt/Cargo.toml | 7 | ||||
-rw-r--r-- | cortex-m-rt/README.md | 2 | ||||
-rw-r--r-- | cortex-m-rt/asm.S | 113 | ||||
-rwxr-xr-x | cortex-m-rt/assemble.sh | 33 | ||||
-rw-r--r-- | cortex-m-rt/bin/thumbv6m-none-eabi.a | bin | 2738 -> 0 bytes | |||
-rw-r--r-- | cortex-m-rt/bin/thumbv7em-none-eabi.a | bin | 2746 -> 0 bytes | |||
-rw-r--r-- | cortex-m-rt/bin/thumbv7em-none-eabihf.a | bin | 2778 -> 0 bytes | |||
-rw-r--r-- | cortex-m-rt/bin/thumbv7m-none-eabi.a | bin | 2746 -> 0 bytes | |||
-rw-r--r-- | cortex-m-rt/bin/thumbv8m.base-none-eabi.a | bin | 2742 -> 0 bytes | |||
-rw-r--r-- | cortex-m-rt/bin/thumbv8m.main-none-eabi.a | bin | 2750 -> 0 bytes | |||
-rw-r--r-- | cortex-m-rt/bin/thumbv8m.main-none-eabihf.a | bin | 2782 -> 0 bytes | |||
-rw-r--r-- | cortex-m-rt/build.rs | 15 | ||||
-rwxr-xr-x | cortex-m-rt/check-blobs.sh | 21 | ||||
-rwxr-xr-x | cortex-m-rt/ci/script.sh | 32 | ||||
-rw-r--r-- | cortex-m-rt/examples/qemu.rs | 30 | ||||
-rw-r--r-- | cortex-m-rt/link.x.in | 8 | ||||
-rw-r--r-- | cortex-m-rt/macros/Cargo.toml | 3 | ||||
-rw-r--r-- | cortex-m-rt/src/lib.rs | 213 | ||||
-rw-r--r-- | cortex-m-rt/tests/compile-fail/non-static-resource.rs | 4 |
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 Binary files differdeleted file mode 100644 index c145cc6..0000000 --- a/cortex-m-rt/bin/thumbv6m-none-eabi.a +++ /dev/null diff --git a/cortex-m-rt/bin/thumbv7em-none-eabi.a b/cortex-m-rt/bin/thumbv7em-none-eabi.a Binary files differdeleted file mode 100644 index 2d6b6a1..0000000 --- a/cortex-m-rt/bin/thumbv7em-none-eabi.a +++ /dev/null diff --git a/cortex-m-rt/bin/thumbv7em-none-eabihf.a b/cortex-m-rt/bin/thumbv7em-none-eabihf.a Binary files differdeleted file mode 100644 index aa765ea..0000000 --- a/cortex-m-rt/bin/thumbv7em-none-eabihf.a +++ /dev/null diff --git a/cortex-m-rt/bin/thumbv7m-none-eabi.a b/cortex-m-rt/bin/thumbv7m-none-eabi.a Binary files differdeleted file mode 100644 index 3d1783c..0000000 --- a/cortex-m-rt/bin/thumbv7m-none-eabi.a +++ /dev/null diff --git a/cortex-m-rt/bin/thumbv8m.base-none-eabi.a b/cortex-m-rt/bin/thumbv8m.base-none-eabi.a Binary files differdeleted file mode 100644 index a9fb434..0000000 --- a/cortex-m-rt/bin/thumbv8m.base-none-eabi.a +++ /dev/null diff --git a/cortex-m-rt/bin/thumbv8m.main-none-eabi.a b/cortex-m-rt/bin/thumbv8m.main-none-eabi.a Binary files differdeleted file mode 100644 index 40a5c51..0000000 --- a/cortex-m-rt/bin/thumbv8m.main-none-eabi.a +++ /dev/null diff --git a/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a b/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a Binary files differdeleted file mode 100644 index 6c523af..0000000 --- a/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a +++ /dev/null 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] |