├── .cargo └── config ├── .github ├── CODEOWNERS ├── bors.toml └── workflows │ ├── ci.yml │ ├── clippy.yml │ └── rustfmt.yml ├── .gitignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── asm.S ├── assemble.sh ├── bin ├── thumbv6m-none-eabi.a ├── thumbv7em-none-eabi.a ├── thumbv7em-none-eabihf.a ├── thumbv7m-none-eabi.a ├── thumbv8m.base-none-eabi.a ├── thumbv8m.main-none-eabi.a └── thumbv8m.main-none-eabihf.a ├── build.rs ├── check-blobs.sh ├── ci └── script.sh ├── device.x ├── examples ├── alignment.rs ├── cfg-static.rs ├── data_overflow.rs ├── device.rs ├── divergent-default-handler.rs ├── divergent-exception.rs ├── entry-static.rs ├── main.rs ├── minimal.rs ├── override-exception.rs ├── pre_init.rs ├── qemu.rs ├── state.rs ├── unsafe-default-handler.rs ├── unsafe-entry.rs ├── unsafe-exception.rs ├── unsafe-hard-fault.rs ├── unsafety.rs └── warnings.rs ├── link.x.in ├── macros ├── Cargo.toml └── src │ └── lib.rs ├── memory.x ├── src └── lib.rs ├── tests ├── compile-fail │ ├── default-handler-bad-signature-1.rs │ ├── default-handler-bad-signature-2.rs │ ├── default-handler-hidden.rs │ ├── default-handler-twice.rs │ ├── duplicate-static.rs │ ├── entry-args.rs │ ├── entry-bad-signature-1.rs │ ├── entry-bad-signature-2.rs │ ├── entry-bad-signature-3.rs │ ├── entry-hidden.rs │ ├── entry-soundness.rs │ ├── entry-twice.rs │ ├── exception-args.rs │ ├── exception-bad-signature-1.rs │ ├── exception-bad-signature-2.rs │ ├── exception-hidden.rs │ ├── exception-nmi-unsafe.rs │ ├── exception-soundness.rs │ ├── exception-twice.rs │ ├── exception-v8only.rs │ ├── hard-fault-bad-signature-1.rs │ ├── hard-fault-hidden.rs │ ├── hard-fault-twice.rs │ ├── interrupt-args.rs │ ├── interrupt-bad-signature-1.rs │ ├── interrupt-bad-signature-2.rs │ ├── interrupt-invalid.rs │ ├── interrupt-not-reexported.rs │ ├── interrupt-soundness.rs │ ├── interrupt-twice.rs │ ├── non-static-resource.rs │ ├── pre-init-args.rs │ ├── pre-init-bad-signature-1.rs │ ├── pre-init-bad-signature-2.rs │ ├── pre-init-hidden.rs │ ├── pre-init-twice.rs │ ├── unsafe-init-static.rs │ ├── whitelist-1.rs │ ├── whitelist-2.rs │ ├── whitelist-3.rs │ ├── whitelist-4.rs │ └── whitelist-double-attr.rs └── compiletest.rs └── triagebot.toml /.cargo/config: -------------------------------------------------------------------------------- 1 | [target.thumbv6m-none-eabi] 2 | runner = "qemu-system-arm -cpu cortex-m0 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel" 3 | 4 | [target.thumbv7m-none-eabi] 5 | runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel" 6 | 7 | [target.thumbv7em-none-eabi] 8 | runner = "qemu-system-arm -cpu cortex-m4 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel" 9 | 10 | [target.thumbv7em-none-eabihf] 11 | runner = "qemu-system-arm -cpu cortex-m4 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel" 12 | 13 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] 14 | # uncomment ONE of these three option to make `cargo run` start a GDB session 15 | # which option to pick depends on your system 16 | # runner = "arm-none-eabi-gdb -q -x openocd.gdb" 17 | # runner = "gdb-multiarch -q -x openocd.gdb" 18 | # runner = "gdb -q -x openocd.gdb" 19 | 20 | rustflags = [ 21 | # LLD (shipped with the Rust toolchain) is used as the default linker 22 | "-C", "link-arg=-Tlink.x", 23 | 24 | # if you run into problems with LLD switch to the GNU linker by commenting out 25 | # this line 26 | # "-C", "linker=arm-none-eabi-ld", 27 | 28 | # if you need to link to pre-compiled C libraries provided by a C toolchain 29 | # use GCC as the linker by commenting out both lines above and then 30 | # uncommenting the three lines below 31 | # "-C", "linker=arm-none-eabi-gcc", 32 | # "-C", "link-arg=-Wl,-Tlink.x", 33 | # "-C", "link-arg=-nostartfiles", 34 | ] 35 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @rust-embedded/cortex-m 2 | -------------------------------------------------------------------------------- /.github/bors.toml: -------------------------------------------------------------------------------- 1 | block_labels = ["needs-decision"] 2 | delete_merged_branches = true 3 | required_approvals = 1 4 | status = [ 5 | "ci-linux (stable)", 6 | "ci-linux (1.39.0)", 7 | "build-other (macOS-latest)", 8 | "build-other (windows-latest)", 9 | "Rustfmt" 10 | ] 11 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [ staging, trying, master ] 4 | pull_request: 5 | 6 | name: Continuous integration 7 | 8 | jobs: 9 | ci-linux: 10 | runs-on: ubuntu-20.04 11 | continue-on-error: ${{ matrix.experimental || false }} 12 | strategy: 13 | matrix: 14 | # All generated code should be running on stable now 15 | rust: [nightly, stable, 1.39.0] 16 | 17 | include: 18 | # Nightly is only for reference and allowed to fail 19 | - rust: nightly 20 | experimental: true 21 | 22 | steps: 23 | - uses: actions/checkout@v2 24 | - uses: actions-rs/toolchain@v1 25 | with: 26 | profile: minimal 27 | toolchain: ${{ matrix.rust }} 28 | override: true 29 | - name: Install all Rust targets for ${{ matrix.rust }} 30 | run: rustup target install --toolchain=${{ matrix.rust }} thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi thumbv7em-none-eabihf thumbv8m.base-none-eabi thumbv8m.main-none-eabi thumbv8m.main-none-eabihf 31 | - name: Install qemu and gcc 32 | run: sudo apt-get update && sudo apt-get install qemu-system-arm gcc-arm-none-eabi 33 | - name: Run CI script for x86_64-unknown-linux-gnu under ${{ matrix.rust }} 34 | run: TARGET=x86_64-unknown-linux-gnu TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh 35 | - name: Run CI script for thumbv6m-none-eabi under ${{ matrix.rust }} 36 | run: TARGET=thumbv6m-none-eabi TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh 37 | - name: Run CI script for thumbv7m-none-eabi under ${{ matrix.rust }} 38 | run: TARGET=thumbv7m-none-eabi TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh 39 | - name: Run CI script for thumbv7em-none-eabi under ${{ matrix.rust }} 40 | run: TARGET=thumbv7em-none-eabi TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh 41 | - name: Run CI script for thumbv7em-none-eabihf under ${{ matrix.rust }} 42 | run: TARGET=thumbv7em-none-eabihf TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh 43 | - name: Run CI script for thumbv8m.base-none-eabi under ${{ matrix.rust }} 44 | run: TARGET=thumbv8m.base-none-eabi TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh 45 | - name: Run CI script for thumbv8m.main-none-eabi under ${{ matrix.rust }} 46 | run: TARGET=thumbv8m.main-none-eabi TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh 47 | - name: Run CI script for thumbv8m.main-none-eabihf under ${{ matrix.rust }} 48 | run: TARGET=thumbv8m.main-none-eabihf TRAVIS_RUST_VERSION=${{ matrix.rust }} bash ci/script.sh 49 | 50 | # On macOS and Windows, we at least make sure that all examples build and link. 51 | build-other: 52 | strategy: 53 | matrix: 54 | os: 55 | - macOS-latest 56 | - windows-latest 57 | runs-on: ${{ matrix.os }} 58 | 59 | steps: 60 | - uses: actions/checkout@v2 61 | - uses: actions-rs/toolchain@v1 62 | with: 63 | profile: minimal 64 | toolchain: stable 65 | override: true 66 | - name: Install all Rust targets 67 | run: rustup target install thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi thumbv7em-none-eabihf thumbv8m.base-none-eabi thumbv8m.main-none-eabi thumbv8m.main-none-eabihf 68 | - name: Build examples for thumbv6m-none-eabi 69 | run: cargo build --target=thumbv6m-none-eabi --examples 70 | - name: Build examples for thumbv7m-none-eabi 71 | run: cargo build --target=thumbv7m-none-eabi --examples 72 | - name: Build examples for thumbv7em-none-eabi 73 | run: cargo build --target=thumbv7em-none-eabi --examples 74 | - name: Build examples for thumbv7em-none-eabihf 75 | run: cargo build --target=thumbv7em-none-eabihf --examples 76 | - name: Build examples for thumbv8m.base-none-eabi 77 | run: cargo build --target=thumbv8m.base-none-eabi --examples 78 | - name: Build examples for thumbv8m.main-none-eabi 79 | run: cargo build --target=thumbv8m.main-none-eabi --examples 80 | - name: Build examples for thumbv8m.main-none-eabihf 81 | run: cargo build --target=thumbv8m.main-none-eabihf --examples 82 | - name: Build crate for host OS 83 | run: cargo build 84 | -------------------------------------------------------------------------------- /.github/workflows/clippy.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [ staging, trying, master ] 4 | pull_request: 5 | 6 | name: Clippy check 7 | jobs: 8 | clippy_check: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions-rs/toolchain@v1 13 | with: 14 | profile: minimal 15 | toolchain: stable 16 | override: true 17 | components: clippy 18 | - uses: actions-rs/clippy-check@v1 19 | with: 20 | token: ${{ secrets.GITHUB_TOKEN }} 21 | -------------------------------------------------------------------------------- /.github/workflows/rustfmt.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [ staging, trying, master ] 4 | pull_request: 5 | 6 | name: Code formatting check 7 | 8 | jobs: 9 | fmt: 10 | name: Rustfmt 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions-rs/toolchain@v1 15 | with: 16 | profile: minimal 17 | toolchain: stable 18 | override: true 19 | components: rustfmt 20 | - uses: actions-rs/cargo@v1 21 | with: 22 | command: fmt 23 | args: --all -- --check 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.rs.bk 2 | .#* 3 | Cargo.lock 4 | bin/*.after 5 | bin/*.before 6 | bin/*.o 7 | target/ 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 6 | and this project adheres to [Semantic Versioning](http://semver.org/). 7 | 8 | ## [Unreleased] 9 | 10 | ## [v0.7.1] 11 | 12 | ## Fixes 13 | 14 | - Fix stack unwinding past `Reset` function ([#337]) 15 | 16 | [#337]: https://github.com/rust-embedded/cortex-m-rt/pull/337 17 | 18 | ## [v0.7.0] 19 | 20 | ### New Features 21 | 22 | - Add support for CMSE secure gateway veneers ([#297]). 23 | - Allow using the crate with custom target JSON specs ([#304]). 24 | - Export Exception enum for other crates to use ([#224]). 25 | 26 | [#224]: https://github.com/rust-embedded/cortex-m-rt/pull/224 27 | [#297]: https://github.com/rust-embedded/cortex-m-rt/pull/297 28 | [#304]: https://github.com/rust-embedded/cortex-m-rt/pull/304 29 | 30 | ### Fixes 31 | 32 | - Various fixes to the linker script ([#265], [#286], [#287], [#323]). 33 | - Use the correct ABI for the `main` symbol ([#278]). 34 | - Add barriers after FPU enabling ([#279]). 35 | - (ARMv6-M) Set LR value to a known value on reset ([#293]). 36 | - Added CFI and size info to external assembly subroutines (`HardFaultTrampoline` and `FpuTrampoline`) ([#294]). 37 | - Allow building the crate for macOS targets ([#306], [#310]). 38 | - Perform RAM initialization in assembly, to avoid potential UB in Rust ([#301]). 39 | - Perform volatile reads of ICSR in DefaultHandler ([#315]). 40 | 41 | [#265]: https://github.com/rust-embedded/cortex-m-rt/pull/265 42 | [#278]: https://github.com/rust-embedded/cortex-m-rt/pull/278 43 | [#279]: https://github.com/rust-embedded/cortex-m-rt/pull/279 44 | [#286]: https://github.com/rust-embedded/cortex-m-rt/pull/286 45 | [#287]: https://github.com/rust-embedded/cortex-m-rt/pull/287 46 | [#293]: https://github.com/rust-embedded/cortex-m-rt/pull/293 47 | [#294]: https://github.com/rust-embedded/cortex-m-rt/pull/294 48 | [#301]: https://github.com/rust-embedded/cortex-m-rt/pull/301 49 | [#306]: https://github.com/rust-embedded/cortex-m-rt/pull/306 50 | [#310]: https://github.com/rust-embedded/cortex-m-rt/pull/310 51 | [#315]: https://github.com/rust-embedded/cortex-m-rt/pull/315 52 | [#323]: https://github.com/rust-embedded/cortex-m-rt/pull/323 53 | 54 | ### Breaking Changes 55 | 56 | - Make `ExceptionFrame`s fields private, adding setters and getters instead 57 | ([#239]). 58 | - Only allow certain attributes on handlers, and apply them to the trampoline 59 | too ([#228]). 60 | - Make it unsafe to define exception handlers for NMIs ([#289]). 61 | - Check that exceptions exist on the target chip when registering a handler for 62 | them ([#308]). 63 | 64 | [#239]: https://github.com/rust-embedded/cortex-m-rt/pull/239 65 | [#228]: https://github.com/rust-embedded/cortex-m-rt/pull/228 66 | [#289]: https://github.com/rust-embedded/cortex-m-rt/pull/289 67 | [#308]: https://github.com/rust-embedded/cortex-m-rt/pull/308 68 | 69 | ### Other 70 | 71 | - Change macros crate to use same version number as cortex-m-rt crate ([#245]). 72 | - Discourage use of `pre_init` in documentation ([#248]). 73 | - Backport: Use `links` in Cargo.toml to prevent multiple linking of 74 | cortex-m-rt ([#276]). 75 | 76 | [#245]: https://github.com/rust-embedded/cortex-m-rt/pull/245 77 | [#248]: https://github.com/rust-embedded/cortex-m-rt/pull/248 78 | [#276]: https://github.com/rust-embedded/cortex-m-rt/pull/276 79 | 80 | ## Backport release: [v0.6.15] - 2021-07-12 81 | 82 | ### Fixed 83 | 84 | - Backport: Mark .bss as NOLOAD ([#265]) 85 | - Backport: Fix possible overflow of .data region ([#286]) 86 | - Backport: Perform volatile reads of ICSR in DefaultHandler ([#315]) 87 | 88 | ### Other 89 | - Backport: Use `links` in Cargo.toml to prevent multiple linking of 90 | cortex-m-rt ([#276]) 91 | - Backport: Use same verison for macros crate as for cortex-m-rt itself 92 | ([#245]) 93 | 94 | [#245]: https://github.com/rust-embedded/cortex-m-rt/pull/245 95 | [#265]: https://github.com/rust-embedded/cortex-m-rt/pull/265 96 | [#276]: https://github.com/rust-embedded/cortex-m-rt/pull/276 97 | [#286]: https://github.com/rust-embedded/cortex-m-rt/pull/286 98 | [#315]: https://github.com/rust-embedded/cortex-m-rt/pull/315 99 | 100 | ## [v0.6.14] - 2021-05-19 101 | 102 | ### Fixed 103 | 104 | - Backport: Allow building the crate for macOS targets ([#306], [#310]). 105 | 106 | [#306]: https://github.com/rust-embedded/cortex-m-rt/issues/306 107 | [#310]: https://github.com/rust-embedded/cortex-m-rt/issues/310 108 | 109 | ## Backport release: [v0.6.13] - 2020-09-07 110 | 111 | ### Fixed 112 | 113 | - (ARMv6-M) Set LR value to a known value on reset (as the ARM spec requires) 114 | - Added CFI and size info to external assembly subroutines (`HardFaultTrampoline`) 115 | 116 | ## Backport release: [v0.6.12] - 2020-01-26 117 | 118 | ### Fixed 119 | 120 | - Fixed lint warnings getting emitted on macro-generated code. 121 | 122 | ## [v0.6.11] - 2019-12-04 123 | 124 | ### Changed 125 | 126 | - Macros now generate a second trampoline function instead of randomizing the 127 | function's symbol name. This makes the build deterministic. 128 | - [breaking-change] `static mut` resources no longer have `'static` lifetime 129 | except in the `#[entry]` function (this is a soundness fix; see [#212]). 130 | 131 | [#212]: https://github.com/rust-embedded/cortex-m-rt/issues/212 132 | 133 | ## [v0.6.10] - 2019-07-25 134 | 135 | ### Fixed 136 | 137 | - Linker template now takes and discard `*(.ARM.exidx)` 138 | 139 | ## [v0.6.9] - 2019-07-11 140 | 141 | ### Added 142 | 143 | - Input `.uninit.*` sections are now collected into an output `.uninit` section. 144 | Uninitialized static variables are meant to be placed in these sections. The 145 | output `.uninit` section is not initialized by the runtime. 146 | 147 | ## [v0.6.8] - 2019-04-02 148 | 149 | ### Fixed 150 | 151 | - Correct stack-pointer is selected on `HardFault` 152 | - Linker template now takes and discard `*(.ARM.extab.*)` 153 | - Misc. documentation fixes 154 | 155 | ### Changed 156 | 157 | - Architecture added: `armv8-m.main` 158 | - Cortex-M team added to `authors` 159 | - The nightly build is allowed to fail in CI 160 | 161 | ## [v0.6.7] - 2018-12-15 162 | 163 | ### Fixed 164 | 165 | - entry / exception / interrupt: `#[cfg]` attributes used on `static mut` 166 | variables are now properly handled. 167 | 168 | ## [v0.6.6] - 2018-12-06 169 | 170 | ### Changed 171 | 172 | - Misuse of attributes now produce compiler errors with proper spans instead of 173 | panicking messages. 174 | 175 | - The `HardFault` symbol has been renamed to `HardFaultTrampoline`; likewise the 176 | `UserHardFault` symbol has been renamed to `HardFault`. If you were using 177 | breakpoints on `UserHardFault` to detect hard fault you should now put those 178 | breakpoints on the `HardFault` symbol. 179 | 180 | ### Fixed 181 | 182 | - Attributes on local `static mut` variables (declared at the beginning of 183 | `entry` / `interrupt` / `exception`) are now respected. 184 | 185 | - The "GDB can now unwind HardFault callstacks" fix from the previous release 186 | broke `HardFault`'s' `&ExceptionFrame` argument (the pointer was off by 8 187 | bytes). This release fixes that problem without compromising GDB's ability to 188 | unwind `HardFault`s. 189 | 190 | ## [v0.6.5] - 2018-10-23 191 | 192 | ### Changed 193 | 194 | - We now keep `.stack_sizes` by default, for use with external tooling. 195 | - (macros) New `#[interrupt]` attribute added, similar to `#[exception]` for 196 | use with device-specific interrupt handlers. 197 | 198 | ### Fixed 199 | 200 | - GDB can now unwind HardFault callstacks 201 | 202 | ## [v0.6.4] - 2018-09-25 203 | 204 | ### Changed 205 | 206 | - (macros) Improved the error message when any of the attribute is used on the 207 | wrong kind of item. 208 | 209 | ### Fixed 210 | 211 | - (macros) The expansion of the `exception` attribute now uses the `extern "C"` 212 | ABI which is what the hardware expects. 213 | 214 | - (macros) `entry` and `exception` now respect the declared unsafety. That is 215 | `#[entry] unsafe main() -> !` won't require `unsafe` blocks to use `unsafe` 216 | API. 217 | 218 | ## [v0.6.3] - 2018-09-09 219 | 220 | ### Fixed 221 | 222 | - Fixed the `rand` problem for real. 223 | 224 | ## [v0.6.2] - 2018-09-09 225 | 226 | ### Fixed 227 | 228 | - Worked around a Cargo limitation that broke builds that depend on `rand`. 229 | 230 | - Updated the documentation link in the README to point to working docs. 231 | 232 | ## [v0.6.1] - 2018-09-06 233 | 234 | ### Changed 235 | 236 | - Produce a better error message if two (or more) copies of `cortex-m-rt` are 237 | going to be linked into a binary. 238 | 239 | ## [v0.6.0] - 2018-09-06 240 | 241 | ### Changed 242 | 243 | - [breaking-change] the `entry!`, `pre_init!` and `exception!` macros have been 244 | replaced with attributes: `#[entry]`, `#[pre_init]` and `#[exception]`, 245 | respectively. This also changes the toolchain requirement to 1.30-beta or 246 | newer. 247 | 248 | ## [v0.5.3] - 2018-08-27 249 | 250 | ### Changed 251 | 252 | - This crate no longer depends on `arm-none-eabi-gcc`. 253 | 254 | ## [v0.5.2] - 2018-08-11 255 | 256 | ### Added 257 | 258 | * A `pre_init!` macro and related functionality to run a function immediately 259 | after reset, before memory initialisation 260 | 261 | ### Changed 262 | 263 | - The `entry!` and `exception!` macros now also accept a closure instead of a path. 264 | 265 | - `DefaultHandler` and `UserHardFault` now default to an infinite loop if left undefined. 266 | 267 | ### Fixed 268 | 269 | * Linked script modified to correctly detect `FLASH` overflow caused by `.data` 270 | 271 | ## [v0.5.1] - 2018-05-14 272 | 273 | ### Fixed 274 | 275 | - A recompilation problem where this `cortex-m-rt` would be recompiled every time `cargo build` is 276 | invoked. 277 | 278 | ## [v0.5.0] - 2018-05-12 279 | 280 | ### Added 281 | 282 | - An `entry!` macro to set the entry point of the program. 283 | 284 | - A `heap_start` function that returns a pointer into the start of the heap region. 285 | 286 | - A `device` feature. When disabled this crate provides the interrupt vectors; when enabled the 287 | interrupt vectors are expected to be provided by another crate. Read the documentation for 288 | details. 289 | 290 | ### Changed 291 | 292 | - This crate now compiles on the beta and stable channels. 293 | 294 | - [breaking-change] this crate now requires `arm-none-eabi-gcc` to be installed and available in 295 | `$PATH` to compile. 296 | 297 | - [breaking-change] the `start` lang item has been removed. The standard `main` interface won't 298 | work. Instead use `#![no_main]` and the `entry!` macro. See documentation for details. 299 | 300 | - [breaking-change] the `default_handler!` macro has been merged into the `exception!` macro. Use 301 | `exception!(*, ..)` to set the default exception handler. 302 | 303 | - [breaking-change] there's no weak default handler so a default handler must be defined by the 304 | application, or one of its dependencies. 305 | 306 | - [breaking-change] the syntax of the third argument of the `exception!` handler has changed. See 307 | the documentation of the macro for details. 308 | 309 | - [breaking-change] the exception names that the `exception!` macro accepts has changed to match the 310 | CMSIS specification. See the documentation of the macro for the list of names it accepts. 311 | 312 | - [breaking-change] The number of symbol interfaces has been reduced. Check the advanced section of 313 | the documentation for details. 314 | 315 | ## [v0.4.0] - 2018-04-09 316 | 317 | ### Added 318 | 319 | - LLD support. The linker script provided by this crate has been tweaked to support both LLD and GNU 320 | LD. To use LLD as a linker change `.cargo/config` to look like this: 321 | 322 | ``` diff 323 | [target.thumbv7m-none-eabi] 324 | rustflags = [ 325 | "-C", "link-arg=-Tlink.x", 326 | - "-C", "linker=arm-none-eabi-ld", 327 | - "-Z", "linker-flavor=ld", 328 | + "-C", "linker=lld", 329 | + "-Z", "linker-flavor=ld.lld", 330 | ] 331 | ``` 332 | 333 | ### Removed 334 | 335 | - [breaking-change] Stack overflow protection has been removed. Unfortunately, supporting this 336 | feature produces totally wrong `arm-none-eabi-size` reports when LLD is used to link the 337 | program. If you need the stack overflow protection feature you can continue to use version 338 | v0.3.13+. 339 | 340 | - [breaking-change] The "abort-on-panic" Cargo feature, which provided a `panic_fmt` implementation, 341 | has been removed. If you were using this feature you can instead use a [panic implementation 342 | crate][panic-impl]. 343 | 344 | [panic-impl]: https://crates.io/keywords/panic-impl 345 | 346 | ## [v0.3.15] - 2018-04-08 347 | 348 | ### Fixed 349 | 350 | - Support the newest nightly 351 | 352 | ## [v0.3.14] - 2018-04-01 353 | 354 | ### Fixed 355 | 356 | - `dev` channel support 357 | 358 | ## [v0.3.13] - 2018-02-17 359 | 360 | ### Added 361 | 362 | - Fictitious `.stack` and `.heap` linker sections that represent the locations of the stack and the 363 | heap in RAM. You can visualize these linker sections by running `arm-none-eabi-size -Ax` over your 364 | binary. 365 | 366 | - Zero cost stack overflow protection when you use the `cortex-m-rt-ld` linker. Check documentation 367 | for details. 368 | 369 | - A `_heap_size` symbol that indicates how large the heap is. This symbol is only used when 370 | `cortex-m-rt-ld` is used as a linker. 371 | 372 | ## [v0.3.12] - 2018-01-17 373 | 374 | ### Fixed 375 | 376 | - Support for recent nightlies. 377 | 378 | ## [v0.3.11] - 2018-01-17 - YANKED 379 | 380 | ### Changed 381 | 382 | - Dynamically support recent nightlies, which have the `termination` lang item, and 383 | nightly-2017-09-22, which doesn't. That nightly version is used by the docs.rs builder. Supporting 384 | that version instead of rejecting it ensures this crate and its reverse-dependencies will get 385 | their documentation built by the docs.rs service. 386 | 387 | ## [v0.3.10] - 2018-01-17 - YANKED 388 | 389 | ### Removed 390 | 391 | - The nightly date check from build script that improved error messages for users of old, 392 | unsupported nightlies. Unfortunately the check was preventing this crate and reverse-dependencies 393 | from getting their documentation build on docs.rs 394 | 395 | ## [v0.3.9] - 2018-01-07 396 | 397 | ### Fixed 398 | 399 | - `cargo doc` warnings 400 | 401 | ## [v0.3.8] - 2017-12-29 402 | 403 | ### Added 404 | 405 | - `Termination` lang item 406 | 407 | ### Changed 408 | 409 | - The `start` lang item to match the new signature 410 | 411 | ## [v0.3.7] - 2017-12-23 412 | 413 | ### Added 414 | 415 | - Support for overriding the DEBUG_MONITOR exception handler on ARMv7-M. 416 | 417 | ## [v0.3.6] - 2017-10-03 418 | 419 | ### Fixed 420 | 421 | - Builds with multiple codegen units by forcing the linker to look harder for the exceptions vector 422 | table. 423 | 424 | ## [v0.3.5] - 2017-07-21 425 | 426 | ### Fixed 427 | 428 | - Remove duplication of default exception handlers. This saves 32 bytes of Flash 429 | memory (.text). 430 | 431 | ## [v0.3.4] - 2017-07-19 432 | 433 | ### Changed 434 | 435 | - Align the end of .rodata to a 4-byte boundary. With this the sections that 436 | will go into Flash memory will be 4 byte aligned at the start and at the 437 | end. Which seems to be required (?) by Cortex-M0 devices. 438 | 439 | - .bss and .data are now padded so their sizes are multiple of 4 bytes. This 440 | improves the output of `objdump`; before, the output showed "Address 441 | 0x20000004 is out of bounds". 442 | 443 | - Linking now aborts if any of the input files contains a .got section. Dynamic 444 | relocations are not supported and Rust code is not relocatable by default. 445 | This error only occurs if C code that was compiled with the -fPIC flag is 446 | linked in. The error message will tell the user how to compile their C code 447 | without -fPIC. 448 | 449 | ## [v0.3.3] - 2017-07-14 450 | 451 | ### Changed 452 | 453 | - Updated the documentation: it's no longer necessary to use the 454 | compiler-builtins repository since that crate landed in rust-lang/rust and 455 | it's now available in the `rust-src` component. 456 | 457 | ## [v0.3.2] - 2017-07-07 458 | 459 | ### Changed 460 | 461 | - Tweaked documentation 462 | 463 | ## [v0.3.1] - 2017-07-07 464 | 465 | ### Fixed 466 | 467 | - A warning when compiling for x86_64 and the "abort-on-panic" feature is 468 | enabled. 469 | 470 | ## [v0.3.0] - 2017-07-07 471 | 472 | ### Added 473 | 474 | - A `default_handler!` macro to override the default exception handler. 475 | 476 | - An `exception!` macro to override the handler for a particular exception. 477 | 478 | ### Changed 479 | 480 | - The FPU will now be enabled before `main` if the target has FPU support. 481 | 482 | - [breaking-change] the features "panic-over-itm" and "panic-over-semihosting" 483 | has been removed. the `panic_fmt` language item is now *not* included by 484 | default. An opt-in feature named "abort-on-panic" can be enabled to make this 485 | crate provide a `panic_fmt` implementation that simply aborts. 486 | 487 | - [breaking-change] The sections `.rodata.{exceptions,interrupts}` have been 488 | renamed to `.vector_table.{exceptions,interrupts}`. This break the old 489 | mechanism for registering exceptions (`static EXCEPTIONS`); use the new ones: 490 | `default_handler!` and `exception!`. 491 | 492 | - The `_stack_start` is now optional in the `memory.x` file. If unspecified its 493 | value will be set to `ORIGIN(RAM) + LENGTH(RAM)`. 494 | 495 | ## [v0.2.4] - 2017-06-03 496 | 497 | ### Added 498 | 499 | - A non-allocatable `.stlog` section to support the [`stlog`] logging framework. 500 | 501 | [`stlog`]: https://crates.io/crates/stlog 502 | 503 | ## [v0.2.3] - 2017-05-30 504 | 505 | ### Added 506 | 507 | - A `_stext` symbol which can be specified in the linker script to customize the 508 | location of the `.text` section. If not specified the `.text` section will be 509 | placed right after the `.vector_table` section. 510 | 511 | ## [v0.2.2] - 2017-05-27 512 | 513 | ### Added 514 | 515 | - A `_sheap` symbol where the heap can be located. 516 | 517 | ### Changed 518 | 519 | - The linker sections have renamed / reorder to make `arm-none-eabi-size -A` 520 | more useful. You'll now see something like this: 521 | 522 | ``` 523 | $ arm-none-eabi-size -A hello 524 | hello : 525 | section size addr 526 | .vector_table 1024 134217728 527 | .text 288 134218752 528 | .rodata 14 134219040 529 | ``` 530 | 531 | - `cortex-m-rt::reset_handler` is now the entry point of all programs that link 532 | to `cortex-m-rt`. This makes GDB's `load` command work correctly. It will now 533 | set the Program Counter to `reset_handler` after flashing the program so 534 | there's no need to reset the microcontroller after flashing. 535 | 536 | - Renamed `__exceptions` and `__interrupts` symbols, which are only used 537 | internally, to `_eexceptions` and `_einterrupts` respectively for consistency. 538 | 539 | ### Fixed 540 | 541 | - Include input `.text` and `.rodata` sections (note: no suffix as in 542 | `.text.foo`) in the output file. (C) Code compiled without the equivalent 543 | `-ffunction-sections` / `-fdata-sections` may place stuff in those unsuffixed 544 | sections. 545 | 546 | ## [v0.2.1] - 2017-05-07 547 | 548 | ### Fixed 549 | 550 | - Do not load the `.debug_gdb_script` section in flash. It's only needed for 551 | debugging. 552 | 553 | ## [v0.2.0] - 2017-04-27 554 | 555 | ### Changed 556 | 557 | - [breaking-change] the `_stack_start` symbol is now required and must be 558 | provided in the `memory.x` file when using the "linker-script" feature. This 559 | symbol indicates where in memory the call stack will be allocated. 560 | 561 | ## [v0.1.3] - 2017-04-25 562 | 563 | ### Fixed 564 | 565 | - A `rustdoc` warning 566 | 567 | ## [v0.1.2] - 2017-04-22 568 | 569 | ### Changed 570 | 571 | - Unclutter the `reset_handler` function for a better debugging experience. 572 | 573 | ## [v0.1.1] - 2017-04-15 574 | 575 | ### Changed 576 | 577 | - Improved linker error messages 578 | 579 | ## v0.1.0 - 2017-04-12 580 | 581 | Initial release 582 | 583 | [Unreleased]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.7.1...HEAD 584 | [v0.7.1]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.7.0...v0.7.1 585 | [v0.7.0]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.11...v0.7.0 586 | [v0.6.15]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.14...v0.6.15 587 | [v0.6.14]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.13...v0.6.14 588 | [v0.6.13]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.12...v0.6.13 589 | [v0.6.12]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.11...v0.6.12 590 | [v0.6.11]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.10...v0.6.11 591 | [v0.6.10]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.9...v0.6.10 592 | [v0.6.9]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.8...v0.6.9 593 | [v0.6.8]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.7...v0.6.8 594 | [v0.6.7]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.6...v0.6.7 595 | [v0.6.6]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.5...v0.6.6 596 | [v0.6.5]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.4...v0.6.5 597 | [v0.6.4]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.3...v0.6.4 598 | [v0.6.3]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.2...v0.6.3 599 | [v0.6.2]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.1...v0.6.2 600 | [v0.6.1]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.0...v0.6.1 601 | [v0.6.0]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.5.3...v0.6.0 602 | [v0.5.3]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.5.2...v0.5.3 603 | [v0.5.2]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.5.1...v0.5.2 604 | [v0.5.1]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.5.0...v0.5.1 605 | [v0.5.0]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.4.0...v0.5.0 606 | [v0.4.0]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.3.15...v0.4.0 607 | [v0.3.15]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.3.14...v0.3.15 608 | [v0.3.14]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.3.13...v0.3.14 609 | [v0.3.13]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.3.12...v0.3.13 610 | [v0.3.12]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.3.11...v0.3.12 611 | [v0.3.11]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.3.10...v0.3.11 612 | [v0.3.10]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.3.9...v0.3.10 613 | [v0.3.9]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.3.8...v0.3.9 614 | [v0.3.8]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.3.7...v0.3.8 615 | [v0.3.7]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.3.6...v0.3.7 616 | [v0.3.6]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.3.5...v0.3.6 617 | [v0.3.5]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.3.4...v0.3.5 618 | [v0.3.4]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.3.3...v0.3.4 619 | [v0.3.3]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.3.2...v0.3.3 620 | [v0.3.2]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.3.1...v0.3.2 621 | [v0.3.1]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.3.0...v0.3.1 622 | [v0.3.0]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.2.4...v0.3.0 623 | [v0.2.4]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.2.3...v0.2.4 624 | [v0.2.3]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.2.2...v0.2.3 625 | [v0.2.2]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.2.1...v0.2.2 626 | [v0.2.1]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.2.0...v0.2.1 627 | [v0.2.0]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.1.3...v0.2.0 628 | [v0.1.3]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.1.2...v0.1.3 629 | [v0.1.2]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.1.1...v0.1.2 630 | [v0.1.1]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.1.0...v0.1.1 631 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # The Rust Code of Conduct 2 | 3 | ## Conduct 4 | 5 | **Contact**: [Cortex-M team](https://github.com/rust-embedded/wg#the-cortex-m-team) 6 | 7 | * We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. 8 | * On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. 9 | * Please be kind and courteous. There's no need to be mean or rude. 10 | * Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. 11 | * Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. 12 | * We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. 13 | * Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [Cortex-M team][team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. 14 | * Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. 15 | 16 | ## Moderation 17 | 18 | These are the policies for upholding our community's standards of conduct. 19 | 20 | 1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.) 21 | 2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. 22 | 3. Moderators will first respond to such remarks with a warning. 23 | 4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off. 24 | 5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded. 25 | 6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology. 26 | 7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed. 27 | 8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others. 28 | 29 | In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely. 30 | 31 | And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust. 32 | 33 | The enforcement policies listed above apply to all official embedded WG venues; including official IRC channels (#rust-embedded); GitHub repositories under rust-embedded; and all forums under rust-embedded.org (forum.rust-embedded.org). 34 | 35 | *Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).* 36 | 37 | [team]: https://github.com/rust-embedded/wg#the-cortex-m-team 38 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = [ 3 | "The Cortex-M Team ", 4 | "Jorge Aparicio ", 5 | "Hideki Sekine ", 6 | ] 7 | categories = ["embedded", "no-std"] 8 | description = "Minimal runtime / startup for Cortex-M microcontrollers" 9 | documentation = "https://docs.rs/cortex-m-rt/" 10 | keywords = ["arm", "cortex-m", "runtime", "startup"] 11 | license = "MIT OR Apache-2.0" 12 | name = "cortex-m-rt" 13 | readme = "README.md" 14 | repository = "https://github.com/rust-embedded/cortex-m-rt" 15 | version = "0.7.1" 16 | autoexamples = true 17 | links = "cortex-m-rt" # Prevent multiple versions of cortex-m-rt being linked 18 | 19 | [dependencies] 20 | cortex-m-rt-macros = { path = "macros", version = "=0.7.0" } 21 | # Note: Do not depend on `cortex-m` here. This crate is used for testing `cortex-m`, so we need to 22 | # avoid pulling in multiple versions of `cortex-m`. 23 | 24 | [dev-dependencies] 25 | cortex-m = "0.7.1" 26 | panic-halt = "0.2.0" 27 | cortex-m-semihosting = "0.3" 28 | 29 | [target.'cfg(not(target_os = "none"))'.dev-dependencies] 30 | compiletest_rs = "0.4.0" 31 | 32 | [[example]] 33 | name = "device" 34 | required-features = ["device"] 35 | 36 | [[example]] 37 | name = "warnings" 38 | required-features = ["device"] 39 | 40 | [[test]] 41 | name = "compiletest" 42 | required-features = ["device"] 43 | 44 | [features] 45 | device = [] 46 | 47 | [package.metadata.docs.rs] 48 | features = ["device"] 49 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Jorge Aparicio 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![crates.io](https://img.shields.io/crates/v/cortex-m-rt.svg)](https://crates.io/crates/cortex-m-rt) 2 | [![crates.io](https://img.shields.io/crates/d/cortex-m-rt.svg)](https://crates.io/crates/cortex-m-rt) 3 | 4 | # `cortex-m-rt` 5 | 6 | > Startup code and minimal runtime for Cortex-M microcontrollers 7 | 8 | **This crate has moved to the [cortex-m] repository, and this repository is 9 | archived. Please direct issues and pull requests to the new repository.** 10 | 11 | [cortex-m]: https://github.com/rust-embedded/cortex-m 12 | 13 | This project is developed and maintained by the [Cortex-M team][team]. 14 | 15 | # [Documentation](https://docs.rs/cortex-m-rt) 16 | 17 | # Minimum Supported Rust Version (MSRV) 18 | 19 | This crate is guaranteed to compile on stable Rust 1.39.0 and up. It *might* 20 | compile with older versions but that may change in any new patch release. 21 | 22 | # License 23 | 24 | Licensed under either of 25 | 26 | - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or 27 | http://www.apache.org/licenses/LICENSE-2.0) 28 | 29 | - MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 30 | 31 | at your option. 32 | 33 | ## Contribution 34 | 35 | Unless you explicitly state otherwise, any contribution intentionally submitted 36 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 37 | dual licensed as above, without any additional terms or conditions. 38 | 39 | ## Code of Conduct 40 | 41 | Contribution to this crate is organized under the terms of the [Rust Code of 42 | Conduct][CoC], the maintainer of this crate, the [Cortex-M team][team], promises 43 | to intervene to uphold that code of conduct. 44 | 45 | [CoC]: CODE_OF_CONDUCT.md 46 | [team]: https://github.com/rust-embedded/wg#the-cortex-m-team 47 | -------------------------------------------------------------------------------- /asm.S: -------------------------------------------------------------------------------- 1 | .cfi_sections .debug_frame 2 | 3 | # Notes for function attributes: 4 | # .type and .thumb_func are _both_ required, otherwise the Thumb mode bit 5 | # will not be set and an invalid vector table is generated. 6 | # LLD requires that section flags are set explicitly. 7 | 8 | .section .HardFaultTrampoline, "ax" 9 | .global HardFaultTrampoline 10 | .type HardFaultTrampoline,%function 11 | .thumb_func 12 | .cfi_startproc 13 | # HardFault exceptions are bounced through this trampoline which grabs the 14 | # stack pointer at the time of the exception and passes it to the user's 15 | # HardFault handler in r0. 16 | HardFaultTrampoline: 17 | # Depending on the stack mode in EXC_RETURN, fetch stack pointer from 18 | # PSP or MSP. 19 | mov r0, lr 20 | mov r1, #4 21 | tst r0, r1 22 | bne 0f 23 | mrs r0, MSP 24 | b HardFault 25 | 0: 26 | mrs r0, PSP 27 | b HardFault 28 | .cfi_endproc 29 | .size HardFaultTrampoline, . - HardFaultTrampoline 30 | 31 | .section .Reset, "ax" 32 | .global Reset 33 | .type Reset,%function 34 | .thumb_func 35 | .cfi_startproc 36 | # Main entry point after reset. This jumps to the user __pre_init function, 37 | # which cannot be called from Rust code without invoking UB, then 38 | # initialises RAM. If the target has an FPU, it is enabled. Finally, jumps 39 | # to the user main function. 40 | Reset: 41 | # ARMv6-M does not initialise LR, but many tools expect it to be 0xFFFF_FFFF 42 | # when reaching the first call frame, so we set it at startup. 43 | # ARMv7-M and above initialise LR to 0xFFFF_FFFF at reset. 44 | ldr r4,=0xffffffff 45 | mov lr,r4 46 | 47 | # Run user pre-init code, which must be executed immediately after startup, 48 | # before the potentially time-consuming memory initialisation takes place. 49 | # Example use cases include disabling default watchdogs or enabling RAM. 50 | bl __pre_init 51 | 52 | # Restore LR after calling __pre_init (r4 is preserved by subroutines). 53 | mov lr,r4 54 | 55 | # Initialise .bss memory. `__sbss` and `__ebss` come from the linker script. 56 | ldr r0,=__sbss 57 | ldr r1,=__ebss 58 | mov r2,#0 59 | 0: 60 | cmp r1, r0 61 | beq 1f 62 | stm r0!, {r2} 63 | b 0b 64 | 1: 65 | 66 | # Initialise .data memory. `__sdata`, `__sidata`, and `__edata` come from the 67 | # linker script. Copy from r2 into r0 until r0 reaches r1. 68 | ldr r0,=__sdata 69 | ldr r1,=__edata 70 | ldr r2,=__sidata 71 | 2: 72 | cmp r1, r0 73 | beq 3f 74 | # load 1 word from r2 to r3, inc r2 75 | ldm r2!, {r3} 76 | # store 1 word from r3 to r0, inc r0 77 | stm r0!, {r3} 78 | b 2b 79 | 3: 80 | 81 | #ifdef HAS_FPU 82 | # Conditionally enable the FPU. 83 | # Address of SCB.CPACR. 84 | ldr r0, =0xE000ED88 85 | # Enable access to CP10 and CP11 from both privileged and unprivileged mode. 86 | ldr r1, =(0b1111 << 20) 87 | # RMW. 88 | ldr r2, [r0] 89 | orr r2, r2, r1 90 | str r2, [r0] 91 | # Barrier is required on some processors. 92 | dsb 93 | isb 94 | #endif 95 | 96 | 4: 97 | # Preserve `lr` and emit debuginfo that lets external tools restore it. 98 | # This fixes unwinding past the `Reset` handler. 99 | # See https://sourceware.org/binutils/docs/as/CFI-directives.html for an 100 | # explanation of the directives. 101 | .cfi_def_cfa sp, 0 102 | push {lr} 103 | .cfi_offset lr, 0 104 | 105 | # Jump to user main function. We use bl for the extended range, but the 106 | # user main function may not return. 107 | bl main 108 | 109 | # Trap on return. 110 | udf 111 | 112 | .cfi_endproc 113 | .size Reset, . - Reset 114 | -------------------------------------------------------------------------------- /assemble.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euxo pipefail 4 | 5 | # cflags taken from cc 1.0.22 6 | 7 | crate=cortex-m-rt 8 | 9 | # remove existing blobs because otherwise this will append object files to the old blobs 10 | rm -f bin/*.a 11 | 12 | arm-none-eabi-gcc -g -c -march=armv6s-m asm.S -o bin/$crate.o 13 | ar crs bin/thumbv6m-none-eabi.a bin/$crate.o 14 | 15 | arm-none-eabi-gcc -g -c -march=armv7-m asm.S -o bin/$crate.o 16 | ar crs bin/thumbv7m-none-eabi.a bin/$crate.o 17 | 18 | arm-none-eabi-gcc -g -c -march=armv7e-m asm.S -o bin/$crate.o 19 | ar crs bin/thumbv7em-none-eabi.a bin/$crate.o 20 | 21 | arm-none-eabi-gcc -g -c -march=armv7e-m asm.S -DHAS_FPU -o bin/$crate.o 22 | ar crs bin/thumbv7em-none-eabihf.a bin/$crate.o 23 | 24 | arm-none-eabi-gcc -g -c -march=armv8-m.base asm.S -o bin/$crate.o 25 | ar crs bin/thumbv8m.base-none-eabi.a bin/$crate.o 26 | 27 | arm-none-eabi-gcc -g -c -march=armv8-m.main asm.S -o bin/$crate.o 28 | ar crs bin/thumbv8m.main-none-eabi.a bin/$crate.o 29 | 30 | arm-none-eabi-gcc -g -c -march=armv8-m.main -DHAS_FPU asm.S -o bin/$crate.o 31 | ar crs bin/thumbv8m.main-none-eabihf.a bin/$crate.o 32 | 33 | rm bin/$crate.o 34 | -------------------------------------------------------------------------------- /bin/thumbv6m-none-eabi.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-embedded/cortex-m-rt/9fff2024da54aa8a3ca9760d69cf0d48e2bf5b19/bin/thumbv6m-none-eabi.a -------------------------------------------------------------------------------- /bin/thumbv7em-none-eabi.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-embedded/cortex-m-rt/9fff2024da54aa8a3ca9760d69cf0d48e2bf5b19/bin/thumbv7em-none-eabi.a -------------------------------------------------------------------------------- /bin/thumbv7em-none-eabihf.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-embedded/cortex-m-rt/9fff2024da54aa8a3ca9760d69cf0d48e2bf5b19/bin/thumbv7em-none-eabihf.a -------------------------------------------------------------------------------- /bin/thumbv7m-none-eabi.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-embedded/cortex-m-rt/9fff2024da54aa8a3ca9760d69cf0d48e2bf5b19/bin/thumbv7m-none-eabi.a -------------------------------------------------------------------------------- /bin/thumbv8m.base-none-eabi.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-embedded/cortex-m-rt/9fff2024da54aa8a3ca9760d69cf0d48e2bf5b19/bin/thumbv8m.base-none-eabi.a -------------------------------------------------------------------------------- /bin/thumbv8m.main-none-eabi.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-embedded/cortex-m-rt/9fff2024da54aa8a3ca9760d69cf0d48e2bf5b19/bin/thumbv8m.main-none-eabi.a -------------------------------------------------------------------------------- /bin/thumbv8m.main-none-eabihf.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-embedded/cortex-m-rt/9fff2024da54aa8a3ca9760d69cf0d48e2bf5b19/bin/thumbv8m.main-none-eabihf.a -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use std::fs::{self, File}; 2 | use std::io::Write; 3 | use std::path::{Path, PathBuf}; 4 | use std::{env, ffi::OsStr}; 5 | 6 | fn main() { 7 | let mut target = env::var("TARGET").unwrap(); 8 | 9 | // When using a custom target JSON, `$TARGET` contains the path to that JSON file. By 10 | // convention, these files are named after the actual target triple, eg. 11 | // `thumbv7m-customos-elf.json`, so we extract the file stem here to allow custom target specs. 12 | let path = Path::new(&target); 13 | if path.extension() == Some(OsStr::new("json")) { 14 | target = path 15 | .file_stem() 16 | .map_or(target.clone(), |stem| stem.to_str().unwrap().to_string()); 17 | } 18 | 19 | let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); 20 | 21 | if target.starts_with("thumbv") { 22 | let lib_path = format!("bin/{}.a", target); 23 | fs::copy(&lib_path, out_dir.join("libcortex-m-rt.a")).unwrap(); 24 | println!("cargo:rustc-link-lib=static=cortex-m-rt"); 25 | println!("cargo:rerun-if-changed={}", lib_path); 26 | } 27 | 28 | // Put the linker script somewhere the linker can find it 29 | let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); 30 | let link_x = include_bytes!("link.x.in"); 31 | let mut f = if env::var_os("CARGO_FEATURE_DEVICE").is_some() { 32 | let mut f = File::create(out.join("link.x")).unwrap(); 33 | 34 | f.write_all(link_x).unwrap(); 35 | 36 | // *IMPORTANT*: The weak aliases (i.e. `PROVIDED`) must come *after* `EXTERN(__INTERRUPTS)`. 37 | // Otherwise the linker will ignore user defined interrupts and always populate the table 38 | // with the weak aliases. 39 | writeln!( 40 | f, 41 | r#" 42 | /* Provides weak aliases (cf. PROVIDED) for device specific interrupt handlers */ 43 | /* This will usually be provided by a device crate generated using svd2rust (see `device.x`) */ 44 | INCLUDE device.x"# 45 | ) 46 | .unwrap(); 47 | f 48 | } else { 49 | let mut f = File::create(out.join("link.x")).unwrap(); 50 | f.write_all(link_x).unwrap(); 51 | f 52 | }; 53 | 54 | let max_int_handlers = if target.starts_with("thumbv6m-") { 55 | println!("cargo:rustc-cfg=cortex_m"); 56 | println!("cargo:rustc-cfg=armv6m"); 57 | 32 58 | } else if target.starts_with("thumbv7m-") || target.starts_with("thumbv7em-") { 59 | println!("cargo:rustc-cfg=cortex_m"); 60 | println!("cargo:rustc-cfg=armv7m"); 61 | 240 62 | } else if target.starts_with("thumbv8m") { 63 | println!("cargo:rustc-cfg=cortex_m"); 64 | println!("cargo:rustc-cfg=armv8m"); 65 | 240 66 | } else { 67 | // Non ARM target. We assume you're just testing the syntax. 68 | // This value seems as soon as any 69 | 240 70 | }; 71 | 72 | // checking the size of the interrupts portion of the vector table is sub-architecture dependent 73 | writeln!( 74 | f, 75 | r#" 76 | ASSERT(SIZEOF(.vector_table) <= 0x{:x}, " 77 | There can't be more than {1} interrupt handlers. This may be a bug in 78 | your device crate, or you may have registered more than {1} interrupt 79 | handlers."); 80 | "#, 81 | max_int_handlers * 4 + 0x40, 82 | max_int_handlers 83 | ) 84 | .unwrap(); 85 | 86 | println!("cargo:rustc-link-search={}", out.display()); 87 | 88 | println!("cargo:rerun-if-changed=build.rs"); 89 | println!("cargo:rerun-if-changed=link.x.in"); 90 | } 91 | -------------------------------------------------------------------------------- /check-blobs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Checks that the blobs are up to date with the committed assembly files 4 | 5 | set -euxo pipefail 6 | 7 | for lib in bin/*.a; do 8 | filename=$(basename "$lib") 9 | arm-none-eabi-objdump -Cd "$lib" > "bin/${filename%.a}.before" 10 | done 11 | 12 | ./assemble.sh 13 | 14 | for lib in bin/*.a; do 15 | filename=$(basename "$lib") 16 | arm-none-eabi-objdump -Cd "$lib" > "bin/${filename%.a}.after" 17 | done 18 | 19 | for cksum in bin/*.after; do 20 | diff -u "$cksum" "${cksum%.after}.before" 21 | done 22 | -------------------------------------------------------------------------------- /ci/script.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euxo pipefail 4 | 5 | main() { 6 | cargo check --target "$TARGET" 7 | 8 | cargo check --target "$TARGET" --features device 9 | 10 | if [ "$TARGET" = x86_64-unknown-linux-gnu ] && [ "$TRAVIS_RUST_VERSION" = stable ]; then 11 | ( cd macros && cargo check && cargo test ) 12 | 13 | cargo test --features device --test compiletest 14 | fi 15 | 16 | local examples=( 17 | alignment 18 | divergent-default-handler 19 | divergent-exception 20 | entry-static 21 | main 22 | minimal 23 | override-exception 24 | pre_init 25 | qemu 26 | state 27 | unsafe-default-handler 28 | unsafe-entry 29 | unsafe-exception 30 | unsafe-hard-fault 31 | ) 32 | local fail_examples=( 33 | data_overflow 34 | ) 35 | local linkers=( 36 | # Link with arm-none-eabi-ld 37 | "-C linker=arm-none-eabi-ld" 38 | # Link with arm-none-eabi-gcc, requires -nostartfiles 39 | "-C linker=arm-none-eabi-gcc -C link-arg=-nostartfiles" 40 | # Link with rust-lld (default) 41 | "" 42 | ) 43 | if [ "$TARGET" != x86_64-unknown-linux-gnu ]; then 44 | # Only test on stable and nightly, not MSRV. 45 | if [ "$TRAVIS_RUST_VERSION" = stable ] || [ "$TRAVIS_RUST_VERSION" = nightly ]; then 46 | RUSTDOCFLAGS="-Cpanic=abort" cargo test --doc 47 | fi 48 | 49 | for linker in "${linkers[@]}"; do 50 | for ex in "${examples[@]}"; do 51 | cargo rustc --target "$TARGET" --example "$ex" -- $linker 52 | cargo rustc --target "$TARGET" --example "$ex" --release -- $linker 53 | done 54 | for ex in "${fail_examples[@]}"; do 55 | ! cargo rustc --target "$TARGET" --example "$ex" -- $linker 56 | ! cargo rustc --target "$TARGET" --example "$ex" --release -- $linker 57 | done 58 | cargo rustc --target "$TARGET" --example device --features device -- $linker 59 | cargo rustc --target "$TARGET" --example device --features device --release -- $linker 60 | done 61 | fi 62 | 63 | case $TARGET in 64 | thumbv6m-none-eabi|thumbv7m-none-eabi) 65 | for linker in "${linkers[@]}"; do 66 | env RUSTFLAGS="$linker -C link-arg=-Tlink.x" cargo run \ 67 | --target "$TARGET" --example qemu | grep "x = 42" 68 | env RUSTFLAGS="$linker -C link-arg=-Tlink.x" cargo run \ 69 | --target "$TARGET" --example qemu --release | grep "x = 42" 70 | done 71 | 72 | ;; 73 | esac 74 | 75 | if [ "$TARGET" = x86_64-unknown-linux-gnu ]; then 76 | ./check-blobs.sh 77 | fi 78 | } 79 | 80 | main 81 | -------------------------------------------------------------------------------- /device.x: -------------------------------------------------------------------------------- 1 | /* Sample device.x file */ 2 | PROVIDE(WWDG = DefaultHandler); 3 | PROVIDE(PVD = DefaultHandler); 4 | -------------------------------------------------------------------------------- /examples/alignment.rs: -------------------------------------------------------------------------------- 1 | //! This is not an example; this is a link-pass test 2 | 3 | #![deny(warnings)] 4 | #![no_main] 5 | #![no_std] 6 | 7 | extern crate cortex_m_rt as rt; 8 | extern crate panic_halt; 9 | 10 | use core::ptr; 11 | 12 | use rt::entry; 13 | 14 | static mut BSS1: u16 = 0; 15 | static mut BSS2: u8 = 0; 16 | static mut DATA1: u8 = 1; 17 | static mut DATA2: u16 = 1; 18 | static RODATA1: &[u8; 3] = b"012"; 19 | static RODATA2: &[u8; 2] = b"34"; 20 | 21 | #[entry] 22 | fn main() -> ! { 23 | unsafe { 24 | let _bss1 = ptr::read_volatile(&BSS1); 25 | let _bss2 = ptr::read_volatile(&BSS2); 26 | let _data1 = ptr::read_volatile(&DATA1); 27 | let _data2 = ptr::read_volatile(&DATA2); 28 | let _rodata1 = ptr::read_volatile(&RODATA1); 29 | let _rodata2 = ptr::read_volatile(&RODATA2); 30 | } 31 | 32 | loop {} 33 | } 34 | -------------------------------------------------------------------------------- /examples/cfg-static.rs: -------------------------------------------------------------------------------- 1 | //! using `#[cfg]` on `static` shouldn't cause compile errors 2 | 3 | #![deny(unsafe_code)] 4 | #![deny(warnings)] 5 | #![no_main] 6 | #![no_std] 7 | 8 | extern crate cortex_m_rt as rt; 9 | extern crate panic_halt; 10 | 11 | use rt::{entry, exception}; 12 | 13 | #[entry] 14 | fn main() -> ! { 15 | #[cfg(never)] 16 | static mut COUNT: u32 = 0; 17 | 18 | loop {} 19 | } 20 | 21 | #[exception] 22 | fn SysTick() { 23 | #[cfg(never)] 24 | static mut FOO: u32 = 0; 25 | } 26 | -------------------------------------------------------------------------------- /examples/data_overflow.rs: -------------------------------------------------------------------------------- 1 | //! This is not an example; this is a linker overflow detection test 2 | //! which should fail to link due to .data overflowing FLASH. 3 | 4 | #![deny(warnings)] 5 | #![no_main] 6 | #![no_std] 7 | 8 | extern crate cortex_m_rt as rt; 9 | extern crate panic_halt; 10 | 11 | use core::ptr; 12 | 13 | use rt::entry; 14 | 15 | // This large static array uses most of .rodata 16 | static RODATA: [u8; 48 * 1024] = [1u8; 48 * 1024]; 17 | 18 | // This large mutable array causes .data to use the rest of FLASH 19 | // without also overflowing RAM. 20 | static mut DATA: [u8; 16 * 1024] = [1u8; 16 * 1024]; 21 | 22 | #[entry] 23 | fn main() -> ! { 24 | unsafe { 25 | let _bigdata = ptr::read_volatile(&RODATA as *const u8); 26 | let _bigdata = ptr::read_volatile(&DATA as *const u8); 27 | } 28 | 29 | loop {} 30 | } 31 | -------------------------------------------------------------------------------- /examples/device.rs: -------------------------------------------------------------------------------- 1 | //! Manually create the interrupts portion of the vector table 2 | 3 | #![deny(unsafe_code)] 4 | #![deny(warnings)] 5 | #![no_main] 6 | #![no_std] 7 | 8 | extern crate cortex_m_rt as rt; 9 | extern crate panic_halt; 10 | 11 | use rt::entry; 12 | 13 | #[entry] 14 | fn main() -> ! { 15 | loop {} 16 | } 17 | 18 | // interrupts portion of the vector table 19 | pub union Vector { 20 | handler: unsafe extern "C" fn(), 21 | reserved: usize, 22 | } 23 | 24 | extern "C" { 25 | fn WWDG(); 26 | fn PVD(); 27 | } 28 | 29 | #[allow(unsafe_code)] 30 | #[link_section = ".vector_table.interrupts"] 31 | #[no_mangle] 32 | pub static __INTERRUPTS: [Vector; 3] = [ 33 | Vector { handler: WWDG }, 34 | Vector { reserved: 0 }, 35 | Vector { handler: PVD }, 36 | ]; 37 | -------------------------------------------------------------------------------- /examples/divergent-default-handler.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | #![no_main] 3 | #![no_std] 4 | 5 | extern crate cortex_m_rt; 6 | extern crate panic_halt; 7 | 8 | use cortex_m_rt::{entry, exception}; 9 | 10 | #[entry] 11 | fn foo() -> ! { 12 | loop {} 13 | } 14 | 15 | #[exception] 16 | unsafe fn DefaultHandler(_irqn: i16) -> ! { 17 | loop {} 18 | } 19 | -------------------------------------------------------------------------------- /examples/divergent-exception.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | #![no_main] 3 | #![no_std] 4 | 5 | extern crate cortex_m_rt; 6 | extern crate panic_halt; 7 | 8 | use cortex_m_rt::{entry, exception}; 9 | 10 | #[entry] 11 | fn foo() -> ! { 12 | loop {} 13 | } 14 | 15 | #[exception] 16 | fn SysTick() -> ! { 17 | loop {} 18 | } 19 | -------------------------------------------------------------------------------- /examples/entry-static.rs: -------------------------------------------------------------------------------- 1 | //! `static mut` variables local to the entry point are safe to use 2 | 3 | #![deny(unsafe_code)] 4 | #![deny(warnings)] 5 | #![no_main] 6 | #![no_std] 7 | 8 | extern crate cortex_m_rt as rt; 9 | extern crate panic_halt; 10 | 11 | use rt::entry; 12 | 13 | #[entry] 14 | fn main() -> ! { 15 | static mut COUNT: u32 = 0; 16 | 17 | loop { 18 | *COUNT += 1; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/main.rs: -------------------------------------------------------------------------------- 1 | //! Directly plug a `main` symbol instead of using `#[entry]` 2 | 3 | #![deny(warnings)] 4 | #![no_main] 5 | #![no_std] 6 | 7 | extern crate cortex_m_rt as rt; 8 | extern crate panic_halt; 9 | 10 | #[no_mangle] 11 | pub unsafe extern "C" fn main() -> ! { 12 | loop {} 13 | } 14 | -------------------------------------------------------------------------------- /examples/minimal.rs: -------------------------------------------------------------------------------- 1 | //! Minimal `cortex-m-rt` based program 2 | 3 | #![deny(unsafe_code)] 4 | #![deny(warnings)] 5 | #![no_main] 6 | #![no_std] 7 | 8 | extern crate cortex_m_rt as rt; 9 | extern crate panic_halt; 10 | 11 | use rt::entry; 12 | 13 | // the program entry point 14 | #[entry] 15 | fn main() -> ! { 16 | loop {} 17 | } 18 | -------------------------------------------------------------------------------- /examples/override-exception.rs: -------------------------------------------------------------------------------- 1 | //! How to override the hard fault exception handler and the default exception handler 2 | 3 | #![deny(warnings)] 4 | #![no_main] 5 | #![no_std] 6 | 7 | extern crate cortex_m; 8 | extern crate cortex_m_rt as rt; 9 | extern crate panic_halt; 10 | 11 | use cortex_m::asm; 12 | use rt::{entry, exception, ExceptionFrame}; 13 | 14 | #[entry] 15 | fn main() -> ! { 16 | loop {} 17 | } 18 | 19 | #[exception] 20 | unsafe fn DefaultHandler(_irqn: i16) { 21 | asm::bkpt(); 22 | } 23 | 24 | #[exception] 25 | unsafe fn HardFault(_ef: &ExceptionFrame) -> ! { 26 | asm::bkpt(); 27 | 28 | loop {} 29 | } 30 | -------------------------------------------------------------------------------- /examples/pre_init.rs: -------------------------------------------------------------------------------- 1 | //! `cortex-m-rt` based program with a function run before RAM is initialized. 2 | 3 | #![deny(warnings)] 4 | #![no_main] 5 | #![no_std] 6 | 7 | extern crate cortex_m_rt as rt; 8 | extern crate panic_halt; 9 | 10 | use rt::{entry, pre_init}; 11 | 12 | #[pre_init] 13 | unsafe fn disable_watchdog() { 14 | // Do what you need to disable the watchdog. 15 | } 16 | 17 | #[entry] 18 | fn main() -> ! { 19 | loop {} 20 | } 21 | -------------------------------------------------------------------------------- /examples/qemu.rs: -------------------------------------------------------------------------------- 1 | // #![feature(stdsimd)] 2 | #![no_main] 3 | #![no_std] 4 | 5 | extern crate cortex_m; 6 | extern crate cortex_m_rt as rt; 7 | extern crate cortex_m_semihosting as semihosting; 8 | 9 | extern crate panic_halt; 10 | 11 | use cortex_m::asm; 12 | use rt::entry; 13 | 14 | #[entry] 15 | fn main() -> ! { 16 | use core::fmt::Write; 17 | let x = 42; 18 | 19 | loop { 20 | asm::nop(); 21 | 22 | // write something through semihosting interface 23 | let mut hstdout = semihosting::hio::hstdout().unwrap(); 24 | write!(hstdout, "x = {}\n", x).unwrap(); 25 | // exit from qemu 26 | semihosting::debug::exit(semihosting::debug::EXIT_SUCCESS); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/state.rs: -------------------------------------------------------------------------------- 1 | //! Preserving state across executions of an exception handler 2 | 3 | #![deny(unsafe_code)] 4 | #![deny(warnings)] 5 | #![no_main] 6 | #![no_std] 7 | 8 | extern crate cortex_m_rt as rt; 9 | extern crate panic_halt; 10 | 11 | use rt::{entry, exception}; 12 | 13 | #[entry] 14 | fn main() -> ! { 15 | loop {} 16 | } 17 | 18 | // exception handler with state 19 | #[exception] 20 | fn SysTick() { 21 | static mut STATE: u32 = 0; 22 | 23 | *STATE += 1; 24 | } 25 | -------------------------------------------------------------------------------- /examples/unsafe-default-handler.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | #![no_main] 3 | #![no_std] 4 | 5 | extern crate cortex_m_rt; 6 | extern crate panic_halt; 7 | 8 | use cortex_m_rt::{entry, exception}; 9 | 10 | #[entry] 11 | fn foo() -> ! { 12 | loop {} 13 | } 14 | 15 | #[exception] 16 | unsafe fn DefaultHandler(_irqn: i16) {} 17 | -------------------------------------------------------------------------------- /examples/unsafe-entry.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | #![no_main] 3 | #![no_std] 4 | 5 | extern crate cortex_m_rt; 6 | extern crate panic_halt; 7 | 8 | use cortex_m_rt::entry; 9 | 10 | #[entry] 11 | unsafe fn foo() -> ! { 12 | loop {} 13 | } 14 | -------------------------------------------------------------------------------- /examples/unsafe-exception.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | #![no_main] 3 | #![no_std] 4 | 5 | extern crate cortex_m_rt; 6 | extern crate panic_halt; 7 | 8 | use cortex_m_rt::{entry, exception}; 9 | 10 | #[entry] 11 | fn foo() -> ! { 12 | loop {} 13 | } 14 | 15 | #[exception] 16 | unsafe fn SysTick() {} 17 | -------------------------------------------------------------------------------- /examples/unsafe-hard-fault.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | #![no_main] 3 | #![no_std] 4 | 5 | extern crate cortex_m_rt; 6 | extern crate panic_halt; 7 | 8 | use cortex_m_rt::{entry, exception, ExceptionFrame}; 9 | 10 | #[entry] 11 | fn foo() -> ! { 12 | loop {} 13 | } 14 | 15 | #[exception] 16 | unsafe fn HardFault(_ef: &ExceptionFrame) -> ! { 17 | loop {} 18 | } 19 | -------------------------------------------------------------------------------- /examples/unsafety.rs: -------------------------------------------------------------------------------- 1 | //! Checks that the declared unsafety is respected by the attributes 2 | 3 | #![deny(warnings)] 4 | #![no_main] 5 | #![no_std] 6 | 7 | extern crate cortex_m_rt; 8 | extern crate panic_halt; 9 | 10 | use cortex_m_rt::{entry, exception, ExceptionFrame}; 11 | 12 | #[entry] 13 | unsafe fn main() -> ! { 14 | foo(); 15 | 16 | loop {} 17 | } 18 | 19 | #[exception] 20 | unsafe fn DefaultHandler(_irqn: i16) { 21 | foo(); 22 | } 23 | 24 | #[exception] 25 | unsafe fn HardFault(_ef: &ExceptionFrame) -> ! { 26 | foo(); 27 | 28 | loop {} 29 | } 30 | 31 | #[exception] 32 | unsafe fn SysTick() { 33 | foo(); 34 | } 35 | 36 | unsafe fn foo() {} 37 | -------------------------------------------------------------------------------- /examples/warnings.rs: -------------------------------------------------------------------------------- 1 | //! Tests that a crate can still build with all warnings enabled. 2 | //! 3 | //! The code generated by the `cortex-m-rt` macros might need to manually 4 | //! `#[allow]` some of them (even though Rust does that by default for a few 5 | //! warnings too). 6 | 7 | #![no_std] 8 | #![no_main] 9 | #![deny(warnings, missing_docs, rust_2018_idioms)] 10 | 11 | extern crate cortex_m_rt; 12 | extern crate panic_halt; 13 | 14 | use cortex_m_rt::{entry, exception, interrupt, pre_init, ExceptionFrame}; 15 | 16 | #[allow(non_camel_case_types)] 17 | enum interrupt { 18 | INT, 19 | } 20 | 21 | extern "C" { 22 | fn INT(); 23 | } 24 | 25 | union Vector { 26 | #[allow(dead_code)] 27 | handler: unsafe extern "C" fn(), 28 | } 29 | 30 | #[link_section = ".vector_table.interrupts"] 31 | #[no_mangle] 32 | #[used] 33 | static __INTERRUPTS: [Vector; 1] = [Vector { handler: INT }]; 34 | 35 | /// Dummy interrupt. 36 | #[interrupt] 37 | fn INT() {} 38 | 39 | #[exception] 40 | fn HardFault(_eh: &ExceptionFrame) -> ! { 41 | loop {} 42 | } 43 | 44 | #[entry] 45 | fn main() -> ! { 46 | loop {} 47 | } 48 | 49 | #[pre_init] 50 | unsafe fn pre_init() {} 51 | -------------------------------------------------------------------------------- /link.x.in: -------------------------------------------------------------------------------- 1 | /* # Developer notes 2 | 3 | - Symbols that start with a double underscore (__) are considered "private" 4 | 5 | - Symbols that start with a single underscore (_) are considered "semi-public"; they can be 6 | overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" { 7 | static mut __sbss }`). 8 | 9 | - `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a 10 | symbol if not dropped if it appears in or near the front of the linker arguments and "it's not 11 | needed" by any of the preceding objects (linker arguments) 12 | 13 | - `PROVIDE` is used to provide default values that can be overridden by a user linker script 14 | 15 | - On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and* 16 | the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization 17 | routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see 18 | "Address (..) is out of bounds" in the disassembly produced by `objdump`. 19 | */ 20 | 21 | /* Provides information about the memory layout of the device */ 22 | /* This will be provided by the user (see `memory.x`) or by a Board Support Crate */ 23 | INCLUDE memory.x 24 | 25 | /* # Entry point = reset vector */ 26 | EXTERN(__RESET_VECTOR); 27 | EXTERN(Reset); 28 | ENTRY(Reset); 29 | 30 | /* # Exception vectors */ 31 | /* This is effectively weak aliasing at the linker level */ 32 | /* The user can override any of these aliases by defining the corresponding symbol themselves (cf. 33 | the `exception!` macro) */ 34 | EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */ 35 | 36 | EXTERN(DefaultHandler); 37 | 38 | PROVIDE(NonMaskableInt = DefaultHandler); 39 | EXTERN(HardFaultTrampoline); 40 | PROVIDE(MemoryManagement = DefaultHandler); 41 | PROVIDE(BusFault = DefaultHandler); 42 | PROVIDE(UsageFault = DefaultHandler); 43 | PROVIDE(SecureFault = DefaultHandler); 44 | PROVIDE(SVCall = DefaultHandler); 45 | PROVIDE(DebugMonitor = DefaultHandler); 46 | PROVIDE(PendSV = DefaultHandler); 47 | PROVIDE(SysTick = DefaultHandler); 48 | 49 | PROVIDE(DefaultHandler = DefaultHandler_); 50 | PROVIDE(HardFault = HardFault_); 51 | 52 | /* # Interrupt vectors */ 53 | EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ 54 | 55 | /* # Pre-initialization function */ 56 | /* If the user overrides this using the `pre_init!` macro or by creating a `__pre_init` function, 57 | then the function this points to will be called before the RAM is initialized. */ 58 | PROVIDE(__pre_init = DefaultPreInit); 59 | 60 | /* # Sections */ 61 | SECTIONS 62 | { 63 | PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM)); 64 | 65 | /* ## Sections in FLASH */ 66 | /* ### Vector table */ 67 | .vector_table ORIGIN(FLASH) : 68 | { 69 | /* Initial Stack Pointer (SP) value */ 70 | LONG(_stack_start); 71 | 72 | /* Reset vector */ 73 | KEEP(*(.vector_table.reset_vector)); /* this is the `__RESET_VECTOR` symbol */ 74 | __reset_vector = .; 75 | 76 | /* Exceptions */ 77 | KEEP(*(.vector_table.exceptions)); /* this is the `__EXCEPTIONS` symbol */ 78 | __eexceptions = .; 79 | 80 | /* Device specific interrupts */ 81 | KEEP(*(.vector_table.interrupts)); /* this is the `__INTERRUPTS` symbol */ 82 | } > FLASH 83 | 84 | PROVIDE(_stext = ADDR(.vector_table) + SIZEOF(.vector_table)); 85 | 86 | /* ### .text */ 87 | .text _stext : 88 | { 89 | __stext = .; 90 | *(.Reset); 91 | 92 | *(.text .text.*); 93 | 94 | /* The HardFaultTrampoline uses the `b` instruction to enter `HardFault`, 95 | so must be placed close to it. */ 96 | *(.HardFaultTrampoline); 97 | *(.HardFault.*); 98 | 99 | . = ALIGN(4); /* Pad .text to the alignment to workaround overlapping load section bug in old lld */ 100 | __etext = .; 101 | } > FLASH 102 | 103 | /* ### .rodata */ 104 | .rodata : ALIGN(4) 105 | { 106 | . = ALIGN(4); 107 | __srodata = .; 108 | *(.rodata .rodata.*); 109 | 110 | /* 4-byte align the end (VMA) of this section. 111 | This is required by LLD to ensure the LMA of the following .data 112 | section will have the correct alignment. */ 113 | . = ALIGN(4); 114 | __erodata = .; 115 | } > FLASH 116 | 117 | /* ## Sections in RAM */ 118 | /* ### .data */ 119 | .data : ALIGN(4) 120 | { 121 | . = ALIGN(4); 122 | __sdata = .; 123 | *(.data .data.*); 124 | . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ 125 | } > RAM AT>FLASH 126 | /* Allow sections from user `memory.x` injected using `INSERT AFTER .data` to 127 | * use the .data loading mechanism by pushing __edata. Note: do not change 128 | * output region or load region in those user sections! */ 129 | . = ALIGN(4); 130 | __edata = .; 131 | 132 | /* LMA of .data */ 133 | __sidata = LOADADDR(.data); 134 | 135 | /* ### .gnu.sgstubs 136 | This section contains the TrustZone-M veneers put there by the Arm GNU linker. */ 137 | /* Security Attribution Unit blocks must be 32 bytes aligned. */ 138 | /* Note that this pads the FLASH usage to 32 byte alignment. */ 139 | .gnu.sgstubs : ALIGN(32) 140 | { 141 | . = ALIGN(32); 142 | __veneer_base = .; 143 | *(.gnu.sgstubs*) 144 | . = ALIGN(32); 145 | __veneer_limit = .; 146 | } > FLASH 147 | 148 | /* ### .bss */ 149 | .bss (NOLOAD) : ALIGN(4) 150 | { 151 | . = ALIGN(4); 152 | __sbss = .; 153 | *(.bss .bss.*); 154 | *(COMMON); /* Uninitialized C statics */ 155 | . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ 156 | } > RAM 157 | /* Allow sections from user `memory.x` injected using `INSERT AFTER .bss` to 158 | * use the .bss zeroing mechanism by pushing __ebss. Note: do not change 159 | * output region or load region in those user sections! */ 160 | . = ALIGN(4); 161 | __ebss = .; 162 | 163 | /* ### .uninit */ 164 | .uninit (NOLOAD) : ALIGN(4) 165 | { 166 | . = ALIGN(4); 167 | __suninit = .; 168 | *(.uninit .uninit.*); 169 | . = ALIGN(4); 170 | __euninit = .; 171 | } > RAM 172 | 173 | /* Place the heap right after `.uninit` in RAM */ 174 | PROVIDE(__sheap = __euninit); 175 | 176 | /* ## .got */ 177 | /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in 178 | the input files and raise an error if relocatable code is found */ 179 | .got (NOLOAD) : 180 | { 181 | KEEP(*(.got .got.*)); 182 | } 183 | 184 | /* ## Discarded sections */ 185 | /DISCARD/ : 186 | { 187 | /* Unused exception related info that only wastes space */ 188 | *(.ARM.exidx); 189 | *(.ARM.exidx.*); 190 | *(.ARM.extab.*); 191 | } 192 | } 193 | 194 | /* Do not exceed this mark in the error messages below | */ 195 | /* # Alignment checks */ 196 | ASSERT(ORIGIN(FLASH) % 4 == 0, " 197 | ERROR(cortex-m-rt): the start of the FLASH region must be 4-byte aligned"); 198 | 199 | ASSERT(ORIGIN(RAM) % 4 == 0, " 200 | ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned"); 201 | 202 | ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, " 203 | BUG(cortex-m-rt): .data is not 4-byte aligned"); 204 | 205 | ASSERT(__sidata % 4 == 0, " 206 | BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned"); 207 | 208 | ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, " 209 | BUG(cortex-m-rt): .bss is not 4-byte aligned"); 210 | 211 | ASSERT(__sheap % 4 == 0, " 212 | BUG(cortex-m-rt): start of .heap is not 4-byte aligned"); 213 | 214 | /* # Position checks */ 215 | 216 | /* ## .vector_table */ 217 | ASSERT(__reset_vector == ADDR(.vector_table) + 0x8, " 218 | BUG(cortex-m-rt): the reset vector is missing"); 219 | 220 | ASSERT(__eexceptions == ADDR(.vector_table) + 0x40, " 221 | BUG(cortex-m-rt): the exception vectors are missing"); 222 | 223 | ASSERT(SIZEOF(.vector_table) > 0x40, " 224 | ERROR(cortex-m-rt): The interrupt vectors are missing. 225 | Possible solutions, from most likely to less likely: 226 | - Link to a svd2rust generated device crate 227 | - Check that you actually use the device/hal/bsp crate in your code 228 | - Disable the 'device' feature of cortex-m-rt to build a generic application (a dependency 229 | may be enabling it) 230 | - Supply the interrupt handlers yourself. Check the documentation for details."); 231 | 232 | /* ## .text */ 233 | ASSERT(ADDR(.vector_table) + SIZEOF(.vector_table) <= _stext, " 234 | ERROR(cortex-m-rt): The .text section can't be placed inside the .vector_table section 235 | Set _stext to an address greater than the end of .vector_table (See output of `nm`)"); 236 | 237 | ASSERT(_stext + SIZEOF(.text) < ORIGIN(FLASH) + LENGTH(FLASH), " 238 | ERROR(cortex-m-rt): The .text section must be placed inside the FLASH memory. 239 | Set _stext to an address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)'"); 240 | 241 | /* # Other checks */ 242 | ASSERT(SIZEOF(.got) == 0, " 243 | ERROR(cortex-m-rt): .got section detected in the input object files 244 | Dynamic relocations are not supported. If you are linking to C code compiled using 245 | the 'cc' crate then modify your build script to compile the C code _without_ 246 | the -fPIC flag. See the documentation of the `cc::Build.pic` method for details."); 247 | /* Do not exceed this mark in the error messages above | */ 248 | -------------------------------------------------------------------------------- /macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Jorge Aparicio "] 3 | categories = ["embedded", "no-std"] 4 | description = "Attributes re-exported in `cortex-m-rt`" 5 | documentation = "https://docs.rs/cortex-m-rt" 6 | keywords = ["arm", "cortex-m", "runtime", "startup"] 7 | license = "MIT OR Apache-2.0" 8 | name = "cortex-m-rt-macros" 9 | repository = "https://github.com/rust-embedded/cortex-m-rt" 10 | version = "0.7.0" 11 | edition = "2018" 12 | 13 | [lib] 14 | proc-macro = true 15 | 16 | [dependencies] 17 | quote = "1.0" 18 | proc-macro2 = "1.0" 19 | 20 | [dependencies.syn] 21 | features = ["extra-traits", "full"] 22 | version = "1.0" 23 | -------------------------------------------------------------------------------- /macros/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Internal implementation details of `cortex-m-rt`. 2 | //! 3 | //! Do not use this crate directly. 4 | 5 | extern crate proc_macro; 6 | 7 | use proc_macro::TokenStream; 8 | use proc_macro2::Span; 9 | use quote::quote; 10 | use std::collections::HashSet; 11 | use std::iter; 12 | use syn::{ 13 | parse, parse_macro_input, spanned::Spanned, AttrStyle, Attribute, FnArg, Ident, Item, ItemFn, 14 | ItemStatic, ReturnType, Stmt, Type, Visibility, 15 | }; 16 | 17 | #[proc_macro_attribute] 18 | pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { 19 | let mut f = parse_macro_input!(input as ItemFn); 20 | 21 | // check the function signature 22 | let valid_signature = f.sig.constness.is_none() 23 | && f.vis == Visibility::Inherited 24 | && f.sig.abi.is_none() 25 | && f.sig.inputs.is_empty() 26 | && f.sig.generics.params.is_empty() 27 | && f.sig.generics.where_clause.is_none() 28 | && f.sig.variadic.is_none() 29 | && match f.sig.output { 30 | ReturnType::Default => false, 31 | ReturnType::Type(_, ref ty) => match **ty { 32 | Type::Never(_) => true, 33 | _ => false, 34 | }, 35 | }; 36 | 37 | if !valid_signature { 38 | return parse::Error::new( 39 | f.span(), 40 | "`#[entry]` function must have signature `[unsafe] fn() -> !`", 41 | ) 42 | .to_compile_error() 43 | .into(); 44 | } 45 | 46 | if !args.is_empty() { 47 | return parse::Error::new(Span::call_site(), "This attribute accepts no arguments") 48 | .to_compile_error() 49 | .into(); 50 | } 51 | 52 | // XXX should we blacklist other attributes? 53 | let (statics, stmts) = match extract_static_muts(f.block.stmts) { 54 | Err(e) => return e.to_compile_error().into(), 55 | Ok(x) => x, 56 | }; 57 | 58 | f.sig.ident = Ident::new(&format!("__cortex_m_rt_{}", f.sig.ident), Span::call_site()); 59 | f.sig.inputs.extend(statics.iter().map(|statik| { 60 | let ident = &statik.ident; 61 | let ty = &statik.ty; 62 | let attrs = &statik.attrs; 63 | 64 | // Note that we use an explicit `'static` lifetime for the entry point arguments. This makes 65 | // it more flexible, and is sound here, since the entry will not be called again, ever. 66 | syn::parse::( 67 | quote!(#[allow(non_snake_case)] #(#attrs)* #ident: &'static mut #ty).into(), 68 | ) 69 | .unwrap() 70 | })); 71 | f.block.stmts = stmts; 72 | 73 | let tramp_ident = Ident::new(&format!("{}_trampoline", f.sig.ident), Span::call_site()); 74 | let ident = &f.sig.ident; 75 | 76 | let resource_args = statics 77 | .iter() 78 | .map(|statik| { 79 | let (ref cfgs, ref attrs) = extract_cfgs(statik.attrs.clone()); 80 | let ident = &statik.ident; 81 | let ty = &statik.ty; 82 | let expr = &statik.expr; 83 | quote! { 84 | #(#cfgs)* 85 | { 86 | #(#attrs)* 87 | static mut #ident: #ty = #expr; 88 | &mut #ident 89 | } 90 | } 91 | }) 92 | .collect::>(); 93 | 94 | if let Err(error) = check_attr_whitelist(&f.attrs, WhiteListCaller::Entry) { 95 | return error; 96 | } 97 | 98 | let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone()); 99 | 100 | quote!( 101 | #(#cfgs)* 102 | #(#attrs)* 103 | #[doc(hidden)] 104 | #[export_name = "main"] 105 | pub unsafe extern "C" fn #tramp_ident() { 106 | #ident( 107 | #(#resource_args),* 108 | ) 109 | } 110 | 111 | #f 112 | ) 113 | .into() 114 | } 115 | 116 | #[derive(Debug, PartialEq)] 117 | enum Exception { 118 | DefaultHandler, 119 | HardFault, 120 | NonMaskableInt, 121 | Other, 122 | } 123 | 124 | #[proc_macro_attribute] 125 | pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { 126 | let mut f = parse_macro_input!(input as ItemFn); 127 | 128 | if !args.is_empty() { 129 | return parse::Error::new(Span::call_site(), "This attribute accepts no arguments") 130 | .to_compile_error() 131 | .into(); 132 | } 133 | 134 | if let Err(error) = check_attr_whitelist(&f.attrs, WhiteListCaller::Exception) { 135 | return error; 136 | } 137 | 138 | let fspan = f.span(); 139 | let ident = f.sig.ident.clone(); 140 | 141 | let ident_s = ident.to_string(); 142 | let exn = match &*ident_s { 143 | "DefaultHandler" => Exception::DefaultHandler, 144 | "HardFault" => Exception::HardFault, 145 | "NonMaskableInt" => Exception::NonMaskableInt, 146 | // NOTE that at this point we don't check if the exception is available on the target (e.g. 147 | // MemoryManagement is not available on Cortex-M0) 148 | "MemoryManagement" | "BusFault" | "UsageFault" | "SecureFault" | "SVCall" 149 | | "DebugMonitor" | "PendSV" | "SysTick" => Exception::Other, 150 | _ => { 151 | return parse::Error::new(ident.span(), "This is not a valid exception name") 152 | .to_compile_error() 153 | .into(); 154 | } 155 | }; 156 | 157 | if f.sig.unsafety.is_none() { 158 | match exn { 159 | Exception::DefaultHandler | Exception::HardFault | Exception::NonMaskableInt => { 160 | // These are unsafe to define. 161 | let name = if exn == Exception::DefaultHandler { 162 | format!("`DefaultHandler`") 163 | } else { 164 | format!("`{:?}` handler", exn) 165 | }; 166 | return parse::Error::new(ident.span(), format_args!("defining a {} is unsafe and requires an `unsafe fn` (see the cortex-m-rt docs)", name)) 167 | .to_compile_error() 168 | .into(); 169 | } 170 | Exception::Other => {} 171 | } 172 | } 173 | 174 | // Emit a reference to the `Exception` variant corresponding to our exception. 175 | // This will fail compilation when the target doesn't have that exception. 176 | let assertion = match exn { 177 | Exception::Other => { 178 | quote! { 179 | const _: () = { 180 | let _ = cortex_m_rt::Exception::#ident; 181 | }; 182 | } 183 | } 184 | _ => quote!(), 185 | }; 186 | 187 | let handler = match exn { 188 | Exception::DefaultHandler => { 189 | let valid_signature = f.sig.constness.is_none() 190 | && f.vis == Visibility::Inherited 191 | && f.sig.abi.is_none() 192 | && f.sig.inputs.len() == 1 193 | && f.sig.generics.params.is_empty() 194 | && f.sig.generics.where_clause.is_none() 195 | && f.sig.variadic.is_none() 196 | && match f.sig.output { 197 | ReturnType::Default => true, 198 | ReturnType::Type(_, ref ty) => match **ty { 199 | Type::Tuple(ref tuple) => tuple.elems.is_empty(), 200 | Type::Never(..) => true, 201 | _ => false, 202 | }, 203 | }; 204 | 205 | if !valid_signature { 206 | return parse::Error::new( 207 | fspan, 208 | "`DefaultHandler` must have signature `unsafe fn(i16) [-> !]`", 209 | ) 210 | .to_compile_error() 211 | .into(); 212 | } 213 | 214 | f.sig.ident = Ident::new(&format!("__cortex_m_rt_{}", f.sig.ident), Span::call_site()); 215 | let tramp_ident = Ident::new(&format!("{}_trampoline", f.sig.ident), Span::call_site()); 216 | let ident = &f.sig.ident; 217 | 218 | let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone()); 219 | 220 | quote!( 221 | #(#cfgs)* 222 | #(#attrs)* 223 | #[doc(hidden)] 224 | #[export_name = #ident_s] 225 | pub unsafe extern "C" fn #tramp_ident() { 226 | extern crate core; 227 | 228 | const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; 229 | 230 | let irqn = unsafe { (core::ptr::read_volatile(SCB_ICSR) & 0x1FF) as i16 - 16 }; 231 | 232 | #ident(irqn) 233 | } 234 | 235 | #f 236 | ) 237 | } 238 | Exception::HardFault => { 239 | let valid_signature = f.sig.constness.is_none() 240 | && f.vis == Visibility::Inherited 241 | && f.sig.abi.is_none() 242 | && f.sig.inputs.len() == 1 243 | && match &f.sig.inputs[0] { 244 | FnArg::Typed(arg) => match arg.ty.as_ref() { 245 | Type::Reference(r) => r.lifetime.is_none() && r.mutability.is_none(), 246 | _ => false, 247 | }, 248 | _ => false, 249 | } 250 | && f.sig.generics.params.is_empty() 251 | && f.sig.generics.where_clause.is_none() 252 | && f.sig.variadic.is_none() 253 | && match f.sig.output { 254 | ReturnType::Default => false, 255 | ReturnType::Type(_, ref ty) => match **ty { 256 | Type::Never(_) => true, 257 | _ => false, 258 | }, 259 | }; 260 | 261 | if !valid_signature { 262 | return parse::Error::new( 263 | fspan, 264 | "`HardFault` handler must have signature `unsafe fn(&ExceptionFrame) -> !`", 265 | ) 266 | .to_compile_error() 267 | .into(); 268 | } 269 | 270 | f.sig.ident = Ident::new(&format!("__cortex_m_rt_{}", f.sig.ident), Span::call_site()); 271 | let tramp_ident = Ident::new(&format!("{}_trampoline", f.sig.ident), Span::call_site()); 272 | let ident = &f.sig.ident; 273 | 274 | let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone()); 275 | 276 | quote!( 277 | #(#cfgs)* 278 | #(#attrs)* 279 | #[doc(hidden)] 280 | #[export_name = "HardFault"] 281 | // Only emit link_section when building for embedded targets, 282 | // because some hosted platforms (used to check the build) 283 | // cannot handle the long link section names. 284 | #[cfg_attr(target_os = "none", link_section = ".HardFault.user")] 285 | pub unsafe extern "C" fn #tramp_ident(frame: &::cortex_m_rt::ExceptionFrame) { 286 | #ident(frame) 287 | } 288 | 289 | #f 290 | ) 291 | } 292 | Exception::NonMaskableInt | Exception::Other => { 293 | let valid_signature = f.sig.constness.is_none() 294 | && f.vis == Visibility::Inherited 295 | && f.sig.abi.is_none() 296 | && f.sig.inputs.is_empty() 297 | && f.sig.generics.params.is_empty() 298 | && f.sig.generics.where_clause.is_none() 299 | && f.sig.variadic.is_none() 300 | && match f.sig.output { 301 | ReturnType::Default => true, 302 | ReturnType::Type(_, ref ty) => match **ty { 303 | Type::Tuple(ref tuple) => tuple.elems.is_empty(), 304 | Type::Never(..) => true, 305 | _ => false, 306 | }, 307 | }; 308 | 309 | if !valid_signature { 310 | return parse::Error::new( 311 | fspan, 312 | "`#[exception]` handlers other than `DefaultHandler` and `HardFault` must have \ 313 | signature `[unsafe] fn() [-> !]`", 314 | ) 315 | .to_compile_error() 316 | .into(); 317 | } 318 | 319 | let (statics, stmts) = match extract_static_muts(f.block.stmts) { 320 | Err(e) => return e.to_compile_error().into(), 321 | Ok(x) => x, 322 | }; 323 | 324 | f.sig.ident = Ident::new(&format!("__cortex_m_rt_{}", f.sig.ident), Span::call_site()); 325 | f.sig.inputs.extend(statics.iter().map(|statik| { 326 | let ident = &statik.ident; 327 | let ty = &statik.ty; 328 | let attrs = &statik.attrs; 329 | syn::parse::( 330 | quote!(#[allow(non_snake_case)] #(#attrs)* #ident: &mut #ty).into(), 331 | ) 332 | .unwrap() 333 | })); 334 | f.block.stmts = iter::once( 335 | syn::parse2(quote! {{ 336 | // check that this exception actually exists 337 | exception::#ident; 338 | }}) 339 | .unwrap(), 340 | ) 341 | .chain(stmts) 342 | .collect(); 343 | 344 | let tramp_ident = Ident::new(&format!("{}_trampoline", f.sig.ident), Span::call_site()); 345 | let ident = &f.sig.ident; 346 | 347 | let resource_args = statics 348 | .iter() 349 | .map(|statik| { 350 | let (ref cfgs, ref attrs) = extract_cfgs(statik.attrs.clone()); 351 | let ident = &statik.ident; 352 | let ty = &statik.ty; 353 | let expr = &statik.expr; 354 | quote! { 355 | #(#cfgs)* 356 | { 357 | #(#attrs)* 358 | static mut #ident: #ty = #expr; 359 | &mut #ident 360 | } 361 | } 362 | }) 363 | .collect::>(); 364 | 365 | let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone()); 366 | 367 | quote!( 368 | #(#cfgs)* 369 | #(#attrs)* 370 | #[doc(hidden)] 371 | #[export_name = #ident_s] 372 | pub unsafe extern "C" fn #tramp_ident() { 373 | #ident( 374 | #(#resource_args),* 375 | ) 376 | } 377 | 378 | #f 379 | ) 380 | } 381 | }; 382 | 383 | quote!( 384 | #assertion 385 | #handler 386 | ) 387 | .into() 388 | } 389 | 390 | #[proc_macro_attribute] 391 | pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { 392 | let mut f: ItemFn = syn::parse(input).expect("`#[interrupt]` must be applied to a function"); 393 | 394 | if !args.is_empty() { 395 | return parse::Error::new(Span::call_site(), "This attribute accepts no arguments") 396 | .to_compile_error() 397 | .into(); 398 | } 399 | 400 | let fspan = f.span(); 401 | let ident = f.sig.ident.clone(); 402 | let ident_s = ident.to_string(); 403 | 404 | // XXX should we blacklist other attributes? 405 | 406 | let valid_signature = f.sig.constness.is_none() 407 | && f.vis == Visibility::Inherited 408 | && f.sig.abi.is_none() 409 | && f.sig.inputs.is_empty() 410 | && f.sig.generics.params.is_empty() 411 | && f.sig.generics.where_clause.is_none() 412 | && f.sig.variadic.is_none() 413 | && match f.sig.output { 414 | ReturnType::Default => true, 415 | ReturnType::Type(_, ref ty) => match **ty { 416 | Type::Tuple(ref tuple) => tuple.elems.is_empty(), 417 | Type::Never(..) => true, 418 | _ => false, 419 | }, 420 | }; 421 | 422 | if !valid_signature { 423 | return parse::Error::new( 424 | fspan, 425 | "`#[interrupt]` handlers must have signature `[unsafe] fn() [-> !]`", 426 | ) 427 | .to_compile_error() 428 | .into(); 429 | } 430 | 431 | let (statics, stmts) = match extract_static_muts(f.block.stmts.iter().cloned()) { 432 | Err(e) => return e.to_compile_error().into(), 433 | Ok(x) => x, 434 | }; 435 | 436 | f.sig.ident = Ident::new(&format!("__cortex_m_rt_{}", f.sig.ident), Span::call_site()); 437 | f.sig.inputs.extend(statics.iter().map(|statik| { 438 | let ident = &statik.ident; 439 | let ty = &statik.ty; 440 | let attrs = &statik.attrs; 441 | syn::parse::(quote!(#[allow(non_snake_case)] #(#attrs)* #ident: &mut #ty).into()) 442 | .unwrap() 443 | })); 444 | f.block.stmts = iter::once( 445 | syn::parse2(quote! {{ 446 | // Check that this interrupt actually exists 447 | interrupt::#ident; 448 | }}) 449 | .unwrap(), 450 | ) 451 | .chain(stmts) 452 | .collect(); 453 | 454 | let tramp_ident = Ident::new(&format!("{}_trampoline", f.sig.ident), Span::call_site()); 455 | let ident = &f.sig.ident; 456 | 457 | let resource_args = statics 458 | .iter() 459 | .map(|statik| { 460 | let (ref cfgs, ref attrs) = extract_cfgs(statik.attrs.clone()); 461 | let ident = &statik.ident; 462 | let ty = &statik.ty; 463 | let expr = &statik.expr; 464 | quote! { 465 | #(#cfgs)* 466 | { 467 | #(#attrs)* 468 | static mut #ident: #ty = #expr; 469 | &mut #ident 470 | } 471 | } 472 | }) 473 | .collect::>(); 474 | 475 | if let Err(error) = check_attr_whitelist(&f.attrs, WhiteListCaller::Interrupt) { 476 | return error; 477 | } 478 | 479 | let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone()); 480 | 481 | quote!( 482 | #(#cfgs)* 483 | #(#attrs)* 484 | #[doc(hidden)] 485 | #[export_name = #ident_s] 486 | pub unsafe extern "C" fn #tramp_ident() { 487 | #ident( 488 | #(#resource_args),* 489 | ) 490 | } 491 | 492 | #f 493 | ) 494 | .into() 495 | } 496 | 497 | #[proc_macro_attribute] 498 | pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream { 499 | let f = parse_macro_input!(input as ItemFn); 500 | 501 | // check the function signature 502 | let valid_signature = f.sig.constness.is_none() 503 | && f.vis == Visibility::Inherited 504 | && f.sig.unsafety.is_some() 505 | && f.sig.abi.is_none() 506 | && f.sig.inputs.is_empty() 507 | && f.sig.generics.params.is_empty() 508 | && f.sig.generics.where_clause.is_none() 509 | && f.sig.variadic.is_none() 510 | && match f.sig.output { 511 | ReturnType::Default => true, 512 | ReturnType::Type(_, ref ty) => match **ty { 513 | Type::Tuple(ref tuple) => tuple.elems.is_empty(), 514 | _ => false, 515 | }, 516 | }; 517 | 518 | if !valid_signature { 519 | return parse::Error::new( 520 | f.span(), 521 | "`#[pre_init]` function must have signature `unsafe fn()`", 522 | ) 523 | .to_compile_error() 524 | .into(); 525 | } 526 | 527 | if !args.is_empty() { 528 | return parse::Error::new(Span::call_site(), "This attribute accepts no arguments") 529 | .to_compile_error() 530 | .into(); 531 | } 532 | 533 | if let Err(error) = check_attr_whitelist(&f.attrs, WhiteListCaller::PreInit) { 534 | return error; 535 | } 536 | 537 | // XXX should we blacklist other attributes? 538 | let attrs = f.attrs; 539 | let ident = f.sig.ident; 540 | let block = f.block; 541 | 542 | quote!( 543 | #[export_name = "__pre_init"] 544 | #[allow(missing_docs)] // we make a private fn public, which can trigger this lint 545 | #(#attrs)* 546 | pub unsafe fn #ident() #block 547 | ) 548 | .into() 549 | } 550 | 551 | /// Extracts `static mut` vars from the beginning of the given statements 552 | fn extract_static_muts( 553 | stmts: impl IntoIterator, 554 | ) -> Result<(Vec, Vec), parse::Error> { 555 | let mut istmts = stmts.into_iter(); 556 | 557 | let mut seen = HashSet::new(); 558 | let mut statics = vec![]; 559 | let mut stmts = vec![]; 560 | while let Some(stmt) = istmts.next() { 561 | match stmt { 562 | Stmt::Item(Item::Static(var)) => { 563 | if var.mutability.is_some() { 564 | if seen.contains(&var.ident) { 565 | return Err(parse::Error::new( 566 | var.ident.span(), 567 | format!("the name `{}` is defined multiple times", var.ident), 568 | )); 569 | } 570 | 571 | seen.insert(var.ident.clone()); 572 | statics.push(var); 573 | } else { 574 | stmts.push(Stmt::Item(Item::Static(var))); 575 | } 576 | } 577 | _ => { 578 | stmts.push(stmt); 579 | break; 580 | } 581 | } 582 | } 583 | 584 | stmts.extend(istmts); 585 | 586 | Ok((statics, stmts)) 587 | } 588 | 589 | fn extract_cfgs(attrs: Vec) -> (Vec, Vec) { 590 | let mut cfgs = vec![]; 591 | let mut not_cfgs = vec![]; 592 | 593 | for attr in attrs { 594 | if eq(&attr, "cfg") { 595 | cfgs.push(attr); 596 | } else { 597 | not_cfgs.push(attr); 598 | } 599 | } 600 | 601 | (cfgs, not_cfgs) 602 | } 603 | 604 | enum WhiteListCaller { 605 | Entry, 606 | Exception, 607 | Interrupt, 608 | PreInit, 609 | } 610 | 611 | fn check_attr_whitelist(attrs: &[Attribute], caller: WhiteListCaller) -> Result<(), TokenStream> { 612 | let whitelist = &[ 613 | "doc", 614 | "link_section", 615 | "cfg", 616 | "allow", 617 | "warn", 618 | "deny", 619 | "forbid", 620 | "cold", 621 | ]; 622 | 623 | 'o: for attr in attrs { 624 | for val in whitelist { 625 | if eq(&attr, &val) { 626 | continue 'o; 627 | } 628 | } 629 | 630 | let err_str = match caller { 631 | WhiteListCaller::Entry => "this attribute is not allowed on a cortex-m-rt entry point", 632 | WhiteListCaller::Exception => { 633 | "this attribute is not allowed on an exception handler controlled by cortex-m-rt" 634 | } 635 | WhiteListCaller::Interrupt => { 636 | "this attribute is not allowed on an interrupt handler controlled by cortex-m-rt" 637 | } 638 | WhiteListCaller::PreInit => { 639 | "this attribute is not allowed on a pre-init controlled by cortex-m-rt" 640 | } 641 | }; 642 | 643 | return Err(parse::Error::new(attr.span(), &err_str) 644 | .to_compile_error() 645 | .into()); 646 | } 647 | 648 | Ok(()) 649 | } 650 | 651 | /// Returns `true` if `attr.path` matches `name` 652 | fn eq(attr: &Attribute, name: &str) -> bool { 653 | attr.style == AttrStyle::Outer && attr.path.is_ident(name) 654 | } 655 | -------------------------------------------------------------------------------- /memory.x: -------------------------------------------------------------------------------- 1 | /* Device specific memory layout */ 2 | 3 | /* This file is used to build the cortex-m-rt examples, 4 | but not other applications using cortex-m-rt. */ 5 | 6 | MEMORY 7 | { 8 | /* FLASH and RAM are mandatory memory regions */ 9 | /* Update examples/data_overflow.rs if you change these sizes. */ 10 | FLASH : ORIGIN = 0x00000000, LENGTH = 256K 11 | RAM : ORIGIN = 0x20000000, LENGTH = 64K 12 | 13 | /* More memory regions can declared: for example this is a second RAM region */ 14 | /* CCRAM : ORIGIN = 0x10000000, LENGTH = 8K */ 15 | } 16 | 17 | /* The location of the stack can be overridden using the `_stack_start` symbol. 18 | By default it will be placed at the end of the RAM region */ 19 | /* _stack_start = ORIGIN(CCRAM) + LENGTH(CCRAM); */ 20 | 21 | /* The location of the .text section can be overridden using the `_stext` symbol. 22 | By default it will place after .vector_table */ 23 | /* _stext = ORIGIN(FLASH) + 0x40c; */ 24 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Startup code and minimal runtime for Cortex-M microcontrollers 2 | //! 3 | //! This crate contains all the required parts to build a `no_std` application (binary crate) that 4 | //! targets a Cortex-M microcontroller. 5 | //! 6 | //! # Features 7 | //! 8 | //! This crates takes care of: 9 | //! 10 | //! - The memory layout of the program. In particular, it populates the vector table so the device 11 | //! can boot correctly, and properly dispatch exceptions and interrupts. 12 | //! 13 | //! - Initializing `static` variables before the program entry point. 14 | //! 15 | //! - Enabling the FPU before the program entry point if the target is `thumbv7em-none-eabihf`. 16 | //! 17 | //! This crate also provides the following attributes: 18 | //! 19 | //! - [`#[entry]`][attr-entry] to declare the entry point of the program 20 | //! - [`#[exception]`][attr-exception] to override an exception handler. If not overridden all 21 | //! exception handlers default to an infinite loop. 22 | //! - [`#[pre_init]`][attr-pre_init] to run code *before* `static` variables are initialized 23 | //! 24 | //! This crate also implements a related attribute called `#[interrupt]`, which allows you 25 | //! to define interrupt handlers. However, since which interrupts are available depends on the 26 | //! microcontroller in use, this attribute should be re-exported and used from a device crate. 27 | //! 28 | //! The documentation for these attributes can be found in the [Attribute Macros](#attributes) 29 | //! section. 30 | //! 31 | //! # Requirements 32 | //! 33 | //! ## `memory.x` 34 | //! 35 | //! This crate expects the user, or some other crate, to provide the memory layout of the target 36 | //! device via a linker script named `memory.x`. This section covers the contents of `memory.x` 37 | //! The `memory.x` file is used by during linking by the `link.x` script provided by this crate. 38 | //! 39 | //! ### `MEMORY` 40 | //! 41 | //! The linker script must specify the memory available in the device as, at least, two `MEMORY` 42 | //! regions: one named `FLASH` and one named `RAM`. The `.text` and `.rodata` sections of the 43 | //! program will be placed in the `FLASH` region, whereas the `.bss` and `.data` sections, as well 44 | //! as the heap,will be placed in the `RAM` region. 45 | //! 46 | //! ```text 47 | //! /* Linker script for the STM32F103C8T6 */ 48 | //! MEMORY 49 | //! { 50 | //! FLASH : ORIGIN = 0x08000000, LENGTH = 64K 51 | //! RAM : ORIGIN = 0x20000000, LENGTH = 20K 52 | //! } 53 | //! ``` 54 | //! 55 | //! ### `_stack_start` 56 | //! 57 | //! This optional symbol can be used to indicate where the call stack of the program should be 58 | //! placed. If this symbol is not used then the stack will be placed at the *end* of the `RAM` 59 | //! region -- the stack grows downwards towards smaller address. This symbol can be used to place 60 | //! the stack in a different memory region, for example: 61 | //! 62 | //! ```text 63 | //! /* Linker script for the STM32F303VCT6 */ 64 | //! MEMORY 65 | //! { 66 | //! FLASH : ORIGIN = 0x08000000, LENGTH = 256K 67 | //! 68 | //! /* .bss, .data and the heap go in this region */ 69 | //! RAM : ORIGIN = 0x20000000, LENGTH = 40K 70 | //! 71 | //! /* Core coupled (faster) RAM dedicated to hold the stack */ 72 | //! CCRAM : ORIGIN = 0x10000000, LENGTH = 8K 73 | //! } 74 | //! 75 | //! _stack_start = ORIGIN(CCRAM) + LENGTH(CCRAM); 76 | //! ``` 77 | //! 78 | //! ### `_stext` 79 | //! 80 | //! This optional symbol can be used to control where the `.text` section is placed. If omitted the 81 | //! `.text` section will be placed right after the vector table, which is placed at the beginning of 82 | //! `FLASH`. Some devices store settings like Flash configuration right after the vector table; 83 | //! for these devices one must place the `.text` section after this configuration section -- 84 | //! `_stext` can be used for this purpose. 85 | //! 86 | //! ```text 87 | //! MEMORY 88 | //! { 89 | //! /* .. */ 90 | //! } 91 | //! 92 | //! /* The device stores Flash configuration in 0x400-0x40C so we place .text after that */ 93 | //! _stext = ORIGIN(FLASH) + 0x40C 94 | //! ``` 95 | //! 96 | //! # An example 97 | //! 98 | //! This section presents a minimal application built on top of `cortex-m-rt`. Apart from the 99 | //! mandatory `memory.x` linker script describing the memory layout of the device, the hard fault 100 | //! handler and the default exception handler must also be defined somewhere in the dependency 101 | //! graph (see [`#[exception]`]). In this example we define them in the binary crate: 102 | //! 103 | //! ```no_run 104 | //! // IMPORTANT the standard `main` interface is not used because it requires nightly 105 | //! #![no_main] 106 | //! #![no_std] 107 | //! 108 | //! // Some panic handler needs to be included. This one halts the processor on panic. 109 | //! extern crate panic_halt; 110 | //! 111 | //! use cortex_m_rt::entry; 112 | //! 113 | //! // use `main` as the entry point of this application 114 | //! // `main` is not allowed to return 115 | //! #[entry] 116 | //! fn main() -> ! { 117 | //! // initialization 118 | //! 119 | //! loop { 120 | //! // application logic 121 | //! } 122 | //! } 123 | //! ``` 124 | //! 125 | //! To actually build this program you need to place a `memory.x` linker script somewhere the linker 126 | //! can find it, e.g. in the current directory; and then link the program using `cortex-m-rt`'s 127 | //! linker script: `link.x`. The required steps are shown below: 128 | //! 129 | //! ```text 130 | //! $ cat > memory.x < !` or its invocation from 247 | //! `Reset` will result in undefined behavior. 248 | //! 249 | //! ## Incorporating device specific interrupts 250 | //! 251 | //! This section covers how an external crate can insert device specific interrupt handlers into the 252 | //! vector table. Most users don't need to concern themselves with these details, but if you are 253 | //! interested in how device crates generated using `svd2rust` integrate with `cortex-m-rt` read on. 254 | //! 255 | //! The information in this section applies when the `"device"` feature has been enabled. 256 | //! 257 | //! ### `__INTERRUPTS` 258 | //! 259 | //! The external crate must provide the interrupts portion of the vector table via a `static` 260 | //! variable named`__INTERRUPTS` (unmangled) that must be placed in the `.vector_table.interrupts` 261 | //! section of its object file. 262 | //! 263 | //! This `static` variable will be placed at `ORIGIN(FLASH) + 0x40`. This address corresponds to the 264 | //! spot where IRQ0 (IRQ number 0) is located. 265 | //! 266 | //! To conform to the Cortex-M ABI `__INTERRUPTS` must be an array of function pointers; some spots 267 | //! in this array may need to be set to 0 if they are marked as *reserved* in the data sheet / 268 | //! reference manual. We recommend using a `union` to set the reserved spots to `0`; `None` 269 | //! (`Option`) may also work but it's not guaranteed that the `None` variant will *always* be 270 | //! represented by the value `0`. 271 | //! 272 | //! Let's illustrate with an artificial example where a device only has two interrupt: `Foo`, with 273 | //! IRQ number = 2, and `Bar`, with IRQ number = 4. 274 | //! 275 | //! ```no_run 276 | //! pub union Vector { 277 | //! handler: unsafe extern "C" fn(), 278 | //! reserved: usize, 279 | //! } 280 | //! 281 | //! extern "C" { 282 | //! fn Foo(); 283 | //! fn Bar(); 284 | //! } 285 | //! 286 | //! #[link_section = ".vector_table.interrupts"] 287 | //! #[no_mangle] 288 | //! pub static __INTERRUPTS: [Vector; 5] = [ 289 | //! // 0-1: Reserved 290 | //! Vector { reserved: 0 }, 291 | //! Vector { reserved: 0 }, 292 | //! 293 | //! // 2: Foo 294 | //! Vector { handler: Foo }, 295 | //! 296 | //! // 3: Reserved 297 | //! Vector { reserved: 0 }, 298 | //! 299 | //! // 4: Bar 300 | //! Vector { handler: Bar }, 301 | //! ]; 302 | //! ``` 303 | //! 304 | //! ### `device.x` 305 | //! 306 | //! Linking in `__INTERRUPTS` creates a bunch of undefined references. If the user doesn't set a 307 | //! handler for *all* the device specific interrupts then linking will fail with `"undefined 308 | //! reference"` errors. 309 | //! 310 | //! We want to provide a default handler for all the interrupts while still letting the user 311 | //! individually override each interrupt handler. In C projects, this is usually accomplished using 312 | //! weak aliases declared in external assembly files. In Rust, we could achieve something similar 313 | //! using `global_asm!`, but that's an unstable feature. 314 | //! 315 | //! A solution that doesn't require `global_asm!` or external assembly files is to use the `PROVIDE` 316 | //! command in a linker script to create the weak aliases. This is the approach that `cortex-m-rt` 317 | //! uses; when the `"device"` feature is enabled `cortex-m-rt`'s linker script (`link.x`) depends on 318 | //! a linker script named `device.x`. The crate that provides `__INTERRUPTS` must also provide this 319 | //! file. 320 | //! 321 | //! For our running example the `device.x` linker script looks like this: 322 | //! 323 | //! ```text 324 | //! /* device.x */ 325 | //! PROVIDE(Foo = DefaultHandler); 326 | //! PROVIDE(Bar = DefaultHandler); 327 | //! ``` 328 | //! 329 | //! This weakly aliases both `Foo` and `Bar`. `DefaultHandler` is the default exception handler and 330 | //! that the core exceptions use unless overridden. 331 | //! 332 | //! Because this linker script is provided by a dependency of the final application the dependency 333 | //! must contain build script that puts `device.x` somewhere the linker can find. An example of such 334 | //! build script is shown below: 335 | //! 336 | //! ```ignore 337 | //! use std::env; 338 | //! use std::fs::File; 339 | //! use std::io::Write; 340 | //! use std::path::PathBuf; 341 | //! 342 | //! fn main() { 343 | //! // Put the linker script somewhere the linker can find it 344 | //! let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); 345 | //! File::create(out.join("device.x")) 346 | //! .unwrap() 347 | //! .write_all(include_bytes!("device.x")) 348 | //! .unwrap(); 349 | //! println!("cargo:rustc-link-search={}", out.display()); 350 | //! } 351 | //! ``` 352 | //! 353 | //! ## Uninitialized static variables 354 | //! 355 | //! The `.uninit` linker section can be used to leave `static mut` variables uninitialized. One use 356 | //! case of unitialized static variables is to avoid zeroing large statically allocated buffers (say 357 | //! to be used as thread stacks) -- this can considerably reduce initialization time on devices that 358 | //! operate at low frequencies. 359 | //! 360 | //! The only correct way to use this section is by placing `static mut` variables with type 361 | //! [`MaybeUninit`] in it. 362 | //! 363 | //! [`MaybeUninit`]: https://doc.rust-lang.org/core/mem/union.MaybeUninit.html 364 | //! 365 | //! ```no_run,edition2018 366 | //! # extern crate core; 367 | //! use core::mem::MaybeUninit; 368 | //! 369 | //! const STACK_SIZE: usize = 8 * 1024; 370 | //! const NTHREADS: usize = 4; 371 | //! 372 | //! #[link_section = ".uninit.STACKS"] 373 | //! static mut STACKS: MaybeUninit<[[u8; STACK_SIZE]; NTHREADS]> = MaybeUninit::uninit(); 374 | //! ``` 375 | //! 376 | //! Be very careful with the `link_section` attribute because it's easy to misuse in ways that cause 377 | //! undefined behavior. At some point in the future we may add an attribute to safely place static 378 | //! variables in this section. 379 | //! 380 | //! ## Extra Sections 381 | //! 382 | //! Some microcontrollers provide additional memory regions beyond RAM and FLASH. 383 | //! For example, some STM32 devices provide "CCM" or core-coupled RAM that is 384 | //! only accessible from the core. In order to access these using 385 | //! [`link_section`] attributes from your code, you need to modify `memory.x` 386 | //! to declare the additional sections: 387 | //! 388 | //! [`link_section`]: https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute 389 | //! 390 | //! ```text 391 | //! MEMORY 392 | //! { 393 | //! FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K 394 | //! RAM (rw) : ORIGIN = 0x20000000, LENGTH = 128K 395 | //! CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K 396 | //! } 397 | //! 398 | //! SECTIONS 399 | //! { 400 | //! .ccmram (NOLOAD) : ALIGN(4) 401 | //! { 402 | //! *(.ccmram .ccmram.*); 403 | //! . = ALIGN(4); 404 | //! } > CCMRAM 405 | //! } 406 | //! ``` 407 | //! 408 | //! You can then use something like this to place a variable into this specific section of memory: 409 | //! 410 | //! ```no_run,edition2018 411 | //! #[link_section=".ccmram.BUFFERS"] 412 | //! static mut BUF: [u8; 1024] = [0u8; 1024]; 413 | //! ``` 414 | //! 415 | //! [attr-entry]: attr.entry.html 416 | //! [attr-exception]: attr.exception.html 417 | //! [attr-pre_init]: attr.pre_init.html 418 | //! 419 | //! # Minimum Supported Rust Version (MSRV) 420 | //! 421 | //! The MSRV of this release is Rust 1.39.0. 422 | 423 | // # Developer notes 424 | // 425 | // - `link_section` is used to place symbols in specific places of the final binary. The names used 426 | // here will appear in the linker script (`link.x`) in conjunction with the `KEEP` command. 427 | 428 | #![deny(missing_docs)] 429 | #![no_std] 430 | 431 | extern crate cortex_m_rt_macros as macros; 432 | 433 | use core::fmt; 434 | use core::sync::atomic::{self, Ordering}; 435 | 436 | /// Attribute to declare an interrupt (AKA device-specific exception) handler 437 | /// 438 | /// **IMPORTANT**: If you are using Rust 1.30 this attribute must be used on reachable items (i.e. 439 | /// there must be no private modules between the item and the root of the crate); if the item is in 440 | /// the root of the crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 441 | /// and newer releases. 442 | /// 443 | /// **NOTE**: This attribute is exposed by `cortex-m-rt` only when the `device` feature is enabled. 444 | /// However, that export is not meant to be used directly -- using it will result in a compilation 445 | /// error. You should instead use the device crate (usually generated using `svd2rust`) re-export of 446 | /// that attribute. You need to use the re-export to have the compiler check that the interrupt 447 | /// exists on the target device. 448 | /// 449 | /// # Syntax 450 | /// 451 | /// ``` ignore 452 | /// extern crate device; 453 | /// 454 | /// // the attribute comes from the device crate not from cortex-m-rt 455 | /// use device::interrupt; 456 | /// 457 | /// #[interrupt] 458 | /// fn USART1() { 459 | /// // .. 460 | /// } 461 | /// ``` 462 | /// 463 | /// where the name of the function must be one of the device interrupts. 464 | /// 465 | /// # Usage 466 | /// 467 | /// `#[interrupt] fn Name(..` overrides the default handler for the interrupt with the given `Name`. 468 | /// These handlers must have signature `[unsafe] fn() [-> !]`. It's possible to add state to these 469 | /// handlers by declaring `static mut` variables at the beginning of the body of the function. These 470 | /// variables will be safe to access from the function body. 471 | /// 472 | /// If the interrupt handler has not been overridden it will be dispatched by the default exception 473 | /// handler (`DefaultHandler`). 474 | /// 475 | /// # Properties 476 | /// 477 | /// Interrupts handlers can only be called by the hardware. Other parts of the program can't refer 478 | /// to the interrupt handlers, much less invoke them as if they were functions. 479 | /// 480 | /// `static mut` variables declared within an interrupt handler are safe to access and can be used 481 | /// to preserve state across invocations of the handler. The compiler can't prove this is safe so 482 | /// the attribute will help by making a transformation to the source code: for this reason a 483 | /// variable like `static mut FOO: u32` will become `let FOO: &mut u32;`. 484 | /// 485 | /// # Examples 486 | /// 487 | /// - Using state within an interrupt handler 488 | /// 489 | /// ``` ignore 490 | /// extern crate device; 491 | /// 492 | /// use device::interrupt; 493 | /// 494 | /// #[interrupt] 495 | /// fn TIM2() { 496 | /// static mut COUNT: i32 = 0; 497 | /// 498 | /// // `COUNT` is safe to access and has type `&mut i32` 499 | /// *COUNT += 1; 500 | /// 501 | /// println!("{}", COUNT); 502 | /// } 503 | /// ``` 504 | #[cfg(feature = "device")] 505 | pub use macros::interrupt; 506 | 507 | /// Attribute to declare the entry point of the program 508 | /// 509 | /// **IMPORTANT**: This attribute must appear exactly *once* in the dependency graph. Also, if you 510 | /// are using Rust 1.30 the attribute must be used on a reachable item (i.e. there must be no 511 | /// private modules between the item and the root of the crate); if the item is in the root of the 512 | /// crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 and newer releases. 513 | /// 514 | /// The specified function will be called by the reset handler *after* RAM has been initialized. In 515 | /// the case of the `thumbv7em-none-eabihf` target the FPU will also be enabled before the function 516 | /// is called. 517 | /// 518 | /// The type of the specified function must be `[unsafe] fn() -> !` (never ending function) 519 | /// 520 | /// # Properties 521 | /// 522 | /// The entry point will be called by the reset handler. The program can't reference to the entry 523 | /// point, much less invoke it. 524 | /// 525 | /// `static mut` variables declared within the entry point are safe to access. The compiler can't 526 | /// prove this is safe so the attribute will help by making a transformation to the source code: for 527 | /// this reason a variable like `static mut FOO: u32` will become `let FOO: &'static mut u32;`. Note 528 | /// that `&'static mut` references have move semantics. 529 | /// 530 | /// # Examples 531 | /// 532 | /// - Simple entry point 533 | /// 534 | /// ``` no_run 535 | /// # #![no_main] 536 | /// # use cortex_m_rt::entry; 537 | /// #[entry] 538 | /// fn main() -> ! { 539 | /// loop { 540 | /// /* .. */ 541 | /// } 542 | /// } 543 | /// ``` 544 | /// 545 | /// - `static mut` variables local to the entry point are safe to modify. 546 | /// 547 | /// ``` no_run 548 | /// # #![no_main] 549 | /// # use cortex_m_rt::entry; 550 | /// #[entry] 551 | /// fn main() -> ! { 552 | /// static mut FOO: u32 = 0; 553 | /// 554 | /// let foo: &'static mut u32 = FOO; 555 | /// assert_eq!(*foo, 0); 556 | /// *foo = 1; 557 | /// assert_eq!(*foo, 1); 558 | /// 559 | /// loop { 560 | /// /* .. */ 561 | /// } 562 | /// } 563 | /// ``` 564 | pub use macros::entry; 565 | 566 | /// Attribute to declare an exception handler 567 | /// 568 | /// **IMPORTANT**: If you are using Rust 1.30 this attribute must be used on reachable items (i.e. 569 | /// there must be no private modules between the item and the root of the crate); if the item is in 570 | /// the root of the crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 571 | /// and newer releases. 572 | /// 573 | /// # Syntax 574 | /// 575 | /// ``` 576 | /// # use cortex_m_rt::exception; 577 | /// #[exception] 578 | /// fn SysTick() { 579 | /// // .. 580 | /// } 581 | /// 582 | /// # fn main() {} 583 | /// ``` 584 | /// 585 | /// where the name of the function must be one of: 586 | /// 587 | /// - `DefaultHandler` 588 | /// - `NonMaskableInt` 589 | /// - `HardFault` 590 | /// - `MemoryManagement` (a) 591 | /// - `BusFault` (a) 592 | /// - `UsageFault` (a) 593 | /// - `SecureFault` (b) 594 | /// - `SVCall` 595 | /// - `DebugMonitor` (a) 596 | /// - `PendSV` 597 | /// - `SysTick` 598 | /// 599 | /// (a) Not available on Cortex-M0 variants (`thumbv6m-none-eabi`) 600 | /// 601 | /// (b) Only available on ARMv8-M 602 | /// 603 | /// # Usage 604 | /// 605 | /// `#[exception] unsafe fn HardFault(..` sets the hard fault handler. The handler must have 606 | /// signature `unsafe fn(&ExceptionFrame) -> !`. This handler is not allowed to return as that can 607 | /// cause undefined behavior. 608 | /// 609 | /// `#[exception] unsafe fn DefaultHandler(..` sets the *default* handler. All exceptions which have 610 | /// not been assigned a handler will be serviced by this handler. This handler must have signature 611 | /// `unsafe fn(irqn: i16) [-> !]`. `irqn` is the IRQ number (See CMSIS); `irqn` will be a negative 612 | /// number when the handler is servicing a core exception; `irqn` will be a positive number when the 613 | /// handler is servicing a device specific exception (interrupt). 614 | /// 615 | /// `#[exception] fn Name(..` overrides the default handler for the exception with the given `Name`. 616 | /// These handlers must have signature `[unsafe] fn() [-> !]`. When overriding these other exception 617 | /// it's possible to add state to them by declaring `static mut` variables at the beginning of the 618 | /// body of the function. These variables will be safe to access from the function body. 619 | /// 620 | /// # Properties 621 | /// 622 | /// Exception handlers can only be called by the hardware. Other parts of the program can't refer to 623 | /// the exception handlers, much less invoke them as if they were functions. 624 | /// 625 | /// `static mut` variables declared within an exception handler are safe to access and can be used 626 | /// to preserve state across invocations of the handler. The compiler can't prove this is safe so 627 | /// the attribute will help by making a transformation to the source code: for this reason a 628 | /// variable like `static mut FOO: u32` will become `let FOO: &mut u32;`. 629 | /// 630 | /// # Safety 631 | /// 632 | /// It is not generally safe to register handlers for non-maskable interrupts. On Cortex-M, 633 | /// `HardFault` is non-maskable (at least in general), and there is an explicitly non-maskable 634 | /// interrupt `NonMaskableInt`. 635 | /// 636 | /// The reason for that is that non-maskable interrupts will preempt any currently running function, 637 | /// even if that function executes within a critical section. Thus, if it was safe to define NMI 638 | /// handlers, critical sections wouldn't work safely anymore. 639 | /// 640 | /// This also means that defining a `DefaultHandler` must be unsafe, as that will catch 641 | /// `NonMaskableInt` and `HardFault` if no handlers for those are defined. 642 | /// 643 | /// The safety requirements on those handlers is as follows: The handler must not access any data 644 | /// that is protected via a critical section and shared with other interrupts that may be preempted 645 | /// by the NMI while holding the critical section. As long as this requirement is fulfilled, it is 646 | /// safe to handle NMIs. 647 | /// 648 | /// # Examples 649 | /// 650 | /// - Setting the default handler 651 | /// 652 | /// ``` 653 | /// use cortex_m_rt::exception; 654 | /// 655 | /// #[exception] 656 | /// unsafe fn DefaultHandler(irqn: i16) { 657 | /// println!("IRQn = {}", irqn); 658 | /// } 659 | /// 660 | /// # fn main() {} 661 | /// ``` 662 | /// 663 | /// - Overriding the `SysTick` handler 664 | /// 665 | /// ``` 666 | /// use cortex_m_rt::exception; 667 | /// 668 | /// #[exception] 669 | /// fn SysTick() { 670 | /// static mut COUNT: i32 = 0; 671 | /// 672 | /// // `COUNT` is safe to access and has type `&mut i32` 673 | /// *COUNT += 1; 674 | /// 675 | /// println!("{}", COUNT); 676 | /// } 677 | /// 678 | /// # fn main() {} 679 | /// ``` 680 | pub use macros::exception; 681 | 682 | /// Attribute to mark which function will be called at the beginning of the reset handler. 683 | /// 684 | /// **IMPORTANT**: This attribute can appear at most *once* in the dependency graph. Also, if you 685 | /// are using Rust 1.30 the attribute must be used on a reachable item (i.e. there must be no 686 | /// private modules between the item and the root of the crate); if the item is in the root of the 687 | /// crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 and newer 688 | /// releases. 689 | /// 690 | /// The function must have the signature of `unsafe fn()`. 691 | /// 692 | /// # Safety 693 | /// 694 | /// The function will be called before memory is initialized, as soon as possible after reset. Any 695 | /// access of memory, including any static variables, will result in undefined behavior. 696 | /// 697 | /// **Warning**: Due to [rvalue static promotion][rfc1414] static variables may be accessed whenever 698 | /// taking a reference to a constant. This means that even trivial expressions such as `&1` in the 699 | /// `#[pre_init]` function *or any code called by it* will cause **immediate undefined behavior**. 700 | /// 701 | /// Users are advised to only use the `#[pre_init]` feature when absolutely necessary as these 702 | /// constraints make safe usage difficult. 703 | /// 704 | /// # Examples 705 | /// 706 | /// ``` 707 | /// # use cortex_m_rt::pre_init; 708 | /// #[pre_init] 709 | /// unsafe fn before_main() { 710 | /// // do something here 711 | /// } 712 | /// 713 | /// # fn main() {} 714 | /// ``` 715 | /// 716 | /// [rfc1414]: https://github.com/rust-lang/rfcs/blob/master/text/1414-rvalue_static_promotion.md 717 | pub use macros::pre_init; 718 | 719 | // We export this static with an informative name so that if an application attempts to link 720 | // two copies of cortex-m-rt together, linking will fail. We also declare a links key in 721 | // Cargo.toml which is the more modern way to solve the same problem, but we have to keep 722 | // __ONCE__ around to prevent linking with versions before the links key was added. 723 | #[export_name = "error: cortex-m-rt appears more than once in the dependency graph"] 724 | #[doc(hidden)] 725 | pub static __ONCE__: () = (); 726 | 727 | /// Registers stacked (pushed onto the stack) during an exception. 728 | #[derive(Clone, Copy)] 729 | #[repr(C)] 730 | pub struct ExceptionFrame { 731 | r0: u32, 732 | r1: u32, 733 | r2: u32, 734 | r3: u32, 735 | r12: u32, 736 | lr: u32, 737 | pc: u32, 738 | xpsr: u32, 739 | } 740 | 741 | impl ExceptionFrame { 742 | /// Returns the value of (general purpose) register 0. 743 | #[inline(always)] 744 | pub fn r0(&self) -> u32 { 745 | self.r0 746 | } 747 | 748 | /// Returns the value of (general purpose) register 1. 749 | #[inline(always)] 750 | pub fn r1(&self) -> u32 { 751 | self.r1 752 | } 753 | 754 | /// Returns the value of (general purpose) register 2. 755 | #[inline(always)] 756 | pub fn r2(&self) -> u32 { 757 | self.r2 758 | } 759 | 760 | /// Returns the value of (general purpose) register 3. 761 | #[inline(always)] 762 | pub fn r3(&self) -> u32 { 763 | self.r3 764 | } 765 | 766 | /// Returns the value of (general purpose) register 12. 767 | #[inline(always)] 768 | pub fn r12(&self) -> u32 { 769 | self.r12 770 | } 771 | 772 | /// Returns the value of the Link Register. 773 | #[inline(always)] 774 | pub fn lr(&self) -> u32 { 775 | self.lr 776 | } 777 | 778 | /// Returns the value of the Program Counter. 779 | #[inline(always)] 780 | pub fn pc(&self) -> u32 { 781 | self.pc 782 | } 783 | 784 | /// Returns the value of the Program Status Register. 785 | #[inline(always)] 786 | pub fn xpsr(&self) -> u32 { 787 | self.xpsr 788 | } 789 | 790 | /// Sets the stacked value of (general purpose) register 0. 791 | /// 792 | /// # Safety 793 | /// 794 | /// This affects the `r0` register of the preempted code, which must not rely on it getting 795 | /// restored to its previous value. 796 | #[inline(always)] 797 | pub unsafe fn set_r0(&mut self, value: u32) { 798 | self.r0 = value; 799 | } 800 | 801 | /// Sets the stacked value of (general purpose) register 1. 802 | /// 803 | /// # Safety 804 | /// 805 | /// This affects the `r1` register of the preempted code, which must not rely on it getting 806 | /// restored to its previous value. 807 | #[inline(always)] 808 | pub unsafe fn set_r1(&mut self, value: u32) { 809 | self.r1 = value; 810 | } 811 | 812 | /// Sets the stacked value of (general purpose) register 2. 813 | /// 814 | /// # Safety 815 | /// 816 | /// This affects the `r2` register of the preempted code, which must not rely on it getting 817 | /// restored to its previous value. 818 | #[inline(always)] 819 | pub unsafe fn set_r2(&mut self, value: u32) { 820 | self.r2 = value; 821 | } 822 | 823 | /// Sets the stacked value of (general purpose) register 3. 824 | /// 825 | /// # Safety 826 | /// 827 | /// This affects the `r3` register of the preempted code, which must not rely on it getting 828 | /// restored to its previous value. 829 | #[inline(always)] 830 | pub unsafe fn set_r3(&mut self, value: u32) { 831 | self.r3 = value; 832 | } 833 | 834 | /// Sets the stacked value of (general purpose) register 12. 835 | /// 836 | /// # Safety 837 | /// 838 | /// This affects the `r12` register of the preempted code, which must not rely on it getting 839 | /// restored to its previous value. 840 | #[inline(always)] 841 | pub unsafe fn set_r12(&mut self, value: u32) { 842 | self.r12 = value; 843 | } 844 | 845 | /// Sets the stacked value of the Link Register. 846 | /// 847 | /// # Safety 848 | /// 849 | /// This affects the `lr` register of the preempted code, which must not rely on it getting 850 | /// restored to its previous value. 851 | #[inline(always)] 852 | pub unsafe fn set_lr(&mut self, value: u32) { 853 | self.lr = value; 854 | } 855 | 856 | /// Sets the stacked value of the Program Counter. 857 | /// 858 | /// # Safety 859 | /// 860 | /// This affects the `pc` register of the preempted code, which must not rely on it getting 861 | /// restored to its previous value. 862 | #[inline(always)] 863 | pub unsafe fn set_pc(&mut self, value: u32) { 864 | self.pc = value; 865 | } 866 | 867 | /// Sets the stacked value of the Program Status Register. 868 | /// 869 | /// # Safety 870 | /// 871 | /// This affects the `xPSR` registers (`IPSR`, `APSR`, and `EPSR`) of the preempted code, which 872 | /// must not rely on them getting restored to their previous value. 873 | #[inline(always)] 874 | pub unsafe fn set_xpsr(&mut self, value: u32) { 875 | self.xpsr = value; 876 | } 877 | } 878 | 879 | impl fmt::Debug for ExceptionFrame { 880 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 881 | struct Hex(u32); 882 | impl fmt::Debug for Hex { 883 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 884 | write!(f, "0x{:08x}", self.0) 885 | } 886 | } 887 | f.debug_struct("ExceptionFrame") 888 | .field("r0", &Hex(self.r0)) 889 | .field("r1", &Hex(self.r1)) 890 | .field("r2", &Hex(self.r2)) 891 | .field("r3", &Hex(self.r3)) 892 | .field("r12", &Hex(self.r12)) 893 | .field("lr", &Hex(self.lr)) 894 | .field("pc", &Hex(self.pc)) 895 | .field("xpsr", &Hex(self.xpsr)) 896 | .finish() 897 | } 898 | } 899 | 900 | /// Returns a pointer to the start of the heap 901 | /// 902 | /// The returned pointer is guaranteed to be 4-byte aligned. 903 | #[inline] 904 | pub fn heap_start() -> *mut u32 { 905 | extern "C" { 906 | static mut __sheap: u32; 907 | } 908 | 909 | unsafe { &mut __sheap } 910 | } 911 | 912 | // Entry point is Reset. 913 | #[doc(hidden)] 914 | #[cfg_attr(cortex_m, link_section = ".vector_table.reset_vector")] 915 | #[no_mangle] 916 | pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = Reset; 917 | 918 | #[allow(unused_variables)] 919 | #[doc(hidden)] 920 | #[cfg_attr(cortex_m, link_section = ".HardFault.default")] 921 | #[no_mangle] 922 | pub unsafe extern "C" fn HardFault_(ef: &ExceptionFrame) -> ! { 923 | loop { 924 | // add some side effect to prevent this from turning into a UDF instruction 925 | // see rust-lang/rust#28728 for details 926 | atomic::compiler_fence(Ordering::SeqCst); 927 | } 928 | } 929 | 930 | #[doc(hidden)] 931 | #[no_mangle] 932 | pub unsafe extern "C" fn DefaultHandler_() -> ! { 933 | loop { 934 | // add some side effect to prevent this from turning into a UDF instruction 935 | // see rust-lang/rust#28728 for details 936 | atomic::compiler_fence(Ordering::SeqCst); 937 | } 938 | } 939 | 940 | #[doc(hidden)] 941 | #[no_mangle] 942 | pub unsafe extern "C" fn DefaultPreInit() {} 943 | 944 | /* Exceptions */ 945 | #[doc(hidden)] 946 | pub enum Exception { 947 | NonMaskableInt, 948 | 949 | // Not overridable 950 | // HardFault, 951 | #[cfg(not(armv6m))] 952 | MemoryManagement, 953 | 954 | #[cfg(not(armv6m))] 955 | BusFault, 956 | 957 | #[cfg(not(armv6m))] 958 | UsageFault, 959 | 960 | #[cfg(armv8m)] 961 | SecureFault, 962 | 963 | SVCall, 964 | 965 | #[cfg(not(armv6m))] 966 | DebugMonitor, 967 | 968 | PendSV, 969 | 970 | SysTick, 971 | } 972 | 973 | #[doc(hidden)] 974 | pub use self::Exception as exception; 975 | 976 | extern "C" { 977 | fn Reset() -> !; 978 | 979 | fn NonMaskableInt(); 980 | 981 | fn HardFaultTrampoline(); 982 | 983 | #[cfg(not(armv6m))] 984 | fn MemoryManagement(); 985 | 986 | #[cfg(not(armv6m))] 987 | fn BusFault(); 988 | 989 | #[cfg(not(armv6m))] 990 | fn UsageFault(); 991 | 992 | #[cfg(armv8m)] 993 | fn SecureFault(); 994 | 995 | fn SVCall(); 996 | 997 | #[cfg(not(armv6m))] 998 | fn DebugMonitor(); 999 | 1000 | fn PendSV(); 1001 | 1002 | fn SysTick(); 1003 | } 1004 | 1005 | #[doc(hidden)] 1006 | pub union Vector { 1007 | handler: unsafe extern "C" fn(), 1008 | reserved: usize, 1009 | } 1010 | 1011 | #[doc(hidden)] 1012 | #[cfg_attr(cortex_m, link_section = ".vector_table.exceptions")] 1013 | #[no_mangle] 1014 | pub static __EXCEPTIONS: [Vector; 14] = [ 1015 | // Exception 2: Non Maskable Interrupt. 1016 | Vector { 1017 | handler: NonMaskableInt, 1018 | }, 1019 | // Exception 3: Hard Fault Interrupt. 1020 | Vector { 1021 | handler: HardFaultTrampoline, 1022 | }, 1023 | // Exception 4: Memory Management Interrupt [not on Cortex-M0 variants]. 1024 | #[cfg(not(armv6m))] 1025 | Vector { 1026 | handler: MemoryManagement, 1027 | }, 1028 | #[cfg(armv6m)] 1029 | Vector { reserved: 0 }, 1030 | // Exception 5: Bus Fault Interrupt [not on Cortex-M0 variants]. 1031 | #[cfg(not(armv6m))] 1032 | Vector { handler: BusFault }, 1033 | #[cfg(armv6m)] 1034 | Vector { reserved: 0 }, 1035 | // Exception 6: Usage Fault Interrupt [not on Cortex-M0 variants]. 1036 | #[cfg(not(armv6m))] 1037 | Vector { 1038 | handler: UsageFault, 1039 | }, 1040 | #[cfg(armv6m)] 1041 | Vector { reserved: 0 }, 1042 | // Exception 7: Secure Fault Interrupt [only on Armv8-M]. 1043 | #[cfg(armv8m)] 1044 | Vector { 1045 | handler: SecureFault, 1046 | }, 1047 | #[cfg(not(armv8m))] 1048 | Vector { reserved: 0 }, 1049 | // 8-10: Reserved 1050 | Vector { reserved: 0 }, 1051 | Vector { reserved: 0 }, 1052 | Vector { reserved: 0 }, 1053 | // Exception 11: SV Call Interrupt. 1054 | Vector { handler: SVCall }, 1055 | // Exception 12: Debug Monitor Interrupt [not on Cortex-M0 variants]. 1056 | #[cfg(not(armv6m))] 1057 | Vector { 1058 | handler: DebugMonitor, 1059 | }, 1060 | #[cfg(armv6m)] 1061 | Vector { reserved: 0 }, 1062 | // 13: Reserved 1063 | Vector { reserved: 0 }, 1064 | // Exception 14: Pend SV Interrupt [not on Cortex-M0 variants]. 1065 | Vector { handler: PendSV }, 1066 | // Exception 15: System Tick Interrupt. 1067 | Vector { handler: SysTick }, 1068 | ]; 1069 | 1070 | // If we are not targeting a specific device we bind all the potential device specific interrupts 1071 | // to the default handler 1072 | #[cfg(all(any(not(feature = "device"), test), not(armv6m)))] 1073 | #[doc(hidden)] 1074 | #[cfg_attr(cortex_m, link_section = ".vector_table.interrupts")] 1075 | #[no_mangle] 1076 | pub static __INTERRUPTS: [unsafe extern "C" fn(); 240] = [{ 1077 | extern "C" { 1078 | fn DefaultHandler(); 1079 | } 1080 | 1081 | DefaultHandler 1082 | }; 240]; 1083 | 1084 | // ARMv6-M can only have a maximum of 32 device specific interrupts 1085 | #[cfg(all(not(feature = "device"), armv6m))] 1086 | #[doc(hidden)] 1087 | #[link_section = ".vector_table.interrupts"] 1088 | #[no_mangle] 1089 | pub static __INTERRUPTS: [unsafe extern "C" fn(); 32] = [{ 1090 | extern "C" { 1091 | fn DefaultHandler(); 1092 | } 1093 | 1094 | DefaultHandler 1095 | }; 32]; 1096 | -------------------------------------------------------------------------------- /tests/compile-fail/default-handler-bad-signature-1.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, exception}; 8 | 9 | #[entry] 10 | fn foo() -> ! { 11 | loop {} 12 | } 13 | 14 | #[exception] 15 | unsafe fn DefaultHandler(_irqn: i16, undef: u32) {} 16 | //~^ ERROR `DefaultHandler` must have signature `unsafe fn(i16) [-> !]` 17 | -------------------------------------------------------------------------------- /tests/compile-fail/default-handler-bad-signature-2.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, exception}; 8 | 9 | #[entry] 10 | fn foo() -> ! { 11 | loop {} 12 | } 13 | 14 | #[exception] 15 | unsafe fn DefaultHandler(_irqn: i16) -> u32 { 16 | //~^ ERROR `DefaultHandler` must have signature `unsafe fn(i16) [-> !]` 17 | 0 18 | } 19 | -------------------------------------------------------------------------------- /tests/compile-fail/default-handler-hidden.rs: -------------------------------------------------------------------------------- 1 | // ignore-test :sadface: it's not possible to prevent this user error at compile time 2 | // see rust-lang/rust#53975 for details 3 | 4 | #![no_main] 5 | #![no_std] 6 | 7 | extern crate cortex_m_rt; 8 | extern crate panic_halt; 9 | 10 | use cortex_m_rt::{entry, exception}; 11 | 12 | #[entry] 13 | fn foo() -> ! { 14 | loop {} 15 | } 16 | 17 | mod hidden { 18 | use cortex_m_rt::exception; 19 | 20 | #[exception] 21 | unsafe fn DefaultHandler(_irqn: i16) {} 22 | } 23 | -------------------------------------------------------------------------------- /tests/compile-fail/default-handler-twice.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, exception}; 8 | 9 | #[entry] 10 | fn foo() -> ! { 11 | loop {} 12 | } 13 | 14 | #[exception] 15 | unsafe fn DefaultHandler(_irqn: i16) {} 16 | 17 | pub mod reachable { 18 | use cortex_m_rt::exception; 19 | 20 | #[exception] //~ ERROR symbol `DefaultHandler` is already defined 21 | unsafe fn DefaultHandler(_irqn: i16) {} 22 | } 23 | -------------------------------------------------------------------------------- /tests/compile-fail/duplicate-static.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, exception, interrupt}; 8 | 9 | #[allow(non_camel_case_types)] 10 | enum interrupt { 11 | UART0, 12 | } 13 | 14 | #[entry] 15 | fn foo() -> ! { 16 | static mut X: u32 = 0; 17 | static mut X: i32 = 0; //~ ERROR the name `X` is defined multiple times 18 | 19 | loop {} 20 | } 21 | 22 | #[exception] 23 | fn SVCall() { 24 | static mut X: u32 = 0; 25 | static mut X: i32 = 0; //~ ERROR the name `X` is defined multiple times 26 | } 27 | 28 | #[interrupt] 29 | fn UART0() { 30 | static mut X: u32 = 0; 31 | static mut X: i32 = 0; //~ ERROR the name `X` is defined multiple times 32 | } 33 | -------------------------------------------------------------------------------- /tests/compile-fail/entry-args.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::entry; 8 | 9 | #[entry(foo)] //~ ERROR This attribute accepts no arguments 10 | fn foo() -> ! { 11 | loop {} 12 | } 13 | -------------------------------------------------------------------------------- /tests/compile-fail/entry-bad-signature-1.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::entry; 8 | 9 | #[entry] 10 | fn foo() {} 11 | //~^ ERROR `#[entry]` function must have signature `[unsafe] fn() -> !` 12 | -------------------------------------------------------------------------------- /tests/compile-fail/entry-bad-signature-2.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::entry; 8 | 9 | #[entry] 10 | fn foo(undef: i32) -> ! {} 11 | //~^ ERROR `#[entry]` function must have signature `[unsafe] fn() -> !` 12 | -------------------------------------------------------------------------------- /tests/compile-fail/entry-bad-signature-3.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::entry; 8 | 9 | #[entry] 10 | extern "C" fn foo() -> ! { 11 | //~^ ERROR `#[entry]` function must have signature `[unsafe] fn() -> !` 12 | loop {} 13 | } 14 | -------------------------------------------------------------------------------- /tests/compile-fail/entry-hidden.rs: -------------------------------------------------------------------------------- 1 | // ignore-test :sadface: it's not possible to prevent this user error at compile time 2 | // see rust-lang/rust#53975 for details 3 | 4 | #![no_main] 5 | #![no_std] 6 | 7 | extern crate cortex_m_rt; 8 | extern crate panic_halt; 9 | 10 | mod hidden { 11 | use cortex_m_rt::entry; 12 | 13 | // this function needs to be "reachable" (all modules between it and the crate root must be 14 | // `pub`) or linking will fail 15 | #[entry] 16 | fn foo() -> ! { //~ ERROR function is never used 17 | loop {} 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/compile-fail/entry-soundness.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, exception}; 8 | 9 | #[entry] 10 | fn foo() -> ! { 11 | static mut COUNT: u64 = 0; 12 | 13 | loop { 14 | if *COUNT % 2 == 0 { 15 | *COUNT += 1; 16 | } else { 17 | *COUNT *= 2; 18 | } 19 | } 20 | } 21 | 22 | #[exception] 23 | fn SysTick() { 24 | // If this was allowed it would lead to a data race as `SysTick` can preempt `foo` 25 | foo(); //~ ERROR cannot find function `foo` in this scope 26 | } 27 | -------------------------------------------------------------------------------- /tests/compile-fail/entry-twice.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::entry; 8 | 9 | #[entry] 10 | fn foo() -> ! { 11 | loop {} 12 | } 13 | 14 | #[entry] //~ ERROR symbol `main` is already defined 15 | fn bar() -> ! { 16 | loop {} 17 | } 18 | -------------------------------------------------------------------------------- /tests/compile-fail/exception-args.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, exception}; 8 | 9 | #[entry] 10 | fn foo() -> ! { 11 | loop {} 12 | } 13 | 14 | #[exception(SysTick)] //~ ERROR This attribute accepts no arguments 15 | fn SysTick() {} 16 | -------------------------------------------------------------------------------- /tests/compile-fail/exception-bad-signature-1.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, exception}; 8 | 9 | #[entry] 10 | fn foo() -> ! { 11 | loop {} 12 | } 13 | 14 | #[exception] 15 | fn SysTick(undef: u32) {} 16 | //~^ ERROR `#[exception]` handlers other than `DefaultHandler` and `HardFault` must have signature `[unsafe] fn() [-> !]` 17 | -------------------------------------------------------------------------------- /tests/compile-fail/exception-bad-signature-2.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, exception}; 8 | 9 | #[entry] 10 | fn foo() -> ! { 11 | loop {} 12 | } 13 | 14 | #[exception] 15 | fn SysTick() -> u32 { 16 | //~^ ERROR `#[exception]` handlers other than `DefaultHandler` and `HardFault` must have signature `[unsafe] fn() [-> !]` 17 | 0 18 | } 19 | -------------------------------------------------------------------------------- /tests/compile-fail/exception-hidden.rs: -------------------------------------------------------------------------------- 1 | // ignore-test :sadface: it's not possible to prevent this user error at compile time 2 | // see rust-lang/rust#53975 for details 3 | 4 | #![no_main] 5 | #![no_std] 6 | 7 | extern crate cortex_m_rt; 8 | extern crate panic_halt; 9 | 10 | use cortex_m_rt::{entry, exception}; 11 | 12 | #[entry] 13 | fn foo() -> ! { 14 | loop {} 15 | } 16 | 17 | mod hidden { 18 | use cortex_m_rt::exception; 19 | 20 | #[exception] 21 | fn SysTick() {} 22 | } 23 | -------------------------------------------------------------------------------- /tests/compile-fail/exception-nmi-unsafe.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, exception}; 8 | 9 | #[entry] 10 | fn foo() -> ! { 11 | loop {} 12 | } 13 | 14 | #[exception] 15 | fn DefaultHandler(_irq: i16) {} 16 | //~^ ERROR defining a `DefaultHandler` is unsafe and requires an `unsafe fn` 17 | 18 | #[exception] 19 | fn HardFault() {} 20 | //~^ ERROR defining a `HardFault` handler is unsafe and requires an `unsafe fn` 21 | 22 | #[exception] 23 | fn NonMaskableInt() {} 24 | //~^ ERROR defining a `NonMaskableInt` handler is unsafe and requires an `unsafe fn` 25 | -------------------------------------------------------------------------------- /tests/compile-fail/exception-soundness.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, exception}; 8 | 9 | #[entry] 10 | fn foo() -> ! { 11 | loop {} 12 | } 13 | 14 | #[exception] 15 | fn SysTick() { 16 | static mut COUNT: u64 = 0; 17 | 18 | if *COUNT % 2 == 0 { 19 | *COUNT += 1; 20 | } else { 21 | *COUNT *= 2; 22 | } 23 | } 24 | 25 | #[exception] 26 | fn SVCall() { 27 | // If this was allowed it would lead to a data race as `SVCall` could preempt `SysTick` 28 | SysTick(); //~ ERROR cannot find function, tuple struct or tuple variant `SysTick` in this scope [E0425] 29 | } 30 | -------------------------------------------------------------------------------- /tests/compile-fail/exception-twice.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, exception}; 8 | 9 | #[entry] 10 | fn foo() -> ! { 11 | loop {} 12 | } 13 | 14 | #[exception] 15 | fn SysTick() {} 16 | 17 | pub mod reachable { 18 | use cortex_m_rt::exception; 19 | 20 | #[exception] //~ ERROR symbol `SysTick` is already defined 21 | fn SysTick() {} 22 | } 23 | -------------------------------------------------------------------------------- /tests/compile-fail/exception-v8only.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, exception}; 8 | 9 | #[entry] 10 | fn foo() -> ! { 11 | loop {} 12 | } 13 | 14 | #[exception] 15 | fn SecureFault() {} 16 | //~^ ERROR no variant or associated item named `SecureFault` 17 | -------------------------------------------------------------------------------- /tests/compile-fail/hard-fault-bad-signature-1.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, exception, ExceptionFrame}; 8 | 9 | #[entry] 10 | fn foo() -> ! { 11 | loop {} 12 | } 13 | 14 | #[exception] 15 | unsafe fn HardFault(_ef: &ExceptionFrame, undef: u32) -> ! { 16 | //~^ ERROR `HardFault` handler must have signature `unsafe fn(&ExceptionFrame) -> !` 17 | loop {} 18 | } 19 | -------------------------------------------------------------------------------- /tests/compile-fail/hard-fault-hidden.rs: -------------------------------------------------------------------------------- 1 | // ignore-test :sadface: it's not possible to prevent this user error at compile time 2 | // see rust-lang/rust#53975 for details 3 | 4 | #![no_main] 5 | #![no_std] 6 | 7 | extern crate cortex_m_rt; 8 | extern crate panic_halt; 9 | 10 | use cortex_m_rt::{entry, exception, ExceptionFrame}; 11 | 12 | #[entry] 13 | fn foo() -> ! { 14 | loop {} 15 | } 16 | 17 | mod hidden { 18 | use cortex_m_rt::{exception, ExceptionFrame}; 19 | 20 | #[exception] 21 | fn HardFault(_ef: &ExceptionFrame) -> ! { 22 | loop {} 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/compile-fail/hard-fault-twice.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, exception, ExceptionFrame}; 8 | 9 | #[entry] 10 | fn foo() -> ! { 11 | loop {} 12 | } 13 | 14 | #[exception] 15 | unsafe fn HardFault(_ef: &ExceptionFrame) -> ! { 16 | loop {} 17 | } 18 | 19 | pub mod reachable { 20 | use cortex_m_rt::{exception, ExceptionFrame}; 21 | 22 | #[exception] //~ ERROR symbol `HardFault` is already defined 23 | unsafe fn HardFault(_ef: &ExceptionFrame) -> ! { 24 | loop {} 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/compile-fail/interrupt-args.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, interrupt}; 8 | 9 | #[entry] 10 | fn foo() -> ! { 11 | loop {} 12 | } 13 | 14 | #[allow(non_camel_case_types)] 15 | enum interrupt { 16 | USART1, 17 | } 18 | 19 | #[interrupt(true)] //~ ERROR This attribute accepts no arguments 20 | fn USART1() {} 21 | -------------------------------------------------------------------------------- /tests/compile-fail/interrupt-bad-signature-1.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, interrupt}; 8 | 9 | #[entry] 10 | fn foo() -> ! { 11 | loop {} 12 | } 13 | 14 | #[allow(non_camel_case_types)] 15 | enum interrupt { 16 | USART1, 17 | } 18 | 19 | #[interrupt] 20 | fn USART1(undef: i32) {} 21 | //~^ ERROR `#[interrupt]` handlers must have signature `[unsafe] fn() [-> !]` 22 | -------------------------------------------------------------------------------- /tests/compile-fail/interrupt-bad-signature-2.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, interrupt}; 8 | 9 | #[entry] 10 | fn foo() -> ! { 11 | loop {} 12 | } 13 | 14 | #[allow(non_camel_case_types)] 15 | enum interrupt { 16 | USART1, 17 | } 18 | 19 | #[interrupt] 20 | fn USART1() -> i32 { 21 | //~^ ERROR `#[interrupt]` handlers must have signature `[unsafe] fn() [-> !]` 22 | 0 23 | } 24 | -------------------------------------------------------------------------------- /tests/compile-fail/interrupt-invalid.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, interrupt}; 8 | 9 | #[entry] 10 | fn entry() -> ! { 11 | loop {} 12 | } 13 | 14 | #[allow(non_camel_case_types)] 15 | enum interrupt { 16 | USART1, 17 | } 18 | 19 | // NOTE this looks a bit better when using a device crate: 20 | // "no variant named `foo` found for type `stm32f30x::Interrupt` in the current scope" 21 | #[interrupt] 22 | fn foo() {} //~ ERROR no variant or associated item named `foo` found for enum `interrupt` in the current scope [E0599] 23 | -------------------------------------------------------------------------------- /tests/compile-fail/interrupt-not-reexported.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, interrupt}; 8 | 9 | #[entry] 10 | fn foo() -> ! { 11 | loop {} 12 | } 13 | 14 | #[interrupt] //~ ERROR failed to resolve: use of undeclared crate or module `interrupt` 15 | fn USART1() {} 16 | -------------------------------------------------------------------------------- /tests/compile-fail/interrupt-soundness.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, interrupt}; 8 | 9 | #[entry] 10 | fn foo() -> ! { 11 | loop {} 12 | } 13 | 14 | #[allow(non_camel_case_types)] 15 | enum interrupt { 16 | USART1, 17 | USART2, 18 | } 19 | 20 | #[interrupt] 21 | fn USART1() { 22 | static mut COUNT: u64 = 0; 23 | 24 | if *COUNT % 2 == 0 { 25 | *COUNT += 1; 26 | } else { 27 | *COUNT *= 2; 28 | } 29 | } 30 | 31 | #[interrupt] 32 | fn USART2() { 33 | USART1(); //~ ERROR cannot find function, tuple struct or tuple variant `USART1` in this scope [E0425] 34 | } 35 | -------------------------------------------------------------------------------- /tests/compile-fail/interrupt-twice.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_camel_case_types)] 2 | #![no_main] 3 | #![no_std] 4 | 5 | extern crate cortex_m_rt; 6 | extern crate panic_halt; 7 | 8 | use cortex_m_rt::{entry, interrupt}; 9 | 10 | #[entry] 11 | fn foo() -> ! { 12 | loop {} 13 | } 14 | 15 | enum interrupt { 16 | USART1, 17 | } 18 | 19 | #[interrupt] 20 | fn USART1() {} 21 | 22 | pub mod reachable { 23 | use cortex_m_rt::interrupt; 24 | 25 | enum interrupt { 26 | USART1, 27 | } 28 | 29 | #[interrupt] //~ ERROR symbol `USART1` is already defined 30 | fn USART1() {} 31 | } 32 | -------------------------------------------------------------------------------- /tests/compile-fail/non-static-resource.rs: -------------------------------------------------------------------------------- 1 | //! Tests that no `&'static mut` to static mutable resources can be obtained, which would be 2 | //! unsound. 3 | //! 4 | //! Regression test for https://github.com/rust-embedded/cortex-m-rt/issues/212 5 | 6 | #![no_std] 7 | #![no_main] 8 | 9 | extern crate cortex_m; 10 | extern crate cortex_m_rt; 11 | extern crate panic_halt; 12 | 13 | use cortex_m_rt::{entry, exception, interrupt, ExceptionFrame}; 14 | 15 | #[allow(non_camel_case_types)] 16 | enum interrupt { 17 | UART0, 18 | } 19 | 20 | #[exception] 21 | fn SVCall() { 22 | static mut STAT: u8 = 0; 23 | 24 | let _stat: &'static mut u8 = STAT; //~ ERROR explicit lifetime required in the type of `STAT` 25 | } 26 | 27 | #[interrupt] 28 | fn UART0() { 29 | static mut STAT: u8 = 0; 30 | 31 | let _stat: &'static mut u8 = STAT; //~ ERROR explicit lifetime required in the type of `STAT` 32 | } 33 | 34 | #[entry] 35 | fn you_died_of_dis_entry() -> ! { 36 | static mut STAT: u8 = 0; 37 | 38 | // Allowed. This is sound for the entry point since it is only ever called once, and it makes 39 | // resources far more useful. 40 | let _stat: &'static mut u8 = STAT; 41 | 42 | loop {} 43 | } 44 | -------------------------------------------------------------------------------- /tests/compile-fail/pre-init-args.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, pre_init}; 8 | 9 | #[pre_init(foo)] //~ ERROR This attribute accepts no arguments 10 | unsafe fn foo() {} 11 | 12 | #[entry] 13 | fn baz() -> ! { 14 | loop {} 15 | } 16 | -------------------------------------------------------------------------------- /tests/compile-fail/pre-init-bad-signature-1.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, pre_init}; 8 | 9 | #[pre_init] 10 | fn foo() {} 11 | //~^ ERROR `#[pre_init]` function must have signature `unsafe fn()` 12 | 13 | #[entry] 14 | fn bar() -> ! { 15 | loop {} 16 | } 17 | -------------------------------------------------------------------------------- /tests/compile-fail/pre-init-bad-signature-2.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, pre_init}; 8 | 9 | #[pre_init] 10 | unsafe fn foo(undef: i32) {} 11 | //~^ ERROR `#[pre_init]` function must have signature `unsafe fn()` 12 | 13 | #[entry] 14 | fn bar() -> ! { 15 | loop {} 16 | } 17 | -------------------------------------------------------------------------------- /tests/compile-fail/pre-init-hidden.rs: -------------------------------------------------------------------------------- 1 | // ignore-test :sadface: it's not possible to prevent this user error at compile time 2 | // see rust-lang/rust#53975 for details 3 | 4 | #![no_main] 5 | #![no_std] 6 | 7 | extern crate cortex_m_rt; 8 | extern crate panic_halt; 9 | 10 | mod hidden { 11 | use cortex_m_rt::pre_init; 12 | 13 | // this function needs to be "reachable" (all modules between it and the crate root must be 14 | // `pub`) or the function will be ignored 15 | #[entry] 16 | unsafe fn pre_init() {} //~ ERROR function is never used 17 | } 18 | 19 | #[entry] 20 | fn foo() -> ! { 21 | //~ ERROR function is never used 22 | loop {} 23 | } 24 | -------------------------------------------------------------------------------- /tests/compile-fail/pre-init-twice.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, pre_init}; 8 | 9 | #[pre_init] 10 | unsafe fn foo() {} 11 | 12 | #[pre_init] //~ ERROR symbol `__pre_init` is already defined 13 | unsafe fn bar() {} 14 | 15 | #[entry] 16 | fn baz() -> ! { 17 | loop {} 18 | } 19 | -------------------------------------------------------------------------------- /tests/compile-fail/unsafe-init-static.rs: -------------------------------------------------------------------------------- 1 | //! Makes sure that the expansion of the attributes doesn't put the resource initializer in an 2 | //! implicit `unsafe` block. 3 | 4 | #![no_main] 5 | #![no_std] 6 | 7 | extern crate cortex_m_rt; 8 | extern crate panic_halt; 9 | 10 | use cortex_m_rt::{entry, exception, interrupt}; 11 | 12 | #[allow(non_camel_case_types)] 13 | enum interrupt { 14 | UART0, 15 | } 16 | 17 | const unsafe fn init() -> u32 { 0 } 18 | 19 | #[entry] 20 | fn foo() -> ! { 21 | static mut X: u32 = init(); //~ ERROR requires unsafe 22 | 23 | loop {} 24 | } 25 | 26 | #[exception] 27 | fn SVCall() { 28 | static mut X: u32 = init(); //~ ERROR requires unsafe 29 | } 30 | 31 | #[exception] 32 | unsafe fn DefaultHandler(_irq: i16) { 33 | static mut X: u32 = init(); //~ ERROR requires unsafe 34 | } 35 | 36 | #[exception] 37 | unsafe fn HardFault(_frame: &cortex_m_rt::ExceptionFrame) -> ! { 38 | static mut X: u32 = init(); //~ ERROR requires unsafe 39 | loop {} 40 | } 41 | 42 | #[interrupt] 43 | fn UART0() { 44 | static mut X: u32 = init(); //~ ERROR requires unsafe 45 | } 46 | -------------------------------------------------------------------------------- /tests/compile-fail/whitelist-1.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, exception, interrupt}; 8 | 9 | #[inline] //~ ERROR this attribute is not allowed on a cortex-m-rt entry point 10 | #[entry] 11 | fn foo() -> ! { 12 | loop {} 13 | } 14 | 15 | #[inline] //~ ERROR this attribute is not allowed on an exception handler controlled by cortex-m-rt 16 | #[exception] 17 | fn SysTick() {} 18 | 19 | #[allow(non_camel_case_types)] 20 | enum interrupt { 21 | USART1, 22 | USART2, 23 | } 24 | 25 | #[inline] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt 26 | #[interrupt] 27 | fn USART1() {} 28 | 29 | #[cfg(feature = "device")] 30 | #[cfg_attr(feature = "device", inline)] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt 31 | #[interrupt] 32 | fn USART2() {} 33 | -------------------------------------------------------------------------------- /tests/compile-fail/whitelist-2.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, exception, interrupt}; 8 | 9 | #[export_name = "not_allowed"] //~ ERROR this attribute is not allowed on a cortex-m-rt entry point 10 | #[entry] 11 | fn foo() -> ! { 12 | loop {} 13 | } 14 | 15 | #[export_name = "not_allowed"] //~ ERROR this attribute is not allowed on an exception handler controlled by cortex-m-rt 16 | #[exception] 17 | fn SysTick() {} 18 | 19 | #[allow(non_camel_case_types)] 20 | enum interrupt { 21 | USART1, 22 | USART2, 23 | } 24 | 25 | #[export_name = "not_allowed"] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt 26 | #[interrupt] 27 | fn USART1() {} 28 | 29 | #[cfg(feature = "device")] 30 | #[cfg_attr(feature = "device", export_name = "not_allowed")] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt 31 | #[interrupt] 32 | fn USART2() {} 33 | -------------------------------------------------------------------------------- /tests/compile-fail/whitelist-3.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, exception, interrupt}; 8 | 9 | #[no_mangle] //~ ERROR this attribute is not allowed on a cortex-m-rt entry point 10 | #[entry] 11 | fn foo() -> ! { 12 | loop {} 13 | } 14 | 15 | #[no_mangle] //~ ERROR this attribute is not allowed on an exception handler controlled by cortex-m-rt 16 | #[exception] 17 | fn SysTick() {} 18 | 19 | #[allow(non_camel_case_types)] 20 | enum interrupt { 21 | USART1, 22 | USART2, 23 | } 24 | 25 | #[no_mangle] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt 26 | #[interrupt] 27 | fn USART1() {} 28 | 29 | #[cfg(feature = "device")] 30 | #[cfg_attr(feature = "device", no_mangle)] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt 31 | #[interrupt] 32 | fn USART2() {} 33 | -------------------------------------------------------------------------------- /tests/compile-fail/whitelist-4.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, exception, interrupt}; 8 | 9 | #[must_use] //~ ERROR this attribute is not allowed on a cortex-m-rt entry point 10 | #[entry] 11 | fn foo() -> ! { 12 | loop {} 13 | } 14 | 15 | #[must_use] //~ ERROR this attribute is not allowed on an exception handler controlled by cortex-m-rt 16 | #[exception] 17 | fn SysTick() {} 18 | 19 | #[allow(non_camel_case_types)] 20 | enum interrupt { 21 | USART1, 22 | USART2, 23 | } 24 | 25 | #[must_use] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt 26 | #[interrupt] 27 | fn USART1() {} 28 | 29 | #[cfg(feature = "device")] 30 | #[cfg_attr(feature = "device", must_use)] //~ ERROR this attribute is not allowed on an interrupt handler controlled by cortex-m-rt 31 | #[interrupt] 32 | fn USART2() {} 33 | -------------------------------------------------------------------------------- /tests/compile-fail/whitelist-double-attr.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate cortex_m_rt; 5 | extern crate panic_halt; 6 | 7 | use cortex_m_rt::{entry, exception}; 8 | 9 | #[exception] 10 | #[entry] //~ ERROR this attribute is not allowed on an exception handler 11 | fn SVCall() -> ! { 12 | loop {} 13 | } 14 | -------------------------------------------------------------------------------- /tests/compiletest.rs: -------------------------------------------------------------------------------- 1 | extern crate compiletest_rs as compiletest; 2 | 3 | use std::path::PathBuf; 4 | 5 | fn run_mode(mode: &'static str) { 6 | let mut config = compiletest::Config::default(); 7 | 8 | config.mode = mode.parse().expect("Invalid mode"); 9 | config.src_base = PathBuf::from(format!("tests/{}", mode)); 10 | // config.link_deps(); // Populate config.target_rustcflags with dependencies on the path 11 | config.target_rustcflags = Some( 12 | "-L target/debug -L target/debug/deps -C panic=abort --cfg feature=\"device\"".to_owned(), 13 | ); 14 | // config.clean_rmeta(); // If your tests import the parent crate, this helps with E0464 15 | 16 | compiletest::run_tests(&config); 17 | } 18 | 19 | #[test] 20 | fn compile_test() { 21 | run_mode("compile-fail"); 22 | } 23 | -------------------------------------------------------------------------------- /triagebot.toml: -------------------------------------------------------------------------------- 1 | [assign] 2 | --------------------------------------------------------------------------------