From 1f2c429ab7e5b12320dbc9616f8a24c0f0c41bf1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 12 Mar 2017 10:51:41 -0500 Subject: initial commit --- cortex-m-rt/src/lang_items.rs | 63 +++++++++++++++++++++++++++++++++ cortex-m-rt/src/lib.rs | 81 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 cortex-m-rt/src/lang_items.rs create mode 100644 cortex-m-rt/src/lib.rs (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lang_items.rs b/cortex-m-rt/src/lang_items.rs new file mode 100644 index 0000000..bd7c4db --- /dev/null +++ b/cortex-m-rt/src/lang_items.rs @@ -0,0 +1,63 @@ +/// Default panic handler +#[lang = "panic_fmt"] +#[linkage = "weak"] +unsafe extern "C" fn panic_fmt( + _args: ::core::fmt::Arguments, + _file: &'static str, + _line: u32, +) -> ! { + match () { + #[cfg(feature = "panic-over-itm")] + () => { + use cortex_m::itm; + use cortex_m::peripheral::ITM; + + let port = &(*ITM.get()).stim[0]; + iprint!(port, "panicked at '"); + itm::write_fmt(port, _args); + iprintln!(port, "', {}:{}", _file, _line); + } + #[cfg(feature = "panic-over-semihosting")] + () => { + hprint!("panicked at '"); + ::cortex_m_semihosting::io::write_fmt(_args); + hprintln!("', {}:{}", _file, _line); + } + #[cfg(not(any(feature = "panic-over-itm", + feature = "panic-over-semihosting")))] + () => {} + } + + asm!("bkpt" :::: "volatile"); + + loop {} +} + +/// Lang item required to make the normal `main` work in applications +// This is how the `start` lang item works: +// When `rustc` compiles a binary crate, it creates a `main` function that looks +// like this: +// +// ``` +// #[export_name = "main"] +// pub extern "C" fn rustc_main(argc: isize, argv: *const *const u8) -> isize { +// start(main) +// } +// ``` +// +// Where `start` is this function and `main` is the binary crate's `main` +// function. +// +// The final piece is that the entry point of our program, the reset handler, +// has to call `rustc_main`. That's covered by the `reset_handler` function in +// root of this crate. +#[lang = "start"] +extern "C" fn start( + main: fn(), + _argc: isize, + _argv: *const *const u8, +) -> isize { + main(); + + 0 +} diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs new file mode 100644 index 0000000..e1ec26f --- /dev/null +++ b/cortex-m-rt/src/lib.rs @@ -0,0 +1,81 @@ +//! Minimal startup / runtime for Cortex-M microcontrollers +//! +//! Provides +//! +//! - Before main initialization of the `.bss` and `.data` sections +//! +//! - An overridable (\*) `panic_fmt` implementation that prints overs the ITM +//! or through semihosting depending on the enabled Cargo feature. +//! +//! - Minimal `start` lang item, to support vanilla `fn main()`. NOTE the +//! processor goes into "reactive" mode (`loop { asm!("wfi") }`) after +//! returning from `main`. +//! +//! (\*) To override the `panic_fmt` implementation, simply create a new +//! `rust_begin_unwind` symbol: +//! +//! ``` +//! #[no_mangle] +//! pub unsafe extern "C" fn rust_begin_unwind( +//! _args: ::core::fmt::Arguments, +//! _file: &'static str, +//! _line: u32, +//! ) -> ! { +//! .. +//! } +//! ``` + +#![deny(missing_docs)] +#![deny(warnings)] +#![feature(asm)] +#![feature(compiler_builtins_lib)] +#![feature(lang_items)] +#![feature(linkage)] +#![no_std] + +#[cfg(feature = "panic-over-itm")] +#[macro_use] +extern crate cortex_m; +extern crate compiler_builtins; +#[cfg(feature = "panic-over-semihosting")] +#[macro_use] +extern crate cortex_m_semihosting; +extern crate r0; + +mod lang_items; + +// TODO make private and use `#[used]` +/// The reset handler +/// +/// This is the entry point of all programs +#[doc(hidden)] +#[export_name = "start"] +pub unsafe extern "C" fn reset_handler() -> ! { + extern "C" { + static mut _ebss: u32; + static mut _sbss: u32; + + static mut _edata: u32; + static mut _sdata: u32; + + static _sidata: u32; + } + + ::r0::zero_bss(&mut _sbss, &mut _ebss); + ::r0::init_data(&mut _sdata, &mut _edata, &_sidata); + + // NOTE `rustc` forces this signature on us. See `src/lang_items.rs` + extern "C" { + fn main(argc: isize, argv: *const *const u8) -> isize; + } + + // Neither `argc` or `argv` make sense in bare metal contexts so we just + // stub them + main(0, ::core::ptr::null()); + + // If `main` returns, then we go into "reactive" mode and attend interrupts + // as they occur. + loop { + asm!("wfi" :::: "volatile"); + } +} -- cgit v1.2.3 From eeaf566b4e76925a77f1d7fc0aee80f7a9f1740c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Apr 2017 16:05:19 -0500 Subject: make the reset handler private --- cortex-m-rt/link.x | 6 +----- cortex-m-rt/src/lib.rs | 11 +++++++---- 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x index a15795e..a41218c 100644 --- a/cortex-m-rt/link.x +++ b/cortex-m-rt/link.x @@ -7,18 +7,14 @@ SECTIONS /* Vector table */ _VECTOR_TABLE = .; LONG(ORIGIN(RAM) + LENGTH(RAM)); - LONG(__reset + 1); + KEEP(*(.rodata.reset_handler)); KEEP(*(.rodata._EXCEPTIONS)); __exceptions = .; KEEP(*(.rodata._INTERRUPTS)); __interrupts = .; - /* Entry point: the reset handler */ - __reset = .; - KEEP(*(.text.start)); - *(.text.*); *(.rodata.*); } > FLASH diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index e1ec26f..7c8acfd 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -31,6 +31,7 @@ #![feature(compiler_builtins_lib)] #![feature(lang_items)] #![feature(linkage)] +#![feature(used)] #![no_std] #[cfg(feature = "panic-over-itm")] @@ -44,13 +45,10 @@ extern crate r0; mod lang_items; -// TODO make private and use `#[used]` /// The reset handler /// /// This is the entry point of all programs -#[doc(hidden)] -#[export_name = "start"] -pub unsafe extern "C" fn reset_handler() -> ! { +unsafe extern "C" fn reset_handler() -> ! { extern "C" { static mut _ebss: u32; static mut _sbss: u32; @@ -79,3 +77,8 @@ pub unsafe extern "C" fn reset_handler() -> ! { asm!("wfi" :::: "volatile"); } } + +#[allow(dead_code)] +#[used] +#[link_section = ".rodata.reset_handler"] +static RESET_HANDLER: unsafe extern "C" fn() -> ! = reset_handler; -- cgit v1.2.3 From 201d4e26728839d856fa08cf9b51fb478a6f2dfa Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 8 Apr 2017 19:26:05 -0500 Subject: add .init_array support --- cortex-m-rt/Cargo.toml | 2 +- cortex-m-rt/link.x | 3 +++ cortex-m-rt/src/lib.rs | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 2f1ce0d..c9ef3e9 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Jorge Aparicio "] [dependencies] -r0 = "0.2.0" +r0 = "0.2.1" [dependencies.cortex-m] optional = true diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x index a41218c..f9f7e2e 100644 --- a/cortex-m-rt/link.x +++ b/cortex-m-rt/link.x @@ -17,6 +17,9 @@ SECTIONS *(.text.*); *(.rodata.*); + _init_array_start = ALIGN(4); + KEEP(*(.init_array)); + _init_array_end = ALIGN(4); } > FLASH .bss : ALIGN(4) diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 7c8acfd..1ef90ae 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -57,10 +57,14 @@ unsafe extern "C" fn reset_handler() -> ! { static mut _sdata: u32; static _sidata: u32; + + static _init_array_start: extern "C" fn(); + static _init_array_end: extern "C" fn(); } ::r0::zero_bss(&mut _sbss, &mut _ebss); ::r0::init_data(&mut _sdata, &mut _edata, &_sidata); + ::r0::run_init_array(&_init_array_start, &_init_array_end); // NOTE `rustc` forces this signature on us. See `src/lang_items.rs` extern "C" { -- cgit v1.2.3 From 58b057011b98f547744c62050fe38c286c9fe535 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 8 Apr 2017 20:07:30 -0500 Subject: stub exception handlers by default, change name of interrupt/exception sections --- cortex-m-rt/Cargo.toml | 5 ++++- cortex-m-rt/link.x | 4 ++-- cortex-m-rt/src/lib.rs | 15 +++++++++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index c9ef3e9..b09500d 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -8,7 +8,7 @@ r0 = "0.2.1" [dependencies.cortex-m] optional = true -version = "0.2.0" +version = "0.2.2" [dependencies.cortex-m-semihosting] optional = true @@ -19,6 +19,9 @@ features = ["mem"] git = "https://github.com/rust-lang-nursery/compiler-builtins" [features] +default = ["exceptions"] +# handle exceptions using the default handler +exceptions = ["cortex-m"] linker-script = [] panic-over-itm = ["cortex-m"] panic-over-semihosting = ["cortex-m-semihosting"] \ No newline at end of file diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x index f9f7e2e..491c9e5 100644 --- a/cortex-m-rt/link.x +++ b/cortex-m-rt/link.x @@ -9,10 +9,10 @@ SECTIONS LONG(ORIGIN(RAM) + LENGTH(RAM)); KEEP(*(.rodata.reset_handler)); - KEEP(*(.rodata._EXCEPTIONS)); + KEEP(*(.rodata.exceptions)); __exceptions = .; - KEEP(*(.rodata._INTERRUPTS)); + KEEP(*(.rodata.interrupts)); __interrupts = .; *(.text.*); diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 1ef90ae..187733c 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -34,8 +34,8 @@ #![feature(used)] #![no_std] -#[cfg(feature = "panic-over-itm")] -#[macro_use] +#[cfg(any(feature = "panic-over-itm", feature = "exceptions"))] +#[cfg_attr(feature = "panic-over-itm", macro_use)] extern crate cortex_m; extern crate compiler_builtins; #[cfg(feature = "panic-over-semihosting")] @@ -45,6 +45,9 @@ extern crate r0; mod lang_items; +#[cfg(feature = "exceptions")] +use cortex_m::exception; + /// The reset handler /// /// This is the entry point of all programs @@ -86,3 +89,11 @@ unsafe extern "C" fn reset_handler() -> ! { #[used] #[link_section = ".rodata.reset_handler"] static RESET_HANDLER: unsafe extern "C" fn() -> ! = reset_handler; + +#[allow(dead_code)] +#[cfg(feature = "exceptions")] +#[link_section = ".rodata.exceptions"] +#[used] +static EXCEPTIONS: exception::Handlers = exception::Handlers { + ..exception::DEFAULT_HANDLERS +}; -- cgit v1.2.3 From f2ff0004f13a22d012c1de7bcee8f7e8dd0d4762 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 9 Apr 2017 20:23:26 -0500 Subject: remove .init_array support --- cortex-m-rt/src/lib.rs | 4 ---- 1 file changed, 4 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 187733c..299617d 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -60,14 +60,10 @@ unsafe extern "C" fn reset_handler() -> ! { static mut _sdata: u32; static _sidata: u32; - - static _init_array_start: extern "C" fn(); - static _init_array_end: extern "C" fn(); } ::r0::zero_bss(&mut _sbss, &mut _ebss); ::r0::init_data(&mut _sdata, &mut _edata, &_sidata); - ::r0::run_init_array(&_init_array_start, &_init_array_end); // NOTE `rustc` forces this signature on us. See `src/lang_items.rs` extern "C" { -- cgit v1.2.3 From 3d145f9ed642c4139122cd1717ace0f1ac7b67b2 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 11 Apr 2017 22:53:50 -0500 Subject: add documentation --- cortex-m-rt/Cargo.toml | 9 +++++++-- cortex-m-rt/README.md | 2 +- cortex-m-rt/src/lib.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 54 insertions(+), 6 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 7bb7478..0618c5c 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -1,14 +1,19 @@ [package] +authors = ["Jorge Aparicio "] +description = "Minimal runtime / startup for Cortex-M microcontrollers" +documentation = "https://docs.rs/cortex-m-rt" +keywords = ["arm", "cortex-m", "runtime", "startup"] +license = "MIT OR Apache-2.0" name = "cortex-m-rt" +repository = "https://github.com/japaric/cortex-m-rt" version = "0.1.0" -authors = ["Jorge Aparicio "] [dependencies] r0 = "0.2.1" [dependencies.cortex-m] optional = true -version = "0.2.2" +version = "0.2.3" [dependencies.cortex-m-semihosting] optional = true diff --git a/cortex-m-rt/README.md b/cortex-m-rt/README.md index 81d2d6f..13fdb81 100644 --- a/cortex-m-rt/README.md +++ b/cortex-m-rt/README.md @@ -1,6 +1,6 @@ # `cortex-m-rt` -> Minimal startup / runtime for Cortex-M microcontrollers +> Minimal runtime / startup for Cortex-M microcontrollers # License diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 299617d..f843dde 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -4,13 +4,46 @@ //! //! - Before main initialization of the `.bss` and `.data` sections //! -//! - An overridable (\*) `panic_fmt` implementation that prints overs the ITM -//! or through semihosting depending on the enabled Cargo feature. +//! - An overridable (\*) `panic_fmt` implementation that prints to the ITM or +//! to the host stdout (through semihosting) depending on which Cargo feature +//! has been enabled: `"panic-over-itm"` or `"panic-over-semihosting"`. //! -//! - Minimal `start` lang item, to support vanilla `fn main()`. NOTE the +//! - A minimal `start` lang item, to support vanilla `fn main()`. NOTE the //! processor goes into "reactive" mode (`loop { asm!("wfi") }`) after //! returning from `main`. //! +//! - An opt-in linker script (`"linker-script"` Cargo feature) that encodes +//! the memory layout of a generic Cortex-M microcontroller. This linker +//! script is missing the definition of the FLASH and RAM memory regions of +//! the device. This missing information must be supplied through a `memory.x` +//! linker script of the form: +//! +//! ``` text +//! MEMORY +//! { +//! FLASH : ORIGIN = 0x08000000, LENGTH = 128K +//! RAM : ORIGIN = 0x20000000, LENGTH = 8K +//! } +//! ``` +//! +//! - A default exception handler tailored for debugging and that provides +//! access to the stacked registers under the debugger. By default, all +//! exceptions (\*\*) are serviced by this handler but this can be overridden +//! on a per exception basis by opting out of the "exceptions" Cargo feature +//! and then defining the following `struct` +//! +//! ``` ignore,no_run +//! use cortex_m::exception; +//! +//! #[link_section = ".rodata.exceptions"] +//! #[used] +//! static EXCEPTIONS: exception::Handlers = exception::Handlers { +//! hard_fault: my_override, +//! nmi: another_handler, +//! ..exception::DEFAULT_HANDLERS +//! }; +//! ```` +//! //! (\*) To override the `panic_fmt` implementation, simply create a new //! `rust_begin_unwind` symbol: //! @@ -24,6 +57,16 @@ //! .. //! } //! ``` +//! +//! (\*\*) All the device specific exceptions, i.e. the interrupts, are left +//! unpopulated. You must fill that part of the vector table by defining the +//! following static (with the right memory layout): +//! +//! ``` ignore,no_run +//! #[link_section = ".rodata.interrupts"] +//! #[used] +//! static INTERRUPTS: SomeStruct = SomeStruct { .. } +//! ``` #![deny(missing_docs)] #![deny(warnings)] -- cgit v1.2.3 From a214bad1f5b436cd276ffea4d146f41156dd9f98 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 12 Apr 2017 00:26:25 -0500 Subject: make the "linker-script" Cargo feature opt-out --- cortex-m-rt/Cargo.toml | 2 +- cortex-m-rt/src/lib.rs | 74 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 2 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 0618c5c..4165852 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -20,7 +20,7 @@ optional = true version = "0.1.3" [features] -default = ["exceptions"] +default = ["exceptions", "linker-script"] # handle exceptions using the default handler exceptions = ["cortex-m"] linker-script = [] diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index f843dde..2da1394 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -1,6 +1,8 @@ //! Minimal startup / runtime for Cortex-M microcontrollers //! -//! Provides +//! # Features +//! +//! This crate provides //! //! - Before main initialization of the `.bss` and `.data` sections //! @@ -67,6 +69,76 @@ //! #[used] //! static INTERRUPTS: SomeStruct = SomeStruct { .. } //! ``` +//! +//! # Usage +//! +//! ``` text +//! $ cargo new --bin app && cd $_ +//! +//! $ cargo add cortex-m cortex-m-rt +//! +//! $ cat Xargo.toml +//! ``` +//! +//! ``` text +//! [dependencies.core] +//! +//! [dependencies.compiler_builtins] +//! features = ["mem"] +//! git = "https://github.com/rust-lang-nursery/compiler-builtins" +//! stage = 1 +//! ``` +//! +//! ``` text +//! $ cat memory.x +//! ``` +//! +//! ``` text +//! MEMORY +//! { +//! FLASH : ORIGIN = 0x08000000, LENGTH = 128K +//! RAM : ORIGIN = 0x20000000, LENGTH = 8K +//! } +//! ``` +//! +//! ``` text +//! $ cat src/main.rs +//! ``` +//! +//! ``` ignore,no_run +//! #![feature(used)] +//! #![no_std] +//! +//! #[macro_use] +//! extern crate cortex_m; +//! extern crate cortex_m_rt; +//! +//! fn main() { +//! hprintln!("Hello, world!"); +//! } +//! +//! #[allow(dead_code)] +//! #[link_section = ".rodata.interrupts"] +//! #[used] +//! static INTERRUPTS: [u32; 240] = [0; 240]; +//! ``` +//! +//! ``` text +//! $ xargo rustc --target thumbv7m-none-eabi -- -C link-args='-Tlink.x -nostartfiles' +//! +//! $ arm-none-eabi-objdump -Cd $(find target -name app) | less +//! 08000000 <_VECTOR_TABLE>: +//! 8000000: 20002000 .word 0x20002000 +//! +//! 08000004 : +//! 8000004: 08000671 q... +//! +//! 08000008 : +//! 8000008: 080005a5 080005bd 08000569 08000599 ........i....... +//! 8000018: 08000581 00000000 00000000 00000000 ................ +//! 8000028: 00000000 080005b1 00000000 00000000 ................ +//! 8000038: 0800058d 08000575 ....u... +//! ``` #![deny(missing_docs)] #![deny(warnings)] -- cgit v1.2.3 From 603a10fe3c8cca4383eccdd14f9223ee93df074b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 12 Apr 2017 00:30:12 -0500 Subject: Usage -> Example --- cortex-m-rt/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 2da1394..188d6a1 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -70,7 +70,7 @@ //! static INTERRUPTS: SomeStruct = SomeStruct { .. } //! ``` //! -//! # Usage +//! # Example //! //! ``` text //! $ cargo new --bin app && cd $_ -- cgit v1.2.3 From f2ce9a599b1045e395994a5362a43ed82390b955 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 12 Apr 2017 00:49:03 -0500 Subject: v0.1.0 --- cortex-m-rt/CHANGELOG.md | 14 ++++++++++++++ cortex-m-rt/Cargo.toml | 5 ++++- cortex-m-rt/README.md | 3 +++ cortex-m-rt/src/lang_items.rs | 1 + cortex-m-rt/src/lib.rs | 1 + 5 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 cortex-m-rt/CHANGELOG.md (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/CHANGELOG.md b/cortex-m-rt/CHANGELOG.md new file mode 100644 index 0000000..13e0512 --- /dev/null +++ b/cortex-m-rt/CHANGELOG.md @@ -0,0 +1,14 @@ +# Change Log + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] + +## v0.1.0 - 2017-04-12 + +Initial release + +[Unreleased]: https://github.com/japaric/cortex-m-rt/compare/v0.1.0...HEAD diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 4165852..9fb967b 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -21,8 +21,11 @@ version = "0.1.3" [features] default = ["exceptions", "linker-script"] -# handle exceptions using the default handler +# service all exceptions using the default handler exceptions = ["cortex-m"] +# generic linker script linker-script = [] +# prints panic messages to the ITM panic-over-itm = ["cortex-m"] +# prints panic messages to the host stdout panic-over-semihosting = ["cortex-m-semihosting"] \ No newline at end of file diff --git a/cortex-m-rt/README.md b/cortex-m-rt/README.md index 13fdb81..49bc8a2 100644 --- a/cortex-m-rt/README.md +++ b/cortex-m-rt/README.md @@ -1,3 +1,6 @@ +[![crates.io](https://img.shields.io/crates/v/cortex-m-rt.svg)](https://crates.io/crates/cortex-m-rt) +[![crates.io](https://img.shields.io/crates/d/cortex-m-rt.svg)](https://crates.io/crates/cortex-m-rt) + # `cortex-m-rt` > Minimal runtime / startup for Cortex-M microcontrollers diff --git a/cortex-m-rt/src/lang_items.rs b/cortex-m-rt/src/lang_items.rs index bd7c4db..7b3fa9d 100644 --- a/cortex-m-rt/src/lang_items.rs +++ b/cortex-m-rt/src/lang_items.rs @@ -28,6 +28,7 @@ unsafe extern "C" fn panic_fmt( () => {} } + #[cfg(target_arch = "arm")] asm!("bkpt" :::: "volatile"); loop {} diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 188d6a1..156edb5 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -192,6 +192,7 @@ unsafe extern "C" fn reset_handler() -> ! { // If `main` returns, then we go into "reactive" mode and attend interrupts // as they occur. loop { + #[cfg(target_arch = "arm")] asm!("wfi" :::: "volatile"); } } -- cgit v1.2.3 From a5363f5497aa8453dcbd8e18e0d7d86bdbb03aa7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 22 Apr 2017 17:39:32 -0500 Subject: v0.1.2 --- cortex-m-rt/CHANGELOG.md | 9 ++++++++- cortex-m-rt/Cargo.toml | 2 +- cortex-m-rt/src/lib.rs | 37 +++++++++++++++++++------------------ 3 files changed, 28 insertions(+), 20 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/CHANGELOG.md b/cortex-m-rt/CHANGELOG.md index 3905275..94c65e5 100644 --- a/cortex-m-rt/CHANGELOG.md +++ b/cortex-m-rt/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.1.2] - 2017-04-22 + +### Changed + +- Unclutter the `reset_handler` function for a better debugging experience. + ## [v0.1.1] - 2017-04-15 ### Changed @@ -17,5 +23,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). Initial release -[Unreleased]: https://github.com/japaric/cortex-m-rt/compare/v0.1.1...HEAD +[Unreleased]: https://github.com/japaric/cortex-m-rt/compare/v0.1.2...HEAD +[v0.1.2]: https://github.com/japaric/cortex-m-rt/compare/v0.1.1...v0.1.2 [v0.1.1]: https://github.com/japaric/cortex-m-rt/compare/v0.1.0...v0.1.1 diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 1609015..7dfcb9c 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -6,7 +6,7 @@ keywords = ["arm", "cortex-m", "runtime", "startup"] license = "MIT OR Apache-2.0" name = "cortex-m-rt" repository = "https://github.com/japaric/cortex-m-rt" -version = "0.1.1" +version = "0.1.2" [dependencies] r0 = "0.2.1" diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 156edb5..9b1c3b3 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -163,34 +163,35 @@ mod lang_items; #[cfg(feature = "exceptions")] use cortex_m::exception; +extern "C" { + // NOTE `rustc` forces this signature on us. See `src/lang_items.rs` + fn main(argc: isize, argv: *const *const u8) -> isize; + + // Boundaries of the .bss section + static mut _ebss: u32; + static mut _sbss: u32; + + // Boundaries of the .data section + static mut _edata: u32; + static mut _sdata: u32; + + // Initial values of the .data section (stored in Flash) + static _sidata: u32; +} + /// The reset handler /// /// This is the entry point of all programs unsafe extern "C" fn reset_handler() -> ! { - extern "C" { - static mut _ebss: u32; - static mut _sbss: u32; - - static mut _edata: u32; - static mut _sdata: u32; - - static _sidata: u32; - } - ::r0::zero_bss(&mut _sbss, &mut _ebss); ::r0::init_data(&mut _sdata, &mut _edata, &_sidata); - // NOTE `rustc` forces this signature on us. See `src/lang_items.rs` - extern "C" { - fn main(argc: isize, argv: *const *const u8) -> isize; - } - - // Neither `argc` or `argv` make sense in bare metal contexts so we just + // Neither `argc` or `argv` make sense in bare metal context so we just // stub them main(0, ::core::ptr::null()); - // If `main` returns, then we go into "reactive" mode and attend interrupts - // as they occur. + // If `main` returns, then we go into "reactive" mode and simply attend + // interrupts as they occur. loop { #[cfg(target_arch = "arm")] asm!("wfi" :::: "volatile"); -- cgit v1.2.3 From adef5af5929cba10d358e61bfd7354fc787e83ce Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 24 Apr 2017 13:48:49 -0500 Subject: remove extra backtick in doc comment --- cortex-m-rt/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 9b1c3b3..d3eb2ab 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -44,7 +44,7 @@ //! nmi: another_handler, //! ..exception::DEFAULT_HANDLERS //! }; -//! ```` +//! ``` //! //! (\*) To override the `panic_fmt` implementation, simply create a new //! `rust_begin_unwind` symbol: -- cgit v1.2.3 From 9cf67450bca5e07d6f4690bd8ce1c4a8e316931d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 27 Apr 2017 10:17:46 -0500 Subject: v0.2.0 --- cortex-m-rt/CHANGELOG.md | 11 ++++++++++- cortex-m-rt/Cargo.toml | 4 ++-- cortex-m-rt/link.x | 2 +- cortex-m-rt/src/lib.rs | 48 +++++++++++++++++++++++++++--------------------- 4 files changed, 40 insertions(+), 25 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/CHANGELOG.md b/cortex-m-rt/CHANGELOG.md index ceebb1d..d78dd56 100644 --- a/cortex-m-rt/CHANGELOG.md +++ b/cortex-m-rt/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.2.0] - 2017-04-27 + +### Changed + +- [breaking-change] the `_stack_start` symbol is now required and must be + provided in the `memory.x` file when using the "linker-script" feature. This + symbol indicates where in memory the call stack will be allocated. + ## [v0.1.3] - 2017-04-25 ### Fixed @@ -29,7 +37,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). Initial release -[Unreleased]: https://github.com/japaric/cortex-m-rt/compare/v0.1.3...HEAD +[Unreleased]: https://github.com/japaric/cortex-m-rt/compare/v0.2.0...HEAD +[v0.2.0]: https://github.com/japaric/cortex-m-rt/compare/v0.1.3...v0.2.0 [v0.1.3]: https://github.com/japaric/cortex-m-rt/compare/v0.1.2...v0.1.3 [v0.1.2]: https://github.com/japaric/cortex-m-rt/compare/v0.1.1...v0.1.2 [v0.1.1]: https://github.com/japaric/cortex-m-rt/compare/v0.1.0...v0.1.1 diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 2ed42d3..94dac87 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -6,14 +6,14 @@ keywords = ["arm", "cortex-m", "runtime", "startup"] license = "MIT OR Apache-2.0" name = "cortex-m-rt" repository = "https://github.com/japaric/cortex-m-rt" -version = "0.1.3" +version = "0.2.0" [dependencies] r0 = "0.2.1" [dependencies.cortex-m] optional = true -version = "0.2.3" +version = "0.2.4" [dependencies.cortex-m-semihosting] optional = true diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x index 5a9be92..9f37fa7 100644 --- a/cortex-m-rt/link.x +++ b/cortex-m-rt/link.x @@ -6,7 +6,7 @@ SECTIONS { /* Vector table */ _VECTOR_TABLE = .; - LONG(ORIGIN(RAM) + LENGTH(RAM)); + LONG(_stack_start); KEEP(*(.rodata.reset_handler)); KEEP(*(.rodata.exceptions)); diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index d3eb2ab..3167ef2 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -16,17 +16,10 @@ //! //! - An opt-in linker script (`"linker-script"` Cargo feature) that encodes //! the memory layout of a generic Cortex-M microcontroller. This linker -//! script is missing the definition of the FLASH and RAM memory regions of -//! the device. This missing information must be supplied through a `memory.x` -//! linker script of the form: -//! -//! ``` text -//! MEMORY -//! { -//! FLASH : ORIGIN = 0x08000000, LENGTH = 128K -//! RAM : ORIGIN = 0x20000000, LENGTH = 8K -//! } -//! ``` +//! script is missing the definitions of the FLASH and RAM memory regions of +//! the device and of the `_stack_start` symbol (address where the call stack +//! is allocated). This missing information must be supplied through a +//! `memory.x` file (see example below). //! //! - A default exception handler tailored for debugging and that provides //! access to the stacked registers under the debugger. By default, all @@ -77,7 +70,7 @@ //! //! $ cargo add cortex-m cortex-m-rt //! -//! $ cat Xargo.toml +//! $ edit Xargo.toml && cat $_ //! ``` //! //! ``` text @@ -90,7 +83,7 @@ //! ``` //! //! ``` text -//! $ cat memory.x +//! $ edit memory.x && cat $_ //! ``` //! //! ``` text @@ -99,10 +92,13 @@ //! FLASH : ORIGIN = 0x08000000, LENGTH = 128K //! RAM : ORIGIN = 0x20000000, LENGTH = 8K //! } +//! +//! /* This is where the call stack will be allocated */ +//! _stack_start = ORIGIN(RAM) + LENGTH(RAM); //! ``` //! //! ``` text -//! $ cat src/main.rs +//! $ edit src/main.rs && cat $_ //! ``` //! //! ``` ignore,no_run @@ -113,31 +109,41 @@ //! extern crate cortex_m; //! extern crate cortex_m_rt; //! +//! use cortex_m::asm; +//! //! fn main() { //! hprintln!("Hello, world!"); //! } //! +//! // As we are not using interrupts, we just register a dummy catch all handler //! #[allow(dead_code)] //! #[link_section = ".rodata.interrupts"] //! #[used] -//! static INTERRUPTS: [u32; 240] = [0; 240]; +//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; +//! +//! extern "C" fn default_handler() { +//! asm::bkpt(); +//! } //! ``` //! //! ``` text -//! $ xargo rustc --target thumbv7m-none-eabi -- -C link-args='-Tlink.x -nostartfiles' +//! $ cargo install xargo +//! +//! $ xargo rustc --target thumbv7m-none-eabi -- \ +//! -C link-arg=-Tlink.x -C linker=arm-none-eabi-ld -Z linker-flavor=ld //! //! $ arm-none-eabi-objdump -Cd $(find target -name app) | less //! 08000000 <_VECTOR_TABLE>: //! 8000000: 20002000 .word 0x20002000 //! //! 08000004 : -//! 8000004: 08000671 q... +//! 8000004: 0800065f _... //! //! 08000008 : -//! 8000008: 080005a5 080005bd 08000569 08000599 ........i....... -//! 8000018: 08000581 00000000 00000000 00000000 ................ -//! 8000028: 00000000 080005b1 00000000 00000000 ................ -//! 8000038: 0800058d 08000575 ....u... +//! 8000008: 08000585 0800058f 080005a3 08000571 ............q... +//! 8000018: 0800057b 00000000 00000000 00000000 {............... +//! 8000028: 00000000 08000567 00000000 00000000 ....g........... +//! 8000038: 080005ad 08000599 ........ //! ``` #![deny(missing_docs)] -- cgit v1.2.3 From 4d1cf60d0e6ca379e6ab365345fda012ddf4e9c1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 27 Apr 2017 10:20:29 -0500 Subject: note that K means 1024 bytes in memory.x --- cortex-m-rt/src/lib.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 3167ef2..32029a5 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -89,6 +89,7 @@ //! ``` text //! MEMORY //! { +//! /* NOTE K = KiBi = 1024 bytes */ //! FLASH : ORIGIN = 0x08000000, LENGTH = 128K //! RAM : ORIGIN = 0x20000000, LENGTH = 8K //! } -- cgit v1.2.3 From 7895609354ef9c56387403729acbfe5cc8958d4a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 25 May 2017 14:27:49 -0500 Subject: reorders the linker sections; make the reset_handler the entry point Before this commit the .rodata sections of the inputs were placed in the output .text section. As the vector table is in the .rodata of the cortex-m-rt crate this placed the vector table first in the output .text section: ``` console $ arm-none-eabi-objdump -Cd hello Disassembly of section .text: 08000000 <_VECTOR_TABLE>: 8000000: 10002000 .word 0x10002000 08000004 : 8000004: 08000405 .... (..) $ arm-none-eabi-readelf -h hello | grep Entry Entry point address: 0x8000000 ``` With this memory layout using `load` and then `step` on a GDB session made the processor execute the vector table (PC = 0x08000000). This commit places the .rodata sections of the inputs into the output .rodata section, and also moves the reset_handler code to the start the output .text section. This turns the reset_handler into the entry point of the program. ``` console $ arm-none-eabi-objdump -Cd hello Disassembly of section .text: 08000410 : (..) $ arm-none-eabi-readelf -h hello | grep Entry Entry point address: 0x8000410 ``` With these changes the GDB commands `load` and `step` work correctly: `load` sets the PC = reset_handler. Also the `size` output is now more helpful: ``` console $ arm-none-eabi-size -Ax hello section size addr .vector_table 0x400 0x8000000 .text 0x120 0x8000400 .rodata 0xd 0x8000520 .bss 0x4 0x20000000 .data 0x4 0x20000004 ``` --- cortex-m-rt/link.x | 21 ++++++++++++++++----- cortex-m-rt/src/lib.rs | 5 +++-- 2 files changed, 19 insertions(+), 7 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x index 16db08a..e7cdcec 100644 --- a/cortex-m-rt/link.x +++ b/cortex-m-rt/link.x @@ -2,21 +2,32 @@ INCLUDE memory.x SECTIONS { - .text ORIGIN(FLASH) : + .vector_table ORIGIN(FLASH) : { /* Vector table */ - _VECTOR_TABLE = .; + _svector_table = .; LONG(_stack_start); - KEEP(*(.rodata.reset_handler)); + KEEP(*(.vector_table.reset_handler)); - KEEP(*(.rodata.exceptions)); + KEEP(*(.vector_table.exceptions)); _eexceptions = .; - KEEP(*(.rodata.interrupts)); + KEEP(*(.vector_table.interrupts)); _einterrupts = .; + } > FLASH + + .text : ALIGN(4) + { + /* Put reset handler first in .text section so it ends up as the entry */ + /* point of the program. */ + KEEP(*(.text.reset_handler)); *(.text .text.*); + } > FLASH + + .rodata : ALIGN(4) + { *(.rodata .rodata.*); } > FLASH diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 32029a5..f9629ba 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -189,6 +189,7 @@ extern "C" { /// The reset handler /// /// This is the entry point of all programs +#[link_section = ".text.reset_handler"] unsafe extern "C" fn reset_handler() -> ! { ::r0::zero_bss(&mut _sbss, &mut _ebss); ::r0::init_data(&mut _sdata, &mut _edata, &_sidata); @@ -207,12 +208,12 @@ unsafe extern "C" fn reset_handler() -> ! { #[allow(dead_code)] #[used] -#[link_section = ".rodata.reset_handler"] +#[link_section = ".vector_table.reset_handler"] static RESET_HANDLER: unsafe extern "C" fn() -> ! = reset_handler; #[allow(dead_code)] #[cfg(feature = "exceptions")] -#[link_section = ".rodata.exceptions"] +#[link_section = ".vector_table.exceptions"] #[used] static EXCEPTIONS: exception::Handlers = exception::Handlers { ..exception::DEFAULT_HANDLERS -- cgit v1.2.3 From 44995b00fabe97ef1f24bef162f42ac922a1dbfe Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 26 May 2017 16:46:37 -0500 Subject: rename .text.reset_handler to .reset_handler --- cortex-m-rt/link.x | 2 +- cortex-m-rt/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x index e7cdcec..a0c92ab 100644 --- a/cortex-m-rt/link.x +++ b/cortex-m-rt/link.x @@ -21,7 +21,7 @@ SECTIONS { /* Put reset handler first in .text section so it ends up as the entry */ /* point of the program. */ - KEEP(*(.text.reset_handler)); + KEEP(*(.reset_handler)); *(.text .text.*); } > FLASH diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index f9629ba..25481cb 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -189,7 +189,7 @@ extern "C" { /// The reset handler /// /// This is the entry point of all programs -#[link_section = ".text.reset_handler"] +#[link_section = ".reset_handler"] unsafe extern "C" fn reset_handler() -> ! { ::r0::zero_bss(&mut _sbss, &mut _ebss); ::r0::init_data(&mut _sdata, &mut _edata, &_sidata); -- cgit v1.2.3 From 6f86357fd41c9544efe7a9f1be1e4dbfe35561ce Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 27 May 2017 10:15:17 -0500 Subject: update CHANGELOG; revert .rodata to .vector_table rename in input sections downstream crates depend on the name of those linker sections. Avoiding the rename let us release a patch version instead of a minor one. --- cortex-m-rt/CHANGELOG.md | 19 +++++++++++++++++++ cortex-m-rt/link.x | 4 ++-- cortex-m-rt/src/lib.rs | 2 +- 3 files changed, 22 insertions(+), 3 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/CHANGELOG.md b/cortex-m-rt/CHANGELOG.md index d9c1278..f31acc8 100644 --- a/cortex-m-rt/CHANGELOG.md +++ b/cortex-m-rt/CHANGELOG.md @@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed + +- The linker sections have renamed / reorder to make `arm-none-eabi-size -A` + more useful. You'll now see something like this: + +``` +$ arm-none-eabi-size -A hello +hello : +section size addr +.vector_table 1024 134217728 +.text 288 134218752 +.rodata 14 134219040 +``` + +- `cortex-m-rt::reset_handler` is now the entry point of all programs that link + to `cortex-m-rt`. This makes GDB's `load` command work correctly. It will now + set the Program Counter to `reset_handler` after flashing the program so + there's no need to reset the microcontroller after flashing. + ## [v0.2.1] - 2017-05-07 ### Fixed diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x index a0c92ab..919d717 100644 --- a/cortex-m-rt/link.x +++ b/cortex-m-rt/link.x @@ -10,10 +10,10 @@ SECTIONS KEEP(*(.vector_table.reset_handler)); - KEEP(*(.vector_table.exceptions)); + KEEP(*(.rodata.exceptions)); _eexceptions = .; - KEEP(*(.vector_table.interrupts)); + KEEP(*(.rodata.interrupts)); _einterrupts = .; } > FLASH diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 25481cb..862af77 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -213,7 +213,7 @@ static RESET_HANDLER: unsafe extern "C" fn() -> ! = reset_handler; #[allow(dead_code)] #[cfg(feature = "exceptions")] -#[link_section = ".vector_table.exceptions"] +#[link_section = ".rodata.exceptions"] #[used] static EXCEPTIONS: exception::Handlers = exception::Handlers { ..exception::DEFAULT_HANDLERS -- cgit v1.2.3 From 484835722e5fb5569e6f79a60ddafde163c838f3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 27 May 2017 10:05:02 -0500 Subject: add a _sheap symbol where a heap can be located closes #5 --- cortex-m-rt/link.x | 3 +++ cortex-m-rt/src/lib.rs | 2 ++ 2 files changed, 5 insertions(+) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x index 919d717..7f319b7 100644 --- a/cortex-m-rt/link.x +++ b/cortex-m-rt/link.x @@ -47,6 +47,9 @@ SECTIONS _sidata = LOADADDR(.data); + /* The heap starts right after the .bss + .data section ends */ + _sheap = _edata; + /* Due to an unfortunate combination of legacy concerns, toolchain drawbacks, and insufficient attention to detail, rustc has no choice but to mark .debug_gdb_scripts as allocatable. diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 862af77..9519fc8 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -27,6 +27,8 @@ //! on a per exception basis by opting out of the "exceptions" Cargo feature //! and then defining the following `struct` //! +//! - A `_sheap` symbol at whose address you can locate the heap. +//! //! ``` ignore,no_run //! use cortex_m::exception; //! -- cgit v1.2.3 From fe0ba0808d08e8a8f10fb1227301a73a1083b00a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 27 May 2017 11:08:57 -0500 Subject: v0.2.2 --- cortex-m-rt/CHANGELOG.md | 19 ++++++++++++++++++- cortex-m-rt/Cargo.toml | 4 ++-- cortex-m-rt/src/lib.rs | 20 ++++++++------------ 3 files changed, 28 insertions(+), 15 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/CHANGELOG.md b/cortex-m-rt/CHANGELOG.md index f31acc8..8f3f1b5 100644 --- a/cortex-m-rt/CHANGELOG.md +++ b/cortex-m-rt/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.2.2] - 2017-05-27 + +### Added + +- A `_sheap` symbol where the heap can be located. + ### Changed - The linker sections have renamed / reorder to make `arm-none-eabi-size -A` @@ -26,6 +32,16 @@ section size addr set the Program Counter to `reset_handler` after flashing the program so there's no need to reset the microcontroller after flashing. +- Renamed `__exceptions` and `__interrupts` symbols, which are only used + internally, to `_eexceptions` and `_einterrupts` respectively for consistency. + +### Fixed + +- Include input `.text` and `.rodata` sections (note: no suffix as in + `.text.foo`) in the output file. (C) Code compiled without the equivalent + `-ffunction-sections` / `-fdata-sections` may place stuff in those unsuffixed + sections. + ## [v0.2.1] - 2017-05-07 ### Fixed @@ -63,7 +79,8 @@ section size addr Initial release -[Unreleased]: https://github.com/japaric/cortex-m-rt/compare/v0.2.1...HEAD +[Unreleased]: https://github.com/japaric/cortex-m-rt/compare/v0.2.2...HEAD +[v0.2.2]: https://github.com/japaric/cortex-m-rt/compare/v0.2.1...v0.2.2 [v0.2.1]: https://github.com/japaric/cortex-m-rt/compare/v0.2.0...v0.2.1 [v0.2.0]: https://github.com/japaric/cortex-m-rt/compare/v0.1.3...v0.2.0 [v0.1.3]: https://github.com/japaric/cortex-m-rt/compare/v0.1.2...v0.1.3 diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index a162b30..577e38d 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -7,14 +7,14 @@ keywords = ["arm", "cortex-m", "runtime", "startup"] license = "MIT OR Apache-2.0" name = "cortex-m-rt" repository = "https://github.com/japaric/cortex-m-rt" -version = "0.2.1" +version = "0.2.2" [dependencies] r0 = "0.2.1" [dependencies.cortex-m] optional = true -version = "0.2.4" +version = "0.2.7" [dependencies.cortex-m-semihosting] optional = true diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 9519fc8..fa87e6f 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -135,18 +135,14 @@ //! $ xargo rustc --target thumbv7m-none-eabi -- \ //! -C link-arg=-Tlink.x -C linker=arm-none-eabi-ld -Z linker-flavor=ld //! -//! $ arm-none-eabi-objdump -Cd $(find target -name app) | less -//! 08000000 <_VECTOR_TABLE>: -//! 8000000: 20002000 .word 0x20002000 -//! -//! 08000004 : -//! 8000004: 0800065f _... -//! -//! 08000008 : -//! 8000008: 08000585 0800058f 080005a3 08000571 ............q... -//! 8000018: 0800057b 00000000 00000000 00000000 {............... -//! 8000028: 00000000 08000567 00000000 00000000 ....g........... -//! 8000038: 080005ad 08000599 ........ +//! $ arm-none-eabi-objdump -Cd $(find target -name app) | head +//! +//! Disassembly of section .text: +//! +//! 08000400 : +//! 8000400: b580 push {r7, lr} +//! 8000402: 466f mov r7, sp +//! 8000404: b084 sub sp, #16 //! ``` #![deny(missing_docs)] -- cgit v1.2.3 From a81bb98141eb8b629da4bfde7109f75177d215af Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 25 Jun 2017 10:56:49 -0500 Subject: default panic! to abort, drop panic-* features, add panic_fmt! macro --- cortex-m-rt/Cargo.toml | 8 -------- cortex-m-rt/src/lang_items.rs | 35 ++++++++++++----------------------- cortex-m-rt/src/lib.rs | 7 ++----- 3 files changed, 14 insertions(+), 36 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 0b24d79..2c70fa8 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -16,17 +16,9 @@ r0 = "0.2.1" optional = true version = "0.2.7" -[dependencies.cortex-m-semihosting] -optional = true -version = "0.1.3" - [features] default = ["exceptions", "linker-script"] # service all exceptions using the default handler exceptions = ["cortex-m"] # generic linker script linker-script = [] -# prints panic messages to the ITM -panic-over-itm = ["cortex-m"] -# prints panic messages to the host stdout -panic-over-semihosting = ["cortex-m-semihosting"] diff --git a/cortex-m-rt/src/lang_items.rs b/cortex-m-rt/src/lang_items.rs index 7b3fa9d..b154b5f 100644 --- a/cortex-m-rt/src/lang_items.rs +++ b/cortex-m-rt/src/lang_items.rs @@ -6,32 +6,21 @@ unsafe extern "C" fn panic_fmt( _file: &'static str, _line: u32, ) -> ! { - match () { - #[cfg(feature = "panic-over-itm")] - () => { - use cortex_m::itm; - use cortex_m::peripheral::ITM; + ::core::intrinsics::abort() +} - let port = &(*ITM.get()).stim[0]; - iprint!(port, "panicked at '"); - itm::write_fmt(port, _args); - iprintln!(port, "', {}:{}", _file, _line); - } - #[cfg(feature = "panic-over-semihosting")] - () => { - hprint!("panicked at '"); - ::cortex_m_semihosting::io::write_fmt(_args); - hprintln!("', {}:{}", _file, _line); +#[macro_export] +macro_rules! panic_fmt { + ($f:expr) => { + #[export_name = "rust_begin_unwind"] + pub unsafe extern "C" fn _panic_fmt( + args: ::core::fmt::Arguments, + file: &'static str, + line: u32, + ) -> ! { + $f(args, file, line) } - #[cfg(not(any(feature = "panic-over-itm", - feature = "panic-over-semihosting")))] - () => {} } - - #[cfg(target_arch = "arm")] - asm!("bkpt" :::: "volatile"); - - loop {} } /// Lang item required to make the normal `main` work in applications diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index fa87e6f..1908c50 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -149,18 +149,15 @@ #![deny(warnings)] #![feature(asm)] #![feature(compiler_builtins_lib)] +#![feature(core_intrinsics)] #![feature(lang_items)] #![feature(linkage)] #![feature(used)] #![no_std] -#[cfg(any(feature = "panic-over-itm", feature = "exceptions"))] -#[cfg_attr(feature = "panic-over-itm", macro_use)] +#[cfg(feature = "exceptions")] extern crate cortex_m; extern crate compiler_builtins; -#[cfg(feature = "panic-over-semihosting")] -#[macro_use] -extern crate cortex_m_semihosting; extern crate r0; mod lang_items; -- cgit v1.2.3 From cfe8c2aad28327b3698dc02abe70b10ddc25b05c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Jun 2017 11:22:56 -0500 Subject: opt-in panic_fmt implementation that just calls intrinsics::abort --- cortex-m-rt/Cargo.toml | 4 +++- cortex-m-rt/src/lang_items.rs | 22 ++++------------------ cortex-m-rt/src/lib.rs | 6 +++--- 3 files changed, 10 insertions(+), 22 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 2c70fa8..fc1c181 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["arm", "cortex-m", "runtime", "startup"] license = "MIT OR Apache-2.0" name = "cortex-m-rt" repository = "https://github.com/japaric/cortex-m-rt" -version = "0.2.4" +version = "0.3.0" [dependencies] r0 = "0.2.1" @@ -22,3 +22,5 @@ default = ["exceptions", "linker-script"] exceptions = ["cortex-m"] # generic linker script linker-script = [] +# provides a panic_fmt implementation that calls the abort instruction (`udf 0xfe`) +abort-on-panic = [] \ No newline at end of file diff --git a/cortex-m-rt/src/lang_items.rs b/cortex-m-rt/src/lang_items.rs index b154b5f..236b2bd 100644 --- a/cortex-m-rt/src/lang_items.rs +++ b/cortex-m-rt/src/lang_items.rs @@ -1,28 +1,14 @@ /// Default panic handler +#[cfg(feature = "abort-on-panic")] #[lang = "panic_fmt"] -#[linkage = "weak"] unsafe extern "C" fn panic_fmt( - _args: ::core::fmt::Arguments, - _file: &'static str, - _line: u32, + _: ::core::fmt::Arguments, + _: &'static str, + _: u32, ) -> ! { ::core::intrinsics::abort() } -#[macro_export] -macro_rules! panic_fmt { - ($f:expr) => { - #[export_name = "rust_begin_unwind"] - pub unsafe extern "C" fn _panic_fmt( - args: ::core::fmt::Arguments, - file: &'static str, - line: u32, - ) -> ! { - $f(args, file, line) - } - } -} - /// Lang item required to make the normal `main` work in applications // This is how the `start` lang item works: // When `rustc` compiles a binary crate, it creates a `main` function that looks diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 1908c50..4e10b59 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -145,11 +145,11 @@ //! 8000404: b084 sub sp, #16 //! ``` +#![cfg_attr(feature = "abort-on-panic", feature(core_intrinsics))] #![deny(missing_docs)] #![deny(warnings)] #![feature(asm)] #![feature(compiler_builtins_lib)] -#![feature(core_intrinsics)] #![feature(lang_items)] #![feature(linkage)] #![feature(used)] @@ -186,8 +186,8 @@ extern "C" { /// This is the entry point of all programs #[link_section = ".reset_handler"] unsafe extern "C" fn reset_handler() -> ! { - ::r0::zero_bss(&mut _sbss, &mut _ebss); - ::r0::init_data(&mut _sdata, &mut _edata, &_sidata); + r0::zero_bss(&mut _sbss, &mut _ebss); + r0::init_data(&mut _sdata, &mut _edata, &_sidata); // Neither `argc` or `argv` make sense in bare metal context so we just // stub them -- cgit v1.2.3 From 9fb5a3cf66a5f9fadc2e41c2d54fea941f875168 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 28 Jun 2017 22:59:18 -0500 Subject: enable the FPU before main if the target has an FPU --- cortex-m-rt/Cargo.toml | 5 ++--- cortex-m-rt/build.rs | 16 +++++++++++++++- cortex-m-rt/src/lib.rs | 18 ++++++++++++++---- 3 files changed, 31 insertions(+), 8 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index fc1c181..e04bdc1 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -13,14 +13,13 @@ version = "0.3.0" r0 = "0.2.1" [dependencies.cortex-m] -optional = true version = "0.2.7" [features] default = ["exceptions", "linker-script"] # service all exceptions using the default handler -exceptions = ["cortex-m"] +exceptions = [] # generic linker script linker-script = [] # provides a panic_fmt implementation that calls the abort instruction (`udf 0xfe`) -abort-on-panic = [] \ No newline at end of file +abort-on-panic = [] diff --git a/cortex-m-rt/build.rs b/cortex-m-rt/build.rs index c52b434..45642c5 100644 --- a/cortex-m-rt/build.rs +++ b/cortex-m-rt/build.rs @@ -1,3 +1,5 @@ +use std::env; + #[cfg(feature = "linker-script")] mod imp { use std::env; @@ -6,6 +8,8 @@ mod imp { use std::path::PathBuf; pub fn main() { + ::has_fpu(); + // Put the linker script somewhere the linker can find it let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); File::create(out.join("link.x")) @@ -21,7 +25,17 @@ mod imp { #[cfg(not(feature = "linker-script"))] mod imp { - pub fn main() {} + pub fn main() { + ::has_fpu(); + } +} + +fn has_fpu() { + let target = env::var("TARGET").unwrap(); + + if target.ends_with("eabihf") { + println!("cargo:rustc-cfg=has_fpu"); + } } fn main() { diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 4e10b59..4a7ce44 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -155,7 +155,6 @@ #![feature(used)] #![no_std] -#[cfg(feature = "exceptions")] extern crate cortex_m; extern crate compiler_builtins; extern crate r0; @@ -189,6 +188,18 @@ unsafe extern "C" fn reset_handler() -> ! { r0::zero_bss(&mut _sbss, &mut _ebss); r0::init_data(&mut _sdata, &mut _edata, &_sidata); + match () { + #[cfg(has_fpu)] + () => { + // NOTE(safe) no exception / interrupt that also accesses the FPU + // can occur here + let scb = &*cortex_m::peripheral::SCB.get(); + scb.enable_fpu(); + } + #[cfg(not(has_fpu))] + () => {} + } + // Neither `argc` or `argv` make sense in bare metal context so we just // stub them main(0, ::core::ptr::null()); @@ -210,6 +221,5 @@ static RESET_HANDLER: unsafe extern "C" fn() -> ! = reset_handler; #[cfg(feature = "exceptions")] #[link_section = ".rodata.exceptions"] #[used] -static EXCEPTIONS: exception::Handlers = exception::Handlers { - ..exception::DEFAULT_HANDLERS -}; +static EXCEPTIONS: exception::Handlers = + exception::Handlers { ..exception::DEFAULT_HANDLERS }; -- cgit v1.2.3 From 1ab2f88e3fd32cf7f58deaf0853f5925300aa131 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 29 Jun 2017 12:08:40 -0500 Subject: make sure main is not inlined into reset_handler when enabling the FPU --- cortex-m-rt/src/lib.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 4a7ce44..843bfa8 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -189,21 +189,34 @@ unsafe extern "C" fn reset_handler() -> ! { r0::init_data(&mut _sdata, &mut _edata, &_sidata); match () { + #[cfg(not(has_fpu))] + () => { + // Neither `argc` or `argv` make sense in bare metal context so we just + // stub them + main(0, ::core::ptr::null()); + } #[cfg(has_fpu)] () => { // NOTE(safe) no exception / interrupt that also accesses the FPU // can occur here let scb = &*cortex_m::peripheral::SCB.get(); scb.enable_fpu(); + + // Make sure the user main function never gets inlined into this + // function as that may cause FPU related instructions like vpush to + // be executed *before* enabling the FPU and that would generate an + // exception + #[inline(never)] + fn main() { + unsafe { + ::main(0, ::core::ptr::null()); + } + } + + main() } - #[cfg(not(has_fpu))] - () => {} } - // Neither `argc` or `argv` make sense in bare metal context so we just - // stub them - main(0, ::core::ptr::null()); - // If `main` returns, then we go into "reactive" mode and simply attend // interrupts as they occur. loop { -- cgit v1.2.3 From 6418b252b60f72a4d508d4c92772ff492618bde3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 23 Jun 2017 16:04:31 -0500 Subject: new exception / interrupt override mechanism check japaric/cortex-m#51 for details --- cortex-m-rt/Cargo.toml | 8 +- cortex-m-rt/link.x | 14 +-- cortex-m-rt/src/lib.rs | 317 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 314 insertions(+), 25 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index e04bdc1..0197147 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -11,14 +11,10 @@ version = "0.3.0" [dependencies] r0 = "0.2.1" - -[dependencies.cortex-m] -version = "0.2.7" +cortex-m = "0.3.0" [features] -default = ["exceptions", "linker-script"] -# service all exceptions using the default handler -exceptions = [] +default = ["linker-script"] # generic linker script linker-script = [] # provides a panic_fmt implementation that calls the abort instruction (`udf 0xfe`) diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x index 05f5dfe..5efca44 100644 --- a/cortex-m-rt/link.x +++ b/cortex-m-rt/link.x @@ -8,12 +8,12 @@ SECTIONS _svector_table = .; LONG(_stack_start); - KEEP(*(.vector_table.reset_handler)); + KEEP(*(.vector_table.reset_vector)); - KEEP(*(.rodata.exceptions)); + KEEP(*(.vector_table.exceptions)); _eexceptions = .; - KEEP(*(.rodata.interrupts)); + KEEP(*(.vector_table.interrupts)); _einterrupts = .; } > FLASH @@ -101,23 +101,23 @@ ASSERT(_eexceptions - ORIGIN(FLASH) > 8, " You must specify the exception handlers. Create a non `pub` static variable with type `cortex_m::exception::Handlers` and place it in the -'.rodata.exceptions' section. (cf. #[link_section]). Apply the +'.vector_table.exceptions' section. (cf. #[link_section]). Apply the `#[used]` attribute to the variable to make it reach the linker."); ASSERT(_eexceptions - ORIGIN(FLASH) == 0x40, " -Invalid '.rodata.exceptions' section. +Invalid '.vector_table.exceptions' section. Make sure to place a static with type `cortex_m::exception::Handlers` in that section (cf. #[link_section]) ONLY ONCE."); ASSERT(_einterrupts - _eexceptions > 0, " You must specify the interrupt handlers. Create a non `pub` static variable and place it in the -'.rodata.interrupts' section. (cf. #[link_section]). Apply the +'.vector_table.interrupts' section. (cf. #[link_section]). Apply the `#[used]` attribute to the variable to help it reach the linker."); ASSERT(_einterrupts - _eexceptions <= 0x3c0, " There can't be more than 240 interrupt handlers. -Fix the '.rodata.interrupts' section. (cf. #[link_section])"); +Fix the '.vector_table.interrupts' section. (cf. #[link_section])"); ASSERT(_einterrupts <= _stext, " The '.text' section can't be placed inside '.vector_table' section. diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 843bfa8..60ceab5 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -118,7 +118,8 @@ //! hprintln!("Hello, world!"); //! } //! -//! // As we are not using interrupts, we just register a dummy catch all handler +//! // As we are not using interrupts, we just register a dummy catch all +//! // handler //! #[allow(dead_code)] //! #[link_section = ".rodata.interrupts"] //! #[used] @@ -150,8 +151,10 @@ #![deny(warnings)] #![feature(asm)] #![feature(compiler_builtins_lib)] +#![feature(core_intrinsics)] #![feature(lang_items)] #![feature(linkage)] +#![feature(naked_functions)] #![feature(used)] #![no_std] @@ -161,8 +164,10 @@ extern crate r0; mod lang_items; -#[cfg(feature = "exceptions")] -use cortex_m::exception; +use core::intrinsics; + +use cortex_m::asm; +use cortex_m::exception::ExceptionFrame; extern "C" { // NOTE `rustc` forces this signature on us. See `src/lang_items.rs` @@ -180,6 +185,10 @@ extern "C" { static _sidata: u32; } +#[link_section = ".vector_table.reset_vector"] +#[used] +static RESET_VECTOR: unsafe extern "C" fn() -> ! = reset_handler; + /// The reset handler /// /// This is the entry point of all programs @@ -220,19 +229,303 @@ unsafe extern "C" fn reset_handler() -> ! { // If `main` returns, then we go into "reactive" mode and simply attend // interrupts as they occur. loop { - #[cfg(target_arch = "arm")] asm!("wfi" :::: "volatile"); } } +#[allow(non_snake_case)] +#[allow(private_no_mangle_fns)] +#[linkage = "weak"] +#[naked] +#[no_mangle] +extern "C" fn NMI() { + unsafe { + asm!("b DEFAULT_HANDLER" :::: "volatile"); + intrinsics::unreachable(); + } +} + +#[allow(non_snake_case)] +#[allow(private_no_mangle_fns)] +#[linkage = "weak"] +#[naked] +#[no_mangle] +extern "C" fn HARD_FAULT() { + unsafe { + asm!("b DEFAULT_HANDLER" :::: "volatile"); + intrinsics::unreachable(); + } +} + +#[allow(non_snake_case)] +#[allow(private_no_mangle_fns)] +#[linkage = "weak"] +#[naked] +#[no_mangle] +extern "C" fn MEM_MANAGE() { + unsafe { + asm!("b DEFAULT_HANDLER" :::: "volatile"); + intrinsics::unreachable(); + } +} + +#[allow(non_snake_case)] +#[allow(private_no_mangle_fns)] +#[linkage = "weak"] +#[naked] +#[no_mangle] +extern "C" fn BUS_FAULT() { + unsafe { + asm!("b DEFAULT_HANDLER" :::: "volatile"); + intrinsics::unreachable(); + } +} + +#[allow(non_snake_case)] +#[allow(private_no_mangle_fns)] +#[linkage = "weak"] +#[naked] +#[no_mangle] +extern "C" fn USAGE_FAULT() { + unsafe { + asm!("b DEFAULT_HANDLER" :::: "volatile"); + intrinsics::unreachable(); + } +} + +#[allow(non_snake_case)] +#[allow(private_no_mangle_fns)] +#[linkage = "weak"] +#[naked] +#[no_mangle] +extern "C" fn SVCALL() { + unsafe { + asm!("b DEFAULT_HANDLER" :::: "volatile"); + intrinsics::unreachable(); + } +} + +#[allow(non_snake_case)] +#[allow(private_no_mangle_fns)] +#[linkage = "weak"] +#[naked] +#[no_mangle] +extern "C" fn PENDSV() { + unsafe { + asm!("b DEFAULT_HANDLER" :::: "volatile"); + intrinsics::unreachable(); + } +} + +#[allow(non_snake_case)] +#[allow(private_no_mangle_fns)] +#[linkage = "weak"] +#[naked] +#[no_mangle] +extern "C" fn SYS_TICK() { + unsafe { + asm!("b DEFAULT_HANDLER" :::: "volatile"); + intrinsics::unreachable(); + } +} -#[allow(dead_code)] #[used] -#[link_section = ".vector_table.reset_handler"] -static RESET_HANDLER: unsafe extern "C" fn() -> ! = reset_handler; +#[link_section = ".vector_table.exceptions"] +static EXCEPTIONS: [Option; 14] = [ + Some(NMI), + Some(HARD_FAULT), + Some(MEM_MANAGE), + Some(BUS_FAULT), + Some(USAGE_FAULT), + None, + None, + None, + None, + Some(SVCALL), + None, + None, + Some(PENDSV), + Some(SYS_TICK), +]; + +extern "C" { + static INTERRUPTS: u32; +} + +// NOTE here we create an undefined reference to the `INTERRUPTS` symbol. This +// symbol will be provided by the device crate and points to the part of the +// vector table that contains the device specific interrupts. We need this +// undefined symbol because otherwise the linker may not include the interrupts +// part of the vector table in the final binary. This can occur when LTO is +// *not* used and several objects are passed to the linker: since the linker is +// lazy it will not look at object files if it has found all the undefined +// symbols that the top crate depends on; in that scenario it may never reach +// the device crate (unlikely scenario but not impossible). With the undefined +// symbol we force the linker to look for the missing part of the vector table. +#[used] +static DEMAND: &u32 = unsafe { &INTERRUPTS }; + +/// `sf` points to the previous stack frame +/// +/// That stack frame is a snapshot of the program state right before the +/// exception occurred. +#[allow(unused_variables)] +extern "C" fn default_handler(sf: &ExceptionFrame) -> ! { + asm::bkpt(); + + loop {} -#[allow(dead_code)] -#[cfg(feature = "exceptions")] -#[link_section = ".rodata.exceptions"] + #[export_name = "DEFAULT_HANDLER"] + #[linkage = "weak"] + #[naked] + extern "C" fn trampoline() -> ! { + unsafe { + asm!("mrs r0, MSP + b $0" + : + : "i"(default_handler as extern "C" fn(&ExceptionFrame) -> !) + : + : "volatile"); + + intrinsics::unreachable() + } + } + + #[used] + static KEEP: extern "C" fn() -> ! = trampoline; +} + +// make sure the compiler emits the DEFAULT_HANDLER symbol so the linker can +// find it! #[used] -static EXCEPTIONS: exception::Handlers = - exception::Handlers { ..exception::DEFAULT_HANDLERS }; +static KEEP: extern "C" fn(&ExceptionFrame) -> ! = default_handler; + +/// This macro lets you override the default exception handler +/// +/// The first and only argument to this macro is the path to the function that +/// will be used as the default handler. That function must have signature +/// `fn()` +/// +/// # Examples +/// +/// ``` ignore +/// default_handler!(foo::bar); +/// +/// mod foo { +/// pub fn bar() { +/// ::cortex_m::asm::bkpt(); +/// loop {} +/// } +/// } +/// ``` +#[macro_export] +macro_rules! default_handler { + ($body:path) => { + #[allow(non_snake_case)] + #[doc(hidden)] + #[no_mangle] + pub unsafe extern "C" fn DEFAULT_HANDLER() { + // type checking + let f: fn() = $body; + f(); + } + } +} + +/// Fault and system exceptions +#[allow(non_camel_case_types)] +#[doc(hidden)] +pub enum Exception { + /// Non-maskable interrupt + NMI, + /// All class of fault. + HARD_FAULT, + /// Memory management. + MEN_MANAGE, + /// Pre-fetch fault, memory access fault. + BUS_FAULT, + /// Undefined instruction or illegal state. + USAGE_FAULT, + /// System service call via SWI instruction + SVCALL, + /// Pendable request for system service + PENDSV, + /// System tick timer + SYS_TICK, +} + +/// Assigns a handler to an exception +/// +/// This macro takes two arguments: the name of an exception and the path to the +/// function that will be used as the handler of that exception. That function +/// must have signature `fn()`. +/// +/// Optionally a third argument may be used to declare static variables local to +/// this exception handler. The handler will have exclusive access to these +/// variables on each invocation. If the third argument is used then the +/// signature of the handler function must be `fn(&mut $NAME::Local)` where +/// `$NAME` is the first argument passed to the macro. +/// +/// # Example +/// +/// ``` ignore +/// exception!(MEM_MANAGE, mpu_fault); +/// +/// fn mpu_fault() { +/// panic!("Oh no! Something went wrong"); +/// } +/// +/// exception!(SYS_TICK, periodic, local: { +/// counter: u32 = 0; +/// }); +/// +/// fn periodic(local: &mut SYS_TICK::Local) { +/// local.counter += 1; +/// println!("This function has been called {} times", local.counter); +/// } +/// ``` +#[macro_export] +macro_rules! exception { + ($NAME:ident, $body:path, local: { + $($lvar:ident:$lty:ident = $lval:expr;)+ + }) => { + #[allow(non_snake_case)] + mod $NAME { + pub struct Local { + $( + pub $lvar: $lty, + )+ + } + } + + #[allow(non_snake_case)] + #[doc(hidden)] + #[no_mangle] + pub unsafe extern "C" fn $NAME() { + // check that the handler exists + let _ = $crate::Exception::$NAME; + + static mut LOCAL: self::$NAME::Local = self::$NAME::Local { + $( + $lvar: $lval, + )* + }; + + // type checking + let f: fn(&mut self::$NAME::Local) = $body; + f(unsafe { &mut LOCAL }); + } + }; + ($NAME:ident, $body:path) => { + #[allow(non_snake_case)] + #[doc(hidden)] + #[no_mangle] + pub unsafe extern "C" fn $NAME() { + // check that the handler exists + let _ = $crate::Exception::$NAME; + + // type checking + let f: fn() = $body; + f(); + } + } +} -- cgit v1.2.3 From 57e2fa799a1ea89c13e41ac815a964feabd3b52d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Jun 2017 23:12:59 -0500 Subject: update documentation and linker assertion messages --- cortex-m-rt/link.x | 28 +++-- cortex-m-rt/src/lib.rs | 280 ++++++++++++++++++++++++++++++++++++------------- 2 files changed, 220 insertions(+), 88 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x index 5efca44..9f1c507 100644 --- a/cortex-m-rt/link.x +++ b/cortex-m-rt/link.x @@ -98,30 +98,28 @@ SECTIONS /* Do not exceed this mark in the error messages below | */ ASSERT(_eexceptions - ORIGIN(FLASH) > 8, " -You must specify the exception handlers. -Create a non `pub` static variable with type -`cortex_m::exception::Handlers` and place it in the -'.vector_table.exceptions' section. (cf. #[link_section]). Apply the -`#[used]` attribute to the variable to make it reach the linker."); +The exception handlers are missing. This is likely a cortex-m-rt bug. +Please file a bug report at: +https://github.com/japaric/cortex-m-rt/issues"); ASSERT(_eexceptions - ORIGIN(FLASH) == 0x40, " -Invalid '.vector_table.exceptions' section. -Make sure to place a static with type `cortex_m::exception::Handlers` -in that section (cf. #[link_section]) ONLY ONCE."); +Invalid '.vector_table.exceptions' section. This is likely a +cortex-m-rt bug. Please file a bug report at: +https://github.com/japaric/cortex-m-rt/issues"); ASSERT(_einterrupts - _eexceptions > 0, " -You must specify the interrupt handlers. -Create a non `pub` static variable and place it in the -'.vector_table.interrupts' section. (cf. #[link_section]). Apply the -`#[used]` attribute to the variable to help it reach the linker."); +The interrupt handlers are missing. If you are not linking to a device +crate then you supply the interrupt handlers yourself. Check the +documentation."); ASSERT(_einterrupts - _eexceptions <= 0x3c0, " -There can't be more than 240 interrupt handlers. -Fix the '.vector_table.interrupts' section. (cf. #[link_section])"); +There can't be more than 240 interrupt handlers. This may be a bug in +your device crate, or you may have registered more than 240 interrupt +handlers."); ASSERT(_einterrupts <= _stext, " The '.text' section can't be placed inside '.vector_table' section. -Set '_stext' to an adress greater than '_einterrupts'"); +Set '_stext' to an address greater than '_einterrupts'"); ASSERT(_stext < ORIGIN(FLASH) + LENGTH(FLASH), " The '.text' section must be placed inside the FLASH memory diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 60ceab5..c0aa56e 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -4,91 +4,65 @@ //! //! This crate provides //! -//! - Before main initialization of the `.bss` and `.data` sections +//! - Before main initialization of the `.bss` and `.data` sections. //! -//! - An overridable (\*) `panic_fmt` implementation that prints to the ITM or -//! to the host stdout (through semihosting) depending on which Cargo feature -//! has been enabled: `"panic-over-itm"` or `"panic-over-semihosting"`. +//! - Before main initialization of the FPU (for targets that have a FPU). //! -//! - A minimal `start` lang item, to support vanilla `fn main()`. NOTE the -//! processor goes into "reactive" mode (`loop { asm!("wfi") }`) after -//! returning from `main`. +//! - A `panic_fmt` implementation that just calls abort that you can opt into +//! through the "abort-on-panic" Cargo feature. If you don't use this feature +//! you'll have to provide the `panic_fmt` lang item yourself. Documentation +//! [here][1] //! -//! - An opt-in linker script (`"linker-script"` Cargo feature) that encodes -//! the memory layout of a generic Cortex-M microcontroller. This linker -//! script is missing the definitions of the FLASH and RAM memory regions of -//! the device and of the `_stack_start` symbol (address where the call stack -//! is allocated). This missing information must be supplied through a -//! `memory.x` file (see example below). +//! [1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html //! -//! - A default exception handler tailored for debugging and that provides -//! access to the stacked registers under the debugger. By default, all -//! exceptions (\*\*) are serviced by this handler but this can be overridden -//! on a per exception basis by opting out of the "exceptions" Cargo feature -//! and then defining the following `struct` +//! - A minimal `start` lang item to support the standard `fn main()` +//! interface. (The processor goes to sleep (`loop { asm!("wfi") }`) after +//! returning from `main`) //! -//! - A `_sheap` symbol at whose address you can locate the heap. +//! - A linker script that encodes the memory layout of a generic Cortex-M +//! microcontroller. This linker script is missing some information that must +//! be supplied through a `memory.x` file (see example below). //! -//! ``` ignore,no_run -//! use cortex_m::exception; -//! -//! #[link_section = ".rodata.exceptions"] -//! #[used] -//! static EXCEPTIONS: exception::Handlers = exception::Handlers { -//! hard_fault: my_override, -//! nmi: another_handler, -//! ..exception::DEFAULT_HANDLERS -//! }; -//! ``` -//! -//! (\*) To override the `panic_fmt` implementation, simply create a new -//! `rust_begin_unwind` symbol: +//! - A default exception handler tailored for debugging that lets you inspect +//! what was the state of the processor at the time of the exception. By +//! default, all exceptions are serviced by this handler but each exception +//! can be individually overridden using the +//! [`exception!`](macro.exception.html) macro. The default exception handler +//! itself can also be overridden using the +//! [`default_handler!`](macro.default_handler.html) macro. //! -//! ``` -//! #[no_mangle] -//! pub unsafe extern "C" fn rust_begin_unwind( -//! _args: ::core::fmt::Arguments, -//! _file: &'static str, -//! _line: u32, -//! ) -> ! { -//! .. -//! } -//! ``` +//! - A `_sheap` symbol at whose address you can locate a heap. //! -//! (\*\*) All the device specific exceptions, i.e. the interrupts, are left -//! unpopulated. You must fill that part of the vector table by defining the -//! following static (with the right memory layout): +//! # Example //! -//! ``` ignore,no_run -//! #[link_section = ".rodata.interrupts"] -//! #[used] -//! static INTERRUPTS: SomeStruct = SomeStruct { .. } -//! ``` +//! Creating a new bare metal project. (I recommend you use the +//! [`cortex-m-quickstart`][qs] template as it takes of all the boilerplate +//! shown here) //! -//! # Example +//! [qs]: https://docs.rs/cortex-m-quickstart/0.2.0/cortex_m_quickstart/ //! //! ``` text //! $ cargo new --bin app && cd $_ //! -//! $ cargo add cortex-m cortex-m-rt +//! $ # add this crate as a dependency +//! $ edit Cargo.toml && cat $_ +//! [dependencies.cortex-m-rt] +//! features = ["abort-on-panic"] +//! version = "0.3.0" //! +//! $ # tell Xargo which standard crates to build //! $ edit Xargo.toml && cat $_ -//! ``` -//! -//! ``` text //! [dependencies.core] +//! stage = 0 //! //! [dependencies.compiler_builtins] //! features = ["mem"] //! git = "https://github.com/rust-lang-nursery/compiler-builtins" //! stage = 1 -//! ``` //! -//! ``` text +//! $ # memory layout of the device //! $ edit memory.x && cat $_ -//! ``` //! -//! ``` text //! MEMORY //! { //! /* NOTE K = KiBi = 1024 bytes */ @@ -98,9 +72,7 @@ //! //! /* This is where the call stack will be allocated */ //! _stack_start = ORIGIN(RAM) + LENGTH(RAM); -//! ``` //! -//! ``` text //! $ edit src/main.rs && cat $_ //! ``` //! @@ -108,25 +80,20 @@ //! #![feature(used)] //! #![no_std] //! -//! #[macro_use] -//! extern crate cortex_m; //! extern crate cortex_m_rt; //! -//! use cortex_m::asm; -//! //! fn main() { -//! hprintln!("Hello, world!"); +//! // do something here //! } //! //! // As we are not using interrupts, we just register a dummy catch all //! // handler -//! #[allow(dead_code)] -//! #[link_section = ".rodata.interrupts"] +//! #[link_section = ".vector_table.interrupts"] //! #[used] //! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; //! //! extern "C" fn default_handler() { -//! asm::bkpt(); +//! loop {} //! } //! ``` //! @@ -143,7 +110,174 @@ //! 08000400 : //! 8000400: b580 push {r7, lr} //! 8000402: 466f mov r7, sp -//! 8000404: b084 sub sp, #16 +//! 8000404: b084 sub sp, #8 +//! ``` +//! +//! # Symbol interfaces +//! +//! This crate makes heavy use of symbols, linker sections and linker scripts to +//! provide most of its functionality. Below are described the main symbol +//! interfaces. +//! +//! ## `DEFAULT_HANDLER` +//! +//! This weak symbol can be overridden to override the default exception handler +//! that this crate provides. It's recommended that you use the +//! `default_handler!` to do the override, but below is shown how to manually +//! override the symbol: +//! +//! ``` ignore,no_run +//! #[no_mangle] +//! pub extern "C" fn DEFAULT_HANDLER() { +//! // do something here +//! } +//! ``` +//! +//! ## `.vector_table.interrupts` +//! +//! This linker section is used to register interrupt handlers in the vector +//! table. The recommended way to use this section is to populate it, once, with +//! an array of *weak* functions that just call the `DEFAULT_HANDLER` symbol. +//! Then the user can override them by name. +//! +//! ### Example +//! +//! Populating the vector table +//! +//! ``` ignore,no_run +//! // Number of interrupts the device has +//! const N: usize = 60; +//! +//! // Default interrupt handler that just calls the `DEFAULT_HANDLER` +//! #[linkage = "weak"] +//! #[naked] +//! #[no_mangle] +//! extern "C" fn WWDG() { +//! unsafe { +//! asm!("b DEFAULT_HANDLER" :::: "volatile"); +//! core::intrinsics::unreachable(); +//! } +//! } +//! +//! // You need one function per interrupt handler +//! #[linkage = "weak"] +//! #[naked] +//! #[no_mangle] +//! extern "C" fn WWDG() { +//! unsafe { +//! asm!("b DEFAULT_HANDLER" :::: "volatile"); +//! core::intrinsics::unreachable(); +//! } +//! } +//! +//! // .. +//! +//! // Use `None` for reserved spots in the vector table +//! #[link_section = ".vector_table.interrupts"] +//! #[no_mangle] +//! #[used] +//! static INTERRUPTS: [Option; N] = [ +//! Some(WWDG), +//! Some(PVD), +//! // .. +//! ]; +//! ``` +//! +//! Overriding an interrupt (this can be in a different crate) +//! +//! ``` ignore,no_run +//! // the name must match the name of one of the weak functions used to +//! // populate the vector table. +//! #[no_mangle] +//! pub extern "C" fn WWDG() { +//! // do something here +//! } +//! ``` +//! +//! ## `memory.x` +//! +//! This file supplies the information about the device to the linker. +//! +//! ### `MEMORY` +//! +//! The main information that this file must provide is the memory layout of +//! the device in the form of the `MEMORY` command. The command is documented +//! [here][2], but at a minimum you'll want to create two memory regions: one +//! for Flash memory and another for RAM. +//! +//! [2]: https://sourceware.org/binutils/docs/ld/MEMORY.html +//! +//! The program instructions (the `.text` section) will be stored in the memory +//! region named FLASH, and the program `static` variables (the sections `.bss` +//! and `.data`) will be allocated in the memory region named RAM. +//! +//! ### `_stack_start` +//! +//! This symbol provides the address at which the call stack will be allocated. +//! The call stack grows downwards so this address is usually set to the highest +//! valid RAM address plus one (this *is* an invalid address but the processor +//! will decrement the stack pointer *before* using its value as an address). +//! +//! #### Example +//! +//! Allocating the call stack on a different RAM region. +//! +//! ``` +//! MEMORY +//! { +//! /* call stack will go here */ +//! CCRAM : ORIGIN = 0x10000000, LENGTH = 8K +//! FLASH : ORIGIN = 0x08000000, LENGTH = 256K +//! /* static variables will go here */ +//! RAM : ORIGIN = 0x20000000, LENGTH = 40K +//! } +//! +//! _stack_start = ORIGIN(CCRAM) + LENGTH(CCRAM); +//! ``` +//! +//! ### `_stext` +//! +//! This symbol indicates where the `.text` section will be located. If not +//! specified in the `memory.x` file it will default to right after the vector +//! table -- the vector table is always located at the start of the FLASH region. +//! +//! The main use of this symbol is leaving some space between the vector table +//! and the `.text` section unused. This is required on some microcontrollers +//! that store some configuration information right after the vector table. +//! +//! #### Example +//! +//! Locate the `.text` section 1024 bytes after the start of the FLASH region. +//! +//! ``` +//! _stext = ORIGIN(FLASH) + 0x400; +//! ``` +//! +//! ### `_sheap` +//! +//! This symbol is located in RAM right after the `.bss` and `.data` sections. +//! You can use the address of this symbol as the start address of a heap +//! region. This symbol is 4 byte aligned so that address will be a multiple of +//! 4. +//! +//! #### Example +//! +//! ``` +//! extern crate some_allocator; +//! +//! // Size of the heap in bytes +//! const SIZE: usize = 1024; +//! +//! extern "C" { +//! static mut _sheap: u8; +//! } +//! +//! fn main() { +//! unsafe { +//! let start_address = &mut _sheap as *mut u8; +//! some_allocator::initialize(start_address, SIZE); +//! } +//! } //! ``` #![cfg_attr(feature = "abort-on-panic", feature(core_intrinsics))] @@ -200,8 +334,8 @@ unsafe extern "C" fn reset_handler() -> ! { match () { #[cfg(not(has_fpu))] () => { - // Neither `argc` or `argv` make sense in bare metal context so we just - // stub them + // Neither `argc` or `argv` make sense in bare metal context so we + // just stub them main(0, ::core::ptr::null()); } #[cfg(has_fpu)] -- cgit v1.2.3 From 2a3a1f66c069d795acacc46b23e0567c8a388903 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 30 Jun 2017 23:34:50 -0500 Subject: make the _stack_start symbol optional --- cortex-m-rt/CHANGELOG.md | 3 +++ cortex-m-rt/link.x | 2 ++ cortex-m-rt/src/lib.rs | 6 ++---- 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/CHANGELOG.md b/cortex-m-rt/CHANGELOG.md index c3dbd63..53fcb51 100644 --- a/cortex-m-rt/CHANGELOG.md +++ b/cortex-m-rt/CHANGELOG.md @@ -27,6 +27,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). mechanism for registering exceptions (`static EXCEPTIONS`); use the new ones: `default_handler!` and `exception!`. +- The `_stack_start` is now optional in the `memory.x` file. If unspecified its + value will be set to `ORIGIN(RAM) + LENGTH(RAM)`. + ## [v0.2.4] - 2017-06-03 ### Added diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x index 9f1c507..02f4055 100644 --- a/cortex-m-rt/link.x +++ b/cortex-m-rt/link.x @@ -1,5 +1,7 @@ INCLUDE memory.x +PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM)); + SECTIONS { .vector_table ORIGIN(FLASH) : diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index c0aa56e..f1a4277 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -62,7 +62,6 @@ //! //! $ # memory layout of the device //! $ edit memory.x && cat $_ -//! //! MEMORY //! { //! /* NOTE K = KiBi = 1024 bytes */ @@ -70,9 +69,6 @@ //! RAM : ORIGIN = 0x20000000, LENGTH = 8K //! } //! -//! /* This is where the call stack will be allocated */ -//! _stack_start = ORIGIN(RAM) + LENGTH(RAM); -//! //! $ edit src/main.rs && cat $_ //! ``` //! @@ -218,6 +214,8 @@ //! valid RAM address plus one (this *is* an invalid address but the processor //! will decrement the stack pointer *before* using its value as an address). //! +//! If omitted this symbol value will default to `ORIGIN(RAM) + LENGTH(RAM)`. +//! //! #### Example //! //! Allocating the call stack on a different RAM region. -- cgit v1.2.3 From a869df06992ea2057fc969d0708a2af1c823cfb0 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 2 Jul 2017 20:48:31 -0500 Subject: use 'EXTERN(INTERRUPTS)' in the linker script instead of #[used] in the source --- cortex-m-rt/link.x | 5 +++++ cortex-m-rt/src/lib.rs | 17 ----------------- 2 files changed, 5 insertions(+), 17 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x index 02f4055..35ee07b 100644 --- a/cortex-m-rt/link.x +++ b/cortex-m-rt/link.x @@ -1,5 +1,10 @@ INCLUDE memory.x +/* Create an undefined reference to the INTERRUPTS symbol. This is required to + force the linker to *not* drop the INTERRUPTS symbol if it comes from an + object file that's passed to the linker *before* this crate */ +EXTERN(INTERRUPTS); + PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM)); SECTIONS diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index f1a4277..9553827 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -479,23 +479,6 @@ static EXCEPTIONS: [Option; 14] = [ Some(SYS_TICK), ]; -extern "C" { - static INTERRUPTS: u32; -} - -// NOTE here we create an undefined reference to the `INTERRUPTS` symbol. This -// symbol will be provided by the device crate and points to the part of the -// vector table that contains the device specific interrupts. We need this -// undefined symbol because otherwise the linker may not include the interrupts -// part of the vector table in the final binary. This can occur when LTO is -// *not* used and several objects are passed to the linker: since the linker is -// lazy it will not look at object files if it has found all the undefined -// symbols that the top crate depends on; in that scenario it may never reach -// the device crate (unlikely scenario but not impossible). With the undefined -// symbol we force the linker to look for the missing part of the vector table. -#[used] -static DEMAND: &u32 = unsafe { &INTERRUPTS }; - /// `sf` points to the previous stack frame /// /// That stack frame is a snapshot of the program state right before the -- cgit v1.2.3 From d4290e0c1968e291c37868b9ab2b04d045a13f3c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 2 Jul 2017 21:11:07 -0500 Subject: tweak exception! documentation --- cortex-m-rt/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 9553827..01e06b2 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -574,11 +574,11 @@ pub enum Exception { /// function that will be used as the handler of that exception. That function /// must have signature `fn()`. /// -/// Optionally a third argument may be used to declare static variables local to -/// this exception handler. The handler will have exclusive access to these -/// variables on each invocation. If the third argument is used then the -/// signature of the handler function must be `fn(&mut $NAME::Local)` where -/// `$NAME` is the first argument passed to the macro. +/// Optionally, a third argument may be used to declare exception local data. +/// The handler will have exclusive access to this data on each invocation. If +/// the third argument is used then the signature of the handler function must +/// be `fn(&mut $NAME::Local)` where `$NAME` is the first argument passed to the +/// macro. /// /// # Example /// -- cgit v1.2.3 From 488cb52c5e45aef946c62c33dbedde2429c50628 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 2 Jul 2017 21:15:00 -0500 Subject: fix unused_unsafe warning --- cortex-m-rt/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 01e06b2..a1a4b4e 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -627,7 +627,7 @@ macro_rules! exception { // type checking let f: fn(&mut self::$NAME::Local) = $body; - f(unsafe { &mut LOCAL }); + f(&mut LOCAL); } }; ($NAME:ident, $body:path) => { -- cgit v1.2.3 From a072f6edee0d0c4e7e924656a8e2195d75bbc574 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 4 Jul 2017 20:07:38 +0200 Subject: Use the new panic_fmt abi Fixes a panic_fmt mismatch with newer rust compiler versions. --- cortex-m-rt/src/lang_items.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lang_items.rs b/cortex-m-rt/src/lang_items.rs index 236b2bd..9ff95b5 100644 --- a/cortex-m-rt/src/lang_items.rs +++ b/cortex-m-rt/src/lang_items.rs @@ -5,6 +5,7 @@ unsafe extern "C" fn panic_fmt( _: ::core::fmt::Arguments, _: &'static str, _: u32, + _: u32, ) -> ! { ::core::intrinsics::abort() } -- cgit v1.2.3 From 787f44bf288fe418cb76ae3253b63a7da0f4929d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 5 Jul 2017 23:22:40 -0500 Subject: add newline --- cortex-m-rt/src/lib.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index a1a4b4e..4738c6d 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -364,6 +364,7 @@ unsafe extern "C" fn reset_handler() -> ! { asm!("wfi" :::: "volatile"); } } + #[allow(non_snake_case)] #[allow(private_no_mangle_fns)] #[linkage = "weak"] -- cgit v1.2.3 From 3267198c404d5075def66ed34f5df0fcbbf4fc28 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Jul 2017 11:27:57 -0500 Subject: s/local/locals/g and drop the linker-script feature most of the functionality provided by this crate relies too much on custom linker sections to be usable with a different linker script. --- cortex-m-rt/Cargo.toml | 6 +----- cortex-m-rt/build.rs | 48 ++++++++++++++++-------------------------------- cortex-m-rt/src/lib.rs | 37 +++++++++++++++++++------------------ 3 files changed, 36 insertions(+), 55 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 5c487f0..7959bf4 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -10,13 +10,9 @@ repository = "https://github.com/japaric/cortex-m-rt" version = "0.3.0" [dependencies] +cortex-m = "0.3.0" r0 = "0.2.1" -# cortex-m = "0.3.0" -cortex-m = { git = "https://github.com/japaric/cortex-m" } [features] -default = ["linker-script"] -# generic linker script -linker-script = [] # provides a panic_fmt implementation that calls the abort instruction (`udf 0xfe`) abort-on-panic = [] diff --git a/cortex-m-rt/build.rs b/cortex-m-rt/build.rs index 45642c5..6494c13 100644 --- a/cortex-m-rt/build.rs +++ b/cortex-m-rt/build.rs @@ -1,33 +1,21 @@ use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; -#[cfg(feature = "linker-script")] -mod imp { - use std::env; - use std::fs::File; - use std::io::Write; - use std::path::PathBuf; - - pub fn main() { - ::has_fpu(); - - // Put the linker script somewhere the linker can find it - let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); - File::create(out.join("link.x")) - .unwrap() - .write_all(include_bytes!("link.x")) - .unwrap(); - println!("cargo:rustc-link-search={}", out.display()); - - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-changed=link.x"); - } -} - -#[cfg(not(feature = "linker-script"))] -mod imp { - pub fn main() { - ::has_fpu(); - } +fn main() { + has_fpu(); + + // Put the linker script somewhere the linker can find it + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("link.x")) + .unwrap() + .write_all(include_bytes!("link.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=link.x"); } fn has_fpu() { @@ -37,7 +25,3 @@ fn has_fpu() { println!("cargo:rustc-cfg=has_fpu"); } } - -fn main() { - imp::main(); -} diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 4738c6d..3c8e6cc 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -237,7 +237,8 @@ //! //! This symbol indicates where the `.text` section will be located. If not //! specified in the `memory.x` file it will default to right after the vector -//! table -- the vector table is always located at the start of the FLASH region. +//! table -- the vector table is always located at the start of the FLASH +//! region. //! //! The main use of this symbol is leaving some space between the vector table //! and the `.text` section unused. This is required on some microcontrollers @@ -535,13 +536,13 @@ static KEEP: extern "C" fn(&ExceptionFrame) -> ! = default_handler; /// ``` #[macro_export] macro_rules! default_handler { - ($body:path) => { + ($path:path) => { #[allow(non_snake_case)] #[doc(hidden)] #[no_mangle] pub unsafe extern "C" fn DEFAULT_HANDLER() { // type checking - let f: fn() = $body; + let f: fn() = $path; f(); } } @@ -576,10 +577,10 @@ pub enum Exception { /// must have signature `fn()`. /// /// Optionally, a third argument may be used to declare exception local data. -/// The handler will have exclusive access to this data on each invocation. If -/// the third argument is used then the signature of the handler function must -/// be `fn(&mut $NAME::Local)` where `$NAME` is the first argument passed to the -/// macro. +/// The handler will have exclusive access to these *local* variables on each +/// invocation. If the third argument is used then the signature of the handler +/// function must be `fn(&mut $NAME::Locals)` where `$NAME` is the first +/// argument passed to the macro. /// /// # Example /// @@ -590,23 +591,23 @@ pub enum Exception { /// panic!("Oh no! Something went wrong"); /// } /// -/// exception!(SYS_TICK, periodic, local: { +/// exception!(SYS_TICK, periodic, locals: { /// counter: u32 = 0; /// }); /// -/// fn periodic(local: &mut SYS_TICK::Local) { -/// local.counter += 1; -/// println!("This function has been called {} times", local.counter); +/// fn periodic(locals: &mut SYS_TICK::Locals) { +/// locals.counter += 1; +/// println!("This function has been called {} times", locals.counter); /// } /// ``` #[macro_export] macro_rules! exception { - ($NAME:ident, $body:path, local: { + ($NAME:ident, $path:path, locals: { $($lvar:ident:$lty:ident = $lval:expr;)+ }) => { #[allow(non_snake_case)] mod $NAME { - pub struct Local { + pub struct Locals { $( pub $lvar: $lty, )+ @@ -620,18 +621,18 @@ macro_rules! exception { // check that the handler exists let _ = $crate::Exception::$NAME; - static mut LOCAL: self::$NAME::Local = self::$NAME::Local { + static mut LOCALS: self::$NAME::Locals = self::$NAME::Locals { $( $lvar: $lval, )* }; // type checking - let f: fn(&mut self::$NAME::Local) = $body; - f(&mut LOCAL); + let f: fn(&mut self::$NAME::Locals) = $path; + f(&mut LOCALS); } }; - ($NAME:ident, $body:path) => { + ($NAME:ident, $path:path) => { #[allow(non_snake_case)] #[doc(hidden)] #[no_mangle] @@ -640,7 +641,7 @@ macro_rules! exception { let _ = $crate::Exception::$NAME; // type checking - let f: fn() = $body; + let f: fn() = $path; f(); } } -- cgit v1.2.3 From aa21afcbc1f4aaf9145af8473fedf3f7f36118cb Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Jul 2017 11:45:33 -0500 Subject: v0.3.0 --- cortex-m-rt/CHANGELOG.md | 5 ++++- cortex-m-rt/src/lib.rs | 20 ++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/CHANGELOG.md b/cortex-m-rt/CHANGELOG.md index 53fcb51..836558f 100644 --- a/cortex-m-rt/CHANGELOG.md +++ b/cortex-m-rt/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.3.0] - 2017-07-07 + ### Added - A `default_handler!` macro to override the default exception handler. @@ -118,7 +120,8 @@ section size addr Initial release -[Unreleased]: https://github.com/japaric/cortex-m-rt/compare/v0.2.4...HEAD +[Unreleased]: https://github.com/japaric/cortex-m-rt/compare/v0.3.0...HEAD +[v0.3.0]: https://github.com/japaric/cortex-m-rt/compare/v0.2.4...v0.3.0 [v0.2.4]: https://github.com/japaric/cortex-m-rt/compare/v0.2.3...v0.2.4 [v0.2.3]: https://github.com/japaric/cortex-m-rt/compare/v0.2.2...v0.2.3 [v0.2.2]: https://github.com/japaric/cortex-m-rt/compare/v0.2.1...v0.2.2 diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 3c8e6cc..b6e6e7a 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -279,12 +279,11 @@ //! } //! ``` -#![cfg_attr(feature = "abort-on-panic", feature(core_intrinsics))] +#![cfg_attr(target_arch = "arm", feature(core_intrinsics))] #![deny(missing_docs)] #![deny(warnings)] #![feature(asm)] #![feature(compiler_builtins_lib)] -#![feature(core_intrinsics)] #![feature(lang_items)] #![feature(linkage)] #![feature(naked_functions)] @@ -297,13 +296,17 @@ extern crate r0; mod lang_items; +#[cfg(target_arch = "arm")] use core::intrinsics; +#[cfg(target_arch = "arm")] use cortex_m::asm; +#[cfg(target_arch = "arm")] use cortex_m::exception::ExceptionFrame; extern "C" { // NOTE `rustc` forces this signature on us. See `src/lang_items.rs` + #[cfg(target_arch = "arm")] fn main(argc: isize, argv: *const *const u8) -> isize; // Boundaries of the .bss section @@ -318,6 +321,7 @@ extern "C" { static _sidata: u32; } +#[cfg(target_arch = "arm")] #[link_section = ".vector_table.reset_vector"] #[used] static RESET_VECTOR: unsafe extern "C" fn() -> ! = reset_handler; @@ -325,6 +329,7 @@ static RESET_VECTOR: unsafe extern "C" fn() -> ! = reset_handler; /// The reset handler /// /// This is the entry point of all programs +#[cfg(target_arch = "arm")] #[link_section = ".reset_handler"] unsafe extern "C" fn reset_handler() -> ! { r0::zero_bss(&mut _sbss, &mut _ebss); @@ -368,6 +373,7 @@ unsafe extern "C" fn reset_handler() -> ! { #[allow(non_snake_case)] #[allow(private_no_mangle_fns)] +#[cfg(target_arch = "arm")] #[linkage = "weak"] #[naked] #[no_mangle] @@ -380,6 +386,7 @@ extern "C" fn NMI() { #[allow(non_snake_case)] #[allow(private_no_mangle_fns)] +#[cfg(target_arch = "arm")] #[linkage = "weak"] #[naked] #[no_mangle] @@ -392,6 +399,7 @@ extern "C" fn HARD_FAULT() { #[allow(non_snake_case)] #[allow(private_no_mangle_fns)] +#[cfg(target_arch = "arm")] #[linkage = "weak"] #[naked] #[no_mangle] @@ -404,6 +412,7 @@ extern "C" fn MEM_MANAGE() { #[allow(non_snake_case)] #[allow(private_no_mangle_fns)] +#[cfg(target_arch = "arm")] #[linkage = "weak"] #[naked] #[no_mangle] @@ -416,6 +425,7 @@ extern "C" fn BUS_FAULT() { #[allow(non_snake_case)] #[allow(private_no_mangle_fns)] +#[cfg(target_arch = "arm")] #[linkage = "weak"] #[naked] #[no_mangle] @@ -428,6 +438,7 @@ extern "C" fn USAGE_FAULT() { #[allow(non_snake_case)] #[allow(private_no_mangle_fns)] +#[cfg(target_arch = "arm")] #[linkage = "weak"] #[naked] #[no_mangle] @@ -440,6 +451,7 @@ extern "C" fn SVCALL() { #[allow(non_snake_case)] #[allow(private_no_mangle_fns)] +#[cfg(target_arch = "arm")] #[linkage = "weak"] #[naked] #[no_mangle] @@ -452,6 +464,7 @@ extern "C" fn PENDSV() { #[allow(non_snake_case)] #[allow(private_no_mangle_fns)] +#[cfg(target_arch = "arm")] #[linkage = "weak"] #[naked] #[no_mangle] @@ -462,6 +475,7 @@ extern "C" fn SYS_TICK() { } } +#[cfg(target_arch = "arm")] #[used] #[link_section = ".vector_table.exceptions"] static EXCEPTIONS: [Option; 14] = [ @@ -486,6 +500,7 @@ static EXCEPTIONS: [Option; 14] = [ /// That stack frame is a snapshot of the program state right before the /// exception occurred. #[allow(unused_variables)] +#[cfg(target_arch = "arm")] extern "C" fn default_handler(sf: &ExceptionFrame) -> ! { asm::bkpt(); @@ -513,6 +528,7 @@ extern "C" fn default_handler(sf: &ExceptionFrame) -> ! { // make sure the compiler emits the DEFAULT_HANDLER symbol so the linker can // find it! +#[cfg(target_arch = "arm")] #[used] static KEEP: extern "C" fn(&ExceptionFrame) -> ! = default_handler; -- cgit v1.2.3 From a41b0856bda7ff3ab043c3a2c83fb913353f74b8 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Jul 2017 15:22:19 -0500 Subject: fix warning when compiling for x86_64 and the abort-on-panic feature is enabled --- cortex-m-rt/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index b6e6e7a..adb553a 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -279,7 +279,8 @@ //! } //! ``` -#![cfg_attr(target_arch = "arm", feature(core_intrinsics))] +#![cfg_attr(any(target_arch = "arm", feature = "abort-on-panic"), + feature(core_intrinsics))] #![deny(missing_docs)] #![deny(warnings)] #![feature(asm)] -- cgit v1.2.3 From f265625401664b61f993b81d027ffdafe6bab0cc Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Jul 2017 15:47:34 -0500 Subject: sf -> ef --- cortex-m-rt/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index adb553a..08ee130 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -496,13 +496,13 @@ static EXCEPTIONS: [Option; 14] = [ Some(SYS_TICK), ]; -/// `sf` points to the previous stack frame +/// `ef` points to the exception frame /// -/// That stack frame is a snapshot of the program state right before the +/// That exception frame is a snapshot of the program state right before the /// exception occurred. #[allow(unused_variables)] #[cfg(target_arch = "arm")] -extern "C" fn default_handler(sf: &ExceptionFrame) -> ! { +extern "C" fn default_handler(ef: &ExceptionFrame) -> ! { asm::bkpt(); loop {} -- cgit v1.2.3 From 73d94c2345a01ac43bf7690790e60efd473c0efe Mon Sep 17 00:00:00 2001 From: protomors Date: Tue, 11 Jul 2017 13:06:20 +0300 Subject: Fixed documentation about creating new project. --- cortex-m-rt/src/lib.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 08ee130..9543fbf 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -57,7 +57,6 @@ //! //! [dependencies.compiler_builtins] //! features = ["mem"] -//! git = "https://github.com/rust-lang-nursery/compiler-builtins" //! stage = 1 //! //! $ # memory layout of the device -- cgit v1.2.3 From a1d223528d534391805699d9714d78e213e9c471 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 18 Jul 2017 12:40:47 -0500 Subject: define handlers as weak aliases of DEFAULT_HANDLER cc japaric/cortex-m#19 --- cortex-m-rt/CHANGELOG.md | 5 ++ cortex-m-rt/src/lib.rs | 124 +++++++++++------------------------------------ 2 files changed, 34 insertions(+), 95 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/CHANGELOG.md b/cortex-m-rt/CHANGELOG.md index 653c55e..b210b23 100644 --- a/cortex-m-rt/CHANGELOG.md +++ b/cortex-m-rt/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Fixed + +- Remove duplication of default exception handlers. This saves 32 bytes of Flash + memory (.text). + ## [v0.3.4] - 2017-07-19 ### Changed diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 9543fbf..2968252 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -284,6 +284,7 @@ #![deny(warnings)] #![feature(asm)] #![feature(compiler_builtins_lib)] +#![feature(global_asm)] #![feature(lang_items)] #![feature(linkage)] #![feature(naked_functions)] @@ -371,108 +372,41 @@ unsafe extern "C" fn reset_handler() -> ! { } } -#[allow(non_snake_case)] -#[allow(private_no_mangle_fns)] -#[cfg(target_arch = "arm")] -#[linkage = "weak"] -#[naked] -#[no_mangle] -extern "C" fn NMI() { - unsafe { - asm!("b DEFAULT_HANDLER" :::: "volatile"); - intrinsics::unreachable(); - } -} +global_asm!(r#" +.weak NMI +NMI = DEFAULT_HANDLER -#[allow(non_snake_case)] -#[allow(private_no_mangle_fns)] -#[cfg(target_arch = "arm")] -#[linkage = "weak"] -#[naked] -#[no_mangle] -extern "C" fn HARD_FAULT() { - unsafe { - asm!("b DEFAULT_HANDLER" :::: "volatile"); - intrinsics::unreachable(); - } -} +.weak HARD_FAULT +HARD_FAULT = DEFAULT_HANDLER -#[allow(non_snake_case)] -#[allow(private_no_mangle_fns)] -#[cfg(target_arch = "arm")] -#[linkage = "weak"] -#[naked] -#[no_mangle] -extern "C" fn MEM_MANAGE() { - unsafe { - asm!("b DEFAULT_HANDLER" :::: "volatile"); - intrinsics::unreachable(); - } -} +.weak MEM_MANAGE +MEM_MANAGE = DEFAULT_HANDLER -#[allow(non_snake_case)] -#[allow(private_no_mangle_fns)] -#[cfg(target_arch = "arm")] -#[linkage = "weak"] -#[naked] -#[no_mangle] -extern "C" fn BUS_FAULT() { - unsafe { - asm!("b DEFAULT_HANDLER" :::: "volatile"); - intrinsics::unreachable(); - } -} +.weak BUS_FAULT +BUS_FAULT = DEFAULT_HANDLER -#[allow(non_snake_case)] -#[allow(private_no_mangle_fns)] -#[cfg(target_arch = "arm")] -#[linkage = "weak"] -#[naked] -#[no_mangle] -extern "C" fn USAGE_FAULT() { - unsafe { - asm!("b DEFAULT_HANDLER" :::: "volatile"); - intrinsics::unreachable(); - } -} +.weak USAGE_FAULT +USAGE_FAULT = DEFAULT_HANDLER -#[allow(non_snake_case)] -#[allow(private_no_mangle_fns)] -#[cfg(target_arch = "arm")] -#[linkage = "weak"] -#[naked] -#[no_mangle] -extern "C" fn SVCALL() { - unsafe { - asm!("b DEFAULT_HANDLER" :::: "volatile"); - intrinsics::unreachable(); - } -} +.weak SVCALL +SVCALL = DEFAULT_HANDLER -#[allow(non_snake_case)] -#[allow(private_no_mangle_fns)] -#[cfg(target_arch = "arm")] -#[linkage = "weak"] -#[naked] -#[no_mangle] -extern "C" fn PENDSV() { - unsafe { - asm!("b DEFAULT_HANDLER" :::: "volatile"); - intrinsics::unreachable(); - } -} +.weak PENDSV +PENDSV = DEFAULT_HANDLER -#[allow(non_snake_case)] -#[allow(private_no_mangle_fns)] -#[cfg(target_arch = "arm")] -#[linkage = "weak"] -#[naked] -#[no_mangle] -extern "C" fn SYS_TICK() { - unsafe { - asm!("b DEFAULT_HANDLER" :::: "volatile"); - intrinsics::unreachable(); - } +.weak SYS_TICK +SYS_TICK = DEFAULT_HANDLER +"#); + +extern "C" { + fn NMI(); + fn HARD_FAULT(); + fn MEM_MANAGE(); + fn BUS_FAULT(); + fn USAGE_FAULT(); + fn SVCALL(); + fn PENDSV(); + fn SYS_TICK(); } #[cfg(target_arch = "arm")] -- cgit v1.2.3 From ee15706c387497e20ad1eb3d95bcc3e22a92341c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 21 Jul 2017 21:36:14 -0500 Subject: v0.3.5 --- cortex-m-rt/CHANGELOG.md | 5 ++++- cortex-m-rt/Cargo.toml | 2 +- cortex-m-rt/src/lib.rs | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/CHANGELOG.md b/cortex-m-rt/CHANGELOG.md index b210b23..a6026cc 100644 --- a/cortex-m-rt/CHANGELOG.md +++ b/cortex-m-rt/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.3.5] - 2017-07-21 + ### Fixed - Remove duplication of default exception handlers. This saves 32 bytes of Flash @@ -164,7 +166,8 @@ section size addr Initial release -[Unreleased]: https://github.com/japaric/cortex-m-rt/compare/v0.3.4...HEAD +[Unreleased]: https://github.com/japaric/cortex-m-rt/compare/v0.3.5...HEAD +[v0.3.5]: https://github.com/japaric/cortex-m-rt/compare/v0.3.4...v0.3.5 [v0.3.4]: https://github.com/japaric/cortex-m-rt/compare/v0.3.3...v0.3.4 [v0.3.3]: https://github.com/japaric/cortex-m-rt/compare/v0.3.2...v0.3.3 [v0.3.2]: https://github.com/japaric/cortex-m-rt/compare/v0.3.1...v0.3.2 diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 97ab921..731c479 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["arm", "cortex-m", "runtime", "startup"] license = "MIT OR Apache-2.0" name = "cortex-m-rt" repository = "https://github.com/japaric/cortex-m-rt" -version = "0.3.4" +version = "0.3.5" [dependencies] cortex-m = "0.3.0" diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 2968252..bc9572f 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -398,6 +398,7 @@ PENDSV = DEFAULT_HANDLER SYS_TICK = DEFAULT_HANDLER "#); +#[cfg(target_arch = "arm")] extern "C" { fn NMI(); fn HARD_FAULT(); -- cgit v1.2.3 From 3a077e641fdbab7e53907740878425426caead5d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 3 Oct 2017 11:15:29 +0200 Subject: tweak the linker script to keep the EXCEPTIONS symbol (vector table) fixes japaric/cortex-m-quickstart#19 fixes japaric/cortex-m-rt#35 closes japaric/cortex-m-quickstart#18 --- cortex-m-rt/link.x | 7 +++++++ cortex-m-rt/src/lib.rs | 7 +++++-- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x index e9605c3..0d043cb 100644 --- a/cortex-m-rt/link.x +++ b/cortex-m-rt/link.x @@ -1,5 +1,12 @@ INCLUDE memory.x +/* With multiple codegen units the rlib produced for this crate has several object files in it. */ +/* Because the linker is Smart it may not look into all the object files and not pick up the */ +/* .vector_table.exceptions section. But we want it to! To workaround the problem we create an */ +/* undefined reference to the EXCEPTIONS symbol (located in .vector_table.exceptions); this way the */ +/* linker will look at all the object of the rlib and pick up our EXCEPTIONS symbol */ +EXTERN(EXCEPTIONS); + /* Create an undefined reference to the INTERRUPTS symbol. This is required to force the linker to *not* drop the INTERRUPTS symbol if it comes from an object file that's passed to the linker *before* this crate */ diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index bc9572f..b83d53c 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -410,10 +410,13 @@ extern "C" { fn SYS_TICK(); } +#[allow(private_no_mangle_statics)] #[cfg(target_arch = "arm")] -#[used] +#[doc(hidden)] #[link_section = ".vector_table.exceptions"] -static EXCEPTIONS: [Option; 14] = [ +#[no_mangle] +#[used] +pub static EXCEPTIONS: [Option; 14] = [ Some(NMI), Some(HARD_FAULT), Some(MEM_MANAGE), -- cgit v1.2.3 From 6565e747ed3154dec02eca0d75a4f8a84208707c Mon Sep 17 00:00:00 2001 From: Vadzim Dambrouski Date: Wed, 11 Oct 2017 21:20:51 +0300 Subject: Put global asm behind target cfg --- cortex-m-rt/src/lib.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index b83d53c..64ef292 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -372,6 +372,7 @@ unsafe extern "C" fn reset_handler() -> ! { } } +#[cfg(target_arch = "arm")] global_asm!(r#" .weak NMI NMI = DEFAULT_HANDLER -- cgit v1.2.3 From 4fecabeb62f62f4d6b2ae86731e14d70fd5c1ee0 Mon Sep 17 00:00:00 2001 From: Vadzim Dambrouski Date: Thu, 12 Oct 2017 01:35:29 +0300 Subject: Don't include lang_items when in test mode. This would allow running regular `cargo test` on a crates that depend on this crate. Depends on #37 --- cortex-m-rt/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index b83d53c..15591d3 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -219,7 +219,7 @@ //! //! Allocating the call stack on a different RAM region. //! -//! ``` +//! ```,ignore //! MEMORY //! { //! /* call stack will go here */ @@ -247,7 +247,7 @@ //! //! Locate the `.text` section 1024 bytes after the start of the FLASH region. //! -//! ``` +//! ```,ignore //! _stext = ORIGIN(FLASH) + 0x400; //! ``` //! @@ -260,7 +260,7 @@ //! //! #### Example //! -//! ``` +//! ```,ignore //! extern crate some_allocator; //! //! // Size of the heap in bytes @@ -295,6 +295,7 @@ extern crate cortex_m; extern crate compiler_builtins; extern crate r0; +#[cfg(not(test))] mod lang_items; #[cfg(target_arch = "arm")] -- cgit v1.2.3 From ed6aa6896e7e1bfcb39c867a105ded475f242129 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 23 Dec 2017 10:00:00 +0100 Subject: provide a DEBUG_MONITOR exception on ARMv7-M --- cortex-m-rt/build.rs | 15 +++++++++++---- cortex-m-rt/src/lib.rs | 14 ++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/build.rs b/cortex-m-rt/build.rs index 6494c13..1d0160c 100644 --- a/cortex-m-rt/build.rs +++ b/cortex-m-rt/build.rs @@ -4,7 +4,10 @@ use std::io::Write; use std::path::PathBuf; fn main() { - has_fpu(); + let target = env::var("TARGET").unwrap(); + + has_fpu(&target); + is_armv6m(&target); // Put the linker script somewhere the linker can find it let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); @@ -18,10 +21,14 @@ fn main() { println!("cargo:rerun-if-changed=link.x"); } -fn has_fpu() { - let target = env::var("TARGET").unwrap(); - +fn has_fpu(target: &str) { if target.ends_with("eabihf") { println!("cargo:rustc-cfg=has_fpu"); } } + +fn is_armv6m(target: &str) { + if target.starts_with("thumbv6m-") { + println!("cargo:rustc-cfg=armv6m"); + } +} diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 82dd9eb..df6640f 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -400,6 +400,12 @@ PENDSV = DEFAULT_HANDLER SYS_TICK = DEFAULT_HANDLER "#); +#[cfg(not(armv6m))] +global_asm!(r#" +.weak DEBUG_MONITOR +DEBUG_MONITOR = DEFAULT_HANDLER +"#); + #[cfg(target_arch = "arm")] extern "C" { fn NMI(); @@ -408,6 +414,8 @@ extern "C" { fn BUS_FAULT(); fn USAGE_FAULT(); fn SVCALL(); + #[cfg(not(armv6m))] + fn DEBUG_MONITOR(); fn PENDSV(); fn SYS_TICK(); } @@ -429,7 +437,10 @@ pub static EXCEPTIONS: [Option; 14] = [ None, None, Some(SVCALL), + #[cfg(armv6m)] None, + #[cfg(not(armv6m))] + Some(DEBUG_MONITOR), None, Some(PENDSV), Some(SYS_TICK), @@ -520,6 +531,9 @@ pub enum Exception { USAGE_FAULT, /// System service call via SWI instruction SVCALL, + /// Debug monitor + #[cfg(not(armv6m))] + DEBUG_MONITOR, /// Pendable request for system service PENDSV, /// System tick timer -- cgit v1.2.3 From 018d54639de034b127b2396c0aef4467f9c3b7c9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 29 Dec 2017 21:43:39 +0100 Subject: adapt to changes in the `start` lang item --- cortex-m-rt/Cargo.toml | 6 +++++- cortex-m-rt/build.rs | 21 +++++++++++++++++++++ cortex-m-rt/src/lang_items.rs | 27 ++++++++++++++++----------- cortex-m-rt/src/lib.rs | 17 ++++++++++------- 4 files changed, 52 insertions(+), 19 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index bc19955..587633e 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["arm", "cortex-m", "runtime", "startup"] license = "MIT OR Apache-2.0" name = "cortex-m-rt" repository = "https://github.com/japaric/cortex-m-rt" -version = "0.3.7" +version = "0.3.8" [dependencies] cortex-m = "0.3.0" @@ -16,3 +16,7 @@ r0 = "0.2.1" [features] # provides a panic_fmt implementation that calls the abort instruction (`udf 0xfe`) abort-on-panic = [] + +[build-dependencies] +rustc_version = "0.2.1" +chrono = "0.4.0" diff --git a/cortex-m-rt/build.rs b/cortex-m-rt/build.rs index 1d0160c..918cbfb 100644 --- a/cortex-m-rt/build.rs +++ b/cortex-m-rt/build.rs @@ -1,9 +1,30 @@ +extern crate chrono; +extern crate rustc_version; + use std::env; use std::fs::File; use std::io::Write; use std::path::PathBuf; +use chrono::NaiveDate; + fn main() { + let date: NaiveDate = rustc_version::version_meta() + .unwrap() + .commit_date + .unwrap() + .parse() + .unwrap(); + + if date <= NaiveDate::from_ymd(2017, 12, 26) { + let version = env!("CARGO_PKG_VERSION"); + panic!( + "cortex-m-rt v{} doesn't support nightly-2017-12-27 and older; \ + to use the current nightly switch to v0.3.7", + version + ); + } + let target = env::var("TARGET").unwrap(); has_fpu(&target); diff --git a/cortex-m-rt/src/lang_items.rs b/cortex-m-rt/src/lang_items.rs index 9ff95b5..6b15f99 100644 --- a/cortex-m-rt/src/lang_items.rs +++ b/cortex-m-rt/src/lang_items.rs @@ -1,12 +1,7 @@ /// Default panic handler #[cfg(feature = "abort-on-panic")] #[lang = "panic_fmt"] -unsafe extern "C" fn panic_fmt( - _: ::core::fmt::Arguments, - _: &'static str, - _: u32, - _: u32, -) -> ! { +unsafe extern "C" fn panic_fmt(_: ::core::fmt::Arguments, _: &'static str, _: u32, _: u32) -> ! { ::core::intrinsics::abort() } @@ -29,12 +24,22 @@ unsafe extern "C" fn panic_fmt( // has to call `rustc_main`. That's covered by the `reset_handler` function in // root of this crate. #[lang = "start"] -extern "C" fn start( - main: fn(), - _argc: isize, - _argv: *const *const u8, -) -> isize { +extern "C" fn start(main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize +where + T: Termination, +{ main(); 0 } + +#[lang = "termination"] +pub trait Termination { + fn report(self) -> i32; +} + +impl Termination for () { + fn report(self) -> i32 { + 0 + } +} diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index df6640f..9c5e7bf 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -278,8 +278,7 @@ //! } //! ``` -#![cfg_attr(any(target_arch = "arm", feature = "abort-on-panic"), - feature(core_intrinsics))] +#![cfg_attr(any(target_arch = "arm", feature = "abort-on-panic"), feature(core_intrinsics))] #![deny(missing_docs)] #![deny(warnings)] #![feature(asm)] @@ -291,8 +290,8 @@ #![feature(used)] #![no_std] -extern crate cortex_m; extern crate compiler_builtins; +extern crate cortex_m; extern crate r0; #[cfg(not(test))] @@ -374,7 +373,8 @@ unsafe extern "C" fn reset_handler() -> ! { } #[cfg(target_arch = "arm")] -global_asm!(r#" +global_asm!( + r#" .weak NMI NMI = DEFAULT_HANDLER @@ -398,13 +398,16 @@ PENDSV = DEFAULT_HANDLER .weak SYS_TICK SYS_TICK = DEFAULT_HANDLER -"#); +"# +); #[cfg(not(armv6m))] -global_asm!(r#" +global_asm!( + r#" .weak DEBUG_MONITOR DEBUG_MONITOR = DEFAULT_HANDLER -"#); +"# +); #[cfg(target_arch = "arm")] extern "C" { -- cgit v1.2.3 From 8d5784a8869168e711eb761a3fb7bb6cc30742e3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Jan 2018 16:29:58 +0100 Subject: fix `cargo doc` warnings --- cortex-m-rt/src/lib.rs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 9c5e7bf..303a3c6 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -11,9 +11,7 @@ //! - A `panic_fmt` implementation that just calls abort that you can opt into //! through the "abort-on-panic" Cargo feature. If you don't use this feature //! you'll have to provide the `panic_fmt` lang item yourself. Documentation -//! [here][1] -//! -//! [1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html +//! [here](https://doc.rust-lang.org/unstable-book/language-features/lang-items.html) //! //! - A minimal `start` lang item to support the standard `fn main()` //! interface. (The processor goes to sleep (`loop { asm!("wfi") }`) after @@ -36,10 +34,8 @@ //! # Example //! //! Creating a new bare metal project. (I recommend you use the -//! [`cortex-m-quickstart`][qs] template as it takes of all the boilerplate -//! shown here) -//! -//! [qs]: https://docs.rs/cortex-m-quickstart/0.2.0/cortex_m_quickstart/ +//! [`cortex-m-quickstart`](https://docs.rs/cortex-m-quickstart/0.2.0/cortex_m_quickstart/) template +//! as it takes of all the boilerplate shown here) //! //! ``` text //! $ cargo new --bin app && cd $_ @@ -197,10 +193,8 @@ //! //! The main information that this file must provide is the memory layout of //! the device in the form of the `MEMORY` command. The command is documented -//! [here][2], but at a minimum you'll want to create two memory regions: one -//! for Flash memory and another for RAM. -//! -//! [2]: https://sourceware.org/binutils/docs/ld/MEMORY.html +//! [here](https://sourceware.org/binutils/docs/ld/MEMORY.html), but at a minimum you'll want to +//! create two memory regions: one for Flash memory and another for RAM. //! //! The program instructions (the `.text` section) will be stored in the memory //! region named FLASH, and the program `static` variables (the sections `.bss` @@ -255,8 +249,7 @@ //! //! This symbol is located in RAM right after the `.bss` and `.data` sections. //! You can use the address of this symbol as the start address of a heap -//! region. This symbol is 4 byte aligned so that address will be a multiple of -//! 4. +//! region. This symbol is 4 byte aligned so that address will be a multiple of 4. //! //! #### Example //! -- cgit v1.2.3 From 781187b11bef6ada1ad9219826a1808473910c3b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 7 Jan 2018 17:29:03 +0100 Subject: fix comment call to `start` has the wrong arguments --- cortex-m-rt/src/lang_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lang_items.rs b/cortex-m-rt/src/lang_items.rs index 6b15f99..206482b 100644 --- a/cortex-m-rt/src/lang_items.rs +++ b/cortex-m-rt/src/lang_items.rs @@ -13,7 +13,7 @@ unsafe extern "C" fn panic_fmt(_: ::core::fmt::Arguments, _: &'static str, _: u3 // ``` // #[export_name = "main"] // pub extern "C" fn rustc_main(argc: isize, argv: *const *const u8) -> isize { -// start(main) +// start(main, argc, argv) // } // ``` // -- cgit v1.2.3 From 35b1a1e553b347a49f5aae7634928cca54105475 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 17 Jan 2018 02:29:19 +0100 Subject: support nightly-2017-09-22 --- cortex-m-rt/CHANGELOG.md | 14 ++++++++++++-- cortex-m-rt/Cargo.toml | 3 ++- cortex-m-rt/build.rs | 14 ++++++++++++++ cortex-m-rt/src/lang_items.rs | 14 +++++++++++++- cortex-m-rt/src/lib.rs | 2 ++ 5 files changed, 43 insertions(+), 4 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/CHANGELOG.md b/cortex-m-rt/CHANGELOG.md index 293b5a5..d9027c8 100644 --- a/cortex-m-rt/CHANGELOG.md +++ b/cortex-m-rt/CHANGELOG.md @@ -7,7 +7,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] -## [v0.3.10] - 2018-01-17 +## [v0.3.11] - 2018-01-17 + +### Changed + +- Dynamically support recent nightlies, which have the `termination` lang item, and + nightly-2017-09-22, which doesn't. That nightly version is used by the docs.rs builder. Supporting + that version instead of rejecting it ensures this crate and its reverse-dependencies will get + their documentation built by the docs.rs service. + +## [v0.3.10] - 2018-01-17 - YANKED ### Removed @@ -203,7 +212,8 @@ section size addr Initial release -[Unreleased]: https://github.com/japaric/cortex-m-rt/compare/v0.3.10...HEAD +[Unreleased]: https://github.com/japaric/cortex-m-rt/compare/v0.3.11...HEAD +[v0.3.11]: https://github.com/japaric/cortex-m-rt/compare/v0.3.10...v0.3.11 [v0.3.10]: https://github.com/japaric/cortex-m-rt/compare/v0.3.9...v0.3.10 [v0.3.9]: https://github.com/japaric/cortex-m-rt/compare/v0.3.8...v0.3.9 [v0.3.8]: https://github.com/japaric/cortex-m-rt/compare/v0.3.7...v0.3.8 diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 6ac3d7e..2a7770e 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["arm", "cortex-m", "runtime", "startup"] license = "MIT OR Apache-2.0" name = "cortex-m-rt" repository = "https://github.com/japaric/cortex-m-rt" -version = "0.3.10" +version = "0.3.11" [dependencies] cortex-m = "0.3.0" @@ -19,3 +19,4 @@ abort-on-panic = [] [build-dependencies] rustc_version = "0.2.1" +chrono = "0.4.0" diff --git a/cortex-m-rt/build.rs b/cortex-m-rt/build.rs index ffe7fa4..dee75b7 100644 --- a/cortex-m-rt/build.rs +++ b/cortex-m-rt/build.rs @@ -1,3 +1,4 @@ +extern crate chrono; extern crate rustc_version; use std::env; @@ -5,7 +6,20 @@ use std::fs::File; use std::io::Write; use std::path::PathBuf; +use chrono::NaiveDate; + fn main() { + let date: NaiveDate = rustc_version::version_meta() + .unwrap() + .commit_date + .unwrap() + .parse() + .unwrap(); + + if date > NaiveDate::from_ymd(2017, 12, 26) { + println!("cargo:rustc-cfg=has_termination_lang") + } + let target = env::var("TARGET").unwrap(); has_fpu(&target); diff --git a/cortex-m-rt/src/lang_items.rs b/cortex-m-rt/src/lang_items.rs index 206482b..63bbc28 100644 --- a/cortex-m-rt/src/lang_items.rs +++ b/cortex-m-rt/src/lang_items.rs @@ -5,7 +5,8 @@ unsafe extern "C" fn panic_fmt(_: ::core::fmt::Arguments, _: &'static str, _: u3 ::core::intrinsics::abort() } -/// Lang item required to make the normal `main` work in applications +// Lang item required to make the normal `main` work in applications +// // This is how the `start` lang item works: // When `rustc` compiles a binary crate, it creates a `main` function that looks // like this: @@ -23,6 +24,7 @@ unsafe extern "C" fn panic_fmt(_: ::core::fmt::Arguments, _: &'static str, _: u3 // The final piece is that the entry point of our program, the reset handler, // has to call `rustc_main`. That's covered by the `reset_handler` function in // root of this crate. +#[cfg(has_termination_trait)] #[lang = "start"] extern "C" fn start(main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize where @@ -33,11 +35,21 @@ where 0 } +#[cfg(not(has_termination_trait))] +#[lang = "start"] +extern "C" fn start(main: fn(), _argc: isize, _argv: *const *const u8) -> isize { + main(); + + 0 +} + #[lang = "termination"] +#[cfg(has_termination_trait)] pub trait Termination { fn report(self) -> i32; } +#[cfg(has_termination_trait)] impl Termination for () { fn report(self) -> i32 { 0 diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 303a3c6..ff5db49 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -284,7 +284,9 @@ #![no_std] extern crate compiler_builtins; +#[cfg(target_arch = "arm")] extern crate cortex_m; +#[cfg(target_arch = "arm")] extern crate r0; #[cfg(not(test))] -- cgit v1.2.3 From 186204410905ce6b75587db67e5c1de631ae2f0c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 17 Jan 2018 02:40:23 +0100 Subject: fix uses #[cfg(has_termination_lang)] it was typo-ed in the source code --- cortex-m-rt/CHANGELOG.md | 11 +++++++++-- cortex-m-rt/Cargo.toml | 2 +- cortex-m-rt/src/lang_items.rs | 8 ++++---- 3 files changed, 14 insertions(+), 7 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/CHANGELOG.md b/cortex-m-rt/CHANGELOG.md index d9027c8..931f60d 100644 --- a/cortex-m-rt/CHANGELOG.md +++ b/cortex-m-rt/CHANGELOG.md @@ -7,7 +7,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] -## [v0.3.11] - 2018-01-17 +## [v0.3.12] - 2018-01-17 + +### Fixed + +- Support for recent nightlies. + +## [v0.3.11] - 2018-01-17 - YANKED ### Changed @@ -212,7 +218,8 @@ section size addr Initial release -[Unreleased]: https://github.com/japaric/cortex-m-rt/compare/v0.3.11...HEAD +[Unreleased]: https://github.com/japaric/cortex-m-rt/compare/v0.3.12...HEAD +[v0.3.12]: https://github.com/japaric/cortex-m-rt/compare/v0.3.11...v0.3.12 [v0.3.11]: https://github.com/japaric/cortex-m-rt/compare/v0.3.10...v0.3.11 [v0.3.10]: https://github.com/japaric/cortex-m-rt/compare/v0.3.9...v0.3.10 [v0.3.9]: https://github.com/japaric/cortex-m-rt/compare/v0.3.8...v0.3.9 diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 2a7770e..f9e32c9 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["arm", "cortex-m", "runtime", "startup"] license = "MIT OR Apache-2.0" name = "cortex-m-rt" repository = "https://github.com/japaric/cortex-m-rt" -version = "0.3.11" +version = "0.3.12" [dependencies] cortex-m = "0.3.0" diff --git a/cortex-m-rt/src/lang_items.rs b/cortex-m-rt/src/lang_items.rs index 63bbc28..f3750a0 100644 --- a/cortex-m-rt/src/lang_items.rs +++ b/cortex-m-rt/src/lang_items.rs @@ -24,7 +24,7 @@ unsafe extern "C" fn panic_fmt(_: ::core::fmt::Arguments, _: &'static str, _: u3 // The final piece is that the entry point of our program, the reset handler, // has to call `rustc_main`. That's covered by the `reset_handler` function in // root of this crate. -#[cfg(has_termination_trait)] +#[cfg(has_termination_lang)] #[lang = "start"] extern "C" fn start(main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize where @@ -35,7 +35,7 @@ where 0 } -#[cfg(not(has_termination_trait))] +#[cfg(not(has_termination_lang))] #[lang = "start"] extern "C" fn start(main: fn(), _argc: isize, _argv: *const *const u8) -> isize { main(); @@ -44,12 +44,12 @@ extern "C" fn start(main: fn(), _argc: isize, _argv: *const *const u8) -> isize } #[lang = "termination"] -#[cfg(has_termination_trait)] +#[cfg(has_termination_lang)] pub trait Termination { fn report(self) -> i32; } -#[cfg(has_termination_trait)] +#[cfg(has_termination_lang)] impl Termination for () { fn report(self) -> i32 { 0 -- cgit v1.2.3 From 7f14d1753fe0f6a2904d41059a26c24e71deb84f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 24 Nov 2017 23:20:36 +0100 Subject: fix rustdoc warnings --- cortex-m-rt/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index ff5db49..37c6566 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -270,6 +270,10 @@ //! } //! } //! ``` +//! +//! [1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html +//! [qs]: https://docs.rs/cortex-m-quickstart/0.2.0/cortex_m_quickstart/ +//! [2]: https://sourceware.org/binutils/docs/ld/MEMORY.html #![cfg_attr(any(target_arch = "arm", feature = "abort-on-panic"), feature(core_intrinsics))] #![deny(missing_docs)] -- cgit v1.2.3 From 6fb7189e0dc9b279703a60b43fa819acf854bdc9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 25 Nov 2017 05:47:13 +0100 Subject: update documentation --- cortex-m-rt/src/lib.rs | 220 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 213 insertions(+), 7 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 37c6566..4bc0570 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -31,6 +31,8 @@ //! //! - A `_sheap` symbol at whose address you can locate a heap. //! +//! - Zero cost stack overflow protection when using the `swap-ld` linker. +//! //! # Example //! //! Creating a new bare metal project. (I recommend you use the @@ -41,13 +43,13 @@ //! $ cargo new --bin app && cd $_ //! //! $ # add this crate as a dependency -//! $ edit Cargo.toml && cat $_ +//! $ $EDITOR Cargo.toml && tail $_ //! [dependencies.cortex-m-rt] //! features = ["abort-on-panic"] //! version = "0.3.0" //! //! $ # tell Xargo which standard crates to build -//! $ edit Xargo.toml && cat $_ +//! $ $EDITOR Xargo.toml && cat $_ //! [dependencies.core] //! stage = 0 //! @@ -56,7 +58,7 @@ //! stage = 1 //! //! $ # memory layout of the device -//! $ edit memory.x && cat $_ +//! $ $EDITOR memory.x && cat $_ //! MEMORY //! { //! /* NOTE K = KiBi = 1024 bytes */ @@ -64,7 +66,7 @@ //! RAM : ORIGIN = 0x20000000, LENGTH = 8K //! } //! -//! $ edit src/main.rs && cat $_ +//! $ $EDITOR src/main.rs && cat $_ //! ``` //! //! ``` ignore,no_run @@ -102,8 +104,203 @@ //! 8000400: b580 push {r7, lr} //! 8000402: 466f mov r7, sp //! 8000404: b084 sub sp, #8 +//! +//! +//! $ arm-none-eabi-size -Ax $(find target -name app) | head +//! target/thumbv7m-none-eabi/debug/app : +//! section size addr +//! .vector_table 0x400 0x8000000 +//! .text 0x24a 0x8000400 +//! .rodata 0x0 0x800064c +//! .stack 0x2000 0x20000000 +//! .bss 0x0 0x20000000 +//! .data 0x0 0x20000000 +//! ``` +//! +//! ## Zero stack overflow protection +//! +//! Consider the following variation of the previous program: +//! +//! ``` ignore +//! extern crate cortex_m_rt; +//! +//! const N: usize = 256; +//! static mut XS: [u32; N] = [0; N]; +//! +//! fn main() { +//! #[inline(never)] +//! fn fib(n: u32) -> u32 { +//! unsafe { assert!(XS.iter().all(|x| *x == 0)) } +//! +//! if n < 2 { +//! 1 +//! } else { +//! fib(n - 1) + fib(n - 2) +//! } +//! } +//! +//! let x = fib(400); +//! unsafe { *XS.iter_mut().first().unwrap() = x } +//! } +//! ``` +//! +//! This program allocates a 1KB array in `.bss`, recursively computes the 400th fibonacci number +//! and stores the result in the head of the array. This program will hit a stack overflow at +//! runtime because there's not enough memory to recursively call the `fib` function so many times. +//! +//! If you inspect the program using GDB you'll see that the assertion failed after `fib` was nested +//! around 300 times. +//! +//! ``` console +//! > continue +//! Program received signal SIGTRAP, Trace/breakpoint trap. +//! +//! > backtrace +//! #0 0x08000516 in cortex_m_rt::default_handler () +//! #1 +//! #2 0x0800050a in rust_begin_unwind () +//! #3 0x08000586 in core::panicking::panic_fmt () +//! #4 0x0800055c in core::panicking::panic () +//! #5 0x080004f6 in app::main::fib () +//! #6 0x080004a0 in app::main::fib () +//! (..) +//! #301 0x080004a0 in app::main::fib () +//! #302 0x080004a0 in app::main::fib () +//! #303 0x08000472 in app::main () +//! #304 0x08000512 in cortex_m_rt::lang_items::start () +//! #305 0x08000460 in cortex_m_rt::reset_handler () +//! ``` +//! +//! What this means is that the stack grew so much that it crashed into the `.bss` section and +//! overwrote the memory in there. Continuing the GDB session you can confirm that the `XS` variable +//! has been modified: +//! +//! ``` console +//! > x/4 0x20000000 # start of .bss +//! 0x20000000 : 0x00000000 0x00000000 0x00000000 0x00000000 +//! +//! > x/4 0x200003f0 # end of .bss +//! 0x200003f0 : 0x20000400 0x080004f5 0x00000000 0x00000001 +//! ``` +//! +//! The problem is that the stack is growing towards the `.bss` section and both sections overlap as +//! shown below: +//! +//! ``` console +//! $ arm-none-eabi-size -Ax $(find target -name app) +//! section size addr +//! .vector_table 0x400 0x8000000 +//! .text 0x186 0x8000400 +//! .rodata 0x50 0x8000590 +//! .stack 0x2000 0x20000000 +//! .bss 0x400 0x20000000 +//! .data 0x0 0x20000400 +//! ``` +//! +//! Graphically the RAM sections look like this: +//! +//!

+//! Stack overflow +//!

+//! +//! To prevent memory corruption due to stack overflows in this scenario it suffices to switch the +//! sections so that the `.bss` section is near the end of the RAM region and the `.stack` comes +//! *before* `.bss`, at a lower address. +//! +//! To swap the sections you can use the [`swap-ld`] linker to link the program. +//! +//! ``` console +//! $ cargo install swap-ld +//! +//! $ xargo rustc --target thumbv7m-none-eabi -- \ +//! -C link-arg=-Tlink.x -C linker=swap-ld -Z linker-flavor=ld //! ``` //! +//! Now you get non overlapping linker sections: +//! +//! ``` console +//! section size addr +//! .vector_table 0x400 0x8000000 +//! .text 0x186 0x8000400 +//! .rodata 0x50 0x8000590 +//! .stack 0x1c00 0x20000000 +//! .bss 0x400 0x20001c00 +//! .data 0x0 0x20002000 +//! ``` +//! +//! Note that the `.stack` section is smaller now. Graphically, the memory layout now looks like +//! this: +//! +//!

+//! Swapped sections +//!

+//! +//! On stack overflows `.stack` will hit the lower boundary of the RAM region raising a hard fault +//! exception, instead of silently corrupting the `.bss` section. +//! +//! You can confirm this by inspecting the program in GDB. +//! +//! ``` console +//! > continue +//! Program received signal SIGTRAP, Trace/breakpoint trap. +//! +//! > p $sp +//! $1 = (void *) 0x1ffffff0 +//! ``` +//! +//! The failure mode this time was the `.stack` crashing into the RAM boundary. The variable `XS` is +//! unaffected this time: +//! +//! ``` console +//! > x/4x app::XS +//! 0x20001c00 : 0x00000000 0x00000000 0x00000000 0x00000000 +//! +//! > x/4x app::XS+252 +//! 0x20001ff0 : 0x00000000 0x00000000 0x00000000 0x00000000 +//! ``` +//! +//! ## `.heap` +//! +//! If your program makes use of a `.heap` section a similar problem can occur: +//! +//!

+//! Memory layout when `.heap` exists +//!

+//! +//! The `.stack` can crash into the `.heap`, or vice versa, and you'll also get memory corruption. +//! +//! `swap-ld` can also be used in this case but the size of the `.heap` section must be specified +//! in the `_heap_size` symbol in `memory.x`, or in any other linker script. +//! +//! ``` console +//! $ $EDITOR memory.x && tail $_ +//! _heap_size = 0x400; +//! ``` +//! +//! ``` console +//! $ xargo rustc --target thumbv7m-none-eabi -- \ +//! -C link-arg=-Tlink.x -C linker=swap-ld -Z linker-flavor=ld +//! +//! $ arm-none-eabi-size -Ax $(find target -name app) | head +//! section size addr +//! .vector_table 0x400 0x8000000 +//! .text 0x1a8 0x8000400 +//! .rodata 0x50 0x80005b0 +//! .stack 0x1800 0x20000000 +//! .bss 0x400 0x20001800 +//! .data 0x0 0x20001c00 +//! .heap 0x400 0x20001c00 +//! ``` +//! +//! Graphically the memory layout looks like this: +//! +//!

+//! Swapped sections when `.heap` exists +//!

+//! +//! Now both stack overflows and dynamic memory over-allocations will generate hard fault +//! exceptions, instead of running into each other. +//! //! # Symbol interfaces //! //! This crate makes heavy use of symbols, linker sections and linker scripts to @@ -213,7 +410,7 @@ //! //! Allocating the call stack on a different RAM region. //! -//! ```,ignore +//! ``` ignore //! MEMORY //! { //! /* call stack will go here */ @@ -226,6 +423,10 @@ //! _stack_start = ORIGIN(CCRAM) + LENGTH(CCRAM); //! ``` //! +//! ### `_heap_size` +//! +//! The size of the `.heap` section. Only meaningful when using `swap-ld`. +//! //! ### `_stext` //! //! This symbol indicates where the `.text` section will be located. If not @@ -241,7 +442,7 @@ //! //! Locate the `.text` section 1024 bytes after the start of the FLASH region. //! -//! ```,ignore +//! ``` ignore //! _stext = ORIGIN(FLASH) + 0x400; //! ``` //! @@ -253,7 +454,7 @@ //! //! #### Example //! -//! ```,ignore +//! ``` ignore //! extern crate some_allocator; //! //! // Size of the heap in bytes @@ -271,8 +472,13 @@ //! } //! ``` //! +//! *NOTE* if you are using `swap-ld` and/or have defined the `_heap_size` symbol then you should +//! use the address of the `_eheap` to compute the size of the `.heap` section, instead of +//! duplicating the value that you wrote in `memory.x`. +//! //! [1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html //! [qs]: https://docs.rs/cortex-m-quickstart/0.2.0/cortex_m_quickstart/ +//! [`swap-ld`]: https://crates.io/crates/swap-ld //! [2]: https://sourceware.org/binutils/docs/ld/MEMORY.html #![cfg_attr(any(target_arch = "arm", feature = "abort-on-panic"), feature(core_intrinsics))] -- cgit v1.2.3 From 537ca613c4871041b9205d673f4c2f5a29431548 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 17 Feb 2018 17:12:24 +0100 Subject: s/swap-ld/cortex-m-rt-ld/g also fix a bug when .bss was empty but .data was not --- cortex-m-rt/link.x | 2 +- cortex-m-rt/src/lib.rs | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x index 4eaa8be..6f39655 100644 --- a/cortex-m-rt/link.x +++ b/cortex-m-rt/link.x @@ -70,7 +70,7 @@ SECTIONS _ebss = .; } > RAM - .data : ALIGN(4) + .data _ebss : ALIGN(4) { _sidata = LOADADDR(.data); _sdata = .; diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 4bc0570..cb85f4e 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -31,7 +31,7 @@ //! //! - A `_sheap` symbol at whose address you can locate a heap. //! -//! - Zero cost stack overflow protection when using the `swap-ld` linker. +//! - Zero cost stack overflow protection when using the `cortex-m-rt-ld` linker. //! //! # Example //! @@ -117,7 +117,7 @@ //! .data 0x0 0x20000000 //! ``` //! -//! ## Zero stack overflow protection +//! ## Zero cost stack overflow protection //! //! Consider the following variation of the previous program: //! @@ -207,13 +207,13 @@ //! sections so that the `.bss` section is near the end of the RAM region and the `.stack` comes //! *before* `.bss`, at a lower address. //! -//! To swap the sections you can use the [`swap-ld`] linker to link the program. +//! To swap the sections you can use the [`cortex-m-rt-ld`] linker to link the program. //! //! ``` console -//! $ cargo install swap-ld +//! $ cargo install cortex-m-rt-ld //! //! $ xargo rustc --target thumbv7m-none-eabi -- \ -//! -C link-arg=-Tlink.x -C linker=swap-ld -Z linker-flavor=ld +//! -C link-arg=-Tlink.x -C linker=cortex-m-rt-ld -Z linker-flavor=ld //! ``` //! //! Now you get non overlapping linker sections: @@ -269,17 +269,17 @@ //! //! The `.stack` can crash into the `.heap`, or vice versa, and you'll also get memory corruption. //! -//! `swap-ld` can also be used in this case but the size of the `.heap` section must be specified -//! in the `_heap_size` symbol in `memory.x`, or in any other linker script. +//! `cortex-m-rt-ld` can also be used in this case but the size of the `.heap` section must be +//! specified via the `_heap_size` symbol in `memory.x`, or in any other linker script. //! //! ``` console -//! $ $EDITOR memory.x && tail $_ +//! $ $EDITOR memory.x && tail -n1 $_ //! _heap_size = 0x400; //! ``` //! //! ``` console //! $ xargo rustc --target thumbv7m-none-eabi -- \ -//! -C link-arg=-Tlink.x -C linker=swap-ld -Z linker-flavor=ld +//! -C link-arg=-Tlink.x -C linker=cortex-m-rt-ld -Z linker-flavor=ld //! //! $ arm-none-eabi-size -Ax $(find target -name app) | head //! section size addr @@ -298,7 +298,7 @@ //! Swapped sections when `.heap` exists //!

//! -//! Now both stack overflows and dynamic memory over-allocations will generate hard fault +//! Now both stack overflows and dynamic memory over-allocations (OOM) will generate hard fault //! exceptions, instead of running into each other. //! //! # Symbol interfaces @@ -425,7 +425,7 @@ //! //! ### `_heap_size` //! -//! The size of the `.heap` section. Only meaningful when using `swap-ld`. +//! The size of the `.heap` section. Only meaningful when using `cortex-m-rt-ld`. //! //! ### `_stext` //! @@ -472,13 +472,13 @@ //! } //! ``` //! -//! *NOTE* if you are using `swap-ld` and/or have defined the `_heap_size` symbol then you should +//! *NOTE* if you are using `cortex-m-rt-ld` and/or have defined the `_heap_size` symbol then you should //! use the address of the `_eheap` to compute the size of the `.heap` section, instead of //! duplicating the value that you wrote in `memory.x`. //! //! [1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html //! [qs]: https://docs.rs/cortex-m-quickstart/0.2.0/cortex_m_quickstart/ -//! [`swap-ld`]: https://crates.io/crates/swap-ld +//! [`cortex-m-rt-ld`]: https://crates.io/crates/cortex-m-rt-ld //! [2]: https://sourceware.org/binutils/docs/ld/MEMORY.html #![cfg_attr(any(target_arch = "arm", feature = "abort-on-panic"), feature(core_intrinsics))] -- cgit v1.2.3 From 208ee4348abc5db7a78afa4d5ccd0e5e4e98f216 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 8 Apr 2018 12:47:02 +0200 Subject: support the newest nightly --- cortex-m-rt/CHANGELOG.md | 9 ++++++++- cortex-m-rt/Cargo.toml | 2 +- cortex-m-rt/build.rs | 10 ++++++++-- cortex-m-rt/src/lib.rs | 3 ++- 4 files changed, 19 insertions(+), 5 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/CHANGELOG.md b/cortex-m-rt/CHANGELOG.md index ac90b58..f9e2abd 100644 --- a/cortex-m-rt/CHANGELOG.md +++ b/cortex-m-rt/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.3.15] - 2018-04-08 + +### Fixed + +- Support the newest nightly + ## [v0.3.14] - 2018-04-01 ### Fixed @@ -238,7 +244,8 @@ section size addr Initial release -[Unreleased]: https://github.com/japaric/cortex-m-rt/compare/v0.3.14...HEAD +[Unreleased]: https://github.com/japaric/cortex-m-rt/compare/v0.3.15...HEAD +[v0.3.15]: https://github.com/japaric/cortex-m-rt/compare/v0.3.14...v0.3.15 [v0.3.14]: https://github.com/japaric/cortex-m-rt/compare/v0.3.13...v0.3.14 [v0.3.13]: https://github.com/japaric/cortex-m-rt/compare/v0.3.12...v0.3.13 [v0.3.12]: https://github.com/japaric/cortex-m-rt/compare/v0.3.11...v0.3.12 diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index d328ee3..1b61917 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["arm", "cortex-m", "runtime", "startup"] license = "MIT OR Apache-2.0" name = "cortex-m-rt" repository = "https://github.com/japaric/cortex-m-rt" -version = "0.3.14" +version = "0.3.15" [dependencies] cortex-m = "0.3.0" diff --git a/cortex-m-rt/build.rs b/cortex-m-rt/build.rs index 7784b98..c1028c4 100644 --- a/cortex-m-rt/build.rs +++ b/cortex-m-rt/build.rs @@ -10,13 +10,19 @@ use chrono::NaiveDate; fn main() { let meta = rustc_version::version_meta().unwrap(); + let commit_date = meta.commit_date.unwrap().parse::().unwrap(); if meta.channel == rustc_version::Channel::Dev - || meta.commit_date.unwrap().parse::().unwrap() - > NaiveDate::from_ymd(2017, 12, 26) + || commit_date > NaiveDate::from_ymd(2017, 12, 26) { println!("cargo:rustc-cfg=has_termination_lang") } + // newest nightlies don't need 'extern crate compiler_builtins' + if commit_date < NaiveDate::from_ymd(2018, 04, 07) + { + println!("cargo:rustc-cfg=needs_cb") + } + let target = env::var("TARGET").unwrap(); has_fpu(&target); diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index cb85f4e..06ee551 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -485,7 +485,7 @@ #![deny(missing_docs)] #![deny(warnings)] #![feature(asm)] -#![feature(compiler_builtins_lib)] +#![cfg_attr(needs_cb, feature(compiler_builtins_lib))] #![feature(global_asm)] #![feature(lang_items)] #![feature(linkage)] @@ -493,6 +493,7 @@ #![feature(used)] #![no_std] +#[cfg(needs_cb)] extern crate compiler_builtins; #[cfg(target_arch = "arm")] extern crate cortex_m; -- cgit v1.2.3 From a460a9a554d4f34ae7f04ed26384e7d9753125fa Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 6 Apr 2018 16:27:08 +0200 Subject: drop support of older nightlies Minor version has been bumped to v0.4.0 so we can stop supporting them This also drop the chrono dependency, which some people have been running into problems with. closes #60 --- cortex-m-rt/Cargo.toml | 4 ---- cortex-m-rt/build.rs | 19 ------------------- cortex-m-rt/src/lang_items.rs | 11 ----------- 3 files changed, 34 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 5086034..45f0b07 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -16,7 +16,3 @@ r0 = "0.2.1" [features] # provides a panic_fmt implementation that calls the abort instruction (`udf 0xfe`) abort-on-panic = [] - -[build-dependencies] -rustc_version = "0.2.1" -chrono = "0.4.0" diff --git a/cortex-m-rt/build.rs b/cortex-m-rt/build.rs index c1028c4..1d0160c 100644 --- a/cortex-m-rt/build.rs +++ b/cortex-m-rt/build.rs @@ -1,28 +1,9 @@ -extern crate chrono; -extern crate rustc_version; - use std::env; use std::fs::File; use std::io::Write; use std::path::PathBuf; -use chrono::NaiveDate; - fn main() { - let meta = rustc_version::version_meta().unwrap(); - let commit_date = meta.commit_date.unwrap().parse::().unwrap(); - if meta.channel == rustc_version::Channel::Dev - || commit_date > NaiveDate::from_ymd(2017, 12, 26) - { - println!("cargo:rustc-cfg=has_termination_lang") - } - - // newest nightlies don't need 'extern crate compiler_builtins' - if commit_date < NaiveDate::from_ymd(2018, 04, 07) - { - println!("cargo:rustc-cfg=needs_cb") - } - let target = env::var("TARGET").unwrap(); has_fpu(&target); diff --git a/cortex-m-rt/src/lang_items.rs b/cortex-m-rt/src/lang_items.rs index f3750a0..7d7a598 100644 --- a/cortex-m-rt/src/lang_items.rs +++ b/cortex-m-rt/src/lang_items.rs @@ -24,7 +24,6 @@ unsafe extern "C" fn panic_fmt(_: ::core::fmt::Arguments, _: &'static str, _: u3 // The final piece is that the entry point of our program, the reset handler, // has to call `rustc_main`. That's covered by the `reset_handler` function in // root of this crate. -#[cfg(has_termination_lang)] #[lang = "start"] extern "C" fn start(main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize where @@ -35,21 +34,11 @@ where 0 } -#[cfg(not(has_termination_lang))] -#[lang = "start"] -extern "C" fn start(main: fn(), _argc: isize, _argv: *const *const u8) -> isize { - main(); - - 0 -} - #[lang = "termination"] -#[cfg(has_termination_lang)] pub trait Termination { fn report(self) -> i32; } -#[cfg(has_termination_lang)] impl Termination for () { fn report(self) -> i32 { 0 -- cgit v1.2.3 From 134f9ffd1f87ed1b94e3c11407ee04344f1dccbb Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 9 Apr 2018 00:53:49 +0200 Subject: remove mentions of Xargo from the docs --- cortex-m-rt/src/lib.rs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 06ee551..6749e27 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -48,15 +48,6 @@ //! features = ["abort-on-panic"] //! version = "0.3.0" //! -//! $ # tell Xargo which standard crates to build -//! $ $EDITOR Xargo.toml && cat $_ -//! [dependencies.core] -//! stage = 0 -//! -//! [dependencies.compiler_builtins] -//! features = ["mem"] -//! stage = 1 -//! //! $ # memory layout of the device //! $ $EDITOR memory.x && cat $_ //! MEMORY @@ -91,9 +82,9 @@ //! ``` //! //! ``` text -//! $ cargo install xargo +//! $ rustup target add thumbv7m-none-eabi //! -//! $ xargo rustc --target thumbv7m-none-eabi -- \ +//! $ cargo rustc --target thumbv7m-none-eabi -- \ //! -C link-arg=-Tlink.x -C linker=arm-none-eabi-ld -Z linker-flavor=ld //! //! $ arm-none-eabi-objdump -Cd $(find target -name app) | head @@ -212,7 +203,7 @@ //! ``` console //! $ cargo install cortex-m-rt-ld //! -//! $ xargo rustc --target thumbv7m-none-eabi -- \ +//! $ cargo rustc --target thumbv7m-none-eabi -- \ //! -C link-arg=-Tlink.x -C linker=cortex-m-rt-ld -Z linker-flavor=ld //! ``` //! @@ -278,7 +269,7 @@ //! ``` //! //! ``` console -//! $ xargo rustc --target thumbv7m-none-eabi -- \ +//! $ cargo rustc --target thumbv7m-none-eabi -- \ //! -C link-arg=-Tlink.x -C linker=cortex-m-rt-ld -Z linker-flavor=ld //! //! $ arm-none-eabi-size -Ax $(find target -name app) | head -- cgit v1.2.3 From e9c8547fcadeecfc09a659f0ded28f7f84376563 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 9 Apr 2018 01:01:26 +0200 Subject: remove more stack overflow protection related stuff mainly from the docs --- cortex-m-rt/link.x | 3 - cortex-m-rt/src/lib.rs | 196 ------------------------------------------------- 2 files changed, 199 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x index 78c1faf..2bfcb47 100644 --- a/cortex-m-rt/link.x +++ b/cortex-m-rt/link.x @@ -68,11 +68,8 @@ SECTIONS _edata = .; } > RAM AT > FLASH - PROVIDE(_heap_size = 0); - /* The heap starts right after the .bss + .data section ends */ _sheap = _edata; - _eheap = _sheap + _heap_size; /* fake output .got section */ /* Dynamic relocations are unsupported. This section is only used to detect diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 6749e27..e57916f 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -31,8 +31,6 @@ //! //! - A `_sheap` symbol at whose address you can locate a heap. //! -//! - Zero cost stack overflow protection when using the `cortex-m-rt-ld` linker. -//! //! # Example //! //! Creating a new bare metal project. (I recommend you use the @@ -103,195 +101,10 @@ //! .vector_table 0x400 0x8000000 //! .text 0x24a 0x8000400 //! .rodata 0x0 0x800064c -//! .stack 0x2000 0x20000000 //! .bss 0x0 0x20000000 //! .data 0x0 0x20000000 //! ``` //! -//! ## Zero cost stack overflow protection -//! -//! Consider the following variation of the previous program: -//! -//! ``` ignore -//! extern crate cortex_m_rt; -//! -//! const N: usize = 256; -//! static mut XS: [u32; N] = [0; N]; -//! -//! fn main() { -//! #[inline(never)] -//! fn fib(n: u32) -> u32 { -//! unsafe { assert!(XS.iter().all(|x| *x == 0)) } -//! -//! if n < 2 { -//! 1 -//! } else { -//! fib(n - 1) + fib(n - 2) -//! } -//! } -//! -//! let x = fib(400); -//! unsafe { *XS.iter_mut().first().unwrap() = x } -//! } -//! ``` -//! -//! This program allocates a 1KB array in `.bss`, recursively computes the 400th fibonacci number -//! and stores the result in the head of the array. This program will hit a stack overflow at -//! runtime because there's not enough memory to recursively call the `fib` function so many times. -//! -//! If you inspect the program using GDB you'll see that the assertion failed after `fib` was nested -//! around 300 times. -//! -//! ``` console -//! > continue -//! Program received signal SIGTRAP, Trace/breakpoint trap. -//! -//! > backtrace -//! #0 0x08000516 in cortex_m_rt::default_handler () -//! #1 -//! #2 0x0800050a in rust_begin_unwind () -//! #3 0x08000586 in core::panicking::panic_fmt () -//! #4 0x0800055c in core::panicking::panic () -//! #5 0x080004f6 in app::main::fib () -//! #6 0x080004a0 in app::main::fib () -//! (..) -//! #301 0x080004a0 in app::main::fib () -//! #302 0x080004a0 in app::main::fib () -//! #303 0x08000472 in app::main () -//! #304 0x08000512 in cortex_m_rt::lang_items::start () -//! #305 0x08000460 in cortex_m_rt::reset_handler () -//! ``` -//! -//! What this means is that the stack grew so much that it crashed into the `.bss` section and -//! overwrote the memory in there. Continuing the GDB session you can confirm that the `XS` variable -//! has been modified: -//! -//! ``` console -//! > x/4 0x20000000 # start of .bss -//! 0x20000000 : 0x00000000 0x00000000 0x00000000 0x00000000 -//! -//! > x/4 0x200003f0 # end of .bss -//! 0x200003f0 : 0x20000400 0x080004f5 0x00000000 0x00000001 -//! ``` -//! -//! The problem is that the stack is growing towards the `.bss` section and both sections overlap as -//! shown below: -//! -//! ``` console -//! $ arm-none-eabi-size -Ax $(find target -name app) -//! section size addr -//! .vector_table 0x400 0x8000000 -//! .text 0x186 0x8000400 -//! .rodata 0x50 0x8000590 -//! .stack 0x2000 0x20000000 -//! .bss 0x400 0x20000000 -//! .data 0x0 0x20000400 -//! ``` -//! -//! Graphically the RAM sections look like this: -//! -//!

-//! Stack overflow -//!

-//! -//! To prevent memory corruption due to stack overflows in this scenario it suffices to switch the -//! sections so that the `.bss` section is near the end of the RAM region and the `.stack` comes -//! *before* `.bss`, at a lower address. -//! -//! To swap the sections you can use the [`cortex-m-rt-ld`] linker to link the program. -//! -//! ``` console -//! $ cargo install cortex-m-rt-ld -//! -//! $ cargo rustc --target thumbv7m-none-eabi -- \ -//! -C link-arg=-Tlink.x -C linker=cortex-m-rt-ld -Z linker-flavor=ld -//! ``` -//! -//! Now you get non overlapping linker sections: -//! -//! ``` console -//! section size addr -//! .vector_table 0x400 0x8000000 -//! .text 0x186 0x8000400 -//! .rodata 0x50 0x8000590 -//! .stack 0x1c00 0x20000000 -//! .bss 0x400 0x20001c00 -//! .data 0x0 0x20002000 -//! ``` -//! -//! Note that the `.stack` section is smaller now. Graphically, the memory layout now looks like -//! this: -//! -//!

-//! Swapped sections -//!

-//! -//! On stack overflows `.stack` will hit the lower boundary of the RAM region raising a hard fault -//! exception, instead of silently corrupting the `.bss` section. -//! -//! You can confirm this by inspecting the program in GDB. -//! -//! ``` console -//! > continue -//! Program received signal SIGTRAP, Trace/breakpoint trap. -//! -//! > p $sp -//! $1 = (void *) 0x1ffffff0 -//! ``` -//! -//! The failure mode this time was the `.stack` crashing into the RAM boundary. The variable `XS` is -//! unaffected this time: -//! -//! ``` console -//! > x/4x app::XS -//! 0x20001c00 : 0x00000000 0x00000000 0x00000000 0x00000000 -//! -//! > x/4x app::XS+252 -//! 0x20001ff0 : 0x00000000 0x00000000 0x00000000 0x00000000 -//! ``` -//! -//! ## `.heap` -//! -//! If your program makes use of a `.heap` section a similar problem can occur: -//! -//!

-//! Memory layout when `.heap` exists -//!

-//! -//! The `.stack` can crash into the `.heap`, or vice versa, and you'll also get memory corruption. -//! -//! `cortex-m-rt-ld` can also be used in this case but the size of the `.heap` section must be -//! specified via the `_heap_size` symbol in `memory.x`, or in any other linker script. -//! -//! ``` console -//! $ $EDITOR memory.x && tail -n1 $_ -//! _heap_size = 0x400; -//! ``` -//! -//! ``` console -//! $ cargo rustc --target thumbv7m-none-eabi -- \ -//! -C link-arg=-Tlink.x -C linker=cortex-m-rt-ld -Z linker-flavor=ld -//! -//! $ arm-none-eabi-size -Ax $(find target -name app) | head -//! section size addr -//! .vector_table 0x400 0x8000000 -//! .text 0x1a8 0x8000400 -//! .rodata 0x50 0x80005b0 -//! .stack 0x1800 0x20000000 -//! .bss 0x400 0x20001800 -//! .data 0x0 0x20001c00 -//! .heap 0x400 0x20001c00 -//! ``` -//! -//! Graphically the memory layout looks like this: -//! -//!

-//! Swapped sections when `.heap` exists -//!

-//! -//! Now both stack overflows and dynamic memory over-allocations (OOM) will generate hard fault -//! exceptions, instead of running into each other. -//! //! # Symbol interfaces //! //! This crate makes heavy use of symbols, linker sections and linker scripts to @@ -414,10 +227,6 @@ //! _stack_start = ORIGIN(CCRAM) + LENGTH(CCRAM); //! ``` //! -//! ### `_heap_size` -//! -//! The size of the `.heap` section. Only meaningful when using `cortex-m-rt-ld`. -//! //! ### `_stext` //! //! This symbol indicates where the `.text` section will be located. If not @@ -463,13 +272,8 @@ //! } //! ``` //! -//! *NOTE* if you are using `cortex-m-rt-ld` and/or have defined the `_heap_size` symbol then you should -//! use the address of the `_eheap` to compute the size of the `.heap` section, instead of -//! duplicating the value that you wrote in `memory.x`. -//! //! [1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html //! [qs]: https://docs.rs/cortex-m-quickstart/0.2.0/cortex_m_quickstart/ -//! [`cortex-m-rt-ld`]: https://crates.io/crates/cortex-m-rt-ld //! [2]: https://sourceware.org/binutils/docs/ld/MEMORY.html #![cfg_attr(any(target_arch = "arm", feature = "abort-on-panic"), feature(core_intrinsics))] -- cgit v1.2.3 From aa39e5c88de45d5231bb0affe3a41aa309f2a23a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 9 Apr 2018 01:24:43 +0200 Subject: drop the panic_fmt lang item and the abort-on-panic feature closes #30 --- cortex-m-rt/Cargo.toml | 6 +----- cortex-m-rt/src/lang_items.rs | 7 ------- cortex-m-rt/src/lib.rs | 15 +++++---------- 3 files changed, 6 insertions(+), 22 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 45f0b07..cd31b2d 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -11,8 +11,4 @@ version = "0.4.0" [dependencies] cortex-m = "0.3.0" -r0 = "0.2.1" - -[features] -# provides a panic_fmt implementation that calls the abort instruction (`udf 0xfe`) -abort-on-panic = [] +r0 = "0.2.1" \ No newline at end of file diff --git a/cortex-m-rt/src/lang_items.rs b/cortex-m-rt/src/lang_items.rs index 7d7a598..571a8a5 100644 --- a/cortex-m-rt/src/lang_items.rs +++ b/cortex-m-rt/src/lang_items.rs @@ -1,10 +1,3 @@ -/// Default panic handler -#[cfg(feature = "abort-on-panic")] -#[lang = "panic_fmt"] -unsafe extern "C" fn panic_fmt(_: ::core::fmt::Arguments, _: &'static str, _: u32, _: u32) -> ! { - ::core::intrinsics::abort() -} - // Lang item required to make the normal `main` work in applications // // This is how the `start` lang item works: diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index e57916f..f639af8 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -8,11 +8,6 @@ //! //! - Before main initialization of the FPU (for targets that have a FPU). //! -//! - A `panic_fmt` implementation that just calls abort that you can opt into -//! through the "abort-on-panic" Cargo feature. If you don't use this feature -//! you'll have to provide the `panic_fmt` lang item yourself. Documentation -//! [here](https://doc.rust-lang.org/unstable-book/language-features/lang-items.html) -//! //! - A minimal `start` lang item to support the standard `fn main()` //! interface. (The processor goes to sleep (`loop { asm!("wfi") }`) after //! returning from `main`) @@ -41,10 +36,10 @@ //! $ cargo new --bin app && cd $_ //! //! $ # add this crate as a dependency -//! $ $EDITOR Cargo.toml && tail $_ -//! [dependencies.cortex-m-rt] -//! features = ["abort-on-panic"] -//! version = "0.3.0" +//! $ cargo add cortex-m-rt --vers 0.4.0 +//! +//! $ # select a panicking behavior +//! $ cargo add panic-abort //! //! $ # memory layout of the device //! $ $EDITOR memory.x && cat $_ @@ -63,6 +58,7 @@ //! #![no_std] //! //! extern crate cortex_m_rt; +//! extern crate panic_abort; // panicking behavior //! //! fn main() { //! // do something here @@ -276,7 +272,6 @@ //! [qs]: https://docs.rs/cortex-m-quickstart/0.2.0/cortex_m_quickstart/ //! [2]: https://sourceware.org/binutils/docs/ld/MEMORY.html -#![cfg_attr(any(target_arch = "arm", feature = "abort-on-panic"), feature(core_intrinsics))] #![deny(missing_docs)] #![deny(warnings)] #![feature(asm)] -- cgit v1.2.3 From 657775cf4896cad6a1c2f7cc182bc0bb14b3d242 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 9 Apr 2018 01:26:22 +0200 Subject: drop compiler-builtins bits they were leftover from rebasing closes #31 --- cortex-m-rt/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index f639af8..e2e52b5 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -275,7 +275,7 @@ #![deny(missing_docs)] #![deny(warnings)] #![feature(asm)] -#![cfg_attr(needs_cb, feature(compiler_builtins_lib))] +#![feature(core_intrinsics)] #![feature(global_asm)] #![feature(lang_items)] #![feature(linkage)] @@ -283,8 +283,6 @@ #![feature(used)] #![no_std] -#[cfg(needs_cb)] -extern crate compiler_builtins; #[cfg(target_arch = "arm")] extern crate cortex_m; #[cfg(target_arch = "arm")] -- cgit v1.2.3 From 7521c609b353a97cb0c7e6f8dc3a1b8833ea3b81 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 9 Apr 2018 23:26:35 +0200 Subject: update the CHANGELOG --- cortex-m-rt/CHANGELOG.md | 31 +++++++++++++++++++++++++++++++ cortex-m-rt/src/lib.rs | 4 ++-- 2 files changed, 33 insertions(+), 2 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/CHANGELOG.md b/cortex-m-rt/CHANGELOG.md index f9e2abd..c2a7045 100644 --- a/cortex-m-rt/CHANGELOG.md +++ b/cortex-m-rt/CHANGELOG.md @@ -7,6 +7,37 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.4.0] - 2018-04-09 + +### Added + +- LLD support. The linker script provided by this crate has been tweaked to support both LLD and GNU + LD. To use LLD as a linker change `.cargo/config` to look like this: + +``` diff + [target.thumbv7m-none-eabi] + rustflags = [ + "-C", "link-arg=-Tlink.x", +- "-C", "linker=arm-none-eabi-ld", +- "-Z", "linker-flavor=ld", ++ "-C", "linker=lld", ++ "-Z", "linker-flavor=ld.lld", + ] +``` + +### Removed + +- [breaking-change] Stack overflow protection has been removed. Unfortunately, supporting this + feature produces totally wrong `arm-none-eabi-size` reports when LLD is used to link the + program. If you need the stack overflow protection feature you can continue to use version + v0.3.13+. + +- [breaking-change] The "abort-on-panic" Cargo feature, which provided a `panic_fmt` implementation, + has been removed. If you were using this feature you can instead use a [panic implementation + crate][panic-impl]. + +[panic-impl]: https://crates.io/keywords/panic-impl + ## [v0.3.15] - 2018-04-08 ### Fixed diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index e2e52b5..7028cce 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -38,7 +38,7 @@ //! $ # add this crate as a dependency //! $ cargo add cortex-m-rt --vers 0.4.0 //! -//! $ # select a panicking behavior +//! $ # select a panicking behavior (look for the panic-impl keyword on crates.io) //! $ cargo add panic-abort //! //! $ # memory layout of the device @@ -151,7 +151,7 @@ //! #[linkage = "weak"] //! #[naked] //! #[no_mangle] -//! extern "C" fn WWDG() { +//! extern "C" fn PVD() { //! unsafe { //! asm!("b DEFAULT_HANDLER" :::: "volatile"); //! core::intrinsics::unreachable(); -- cgit v1.2.3 From 7739bc6a36652ac8d38f81b95eb149789a75edce Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 24 Apr 2018 09:38:46 +0200 Subject: compile on stable --- cortex-m-rt/Cargo.toml | 3 +- cortex-m-rt/link.x | 192 ++++++++---- cortex-m-rt/src/lang_items.rs | 39 --- cortex-m-rt/src/lib.rs | 697 +++++++++--------------------------------- 4 files changed, 277 insertions(+), 654 deletions(-) delete mode 100644 cortex-m-rt/src/lang_items.rs (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index cd31b2d..9648b76 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -7,8 +7,7 @@ keywords = ["arm", "cortex-m", "runtime", "startup"] license = "MIT OR Apache-2.0" name = "cortex-m-rt" repository = "https://github.com/japaric/cortex-m-rt" -version = "0.4.0" +version = "0.5.0" [dependencies] -cortex-m = "0.3.0" r0 = "0.2.1" \ No newline at end of file diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x index 7e398de..1f5fd6f 100644 --- a/cortex-m-rt/link.x +++ b/cortex-m-rt/link.x @@ -1,123 +1,191 @@ -INCLUDE memory.x - -/* With multiple codegen units the rlib produced for this crate has several object files in it. */ -/* Because the linker is Smart it may not look into all the object files and not pick up the */ -/* .vector_table.exceptions section. But we want it to! To workaround the problem we create an */ -/* undefined reference to the EXCEPTIONS symbol (located in .vector_table.exceptions); this way the */ -/* linker will look at all the object of the rlib and pick up our EXCEPTIONS symbol */ -EXTERN(EXCEPTIONS); - -/* Create an undefined reference to the INTERRUPTS symbol. This is required to - force the linker to *not* drop the INTERRUPTS symbol if it comes from an - object file that's passed to the linker *before* this crate */ -EXTERN(INTERRUPTS); +/* # Developer notes + +- Symbols that start with a double underscore (__) are considered "private" +- Symbols that start with a single underscore (_) are considered "semi-public"; they can be + overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" { + static mut __sbss }`). +- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a + symbol if not dropped if it appears in or near the front of the linker arguments and "it's not + needed" by any of the preceding objects (linker arguments) +- `PROVIDE` is used to provide default values that can be overridden by a user linker script +- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and* + the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization + routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see + "Address (..) is out of bounds" in the disassembly produced by `objdump`. +*/ +INCLUDE memory.x +INCLUDE interrupts.x + +/* # Entry point */ +ENTRY(__reset); +EXTERN(__RESET_VECTOR); /* depends on the `__reset` symbol */ + +EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */ + +/* # Exception vectors */ +/* This is effectively weak aliasing at the linker level */ +/* The user can override any of these aliases by defining the corresponding symbol themselves (cf. + the `exception!` macro) */ +EXTERN(DefaultHandler); +PROVIDE(NMI = DefaultHandler); +PROVIDE(HardFault = DefaultHandler); +PROVIDE(MemManage = DefaultHandler); +PROVIDE(BusFault = DefaultHandler); +PROVIDE(UsageFault = DefaultHandler); +PROVIDE(SVC = DefaultHandler); +PROVIDE(DebugMon = DefaultHandler); +PROVIDE(PendSV = DefaultHandler); +PROVIDE(SysTick = DefaultHandler); + +/* # Interrupt vectors */ +EXTERN(__INTERRUPTS); /* to be provided by the device crate or equivalent */ + +/* # User overridable symbols I */ +/* Lets the user place the stack in a different RAM region */ PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM)); +/* # Sections */ SECTIONS { + /* ## Sections in FLASH */ + /* ### Vector table */ .vector_table ORIGIN(FLASH) : ALIGN(4) { - /* Vector table */ - _svector_table = .; + /* Initial Stack Pointer (SP) value */ + __STACK_START = .; /* Just to get a nicer name in the disassembly */ LONG(_stack_start); + /* Reset vector */ KEEP(*(.vector_table.reset_vector)); + __reset_vector = ABSOLUTE(.); + /* Exceptions */ KEEP(*(.vector_table.exceptions)); - _eexceptions = .; + __eexceptions = ABSOLUTE(.); + /* Device specific interrupts */ KEEP(*(.vector_table.interrupts)); - _einterrupts = .; + __einterrupts = ABSOLUTE(.); } > FLASH - PROVIDE(_stext = _einterrupts); - - .text _stext : ALIGN(4) + /* ### .text */ + .text _stext : { - /* Put reset handler first in .text section so it ends up as the entry */ - /* point of the program. */ - KEEP(*(.reset_handler)); - *(.text .text.*); + __etext = ABSOLUTE(.); } > FLASH - .rodata : ALIGN(4) + /* ### .rodata */ + .rodata : { + . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ + /* __srodata = ABSOLUTE(.); */ + *(.rodata .rodata.*); - . = ALIGN(4); + + . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ + __erodata = ABSOLUTE(.); } > FLASH - PROVIDE(_sbss = ORIGIN(RAM)); - .bss _sbss : ALIGN(4) - { - *(.bss .bss.*); - . = ALIGN(4); - _ebss = .; - } > RAM AT > FLASH - /* NOTE(AT > FLASH) without this LLD v6 produces a binary that crashes OpenOCD whereas LLD v7 - emits a ".rodata and .bss sections overlap" error ... This hacky workaround doesn't increase - the binary size AFAICT */ - - .data : ALIGN(4) + /* ## Sections in RAM */ + /* ### .data */ + .data : AT(__erodata) /* LMA */ { - _sidata = LOADADDR(.data); - _sdata = .; + . = ALIGN(4); /* 4-byte align the start (VMA) of this section */ + __sdata = ABSOLUTE(.); + *(.data .data.*); - . = ALIGN(4); - _edata = .; - } > RAM AT > FLASH - /* The heap starts right after the .bss + .data section ends */ - _sheap = _edata; + . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ + __edata = ABSOLUTE(.); + } > RAM + + /* ### .bss */ + .bss : + { + . = ALIGN(4); /* 4-byte align the start (VMA) of this section */ + __sbss = ABSOLUTE(.); + + *(.bss .bss.*); - /* fake output .got section */ - /* Dynamic relocations are unsupported. This section is only used to detect - relocatable code in the input files and raise an error if relocatable code - is found */ + . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ + __ebss = ABSOLUTE(.); + } > RAM + + /* ## Fake output .got section */ + /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in + the input files and raise an error if relocatable code is found */ .got : { - _sgot = .; + __sgot = ABSOLUTE(.); KEEP(*(.got .got.*)); - _egot = .; - } > RAM AT > FLASH + __egot = ABSOLUTE(.); + } > FLASH + /* ## Discarded sections */ /DISCARD/ : { + /* Unused exception related info that only wastes space */ *(.ARM.exidx.*); } } +/* # User overridable symbols II */ +/* (The user overridable symbols are split in two parts because LLD demands that the RHS of PROVIDE + to be defined before the PROVIDE invocation) */ +/* Lets the user override this to place .text a bit further than the vector table. Required by +microcontrollers that store their configuration right after the vector table. */ +PROVIDE(_stext = __einterrupts); + +/* # Hardcoded symbols */ +/* Place `.bss` at the start of the RAM region */ +__sidata = LOADADDR(.data); +/* Place the heap right after `.bss` and `.data` */ +__sheap = __edata; + +/* # Sanity checks */ + /* Do not exceed this mark in the error messages below | */ -ASSERT(_eexceptions - ORIGIN(FLASH) > 8, " -The exception handlers are missing. This is likely a cortex-m-rt bug. +ASSERT(__reset_vector == ORIGIN(FLASH) + 0x8, +"Reset vector is missing. This is a cortex-m-rt bug. Please file a bug report at: https://github.com/japaric/cortex-m-rt/issues"); -ASSERT(_eexceptions - ORIGIN(FLASH) == 0x40, " -Invalid '.vector_table.exceptions' section. This is likely a -cortex-m-rt bug. Please file a bug report at: +ASSERT(__eexceptions - ORIGIN(FLASH) == 0x40, " +The exception handlers are missing. This is a cortex-m-rt bug. +Please file a bug report at: https://github.com/japaric/cortex-m-rt/issues"); -ASSERT(_einterrupts - _eexceptions > 0, " +ASSERT(__einterrupts - __eexceptions > 0, " The interrupt handlers are missing. If you are not linking to a device crate then you supply the interrupt handlers yourself. Check the documentation."); -ASSERT(_einterrupts - _eexceptions <= 0x3c0, " +ASSERT(__einterrupts - __eexceptions <= 0x3c0, " There can't be more than 240 interrupt handlers. This may be a bug in your device crate, or you may have registered more than 240 interrupt handlers."); -ASSERT(_einterrupts <= _stext, " +ASSERT(__einterrupts <= _stext, " The '.text' section can't be placed inside '.vector_table' section. -Set '_stext' to an address greater than '_einterrupts'"); +Set '_stext' to an address greater than '__einterrupts'"); ASSERT(_stext < ORIGIN(FLASH) + LENGTH(FLASH), " The '.text' section must be placed inside the FLASH memory Set '_stext' to an address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)"); -ASSERT(_sgot == _egot, " +/* This has been temporarily omitted because it's not supported by LLD */ +/* ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, " */ +/* .bss is not 4-byte aligned at its boundaries. This is a cortex-m-rt bug."); */ + +/* ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, " */ +/* .data is not 4-byte aligned at its boundaries. This is a cortex-m-rt bug."); */ + +/* ASSERT(__sidata % 4 == 0, " */ +/* __sidata is not 4-byte aligned. This is a cortex-m-rt bug."); */ + +ASSERT(__sgot == __egot, " .got section detected in the input files. Dynamic relocations are not supported. If you are linking to C code compiled using the `gcc` crate then modify your build script to compile the C code _without_ the diff --git a/cortex-m-rt/src/lang_items.rs b/cortex-m-rt/src/lang_items.rs deleted file mode 100644 index 571a8a5..0000000 --- a/cortex-m-rt/src/lang_items.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Lang item required to make the normal `main` work in applications -// -// This is how the `start` lang item works: -// When `rustc` compiles a binary crate, it creates a `main` function that looks -// like this: -// -// ``` -// #[export_name = "main"] -// pub extern "C" fn rustc_main(argc: isize, argv: *const *const u8) -> isize { -// start(main, argc, argv) -// } -// ``` -// -// Where `start` is this function and `main` is the binary crate's `main` -// function. -// -// The final piece is that the entry point of our program, the reset handler, -// has to call `rustc_main`. That's covered by the `reset_handler` function in -// root of this crate. -#[lang = "start"] -extern "C" fn start(main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize -where - T: Termination, -{ - main(); - - 0 -} - -#[lang = "termination"] -pub trait Termination { - fn report(self) -> i32; -} - -impl Termination for () { - fn report(self) -> i32 { - 0 - } -} diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 7028cce..b689387 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -1,615 +1,210 @@ //! Minimal startup / runtime for Cortex-M microcontrollers -//! -//! # Features -//! -//! This crate provides -//! -//! - Before main initialization of the `.bss` and `.data` sections. -//! -//! - Before main initialization of the FPU (for targets that have a FPU). -//! -//! - A minimal `start` lang item to support the standard `fn main()` -//! interface. (The processor goes to sleep (`loop { asm!("wfi") }`) after -//! returning from `main`) -//! -//! - A linker script that encodes the memory layout of a generic Cortex-M -//! microcontroller. This linker script is missing some information that must -//! be supplied through a `memory.x` file (see example below). -//! -//! - A default exception handler tailored for debugging that lets you inspect -//! what was the state of the processor at the time of the exception. By -//! default, all exceptions are serviced by this handler but each exception -//! can be individually overridden using the -//! [`exception!`](macro.exception.html) macro. The default exception handler -//! itself can also be overridden using the -//! [`default_handler!`](macro.default_handler.html) macro. -//! -//! - A `_sheap` symbol at whose address you can locate a heap. -//! -//! # Example -//! -//! Creating a new bare metal project. (I recommend you use the -//! [`cortex-m-quickstart`](https://docs.rs/cortex-m-quickstart/0.2.0/cortex_m_quickstart/) template -//! as it takes of all the boilerplate shown here) -//! -//! ``` text -//! $ cargo new --bin app && cd $_ -//! -//! $ # add this crate as a dependency -//! $ cargo add cortex-m-rt --vers 0.4.0 -//! -//! $ # select a panicking behavior (look for the panic-impl keyword on crates.io) -//! $ cargo add panic-abort -//! -//! $ # memory layout of the device -//! $ $EDITOR memory.x && cat $_ -//! MEMORY -//! { -//! /* NOTE K = KiBi = 1024 bytes */ -//! FLASH : ORIGIN = 0x08000000, LENGTH = 128K -//! RAM : ORIGIN = 0x20000000, LENGTH = 8K -//! } -//! -//! $ $EDITOR src/main.rs && cat $_ -//! ``` -//! -//! ``` ignore,no_run -//! #![feature(used)] -//! #![no_std] -//! -//! extern crate cortex_m_rt; -//! extern crate panic_abort; // panicking behavior -//! -//! fn main() { -//! // do something here -//! } -//! -//! // As we are not using interrupts, we just register a dummy catch all -//! // handler -//! #[link_section = ".vector_table.interrupts"] -//! #[used] -//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; -//! -//! extern "C" fn default_handler() { -//! loop {} -//! } -//! ``` -//! -//! ``` text -//! $ rustup target add thumbv7m-none-eabi -//! -//! $ cargo rustc --target thumbv7m-none-eabi -- \ -//! -C link-arg=-Tlink.x -C linker=arm-none-eabi-ld -Z linker-flavor=ld -//! -//! $ arm-none-eabi-objdump -Cd $(find target -name app) | head -//! -//! Disassembly of section .text: -//! -//! 08000400 : -//! 8000400: b580 push {r7, lr} -//! 8000402: 466f mov r7, sp -//! 8000404: b084 sub sp, #8 -//! -//! -//! $ arm-none-eabi-size -Ax $(find target -name app) | head -//! target/thumbv7m-none-eabi/debug/app : -//! section size addr -//! .vector_table 0x400 0x8000000 -//! .text 0x24a 0x8000400 -//! .rodata 0x0 0x800064c -//! .bss 0x0 0x20000000 -//! .data 0x0 0x20000000 -//! ``` -//! -//! # Symbol interfaces -//! -//! This crate makes heavy use of symbols, linker sections and linker scripts to -//! provide most of its functionality. Below are described the main symbol -//! interfaces. -//! -//! ## `DEFAULT_HANDLER` -//! -//! This weak symbol can be overridden to override the default exception handler -//! that this crate provides. It's recommended that you use the -//! `default_handler!` to do the override, but below is shown how to manually -//! override the symbol: -//! -//! ``` ignore,no_run -//! #[no_mangle] -//! pub extern "C" fn DEFAULT_HANDLER() { -//! // do something here -//! } -//! ``` -//! -//! ## `.vector_table.interrupts` -//! -//! This linker section is used to register interrupt handlers in the vector -//! table. The recommended way to use this section is to populate it, once, with -//! an array of *weak* functions that just call the `DEFAULT_HANDLER` symbol. -//! Then the user can override them by name. -//! -//! ### Example -//! -//! Populating the vector table -//! -//! ``` ignore,no_run -//! // Number of interrupts the device has -//! const N: usize = 60; -//! -//! // Default interrupt handler that just calls the `DEFAULT_HANDLER` -//! #[linkage = "weak"] -//! #[naked] -//! #[no_mangle] -//! extern "C" fn WWDG() { -//! unsafe { -//! asm!("b DEFAULT_HANDLER" :::: "volatile"); -//! core::intrinsics::unreachable(); -//! } -//! } -//! -//! // You need one function per interrupt handler -//! #[linkage = "weak"] -//! #[naked] -//! #[no_mangle] -//! extern "C" fn PVD() { -//! unsafe { -//! asm!("b DEFAULT_HANDLER" :::: "volatile"); -//! core::intrinsics::unreachable(); -//! } -//! } -//! -//! // .. -//! -//! // Use `None` for reserved spots in the vector table -//! #[link_section = ".vector_table.interrupts"] -//! #[no_mangle] -//! #[used] -//! static INTERRUPTS: [Option; N] = [ -//! Some(WWDG), -//! Some(PVD), -//! // .. -//! ]; -//! ``` -//! -//! Overriding an interrupt (this can be in a different crate) -//! -//! ``` ignore,no_run -//! // the name must match the name of one of the weak functions used to -//! // populate the vector table. -//! #[no_mangle] -//! pub extern "C" fn WWDG() { -//! // do something here -//! } -//! ``` -//! -//! ## `memory.x` -//! -//! This file supplies the information about the device to the linker. -//! -//! ### `MEMORY` -//! -//! The main information that this file must provide is the memory layout of -//! the device in the form of the `MEMORY` command. The command is documented -//! [here](https://sourceware.org/binutils/docs/ld/MEMORY.html), but at a minimum you'll want to -//! create two memory regions: one for Flash memory and another for RAM. -//! -//! The program instructions (the `.text` section) will be stored in the memory -//! region named FLASH, and the program `static` variables (the sections `.bss` -//! and `.data`) will be allocated in the memory region named RAM. -//! -//! ### `_stack_start` -//! -//! This symbol provides the address at which the call stack will be allocated. -//! The call stack grows downwards so this address is usually set to the highest -//! valid RAM address plus one (this *is* an invalid address but the processor -//! will decrement the stack pointer *before* using its value as an address). -//! -//! If omitted this symbol value will default to `ORIGIN(RAM) + LENGTH(RAM)`. -//! -//! #### Example -//! -//! Allocating the call stack on a different RAM region. -//! -//! ``` ignore -//! MEMORY -//! { -//! /* call stack will go here */ -//! CCRAM : ORIGIN = 0x10000000, LENGTH = 8K -//! FLASH : ORIGIN = 0x08000000, LENGTH = 256K -//! /* static variables will go here */ -//! RAM : ORIGIN = 0x20000000, LENGTH = 40K -//! } -//! -//! _stack_start = ORIGIN(CCRAM) + LENGTH(CCRAM); -//! ``` -//! -//! ### `_stext` -//! -//! This symbol indicates where the `.text` section will be located. If not -//! specified in the `memory.x` file it will default to right after the vector -//! table -- the vector table is always located at the start of the FLASH -//! region. -//! -//! The main use of this symbol is leaving some space between the vector table -//! and the `.text` section unused. This is required on some microcontrollers -//! that store some configuration information right after the vector table. -//! -//! #### Example -//! -//! Locate the `.text` section 1024 bytes after the start of the FLASH region. -//! -//! ``` ignore -//! _stext = ORIGIN(FLASH) + 0x400; -//! ``` -//! -//! ### `_sheap` -//! -//! This symbol is located in RAM right after the `.bss` and `.data` sections. -//! You can use the address of this symbol as the start address of a heap -//! region. This symbol is 4 byte aligned so that address will be a multiple of 4. -//! -//! #### Example -//! -//! ``` ignore -//! extern crate some_allocator; -//! -//! // Size of the heap in bytes -//! const SIZE: usize = 1024; -//! -//! extern "C" { -//! static mut _sheap: u8; -//! } -//! -//! fn main() { -//! unsafe { -//! let start_address = &mut _sheap as *mut u8; -//! some_allocator::initialize(start_address, SIZE); -//! } -//! } -//! ``` -//! -//! [1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html -//! [qs]: https://docs.rs/cortex-m-quickstart/0.2.0/cortex_m_quickstart/ -//! [2]: https://sourceware.org/binutils/docs/ld/MEMORY.html + +// # Developer notes +// +// - `link_section` is used to place symbols in specific places if the final binary. The names used +// here will appear in the linker script (`link.x`) in conjunction with the `KEEP` command. #![deny(missing_docs)] #![deny(warnings)] -#![feature(asm)] -#![feature(core_intrinsics)] -#![feature(global_asm)] -#![feature(lang_items)] -#![feature(linkage)] -#![feature(naked_functions)] -#![feature(used)] #![no_std] -#[cfg(target_arch = "arm")] -extern crate cortex_m; -#[cfg(target_arch = "arm")] extern crate r0; -#[cfg(not(test))] -mod lang_items; - -#[cfg(target_arch = "arm")] -use core::intrinsics; - -#[cfg(target_arch = "arm")] -use cortex_m::asm; -#[cfg(target_arch = "arm")] -use cortex_m::exception::ExceptionFrame; - -extern "C" { - // NOTE `rustc` forces this signature on us. See `src/lang_items.rs` - #[cfg(target_arch = "arm")] - fn main(argc: isize, argv: *const *const u8) -> isize; - - // Boundaries of the .bss section - static mut _ebss: u32; - static mut _sbss: u32; - - // Boundaries of the .data section - static mut _edata: u32; - static mut _sdata: u32; +/// Returns a pointer into which the heap can be placed +#[inline] +pub fn heap_start() -> *mut u32 { + extern "C" { + static mut __sheap: u32; + } - // Initial values of the .data section (stored in Flash) - static _sidata: u32; + unsafe { &mut __sheap } } -#[cfg(target_arch = "arm")] +/* Entry point */ +#[doc(hidden)] #[link_section = ".vector_table.reset_vector"] -#[used] -static RESET_VECTOR: unsafe extern "C" fn() -> ! = reset_handler; +#[no_mangle] +pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = __reset; -/// The reset handler -/// -/// This is the entry point of all programs -#[cfg(target_arch = "arm")] -#[link_section = ".reset_handler"] -unsafe extern "C" fn reset_handler() -> ! { - r0::zero_bss(&mut _sbss, &mut _ebss); - r0::init_data(&mut _sdata, &mut _edata, &_sidata); +#[doc(hidden)] +#[no_mangle] +pub unsafe extern "C" fn __reset() -> ! { + extern "C" { + // This symbol will be provided by the user via the `main!` macro + fn main() -> !; + + // These symbols come from `link.x` + static mut __sbss: u32; + static mut __ebss: u32; + + static mut __sdata: u32; + static mut __edata: u32; + static __sidata: u32; + } + + // Initialize RAM + r0::zero_bss(&mut __sbss, &mut __ebss); + r0::init_data(&mut __sdata, &mut __edata, &__sidata); match () { #[cfg(not(has_fpu))] - () => { - // Neither `argc` or `argv` make sense in bare metal context so we - // just stub them - main(0, ::core::ptr::null()); - } + () => main(), #[cfg(has_fpu)] () => { - // NOTE(safe) no exception / interrupt that also accesses the FPU - // can occur here - let scb = &*cortex_m::peripheral::SCB.get(); - scb.enable_fpu(); - - // Make sure the user main function never gets inlined into this - // function as that may cause FPU related instructions like vpush to - // be executed *before* enabling the FPU and that would generate an - // exception + // We redefine these here to avoid pulling the `cortex-m` crate as a dependency + const SCB_CPACR: *mut u32 = 0xE000_ED88 as *mut u32; + const SCB_CPACR_FPU_ENABLE: u32 = 0b01_01 << 20; + const SCB_CPACR_FPU_USER: u32 = 0b10_10 << 20; + + // enable the FPU + core::ptr::write_volatile( + SCB_CPACR, + *SCB_CPACR | SCB_CPACR_FPU_ENABLE | SCB_CPACR_FPU_USER, + ); + + // this is used to prevent the compiler from inlining the user `main` into the reset + // handler. Inlining can cause the FPU instructions in the user `main` to be executed + // before enabling the FPU, and that would produce a hard to diagnose hard fault at + // runtime. #[inline(never)] - fn main() { - unsafe { - ::main(0, ::core::ptr::null()); - } + #[export_name = "__reset_trampoline"] + fn trampoline() -> ! { + unsafe { main() } } - main() + trampoline() } } - - // If `main` returns, then we go into "reactive" mode and simply attend - // interrupts as they occur. - loop { - asm!("wfi" :::: "volatile"); - } } -#[cfg(target_arch = "arm")] -global_asm!( - r#" -.weak NMI -NMI = DEFAULT_HANDLER - -.weak HARD_FAULT -HARD_FAULT = DEFAULT_HANDLER - -.weak MEM_MANAGE -MEM_MANAGE = DEFAULT_HANDLER - -.weak BUS_FAULT -BUS_FAULT = DEFAULT_HANDLER - -.weak USAGE_FAULT -USAGE_FAULT = DEFAULT_HANDLER - -.weak SVCALL -SVCALL = DEFAULT_HANDLER - -.weak PENDSV -PENDSV = DEFAULT_HANDLER +/// Macro to define the user entry point of a program +/// +/// Usage: `main!(path::to::user::main)` +/// +/// This function will be called by the reset handler *after* RAM has been initialized. In the case +/// of the `thumbv7em-none-eabihf` target the FPU will also be enabled before the user `main` is +/// called. +#[macro_export] +macro_rules! main { + ($path:path) => { + #[export_name = "main"] + pub extern "C" fn __impl_main() -> ! { + // validate the signature of the user provide `main` + let f: fn() -> ! = $path; -.weak SYS_TICK -SYS_TICK = DEFAULT_HANDLER -"# -); + f() + } + }; +} -#[cfg(not(armv6m))] -global_asm!( - r#" -.weak DEBUG_MONITOR -DEBUG_MONITOR = DEFAULT_HANDLER -"# -); +/* Exceptions */ +// NOTE we purposefully go against Rust style here and use PascalCase for the handlers. The +// rationale is in the definition of the `exception!` macro. +#[doc(hidden)] +pub enum Exception { + NMI, + MenManage, + BusFault, + UsageFault, + SVC, + DebugMon, + PendSV, + SysTick, +} -#[cfg(target_arch = "arm")] extern "C" { fn NMI(); - fn HARD_FAULT(); - fn MEM_MANAGE(); - fn BUS_FAULT(); - fn USAGE_FAULT(); - fn SVCALL(); + fn HardFault(); + fn MemManage(); + fn BusFault(); + fn UsageFault(); + fn SVC(); #[cfg(not(armv6m))] - fn DEBUG_MONITOR(); - fn PENDSV(); - fn SYS_TICK(); + fn DebugMon(); + fn PendSV(); + fn SysTick(); } -#[allow(private_no_mangle_statics)] -#[cfg(target_arch = "arm")] #[doc(hidden)] #[link_section = ".vector_table.exceptions"] #[no_mangle] -#[used] -pub static EXCEPTIONS: [Option; 14] = [ +pub static __EXCEPTIONS: [Option; 14] = [ Some(NMI), - Some(HARD_FAULT), - Some(MEM_MANAGE), - Some(BUS_FAULT), - Some(USAGE_FAULT), + Some(HardFault), + Some(MemManage), + Some(BusFault), + Some(UsageFault), None, None, None, None, - Some(SVCALL), + Some(SVC), #[cfg(armv6m)] None, #[cfg(not(armv6m))] - Some(DEBUG_MONITOR), + Some(DebugMon), None, - Some(PENDSV), - Some(SYS_TICK), + Some(PendSV), + Some(SysTick), ]; -/// `ef` points to the exception frame +/// Macro to override an exception handler /// -/// That exception frame is a snapshot of the program state right before the -/// exception occurred. -#[allow(unused_variables)] -#[cfg(target_arch = "arm")] -extern "C" fn default_handler(ef: &ExceptionFrame) -> ! { - asm::bkpt(); - - loop {} - - #[export_name = "DEFAULT_HANDLER"] - #[linkage = "weak"] - #[naked] - extern "C" fn trampoline() -> ! { - unsafe { - asm!("mrs r0, MSP - b $0" - : - : "i"(default_handler as extern "C" fn(&ExceptionFrame) -> !) - : - : "volatile"); - - intrinsics::unreachable() - } - } - - #[used] - static KEEP: extern "C" fn() -> ! = trampoline; -} - -// make sure the compiler emits the DEFAULT_HANDLER symbol so the linker can -// find it! -#[cfg(target_arch = "arm")] -#[used] -static KEEP: extern "C" fn(&ExceptionFrame) -> ! = default_handler; - -/// This macro lets you override the default exception handler -/// -/// The first and only argument to this macro is the path to the function that -/// will be used as the default handler. That function must have signature -/// `fn()` +/// Usage: `exception!(ExceptionName, path::to::handler)` /// -/// # Examples +/// All exceptions are serviced by the `DefaultHandler` exception handler unless overridden using +/// this macro. `ExceptionName` can be one of are: /// -/// ``` ignore -/// default_handler!(foo::bar); +/// - `DefaultHandler` (\*) +/// - `NMI` +/// - `HardFault` +/// - `MemManage` +/// - `BusFault` +/// - `UsageFault` +/// - `SVC` +/// - `DebugMon` (not available on ARMv6-M) +/// - `PendSV` +/// - `SysTick` /// -/// mod foo { -/// pub fn bar() { -/// ::cortex_m::asm::bkpt(); -/// loop {} -/// } -/// } -/// ``` -#[macro_export] -macro_rules! default_handler { - ($path:path) => { - #[allow(non_snake_case)] - #[doc(hidden)] - #[no_mangle] - pub unsafe extern "C" fn DEFAULT_HANDLER() { - // type checking - let f: fn() = $path; - f(); - } - } -} - -/// Fault and system exceptions -#[allow(non_camel_case_types)] -#[doc(hidden)] -pub enum Exception { - /// Non-maskable interrupt - NMI, - /// All class of fault. - HARD_FAULT, - /// Memory management. - MEN_MANAGE, - /// Pre-fetch fault, memory access fault. - BUS_FAULT, - /// Undefined instruction or illegal state. - USAGE_FAULT, - /// System service call via SWI instruction - SVCALL, - /// Debug monitor - #[cfg(not(armv6m))] - DEBUG_MONITOR, - /// Pendable request for system service - PENDSV, - /// System tick timer - SYS_TICK, -} - -/// Assigns a handler to an exception -/// -/// This macro takes two arguments: the name of an exception and the path to the -/// function that will be used as the handler of that exception. That function -/// must have signature `fn()`. -/// -/// Optionally, a third argument may be used to declare exception local data. -/// The handler will have exclusive access to these *local* variables on each -/// invocation. If the third argument is used then the signature of the handler -/// function must be `fn(&mut $NAME::Locals)` where `$NAME` is the first -/// argument passed to the macro. -/// -/// # Example -/// -/// ``` ignore -/// exception!(MEM_MANAGE, mpu_fault); -/// -/// fn mpu_fault() { -/// panic!("Oh no! Something went wrong"); -/// } -/// -/// exception!(SYS_TICK, periodic, locals: { -/// counter: u32 = 0; -/// }); -/// -/// fn periodic(locals: &mut SYS_TICK::Locals) { -/// locals.counter += 1; -/// println!("This function has been called {} times", locals.counter); -/// } -/// ``` +/// (\*) Note that `DefaultHandler` is left undefined and *must* be defined by the user somewhere +/// using this macro. #[macro_export] macro_rules! exception { - ($NAME:ident, $path:path, locals: { - $($lvar:ident:$lty:ident = $lval:expr;)+ - }) => { + (DefaultHandler, $path:path) => { #[allow(non_snake_case)] - mod $NAME { - pub struct Locals { - $( - pub $lvar: $lty, - )+ - } - } + #[export_name = "DefaultHandler"] + pub unsafe extern "C" fn __impl_DefaultHandler() { + // XXX should we really prevent this handler from returning? + // validate the signature of the user provided handler + let f: fn() -> ! = $path; + f() + } + }; + (HardFault, $path:path) => { #[allow(non_snake_case)] - #[doc(hidden)] - #[no_mangle] - pub unsafe extern "C" fn $NAME() { - // check that the handler exists - let _ = $crate::Exception::$NAME; - - static mut LOCALS: self::$NAME::Locals = self::$NAME::Locals { - $( - $lvar: $lval, - )* - }; + #[export_name = "HardFaultr"] + pub unsafe extern "C" fn __impl_HardFault() { + // XXX should we really prevent this handler from returning? + // validate the signature of the user provided handler + let f: fn() -> ! = $path; - // type checking - let f: fn(&mut self::$NAME::Locals) = $path; - f(&mut LOCALS); + f() } }; - ($NAME:ident, $path:path) => { - #[allow(non_snake_case)] - #[doc(hidden)] + // NOTE Unfortunately, this will end up leaking `$exception` into the function call namespace. + // But the damage is somewhat reduced by having `$exception` not being a `snake_case` function. + ($ExceptionName:ident, $path:path) => { #[no_mangle] - pub unsafe extern "C" fn $NAME() { - // check that the handler exists - let _ = $crate::Exception::$NAME; + pub unsafe extern "C" fn $ExceptionName() { + // check that this exception exists + let _ = $crate::Exception::$ExceptionName; - // type checking + // validate the signature of the user provided handler let f: fn() = $path; - f(); + + f() } - } + }; } -- cgit v1.2.3 From 45803fac793c65539fa11a11a6e5f475b9058b38 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 24 Apr 2018 18:07:09 +0200 Subject: fix typo --- cortex-m-rt/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index b689387..f2a7929 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -104,7 +104,7 @@ macro_rules! main { #[doc(hidden)] pub enum Exception { NMI, - MenManage, + MemManage, BusFault, UsageFault, SVC, -- cgit v1.2.3 From 9976eb18cfe753dd388504c7ef54fb0de6a56a02 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 24 Apr 2018 20:50:13 +0200 Subject: fix typo in export name --- cortex-m-rt/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index f2a7929..fe2156f 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -182,9 +182,10 @@ macro_rules! exception { f() } }; + (HardFault, $path:path) => { #[allow(non_snake_case)] - #[export_name = "HardFaultr"] + #[export_name = "HardFault"] pub unsafe extern "C" fn __impl_HardFault() { // XXX should we really prevent this handler from returning? // validate the signature of the user provided handler @@ -193,6 +194,7 @@ macro_rules! exception { f() } }; + // NOTE Unfortunately, this will end up leaking `$exception` into the function call namespace. // But the damage is somewhat reduced by having `$exception` not being a `snake_case` function. ($ExceptionName:ident, $path:path) => { -- cgit v1.2.3 From 857eb6579852b1578bcf9e8743ff9ba4a9276e5b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 24 Apr 2018 20:50:56 +0200 Subject: expose exception number to DefaultHandler --- cortex-m-rt/src/lib.rs | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index fe2156f..d4486e1 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -156,30 +156,36 @@ pub static __EXCEPTIONS: [Option; 14] = [ /// All exceptions are serviced by the `DefaultHandler` exception handler unless overridden using /// this macro. `ExceptionName` can be one of are: /// -/// - `DefaultHandler` (\*) -/// - `NMI` -/// - `HardFault` -/// - `MemManage` -/// - `BusFault` -/// - `UsageFault` -/// - `SVC` -/// - `DebugMon` (not available on ARMv6-M) -/// - `PendSV` -/// - `SysTick` +/// - `DefaultHandler` (a) -- `fn(u8) -> !` -- the argument is the exception number (VECTACTIVE) +/// - `NMI` -- `fn()` +/// - `HardFault` -- `fn() -> !` +/// - `MemManage` -- `fn()` +/// - `BusFault` -- `fn()` +/// - `UsageFault` -- `fn()` +/// - `SVC` -- `fn()` +/// - `DebugMon` (b) -- `fn()` +/// - `PendSV` -- `fn()` +/// - `SysTick` -- `fn()` /// -/// (\*) Note that `DefaultHandler` is left undefined and *must* be defined by the user somewhere +/// (a) Note that `DefaultHandler` is left undefined and *must* be defined by the user somewhere /// using this macro. +/// +/// (b) Not available on ARMv6-M +// XXX should we prevent the fault handlers from returning? #[macro_export] macro_rules! exception { (DefaultHandler, $path:path) => { #[allow(non_snake_case)] #[export_name = "DefaultHandler"] pub unsafe extern "C" fn __impl_DefaultHandler() { - // XXX should we really prevent this handler from returning? // validate the signature of the user provided handler - let f: fn() -> ! = $path; + let f: fn(u8) -> ! = $path; - f() + const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; + + // NOTE not volatile so the compiler can opt the load operation away if the value is + // unused + f(core::ptr::read(SCB_ICSR) as u8) } }; @@ -187,7 +193,6 @@ macro_rules! exception { #[allow(non_snake_case)] #[export_name = "HardFault"] pub unsafe extern "C" fn __impl_HardFault() { - // XXX should we really prevent this handler from returning? // validate the signature of the user provided handler let f: fn() -> ! = $path; -- cgit v1.2.3 From d54f8bb52f9d4f38544d448713f047a63ce5fb9c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 24 Apr 2018 20:51:10 +0200 Subject: add macro to bind all interrupts to DefaultHandler --- cortex-m-rt/src/lib.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index d4486e1..e0ddb76 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -215,3 +215,22 @@ macro_rules! exception { } }; } + +/// Macro to bind all the 240 interrupt handlers to the `DefaultHandler` exception handler. +/// +/// The use case for this macro is writing device agnostic programs +#[macro_export] +macro_rules! interrupts { + (DefaultHandler) => { + #[doc(hidden)] + #[link_section = ".vector_table.interrupts"] + #[no_mangle] + pub static __INTERRUPTS: [Option; 240] = [{ + extern "C" { + fn DefaultHandler(); + } + + Some(DefaultHandler) + }; 240]; + }; +} -- cgit v1.2.3 From c4b580b957853aaa7b0680ce12da81049e30d978 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 26 Apr 2018 03:57:08 +0200 Subject: tweak HardFault and DefaultHandler --- cortex-m-rt/Cargo.toml | 5 ++++- cortex-m-rt/asm.s | 4 ++++ cortex-m-rt/build.rs | 6 ++++++ cortex-m-rt/link.x | 31 ++++++++++++++++++---------- cortex-m-rt/memory.x | 19 +++++++++++++++++ cortex-m-rt/src/lib.rs | 56 +++++++++++++++++++++++++++++++++++++++++--------- 6 files changed, 99 insertions(+), 22 deletions(-) create mode 100644 cortex-m-rt/asm.s create mode 100644 cortex-m-rt/memory.x (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 9648b76..4d5e592 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -10,4 +10,7 @@ repository = "https://github.com/japaric/cortex-m-rt" version = "0.5.0" [dependencies] -r0 = "0.2.1" \ No newline at end of file +r0 = "0.2.1" + +[build-dependencies] +cc = "1.0.10" diff --git a/cortex-m-rt/asm.s b/cortex-m-rt/asm.s new file mode 100644 index 0000000..1ad7721 --- /dev/null +++ b/cortex-m-rt/asm.s @@ -0,0 +1,4 @@ + .global HardFault +HardFault: + mrs r0, MSP + b UserHardFault diff --git a/cortex-m-rt/build.rs b/cortex-m-rt/build.rs index 1d0160c..70b7a43 100644 --- a/cortex-m-rt/build.rs +++ b/cortex-m-rt/build.rs @@ -1,3 +1,5 @@ +extern crate cc; + use std::env; use std::fs::File; use std::io::Write; @@ -9,6 +11,10 @@ fn main() { has_fpu(&target); is_armv6m(&target); + if target.starts_with("thumbv") { + cc::Build::new().file("asm.s").compile("asm"); + } + // Put the linker script somewhere the linker can find it let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); File::create(out.join("link.x")) diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x index 1f5fd6f..0fb3592 100644 --- a/cortex-m-rt/link.x +++ b/cortex-m-rt/link.x @@ -1,35 +1,44 @@ /* # Developer notes - Symbols that start with a double underscore (__) are considered "private" + - Symbols that start with a single underscore (_) are considered "semi-public"; they can be overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" { static mut __sbss }`). + - `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a symbol if not dropped if it appears in or near the front of the linker arguments and "it's not needed" by any of the preceding objects (linker arguments) + - `PROVIDE` is used to provide default values that can be overridden by a user linker script + - On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and* the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see "Address (..) is out of bounds" in the disassembly produced by `objdump`. */ +/* Provides information about the memory layout of the device */ +/* This will be provided by the user (see `memory.x`) or by a Board Support Crate */ INCLUDE memory.x + +/* Provides weak aliases (cf. PROVIDED) for device specific interrupt handlers */ +/* This will usually be provided by a device crate generated using svd2rust (see `interrupts.x`) */ INCLUDE interrupts.x -/* # Entry point */ +/* # Entry point = reset vector */ ENTRY(__reset); EXTERN(__RESET_VECTOR); /* depends on the `__reset` symbol */ -EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */ - /* # Exception vectors */ /* This is effectively weak aliasing at the linker level */ /* The user can override any of these aliases by defining the corresponding symbol themselves (cf. the `exception!` macro) */ +EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */ + EXTERN(DefaultHandler); PROVIDE(NMI = DefaultHandler); -PROVIDE(HardFault = DefaultHandler); +EXTERN(HardFault); PROVIDE(MemManage = DefaultHandler); PROVIDE(BusFault = DefaultHandler); PROVIDE(UsageFault = DefaultHandler); @@ -39,7 +48,7 @@ PROVIDE(PendSV = DefaultHandler); PROVIDE(SysTick = DefaultHandler); /* # Interrupt vectors */ -EXTERN(__INTERRUPTS); /* to be provided by the device crate or equivalent */ +EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ /* # User overridable symbols I */ /* Lets the user place the stack in a different RAM region */ @@ -57,15 +66,15 @@ SECTIONS LONG(_stack_start); /* Reset vector */ - KEEP(*(.vector_table.reset_vector)); + KEEP(*(.vector_table.reset_vector)); /* this is `__RESET_VECTOR` symbol */ __reset_vector = ABSOLUTE(.); /* Exceptions */ - KEEP(*(.vector_table.exceptions)); + KEEP(*(.vector_table.exceptions)); /* this is `__EXCEPTIONS` symbol */ __eexceptions = ABSOLUTE(.); /* Device specific interrupts */ - KEEP(*(.vector_table.interrupts)); + KEEP(*(.vector_table.interrupts)); /* this is `__INTERRUPTS` symbol */ __einterrupts = ABSOLUTE(.); } > FLASH @@ -79,7 +88,7 @@ SECTIONS /* ### .rodata */ .rodata : { - . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ + . = ALIGN(4); /* 4-byte align the start (VMA) of this section */ /* __srodata = ABSOLUTE(.); */ *(.rodata .rodata.*); @@ -187,7 +196,7 @@ Set '_stext' to an address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)"); ASSERT(__sgot == __egot, " .got section detected in the input files. Dynamic relocations are not -supported. If you are linking to C code compiled using the `gcc` crate +supported. If you are linking to C code compiled using the `cc` crate then modify your build script to compile the C code _without_ the --fPIC flag. See the documentation of the `gcc::Config.fpic` method for +-fPIC flag. See the documentation of the `cc::Build.pic` method for details."); diff --git a/cortex-m-rt/memory.x b/cortex-m-rt/memory.x new file mode 100644 index 0000000..8027efc --- /dev/null +++ b/cortex-m-rt/memory.x @@ -0,0 +1,19 @@ +/* Device specific memory layout */ + +MEMORY +{ + /* FLASH and RAM are mandatory memory regions */ + FLASH : ORIGIN = 0x08000000, LENGTH = 64K + RAM : ORIGIN = 0x20000000, LENGTH = 20K + + /* More memory regions can declared: for example this is a second RAM region */ + /* CCRAM : ORIGIN = 0x10000000, LENGTH = 8K */ +} + +/* The location of the stack can be overridden using the `_stack_start` symbol. + By default it will be placed at the end of the RAM region */ +/* _stack_start = ORIGIN(CCRAM) + LENGTH(CCRAM); */ + +/* The location of the .text section can be overridden using the `_stext` symbol. + By default it will place after .vector_table */ +/* _stext = ORIGIN(FLASH) + 0x100; */ diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index e0ddb76..128d7b4 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -1,4 +1,16 @@ //! Minimal startup / runtime for Cortex-M microcontrollers +//! +//! TODO +//! +//! # Example +//! +//! # User interface +//! +//! ## `memory.x` +//! +//! ## `interrupts.x` +//! +//! # Diagnostics // # Developer notes // @@ -11,7 +23,32 @@ extern crate r0; +/// Registers stacked (pushed into the stack) during an exception +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub struct ExceptionFrame { + /// (General purpose) Register 0 + pub r0: u32, + /// (General purpose) Register 1 + pub r1: u32, + /// (General purpose) Register 2 + pub r2: u32, + /// (General purpose) Register 3 + pub r3: u32, + /// (General purpose) Register 12 + pub r12: u32, + /// Linker Register + pub lr: u32, + /// Program Counter + pub pc: u32, + /// Program Status Register + pub xpsr: u32, +} + /// Returns a pointer into which the heap can be placed +/// +/// The start of the heap is guaranteed to be 4-byte aligned; that is the pointer returned by this +/// function is a multiple of 4. #[inline] pub fn heap_start() -> *mut u32 { extern "C" { @@ -153,12 +190,12 @@ pub static __EXCEPTIONS: [Option; 14] = [ /// /// Usage: `exception!(ExceptionName, path::to::handler)` /// -/// All exceptions are serviced by the `DefaultHandler` exception handler unless overridden using -/// this macro. `ExceptionName` can be one of are: +/// All exceptions are serviced by the `DefaultHandler` unless overridden using this macro. +/// `ExceptionName` can be one of: /// -/// - `DefaultHandler` (a) -- `fn(u8) -> !` -- the argument is the exception number (VECTACTIVE) +/// - `DefaultHandler` (a) -- `fn(u8)` -- the argument is the exception number (VECTACTIVE) /// - `NMI` -- `fn()` -/// - `HardFault` -- `fn() -> !` +/// - `HardFault` -- `fn(&ExceptionFrame) -> !` /// - `MemManage` -- `fn()` /// - `BusFault` -- `fn()` /// - `UsageFault` -- `fn()` @@ -171,7 +208,6 @@ pub static __EXCEPTIONS: [Option; 14] = [ /// using this macro. /// /// (b) Not available on ARMv6-M -// XXX should we prevent the fault handlers from returning? #[macro_export] macro_rules! exception { (DefaultHandler, $path:path) => { @@ -179,7 +215,7 @@ macro_rules! exception { #[export_name = "DefaultHandler"] pub unsafe extern "C" fn __impl_DefaultHandler() { // validate the signature of the user provided handler - let f: fn(u8) -> ! = $path; + let f: fn(u8) = $path; const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; @@ -191,12 +227,12 @@ macro_rules! exception { (HardFault, $path:path) => { #[allow(non_snake_case)] - #[export_name = "HardFault"] - pub unsafe extern "C" fn __impl_HardFault() { + #[export_name = "UserHardFault"] + pub unsafe extern "C" fn __impl_UserHardFault(ef: &$crate::ExceptionFrame) { // validate the signature of the user provided handler - let f: fn() -> ! = $path; + let f: fn(&$crate::ExceptionFrame) -> ! = $path; - f() + f(ef) } }; -- cgit v1.2.3 From 6dd420ff082b4a9d9151e27d1edf724e416d712b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 26 Apr 2018 05:26:35 +0200 Subject: re-implement interrupt / exception state --- cortex-m-rt/src/lib.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 128d7b4..23cb1d4 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -211,6 +211,7 @@ pub static __EXCEPTIONS: [Option; 14] = [ #[macro_export] macro_rules! exception { (DefaultHandler, $path:path) => { + #[allow(unsafe_code)] #[allow(non_snake_case)] #[export_name = "DefaultHandler"] pub unsafe extern "C" fn __impl_DefaultHandler() { @@ -226,6 +227,7 @@ macro_rules! exception { }; (HardFault, $path:path) => { + #[allow(unsafe_code)] #[allow(non_snake_case)] #[export_name = "UserHardFault"] pub unsafe extern "C" fn __impl_UserHardFault(ef: &$crate::ExceptionFrame) { @@ -238,7 +240,24 @@ macro_rules! exception { // NOTE Unfortunately, this will end up leaking `$exception` into the function call namespace. // But the damage is somewhat reduced by having `$exception` not being a `snake_case` function. + ($ExceptionName:ident, $path:path, state: $State:ty = $init:expr) => { + #[allow(unsafe_code)] + #[no_mangle] + pub unsafe extern "C" fn $ExceptionName() { + static mut STATE: $State = $init; + + // check that this exception exists + let _ = $crate::Exception::$ExceptionName; + + // validate the signature of the user provided handler + let f: fn(&mut $State) = $path; + + f(&mut STATE) + } + }; + ($ExceptionName:ident, $path:path) => { + #[allow(unsafe_code)] #[no_mangle] pub unsafe extern "C" fn $ExceptionName() { // check that this exception exists -- cgit v1.2.3 From 962d91c8be5abb71f5dbd54f6e82ace93fd69474 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 11 May 2018 20:01:54 +0200 Subject: doc up, __reset -> Reset, main! -> entry!, weak syntax of `exception!` .. - remove some variants from `Exception` when targeting ARMv6-M - future proof the ABI of `__EXCEPTIONS` by using a `union` instead of `Option` (the `None` variant is not guaranteed to always be represented as the value `0`) - tweak exception names to match CMSIS and the names used in cortex-m v0.5.0 - add an opt-in "device" feature to opt into a device specific build (interrupts must be supplied by a different crate, or manually by the user). - drop the `interrupts!` macro. If you don't enable the "device" feature `cortex-m-rt` will bind all possible interrupts to the default exception handler. --- cortex-m-rt/Cargo.toml | 3 + cortex-m-rt/asm.s | 2 +- cortex-m-rt/build.rs | 22 +- cortex-m-rt/link.x | 18 +- cortex-m-rt/src/lib.rs | 643 ++++++++++++++++++++++++++++++++++++++++++------- 5 files changed, 580 insertions(+), 108 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 4d5e592..51269af 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -14,3 +14,6 @@ r0 = "0.2.1" [build-dependencies] cc = "1.0.10" + +[features] +device = [] \ No newline at end of file diff --git a/cortex-m-rt/asm.s b/cortex-m-rt/asm.s index 1ad7721..f86b1e2 100644 --- a/cortex-m-rt/asm.s +++ b/cortex-m-rt/asm.s @@ -1,4 +1,4 @@ .global HardFault HardFault: mrs r0, MSP - b UserHardFault + bl UserHardFault diff --git a/cortex-m-rt/build.rs b/cortex-m-rt/build.rs index 70b7a43..1098dca 100644 --- a/cortex-m-rt/build.rs +++ b/cortex-m-rt/build.rs @@ -17,10 +17,24 @@ fn main() { // Put the linker script somewhere the linker can find it let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); - File::create(out.join("link.x")) - .unwrap() - .write_all(include_bytes!("link.x")) - .unwrap(); + let link_x = include_bytes!("link.x"); + if env::var_os("CARGO_FEATURE_DEVICE").is_some() { + let mut f = File::create(out.join("link.x")).unwrap(); + + writeln!( + f, + r#" +/* Provides weak aliases (cf. PROVIDED) for device specific interrupt handlers */ +/* This will usually be provided by a device crate generated using svd2rust (see `device.x`) */ +INCLUDE device.x"# + ).unwrap(); + f.write_all(link_x).unwrap(); + } else { + File::create(out.join("link.x")) + .unwrap() + .write_all(link_x) + .unwrap(); + }; println!("cargo:rustc-link-search={}", out.display()); println!("cargo:rerun-if-changed=build.rs"); diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x index 0fb3592..44c427d 100644 --- a/cortex-m-rt/link.x +++ b/cortex-m-rt/link.x @@ -22,13 +22,9 @@ /* This will be provided by the user (see `memory.x`) or by a Board Support Crate */ INCLUDE memory.x -/* Provides weak aliases (cf. PROVIDED) for device specific interrupt handlers */ -/* This will usually be provided by a device crate generated using svd2rust (see `interrupts.x`) */ -INCLUDE interrupts.x - /* # Entry point = reset vector */ -ENTRY(__reset); -EXTERN(__RESET_VECTOR); /* depends on the `__reset` symbol */ +ENTRY(Reset); +EXTERN(__RESET_VECTOR); /* depends on the `Reset` symbol */ /* # Exception vectors */ /* This is effectively weak aliasing at the linker level */ @@ -37,13 +33,15 @@ EXTERN(__RESET_VECTOR); /* depends on the `__reset` symbol */ EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */ EXTERN(DefaultHandler); -PROVIDE(NMI = DefaultHandler); + +PROVIDE(NonMaskableInt = DefaultHandler); EXTERN(HardFault); -PROVIDE(MemManage = DefaultHandler); +PROVIDE(MemoryManagement = DefaultHandler); PROVIDE(BusFault = DefaultHandler); PROVIDE(UsageFault = DefaultHandler); -PROVIDE(SVC = DefaultHandler); -PROVIDE(DebugMon = DefaultHandler); +PROVIDE(SecureFault = DefaultHandler); +PROVIDE(SVCall = DefaultHandler); +PROVIDE(DebugMonitor = DefaultHandler); PROVIDE(PendSV = DefaultHandler); PROVIDE(SysTick = DefaultHandler); diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 23cb1d4..a5e3856 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -1,20 +1,330 @@ //! Minimal startup / runtime for Cortex-M microcontrollers //! -//! TODO +//! This crate contains all the required parts to build a `no_std` application (binary crate) that +//! targets a Cortex-M microcontroller. +//! +//! # Features +//! +//! This crates takes care of: +//! +//! - The memory layout of the program. In particular, it populates the vector table so the device +//! can boot correctly, and properly dispatch exceptions and interrupts. +//! +//! - Initializing `static` variables before the user entry point. +//! +//! - Enabling the FPU before the user entry point if the target is `thumbv7em-none-eabihf`. +//! +//! This crate also provides a mechanism to set exception handlers: see the [`exception!`] macro. +//! +//! [`exception!`]: macro.exception.html +//! +//! # `memory.x` +//! +//! This crate expects the user, or some other crate, to provide the memory layout of the target +//! device via a linker named `memory.x`. This section covers the contents of `memory.x` +//! +//! ## `MEMORY` +//! +//! The linker script must specify the memory available in the device as, at least, two `MEMORY` +//! regions: one named `FLASH` and one named `RAM`. The `.text` and `.rodata` sections of the +//! program will be placed in the `FLASH` region, whereas the `.bss` and `.data` sections, as well +//! as the heap,will be placed in the `RAM` region. +//! +//! ``` text +//! /* Linker script for the STM32F103C8T6 */ +//! MEMORY +//! { +//! FLASH : ORIGIN = 0x08000000, LENGTH = 64K +//! RAM : ORIGIN = 0x20000000, LENGTH = 20K +//! } +//! ``` +//! +//! ## `_stack_start` +//! +//! This optional symbol can be used to indicate where the call stack of the program should be +//! placed. If this symbol is not used then the stack will be placed at the *end* of the `RAM` +//! region -- the stack grows downwards towards smaller address. This symbol can be used to place +//! the stack in a different memory region, for example: +//! +//! ``` text +//! /* Linker script for the STM32F303VCT6 */ +//! MEMORY +//! { +//! FLASH : ORIGIN = 0x08000000, LENGTH = 256K +//! +//! /* .bss, .data and the heap go in this region */ +//! RAM : ORIGIN = 0x20000000, LENGTH = 40K +//! +//! /* Core coupled (faster) RAM dedicated to hold the stack */ +//! CCRAM : ORIGIN = 0x10000000, LENGTH = 8K +//! } +//! +//! _stack_start = ORIGIN(CCRAM) + LENGTH(CCRAM); +//! ``` +//! +//! ## `_stext` +//! +//! This optional symbol can be used to control where the `.text` section is placed. If omitted the +//! `.text` section will be placed right after the vector table (which is placed at the beginning of +//! `FLASH`). Some devices store settings like Flash configuration right after the vector table; +//! for these devices one must place the `.text` section after this configuration section -- +//! `_stext` can be used for this purpose. +//! +//! ``` text +//! MEMORY +//! { +//! /* .. */ +//! } +//! +//! /* The device stores Flash configuration in 0x400-0x40C so we place .text after that */ +//! _stext = ORIGIN(FLASH) + 0x40C +//! ``` //! //! # Example //! -//! # User interface +//! This section presents a minimal application built on top of `cortex-m-rt`. Apart from the +//! mandatory `memory.x` linker script describing the memory layout of the device, the hard fault +//! handler and the default exception handler must also be defined somewhere in the dependency +//! graph (cf. [`exception!`]). In this example we define them in the binary crate: +//! +//! ``` ignore +//! // IMPORTANT the standard `main` interface is not used because it requires nightly +//! #![no_main] +//! #![no_std] +//! +//! #[macro_use(entry, exception)] +//! extern crate cortex_m_rt as rt; +//! +//! // makes `panic!` print messages to the host stderr using semihosting +//! extern crate panic_semihosting; +//! +//! use rt::ExceptionFrame; +//! +//! // use `main` as the entry point of this application +//! entry!(main); +//! +//! // `main` is not allowed to return +//! fn main() -> ! { +//! // initialization +//! +//! loop { +//! // application logic +//! } +//! } +//! +//! // define the hard fault handler +//! exception!(HardFault, hard_fault); +//! +//! fn hard_fault(ef: &ExceptionFrame) -> ! { +//! panic!("{:#?}", ef); +//! } +//! +//! // define the default exception handler +//! exception!(*, default_handler); +//! +//! fn default_handler(irqn: i16) { +//! panic!("unhandled exception (IRQn={})", irqn); +//! } +//! ``` +//! +//! To actually build this program you need to place a `memory.x` linker script somewhere the linker +//! can find it, e.g. in the current directory; and then link the program using `cortex-m-rt`'s +//! linker script: `link.x`. The required steps are shown below: +//! +//! ``` text +//! $ cat > memory.x <`) may also work but it's not guaranteed that the `None` variant will *always* be +//! represented by the value `0`. +//! +//! Let's illustrate with an artificial example where a device only has two interrupt: `Foo`, with +//! IRQ number = 2, and `Bar`, with IRQ number = 4. +//! +//! ``` ignore +//! union Vector { +//! handler: extern "C" fn(), +//! reserved: usize, +//! } +//! +//! extern "C" { +//! fn Foo(); +//! fn Bar(); +//! } +//! +//! #[link_section = ".vector_table.interrupts"] +//! #[no_mangle] +//! pub static __INTERRUPTS: [Vector; 5] = [ +//! // 0-1: Reserved +//! Vector { reserved: 0 }, +//! Vector { reserved: 0 }, +//! +//! // 2: Foo +//! Vector { handler: Foo }, +//! +//! // 3: Reserved +//! Vector { reserved: 0 }, +//! +//! // 4: Bar +//! Vector { handler: Bar }, +//! ]; +//! ``` +//! +//! ## `device.x` +//! +//! Linking in `__INTERRUPTS` creates a bunch of undefined references. If the user doesn't set a +//! handler for *all* the device specific interrupts then linking will fail with `"undefined +//! reference"` errors. +//! +//! We want to provide a default handler for all the interrupts while still letting the user +//! individually override each interrupt handler. In C projects, this is usually accomplished using +//! weak aliases declared in external assembly files. In Rust, we could achieve something similar +//! using `global_asm!`, but that's an unstable feature. +//! +//! A solution that doesn't require `global_asm!` or external assembly files is to use the `PROVIDE` +//! command in a linker script to create the weak aliases. This is the approach that `cortex-m-rt` +//! uses; when the `"device"` feature is enabled `cortex-m-rt`'s linker script (`link.x`) depends on +//! a linker script named `device.x`. The crate that provides `__INTERRUPTS` must also provide this +//! file. +//! +//! For our running example the `device.x` linker script looks like this: +//! +//! ``` text +//! /* device.x */ +//! PROVIDE(Foo = DefaultHandler); +//! PROVIDE(Bar = DefaultHandler); +//! ``` //! -//! ## `memory.x` +//! This weakly aliases both `Foo` and `Bar`. `DefaultHandler` is the default exception handler that +//! the user provides via `exception!(*, ..)` and that the core exceptions use unless overridden. //! -//! ## `interrupts.x` +//! Because this linker script is provided by a dependency of the final application the dependency +//! must contain build script that puts `device.x` somewhere the linker can find. An example of such +//! build script is shown below: //! -//! # Diagnostics +//! ``` ignore +//! use std::env; +//! use std::fs::File; +//! use std::io::Write; +//! use std::path::PathBuf; +//! +//! fn main() { +//! // Put the linker script somewhere the linker can find it +//! let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); +//! File::create(out.join("device.x")) +//! .unwrap() +//! .write_all(include_bytes!("device.x")) +//! .unwrap(); +//! println!("cargo:rustc-link-search={}", out.display()); +//! } +//! ``` // # Developer notes // -// - `link_section` is used to place symbols in specific places if the final binary. The names used +// - `link_section` is used to place symbols in specific places of the final binary. The names used // here will appear in the linker script (`link.x`) in conjunction with the `KEEP` command. #![deny(missing_docs)] @@ -62,13 +372,13 @@ pub fn heap_start() -> *mut u32 { #[doc(hidden)] #[link_section = ".vector_table.reset_vector"] #[no_mangle] -pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = __reset; +pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = Reset; #[doc(hidden)] #[no_mangle] -pub unsafe extern "C" fn __reset() -> ! { +pub unsafe extern "C" fn Reset() -> ! { extern "C" { - // This symbol will be provided by the user via the `main!` macro + // This symbol will be provided by the user via the `entry!` macro fn main() -> !; // These symbols come from `link.x` @@ -105,7 +415,7 @@ pub unsafe extern "C" fn __reset() -> ! { // before enabling the FPU, and that would produce a hard to diagnose hard fault at // runtime. #[inline(never)] - #[export_name = "__reset_trampoline"] + #[export_name = "ResetTrampoline"] fn trampoline() -> ! { unsafe { main() } } @@ -117,13 +427,15 @@ pub unsafe extern "C" fn __reset() -> ! { /// Macro to define the user entry point of a program /// -/// Usage: `main!(path::to::user::main)` +/// Usage: `entry!($path::to::user::entry)` +/// +/// The specified function will be called by the reset handler *after* RAM has been initialized. In +/// the case of the `thumbv7em-none-eabihf` target the FPU will also be enabled before the function +/// is called. /// -/// This function will be called by the reset handler *after* RAM has been initialized. In the case -/// of the `thumbv7em-none-eabihf` target the FPU will also be enabled before the user `main` is -/// called. +/// The signature of the specified function must be `fn() -> !` (never ending function) #[macro_export] -macro_rules! main { +macro_rules! entry { ($path:path) => { #[export_name = "main"] pub extern "C" fn __impl_main() -> ! { @@ -136,156 +448,301 @@ macro_rules! main { } /* Exceptions */ -// NOTE we purposefully go against Rust style here and use PascalCase for the handlers. The -// rationale is in the definition of the `exception!` macro. #[doc(hidden)] pub enum Exception { - NMI, - MemManage, + NonMaskableInt, + + // Not overridable + // HardFault, + #[cfg(not(armv6m))] + MemoryManagement, + + #[cfg(not(armv6m))] BusFault, + + #[cfg(not(armv6m))] UsageFault, - SVC, - DebugMon, + + #[cfg(armv8m)] + SecureFault, + + SVCall, + + #[cfg(not(armv6m))] + DebugMonitor, + PendSV, + SysTick, } extern "C" { - fn NMI(); + fn NonMaskableInt(); + fn HardFault(); - fn MemManage(); + + #[cfg(not(armv6m))] + fn MemoryManagement(); + + #[cfg(not(armv6m))] fn BusFault(); + + #[cfg(not(armv6m))] fn UsageFault(); - fn SVC(); + + #[cfg(armv8m)] + fn SecureFault(); + + fn SVCall(); + #[cfg(not(armv6m))] - fn DebugMon(); + fn DebugMonitor(); + fn PendSV(); + fn SysTick(); } +#[doc(hidden)] +pub union Vector { + handler: unsafe extern "C" fn(), + reserved: usize, +} + #[doc(hidden)] #[link_section = ".vector_table.exceptions"] #[no_mangle] -pub static __EXCEPTIONS: [Option; 14] = [ - Some(NMI), - Some(HardFault), - Some(MemManage), - Some(BusFault), - Some(UsageFault), - None, - None, - None, - None, - Some(SVC), +pub static __EXCEPTIONS: [Vector; 14] = [ + // Exception 2: Non Maskable Interrupt. + Vector { + handler: NonMaskableInt, + }, + // Exception 3: Hard Fault Interrupt. + Vector { handler: HardFault }, + // Exception 4: Memory Management Interrupt [not on Cortex-M0 variants]. + #[cfg(not(armv6m))] + Vector { + handler: MemoryManagement, + }, + #[cfg(armv6m)] + Vector { reserved: 0 }, + // Exception 5: Bus Fault Interrupt [not on Cortex-M0 variants]. + #[cfg(not(armv6m))] + Vector { handler: BusFault }, + #[cfg(armv6m)] + Vector { reserved: 0 }, + // Exception 6: Usage Fault Interrupt [not on Cortex-M0 variants]. + #[cfg(not(armv6m))] + Vector { + handler: UsageFault, + }, #[cfg(armv6m)] - None, + Vector { reserved: 0 }, + // Exception 7: Secure Fault Interrupt [only on Armv8-M]. + #[cfg(armv8m)] + Vector { + handler: SecureFault, + }, + #[cfg(not(armv8m))] + Vector { reserved: 0 }, + // 8-10: Reserved + Vector { reserved: 0 }, + Vector { reserved: 0 }, + Vector { reserved: 0 }, + // Exception 11: SV Call Interrupt. + Vector { handler: SVCall }, + // Exception 12: Debug Monitor Interrupt [not on Cortex-M0 variants]. #[cfg(not(armv6m))] - Some(DebugMon), - None, - Some(PendSV), - Some(SysTick), + Vector { + handler: DebugMonitor, + }, + #[cfg(armv6m)] + Vector { reserved: 0 }, + // 13: Reserved + Vector { reserved: 0 }, + // Exception 14: Pend SV Interrupt [not on Cortex-M0 variants]. + #[cfg(not(armv6m))] + Vector { handler: PendSV }, + #[cfg(armv6m)] + Vector { reserved: 0 }, + // Exception 15: System Tick Interrupt. + Vector { handler: SysTick }, ]; -/// Macro to override an exception handler +// If we are not targeting a specific device we bind all the potential device specific interrupts +// to the default handler +#[cfg(not(feature = "device"))] +#[doc(hidden)] +#[link_section = ".vector_table.interrupts"] +#[no_mangle] +pub static __INTERRUPTS: [unsafe extern "C" fn(); 240] = [{ + extern "C" { + fn DefaultHandler(); + } + + DefaultHandler +}; 240]; + +/// Macro to set or override a processor core exception handler +/// +/// # Syntax +/// +/// ``` ignore +/// exception!( +/// // Name of the exception +/// $Name:ident, +/// +/// // Path to the exception handler (a function) +/// $handler:path, +/// +/// // Optional, state preserved across invocations of the handler +/// state: $State:ty = $initial_state:expr, +/// ); +/// ``` +/// +/// `$Name` can be one of: +/// +/// - `*` +/// - `NonMaskableInt` +/// - `HardFault` +/// - `MemoryManagement` (a) +/// - `BusFault` (a) +/// - `UsageFault` (a) +/// - `SecureFault` (b) +/// - `SVCall` +/// - `DebugMonitor` (a) +/// - `PendSV` +/// - `SysTick` +/// +/// (a) Not available on Cortex-M0 variants (`thumbv6m-none-eabi`) +/// +/// (b) Only available on ARMv8-M +/// +/// `exception!(HardFault, ..)` sets the hard fault handler. The handler must have signature +/// `fn(&ExceptionFrame) -> !`. This handler is not allowed to return as that can cause undefined +/// behavior. It's mandatory to set the `HardFault` handler somewhere in the dependency graph of an +/// application. +/// +/// `exception!(*, ..)` sets the *default* handler. All exceptions which have not been assigned a +/// handler will be serviced by this handler. This handler must have signature `fn(irqn: i16)`. +/// `irqn` is the IRQ number (cf. CMSIS); `irqn` will be a negative number when the handler is +/// servicing a core exception; `irqn` will be a positive number when the handler is servicing a +/// device specific exception (interrupt). It's mandatory to set the default handler somewhere +/// in the dependency graph of an application. +/// +/// `exception!($Exception, ..)` overrides the default handler for `$Exception`. All exceptions, +/// except for `HardFault`, can be assigned some `$State`. +/// +/// # Examples +/// +/// Setting the `HardFault` handler +/// +/// ``` +/// #[macro_use(exception)] +/// extern crate cortex_m_rt as rt; /// -/// Usage: `exception!(ExceptionName, path::to::handler)` +/// use rt::ExceptionFrame; /// -/// All exceptions are serviced by the `DefaultHandler` unless overridden using this macro. -/// `ExceptionName` can be one of: +/// exception!(HardFault, hard_fault); /// -/// - `DefaultHandler` (a) -- `fn(u8)` -- the argument is the exception number (VECTACTIVE) -/// - `NMI` -- `fn()` -/// - `HardFault` -- `fn(&ExceptionFrame) -> !` -/// - `MemManage` -- `fn()` -/// - `BusFault` -- `fn()` -/// - `UsageFault` -- `fn()` -/// - `SVC` -- `fn()` -/// - `DebugMon` (b) -- `fn()` -/// - `PendSV` -- `fn()` -/// - `SysTick` -- `fn()` +/// fn hard_fault(ef: &ExceptionFrame) -> ! { +/// // prints the exception frame as a panic message +/// panic!("{:#?}", ef); +/// } /// -/// (a) Note that `DefaultHandler` is left undefined and *must* be defined by the user somewhere -/// using this macro. +/// # fn main() {} +/// ``` /// -/// (b) Not available on ARMv6-M +/// Setting the default handler +/// +/// ``` +/// #[macro_use(exception)] +/// extern crate cortex_m_rt as rt; +/// +/// exception!(*, default_handler); +/// +/// fn default_handler(irqn: i16) { +/// println!("IRQn = {}", irqn); +/// } +/// +/// # fn main() {} +/// ``` +/// +/// Overriding the `SysTick` handler +/// +/// ``` +/// #[macro_use(exception)] +/// extern crate cortex_m_rt as rt; +/// +/// exception!(SysTick, sys_tick, state: u32 = 0); +/// +/// fn sys_tick(count: &mut u32) { +/// println!("count = {}", *count); +/// +/// *count += 1; +/// } +/// +/// # fn main() {} +/// ``` #[macro_export] macro_rules! exception { - (DefaultHandler, $path:path) => { + (* , $handler:path) => { #[allow(unsafe_code)] #[allow(non_snake_case)] #[export_name = "DefaultHandler"] pub unsafe extern "C" fn __impl_DefaultHandler() { + extern crate core; + // validate the signature of the user provided handler - let f: fn(u8) = $path; + let f: fn(i16) = $handler; const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; // NOTE not volatile so the compiler can opt the load operation away if the value is // unused - f(core::ptr::read(SCB_ICSR) as u8) + f(core::ptr::read(SCB_ICSR) as i16 - 16) } }; - (HardFault, $path:path) => { + (HardFault, $handler:path) => { #[allow(unsafe_code)] #[allow(non_snake_case)] #[export_name = "UserHardFault"] pub unsafe extern "C" fn __impl_UserHardFault(ef: &$crate::ExceptionFrame) { // validate the signature of the user provided handler - let f: fn(&$crate::ExceptionFrame) -> ! = $path; + let f: fn(&$crate::ExceptionFrame) -> ! = $handler; f(ef) } }; - // NOTE Unfortunately, this will end up leaking `$exception` into the function call namespace. - // But the damage is somewhat reduced by having `$exception` not being a `snake_case` function. - ($ExceptionName:ident, $path:path, state: $State:ty = $init:expr) => { + ($Name:ident, $handler:path,state: $State:ty = $initial_state:expr) => { #[allow(unsafe_code)] #[no_mangle] - pub unsafe extern "C" fn $ExceptionName() { - static mut STATE: $State = $init; + pub unsafe extern "C" fn $Name() { + static mut STATE: $State = $initial_state; // check that this exception exists - let _ = $crate::Exception::$ExceptionName; + let _ = $crate::Exception::$Name; // validate the signature of the user provided handler - let f: fn(&mut $State) = $path; + let f: fn(&mut $State) = $handler; f(&mut STATE) } }; - ($ExceptionName:ident, $path:path) => { + ($Name:ident, $handler:path) => { #[allow(unsafe_code)] #[no_mangle] - pub unsafe extern "C" fn $ExceptionName() { + pub unsafe extern "C" fn $Name() { // check that this exception exists - let _ = $crate::Exception::$ExceptionName; + let _ = $crate::Exception::$Name; // validate the signature of the user provided handler - let f: fn() = $path; + let f: fn() = $handler; f() } }; } - -/// Macro to bind all the 240 interrupt handlers to the `DefaultHandler` exception handler. -/// -/// The use case for this macro is writing device agnostic programs -#[macro_export] -macro_rules! interrupts { - (DefaultHandler) => { - #[doc(hidden)] - #[link_section = ".vector_table.interrupts"] - #[no_mangle] - pub static __INTERRUPTS: [Option; 240] = [{ - extern "C" { - fn DefaultHandler(); - } - - Some(DefaultHandler) - }; 240]; - }; -} -- cgit v1.2.3 From 7719662f287a8fc184b59822fb90d2297a72ea15 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 11 May 2018 20:59:18 +0200 Subject: ARMv6-M can only have 32 interrupts --- cortex-m-rt/src/lib.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index a5e3856..4bb5fe1 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -571,7 +571,7 @@ pub static __EXCEPTIONS: [Vector; 14] = [ // If we are not targeting a specific device we bind all the potential device specific interrupts // to the default handler -#[cfg(not(feature = "device"))] +#[cfg(all(not(feature = "device"), not(armv6m)))] #[doc(hidden)] #[link_section = ".vector_table.interrupts"] #[no_mangle] @@ -583,6 +583,19 @@ pub static __INTERRUPTS: [unsafe extern "C" fn(); 240] = [{ DefaultHandler }; 240]; +// ARMv6-M can only have a maximum of 32 device specific interrupts +#[cfg(all(not(feature = "device"), armv6m))] +#[doc(hidden)] +#[link_section = ".vector_table.interrupts"] +#[no_mangle] +pub static __INTERRUPTS: [unsafe extern "C" fn(); 32] = [{ + extern "C" { + fn DefaultHandler(); + } + + DefaultHandler +}; 32]; + /// Macro to set or override a processor core exception handler /// /// # Syntax -- cgit v1.2.3 From c3dbc7225d666043a57ca0cb36b32e938a06c7e6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 11 May 2018 22:24:37 +0200 Subject: add CI, add device specific check of the vector table size, .. - document the `main` symbol as an alternative to `entry!` - document `ResetTrampoline` - fix: `PendSV` is available on ARMv6-M - document that `entry!` and `exception!` must be called from accessible modules. - add a deny lint to `entry!` and `exception!` to prevent them from being invoked from inaccessible modules. --- cortex-m-rt/.travis.yml | 85 +++++++++++++++++ cortex-m-rt/Cargo.toml | 9 +- cortex-m-rt/bors.toml | 3 + cortex-m-rt/build.rs | 35 +++++-- cortex-m-rt/ci/install.sh | 9 ++ cortex-m-rt/ci/script.sh | 34 +++++++ cortex-m-rt/device.x | 3 + cortex-m-rt/examples/device.rs | 50 ++++++++++ cortex-m-rt/examples/main.rs | 28 ++++++ cortex-m-rt/examples/minimal.rs | 31 +++++++ cortex-m-rt/examples/state.rs | 38 ++++++++ cortex-m-rt/link.x | 200 ---------------------------------------- cortex-m-rt/link.x.in | 196 +++++++++++++++++++++++++++++++++++++++ cortex-m-rt/memory.x | 2 +- cortex-m-rt/src/lib.rs | 78 ++++++++++++---- 15 files changed, 570 insertions(+), 231 deletions(-) create mode 100644 cortex-m-rt/.travis.yml create mode 100644 cortex-m-rt/bors.toml create mode 100644 cortex-m-rt/ci/install.sh create mode 100644 cortex-m-rt/ci/script.sh create mode 100644 cortex-m-rt/device.x create mode 100644 cortex-m-rt/examples/device.rs create mode 100644 cortex-m-rt/examples/main.rs create mode 100644 cortex-m-rt/examples/minimal.rs create mode 100644 cortex-m-rt/examples/state.rs delete mode 100644 cortex-m-rt/link.x create mode 100644 cortex-m-rt/link.x.in (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/.travis.yml b/cortex-m-rt/.travis.yml new file mode 100644 index 0000000..518037d --- /dev/null +++ b/cortex-m-rt/.travis.yml @@ -0,0 +1,85 @@ +language: rust + +matrix: + include: + - env: TARGET=x86_64-unknown-linux-gnu + + - env: TARGET=thumbv6m-none-eabi + rust: beta + addons: + apt: + packages: + - gcc-arm-none-eabi + + - env: TARGET=thumbv7m-none-eabi + rust: beta + addons: + apt: + packages: + - gcc-arm-none-eabi + + - env: TARGET=thumbv7em-none-eabi + rust: beta + addons: + apt: + packages: + - gcc-arm-none-eabi + + - env: TARGET=thumbv7em-none-eabihf + rust: beta + addons: + apt: + packages: + - gcc-arm-none-eabi + + - env: TARGET=thumbv6m-none-eabi + rust: nightly + addons: + apt: + packages: + - gcc-arm-none-eabi + + - env: TARGET=thumbv7m-none-eabi + rust: nightly + addons: + apt: + packages: + - gcc-arm-none-eabi + + - env: TARGET=thumbv7em-none-eabi + rust: nightly + addons: + apt: + packages: + - gcc-arm-none-eabi + + - env: TARGET=thumbv7em-none-eabihf + rust: nightly + addons: + apt: + packages: + - gcc-arm-none-eabi + +before_install: set -e + +install: + - bash ci/install.sh + +script: + - bash ci/script.sh + +after_script: set +e + +cache: cache + +before_cache: + - chmod -R a+r $HOME/.cargo; + +branches: + only: + - staging + - trying + +notifications: + email: + on_success: never diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 51269af..460917b 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -9,11 +9,14 @@ name = "cortex-m-rt" repository = "https://github.com/japaric/cortex-m-rt" version = "0.5.0" +[build-dependencies] +cc = "1.0.10" + [dependencies] r0 = "0.2.1" -[build-dependencies] -cc = "1.0.10" +[dev-dependencies] +panic-semihosting = "0.2.0" [features] -device = [] \ No newline at end of file +device = [] diff --git a/cortex-m-rt/bors.toml b/cortex-m-rt/bors.toml new file mode 100644 index 0000000..5ccee21 --- /dev/null +++ b/cortex-m-rt/bors.toml @@ -0,0 +1,3 @@ +status = [ + "continuous-integration/travis-ci/push", +] \ No newline at end of file diff --git a/cortex-m-rt/build.rs b/cortex-m-rt/build.rs index 1098dca..1b5c3d1 100644 --- a/cortex-m-rt/build.rs +++ b/cortex-m-rt/build.rs @@ -9,7 +9,7 @@ fn main() { let target = env::var("TARGET").unwrap(); has_fpu(&target); - is_armv6m(&target); + let is_armv6m = is_armv6m(&target); if target.starts_with("thumbv") { cc::Build::new().file("asm.s").compile("asm"); @@ -17,8 +17,8 @@ fn main() { // Put the linker script somewhere the linker can find it let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); - let link_x = include_bytes!("link.x"); - if env::var_os("CARGO_FEATURE_DEVICE").is_some() { + let link_x = include_bytes!("link.x.in"); + let mut f = if env::var_os("CARGO_FEATURE_DEVICE").is_some() { let mut f = File::create(out.join("link.x")).unwrap(); writeln!( @@ -29,12 +29,28 @@ fn main() { INCLUDE device.x"# ).unwrap(); f.write_all(link_x).unwrap(); + f } else { - File::create(out.join("link.x")) - .unwrap() - .write_all(link_x) - .unwrap(); + let mut f = File::create(out.join("link.x")).unwrap(); + f.write_all(link_x).unwrap(); + f }; + + let max_int_handlers = if is_armv6m { 32 } else { 240 }; + + // checking the size of the interrupts portion of the vector table is sub-architecture dependent + writeln!( + f, + r#" +ASSERT(__einterrupts - __eexceptions <= 0x{:x}, " +There can't be more than {} interrupt handlers. This may be a bug in +your device crate, or you may have registered more than 240 interrupt +handlers."); +"#, + max_int_handlers * 4, + max_int_handlers + ).unwrap(); + println!("cargo:rustc-link-search={}", out.display()); println!("cargo:rerun-if-changed=build.rs"); @@ -47,8 +63,11 @@ fn has_fpu(target: &str) { } } -fn is_armv6m(target: &str) { +fn is_armv6m(target: &str) -> bool { if target.starts_with("thumbv6m-") { println!("cargo:rustc-cfg=armv6m"); + true + } else { + false } } diff --git a/cortex-m-rt/ci/install.sh b/cortex-m-rt/ci/install.sh new file mode 100644 index 0000000..3c41921 --- /dev/null +++ b/cortex-m-rt/ci/install.sh @@ -0,0 +1,9 @@ +set -euxo pipefail + +main() { + if [ $TARGET != x86_64-unknown-linux-gnu ]; then + rustup target add $TARGET + fi +} + +main diff --git a/cortex-m-rt/ci/script.sh b/cortex-m-rt/ci/script.sh new file mode 100644 index 0000000..221386d --- /dev/null +++ b/cortex-m-rt/ci/script.sh @@ -0,0 +1,34 @@ +set -euxo pipefail + +main() { + cargo check --target $TARGET + + cargo check --target $TARGET --features device + + local examples=( + minimal + main + state + ) + if [ $TRAVIS_RUST_VERSION = nightly ]; then + for ex in "${examples[@]}"; do + cargo rustc --target $TARGET --example $ex -- \ + -C link-arg=-nostartfiles \ + -C link-arg=-Wl,-Tlink.x + + cargo rustc --target $TARGET --example $ex --release -- \ + -C link-arg=-nostartfiles \ + -C link-arg=-Wl,-Tlink.x + done + + cargo rustc --target $TARGET --example device --features device -- \ + -C link-arg=-nostartfiles \ + -C link-arg=-Wl,-Tlink.x + + cargo rustc --target $TARGET --example device --features device --release -- \ + -C link-arg=-nostartfiles \ + -C link-arg=-Wl,-Tlink.x + fi +} + +main diff --git a/cortex-m-rt/device.x b/cortex-m-rt/device.x new file mode 100644 index 0000000..28f975e --- /dev/null +++ b/cortex-m-rt/device.x @@ -0,0 +1,3 @@ +/* Sample device.x file */ +PROVIDE(WWDG = DefaultHandler); +PROVIDE(PVD = DefaultHandler); diff --git a/cortex-m-rt/examples/device.rs b/cortex-m-rt/examples/device.rs new file mode 100644 index 0000000..cf91f21 --- /dev/null +++ b/cortex-m-rt/examples/device.rs @@ -0,0 +1,50 @@ +//! Manually create the interrupts portion of the vector table + +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +#[macro_use(entry, exception)] +extern crate cortex_m_rt as rt; +extern crate panic_semihosting; + +use rt::ExceptionFrame; + +// the program entry point +entry!(main); + +fn main() -> ! { + loop {} +} + +// the hard fault handler +exception!(HardFault, hard_fault); + +fn hard_fault(_ef: &ExceptionFrame) -> ! { + loop {} +} + +// the default exception handler +exception!(*, default_handler); + +fn default_handler(_irqn: i16) {} + +// interrupts portion of the vector table +pub union Vector { + handler: unsafe extern "C" fn(), + reserved: usize, +} + +extern "C" { + fn WWDG(); + fn PVD(); +} + +#[link_section = ".vector_table.interrupts"] +#[no_mangle] +pub static __INTERRUPTS: [Vector; 3] = [ + Vector { handler: WWDG }, + Vector { reserved: 0 }, + Vector { handler: PVD }, +]; diff --git a/cortex-m-rt/examples/main.rs b/cortex-m-rt/examples/main.rs new file mode 100644 index 0000000..d319249 --- /dev/null +++ b/cortex-m-rt/examples/main.rs @@ -0,0 +1,28 @@ +//! Directly plug a `main` symbol instead of using `entry!` + +#![deny(warnings)] +#![no_main] +#![no_std] + +#[macro_use(exception)] +extern crate cortex_m_rt as rt; +extern crate panic_semihosting; + +use rt::ExceptionFrame; + +#[no_mangle] +pub unsafe extern "C" fn main() -> ! { + loop {} +} + +// the hard fault handler +exception!(HardFault, hard_fault); + +fn hard_fault(_ef: &ExceptionFrame) -> ! { + loop {} +} + +// the default exception handler +exception!(*, default_handler); + +fn default_handler(_irqn: i16) {} diff --git a/cortex-m-rt/examples/minimal.rs b/cortex-m-rt/examples/minimal.rs new file mode 100644 index 0000000..c12d12d --- /dev/null +++ b/cortex-m-rt/examples/minimal.rs @@ -0,0 +1,31 @@ +//! Minimal `cortex-m-rt` based program + +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +#[macro_use(entry, exception)] +extern crate cortex_m_rt as rt; +extern crate panic_semihosting; + +use rt::ExceptionFrame; + +// the program entry point +entry!(main); + +fn main() -> ! { + loop {} +} + +// the hard fault handler +exception!(HardFault, hard_fault); + +fn hard_fault(_ef: &ExceptionFrame) -> ! { + loop {} +} + +// the default exception handler +exception!(*, default_handler); + +fn default_handler(_irqn: i16) {} diff --git a/cortex-m-rt/examples/state.rs b/cortex-m-rt/examples/state.rs new file mode 100644 index 0000000..0b5eeeb --- /dev/null +++ b/cortex-m-rt/examples/state.rs @@ -0,0 +1,38 @@ +//! Preserving state across executions of an exception handler + +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +#[macro_use(entry, exception)] +extern crate cortex_m_rt as rt; +extern crate panic_semihosting; + +use rt::ExceptionFrame; + +// the program entry point +entry!(main); + +fn main() -> ! { + loop {} +} + +// exception handler with state +exception!(SysTick, sys_tick, state: u32 = 0); + +fn sys_tick(state: &mut u32) { + *state += 1; +} + +// the hard fault handler +exception!(HardFault, hard_fault); + +fn hard_fault(_ef: &ExceptionFrame) -> ! { + loop {} +} + +// the default exception handler +exception!(*, default_handler); + +fn default_handler(_irqn: i16) {} diff --git a/cortex-m-rt/link.x b/cortex-m-rt/link.x deleted file mode 100644 index 44c427d..0000000 --- a/cortex-m-rt/link.x +++ /dev/null @@ -1,200 +0,0 @@ -/* # Developer notes - -- Symbols that start with a double underscore (__) are considered "private" - -- Symbols that start with a single underscore (_) are considered "semi-public"; they can be - overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" { - static mut __sbss }`). - -- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a - symbol if not dropped if it appears in or near the front of the linker arguments and "it's not - needed" by any of the preceding objects (linker arguments) - -- `PROVIDE` is used to provide default values that can be overridden by a user linker script - -- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and* - the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization - routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see - "Address (..) is out of bounds" in the disassembly produced by `objdump`. -*/ - -/* Provides information about the memory layout of the device */ -/* This will be provided by the user (see `memory.x`) or by a Board Support Crate */ -INCLUDE memory.x - -/* # Entry point = reset vector */ -ENTRY(Reset); -EXTERN(__RESET_VECTOR); /* depends on the `Reset` symbol */ - -/* # Exception vectors */ -/* This is effectively weak aliasing at the linker level */ -/* The user can override any of these aliases by defining the corresponding symbol themselves (cf. - the `exception!` macro) */ -EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */ - -EXTERN(DefaultHandler); - -PROVIDE(NonMaskableInt = DefaultHandler); -EXTERN(HardFault); -PROVIDE(MemoryManagement = DefaultHandler); -PROVIDE(BusFault = DefaultHandler); -PROVIDE(UsageFault = DefaultHandler); -PROVIDE(SecureFault = DefaultHandler); -PROVIDE(SVCall = DefaultHandler); -PROVIDE(DebugMonitor = DefaultHandler); -PROVIDE(PendSV = DefaultHandler); -PROVIDE(SysTick = DefaultHandler); - -/* # Interrupt vectors */ -EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ - -/* # User overridable symbols I */ -/* Lets the user place the stack in a different RAM region */ -PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM)); - -/* # Sections */ -SECTIONS -{ - /* ## Sections in FLASH */ - /* ### Vector table */ - .vector_table ORIGIN(FLASH) : ALIGN(4) - { - /* Initial Stack Pointer (SP) value */ - __STACK_START = .; /* Just to get a nicer name in the disassembly */ - LONG(_stack_start); - - /* Reset vector */ - KEEP(*(.vector_table.reset_vector)); /* this is `__RESET_VECTOR` symbol */ - __reset_vector = ABSOLUTE(.); - - /* Exceptions */ - KEEP(*(.vector_table.exceptions)); /* this is `__EXCEPTIONS` symbol */ - __eexceptions = ABSOLUTE(.); - - /* Device specific interrupts */ - KEEP(*(.vector_table.interrupts)); /* this is `__INTERRUPTS` symbol */ - __einterrupts = ABSOLUTE(.); - } > FLASH - - /* ### .text */ - .text _stext : - { - *(.text .text.*); - __etext = ABSOLUTE(.); - } > FLASH - - /* ### .rodata */ - .rodata : - { - . = ALIGN(4); /* 4-byte align the start (VMA) of this section */ - /* __srodata = ABSOLUTE(.); */ - - *(.rodata .rodata.*); - - . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ - __erodata = ABSOLUTE(.); - } > FLASH - - /* ## Sections in RAM */ - /* ### .data */ - .data : AT(__erodata) /* LMA */ - { - . = ALIGN(4); /* 4-byte align the start (VMA) of this section */ - __sdata = ABSOLUTE(.); - - *(.data .data.*); - - . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ - __edata = ABSOLUTE(.); - } > RAM - - /* ### .bss */ - .bss : - { - . = ALIGN(4); /* 4-byte align the start (VMA) of this section */ - __sbss = ABSOLUTE(.); - - *(.bss .bss.*); - - . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ - __ebss = ABSOLUTE(.); - } > RAM - - /* ## Fake output .got section */ - /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in - the input files and raise an error if relocatable code is found */ - .got : - { - __sgot = ABSOLUTE(.); - KEEP(*(.got .got.*)); - __egot = ABSOLUTE(.); - } > FLASH - - /* ## Discarded sections */ - /DISCARD/ : - { - /* Unused exception related info that only wastes space */ - *(.ARM.exidx.*); - } -} - -/* # User overridable symbols II */ -/* (The user overridable symbols are split in two parts because LLD demands that the RHS of PROVIDE - to be defined before the PROVIDE invocation) */ -/* Lets the user override this to place .text a bit further than the vector table. Required by -microcontrollers that store their configuration right after the vector table. */ -PROVIDE(_stext = __einterrupts); - -/* # Hardcoded symbols */ -/* Place `.bss` at the start of the RAM region */ -__sidata = LOADADDR(.data); -/* Place the heap right after `.bss` and `.data` */ -__sheap = __edata; - -/* # Sanity checks */ - -/* Do not exceed this mark in the error messages below | */ -ASSERT(__reset_vector == ORIGIN(FLASH) + 0x8, -"Reset vector is missing. This is a cortex-m-rt bug. -Please file a bug report at: -https://github.com/japaric/cortex-m-rt/issues"); - -ASSERT(__eexceptions - ORIGIN(FLASH) == 0x40, " -The exception handlers are missing. This is a cortex-m-rt bug. -Please file a bug report at: -https://github.com/japaric/cortex-m-rt/issues"); - -ASSERT(__einterrupts - __eexceptions > 0, " -The interrupt handlers are missing. If you are not linking to a device -crate then you supply the interrupt handlers yourself. Check the -documentation."); - -ASSERT(__einterrupts - __eexceptions <= 0x3c0, " -There can't be more than 240 interrupt handlers. This may be a bug in -your device crate, or you may have registered more than 240 interrupt -handlers."); - -ASSERT(__einterrupts <= _stext, " -The '.text' section can't be placed inside '.vector_table' section. -Set '_stext' to an address greater than '__einterrupts'"); - -ASSERT(_stext < ORIGIN(FLASH) + LENGTH(FLASH), " -The '.text' section must be placed inside the FLASH memory -Set '_stext' to an address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)"); - -/* This has been temporarily omitted because it's not supported by LLD */ -/* ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, " */ -/* .bss is not 4-byte aligned at its boundaries. This is a cortex-m-rt bug."); */ - -/* ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, " */ -/* .data is not 4-byte aligned at its boundaries. This is a cortex-m-rt bug."); */ - -/* ASSERT(__sidata % 4 == 0, " */ -/* __sidata is not 4-byte aligned. This is a cortex-m-rt bug."); */ - -ASSERT(__sgot == __egot, " -.got section detected in the input files. Dynamic relocations are not -supported. If you are linking to C code compiled using the `cc` crate -then modify your build script to compile the C code _without_ the --fPIC flag. See the documentation of the `cc::Build.pic` method for -details."); diff --git a/cortex-m-rt/link.x.in b/cortex-m-rt/link.x.in new file mode 100644 index 0000000..0e68199 --- /dev/null +++ b/cortex-m-rt/link.x.in @@ -0,0 +1,196 @@ +/* # Developer notes + +- Symbols that start with a double underscore (__) are considered "private" + +- Symbols that start with a single underscore (_) are considered "semi-public"; they can be + overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" { + static mut __sbss }`). + +- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a + symbol if not dropped if it appears in or near the front of the linker arguments and "it's not + needed" by any of the preceding objects (linker arguments) + +- `PROVIDE` is used to provide default values that can be overridden by a user linker script + +- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and* + the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization + routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see + "Address (..) is out of bounds" in the disassembly produced by `objdump`. +*/ + +/* Provides information about the memory layout of the device */ +/* This will be provided by the user (see `memory.x`) or by a Board Support Crate */ +INCLUDE memory.x + +/* # Entry point = reset vector */ +ENTRY(Reset); +EXTERN(__RESET_VECTOR); /* depends on the `Reset` symbol */ + +/* # Exception vectors */ +/* This is effectively weak aliasing at the linker level */ +/* The user can override any of these aliases by defining the corresponding symbol themselves (cf. + the `exception!` macro) */ +EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */ + +EXTERN(DefaultHandler); + +PROVIDE(NonMaskableInt = DefaultHandler); +EXTERN(HardFault); +PROVIDE(MemoryManagement = DefaultHandler); +PROVIDE(BusFault = DefaultHandler); +PROVIDE(UsageFault = DefaultHandler); +PROVIDE(SecureFault = DefaultHandler); +PROVIDE(SVCall = DefaultHandler); +PROVIDE(DebugMonitor = DefaultHandler); +PROVIDE(PendSV = DefaultHandler); +PROVIDE(SysTick = DefaultHandler); + +/* # Interrupt vectors */ +EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ + +/* # User overridable symbols I */ +/* Lets the user place the stack in a different RAM region */ +PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM)); + +/* # Sections */ +SECTIONS +{ + /* ## Sections in FLASH */ + /* ### Vector table */ + .vector_table ORIGIN(FLASH) : ALIGN(4) + { + /* Initial Stack Pointer (SP) value */ + __STACK_START = .; /* Just to get a nicer name in the disassembly */ + LONG(_stack_start); + + /* Reset vector */ + KEEP(*(.vector_table.reset_vector)); /* this is `__RESET_VECTOR` symbol */ + __reset_vector = ABSOLUTE(.); + + /* Exceptions */ + KEEP(*(.vector_table.exceptions)); /* this is `__EXCEPTIONS` symbol */ + __eexceptions = ABSOLUTE(.); + + /* Device specific interrupts */ + KEEP(*(.vector_table.interrupts)); /* this is `__INTERRUPTS` symbol */ + __einterrupts = ABSOLUTE(.); + } > FLASH + + /* ### .text */ + .text _stext : + { + *(.text .text.*); + __etext = ABSOLUTE(.); + } > FLASH + + /* ### .rodata */ + .rodata : + { + . = ALIGN(4); /* 4-byte align the start (VMA) of this section */ + /* __srodata = ABSOLUTE(.); */ + + *(.rodata .rodata.*); + + . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ + __erodata = ABSOLUTE(.); + } > FLASH + + /* ## Sections in RAM */ + /* ### .data */ + .data : AT(__erodata) /* LMA */ + { + . = ALIGN(4); /* 4-byte align the start (VMA) of this section */ + __sdata = ABSOLUTE(.); + + *(.data .data.*); + + . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ + __edata = ABSOLUTE(.); + } > RAM + + /* ### .bss */ + .bss : + { + . = ALIGN(4); /* 4-byte align the start (VMA) of this section */ + __sbss = ABSOLUTE(.); + + *(.bss .bss.*); + + . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ + __ebss = ABSOLUTE(.); + } > RAM + + /* ## Fake output .got section */ + /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in + the input files and raise an error if relocatable code is found */ + .got : + { + __sgot = ABSOLUTE(.); + KEEP(*(.got .got.*)); + __egot = ABSOLUTE(.); + } > FLASH + + /* ## Discarded sections */ + /DISCARD/ : + { + /* Unused exception related info that only wastes space */ + *(.ARM.exidx.*); + } +} + +/* # User overridable symbols II */ +/* (The user overridable symbols are split in two parts because LLD demands that the RHS of PROVIDE + to be defined before the PROVIDE invocation) */ +/* Lets the user override this to place .text a bit further than the vector table. Required by +microcontrollers that store their configuration right after the vector table. */ +PROVIDE(_stext = __einterrupts); + +/* # Hardcoded symbols */ +/* Place `.bss` at the start of the RAM region */ +__sidata = LOADADDR(.data); +/* Place the heap right after `.bss` and `.data` */ +__sheap = __edata; + +/* # Sanity checks */ + +/* Do not exceed this mark in the error messages below | */ +ASSERT(__reset_vector == ORIGIN(FLASH) + 0x8, +"The reset vector is missing. This is a cortex-m-rt bug. +Please file a bug report at: +https://github.com/japaric/cortex-m-rt/issues"); + +ASSERT(__eexceptions - ORIGIN(FLASH) == 0x40, " +The exception handlers are missing. This is a cortex-m-rt bug. +Please file a bug report at: +https://github.com/japaric/cortex-m-rt/issues"); + +ASSERT(__einterrupts - __eexceptions > 0, " +The interrupt handlers are missing. If you are not linking to a device +crate then you supply the interrupt handlers yourself. Check the +documentation."); + +ASSERT(__einterrupts <= _stext, " +The '.text' section can't be placed inside '.vector_table' section. +Set '_stext' to an address greater than '__einterrupts' (cf. `nm`)"); + +ASSERT(_stext < ORIGIN(FLASH) + LENGTH(FLASH), " +The '.text' section must be placed inside the FLASH memory +Set '_stext' to an address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)"); + +/* This has been temporarily omitted because it's not supported by LLD */ +/* ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, " */ +/* .bss is not 4-byte aligned at its boundaries. This is a cortex-m-rt bug."); */ + +/* ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, " */ +/* .data is not 4-byte aligned at its boundaries. This is a cortex-m-rt bug."); */ + +/* ASSERT(__sidata % 4 == 0, " */ +/* __sidata is not 4-byte aligned. This is a cortex-m-rt bug."); */ + +ASSERT(__sgot == __egot, " +.got section detected in the input object files. Dynamic relocations +are not supported. If you are linking to C code compiled using the +`cc` crate then modify your build script to compile the C code +_without_ the -fPIC flag. See the documentation of the +`cc::Build.pic` method for details."); +/* Do not exceed this mark in the error messages above | */ diff --git a/cortex-m-rt/memory.x b/cortex-m-rt/memory.x index 8027efc..3d97414 100644 --- a/cortex-m-rt/memory.x +++ b/cortex-m-rt/memory.x @@ -16,4 +16,4 @@ MEMORY /* The location of the .text section can be overridden using the `_stext` symbol. By default it will place after .vector_table */ -/* _stext = ORIGIN(FLASH) + 0x100; */ +/* _stext = ORIGIN(FLASH) + 0x40c; */ diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 4bb5fe1..e9aacf7 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -21,7 +21,7 @@ //! # `memory.x` //! //! This crate expects the user, or some other crate, to provide the memory layout of the target -//! device via a linker named `memory.x`. This section covers the contents of `memory.x` +//! device via a linker script named `memory.x`. This section covers the contents of `memory.x` //! //! ## `MEMORY` //! @@ -65,8 +65,8 @@ //! ## `_stext` //! //! This optional symbol can be used to control where the `.text` section is placed. If omitted the -//! `.text` section will be placed right after the vector table (which is placed at the beginning of -//! `FLASH`). Some devices store settings like Flash configuration right after the vector table; +//! `.text` section will be placed right after the vector table, which is placed at the beginning of +//! `FLASH`. Some devices store settings like Flash configuration right after the vector table; //! for these devices one must place the `.text` section after this configuration section -- //! `_stext` can be used for this purpose. //! @@ -218,7 +218,42 @@ //! If you override any exception handler you'll find it as an unmangled symbol, e.g. `SysTick` or //! `SVCall`, in the output of `objdump`, //! -//! # Incorporating device specific interrupts +//! If you are targeting the `thumbv7em-none-eabihf` target you'll also see a `ResetTrampoline` +//! symbol in the output. To avoid the compiler placing FPU instructions before the FPU has been +//! enabled (cf. `vpush`) `Reset` calls the function `ResetTrampoline` which is marked as +//! `#[inline(never)]` and `ResetTrampoline` calls `main`. The compiler is free to inline `main` +//! into `ResetTrampoline` but it can't inline `ResetTrampoline` into `Reset` -- the FPU is enabled +//! in `Reset`. +//! +//! # Advanced usage +//! +//! ## Setting the program entry point +//! +//! This section describes how `entry!` is implemented. This information is useful to developers who +//! want to provide an alternative to `entry!` that provides extra guarantees. +//! +//! The `Reset` handler will call a symbol named `main` (unmangled) *after* initializing `.bss` and +//! `.data`, and enabling the FPU (if the target is `thumbv7em-none-eabihf`). `entry!` provides this +//! symbol in its expansion: +//! +//! ``` ignore +//! entry!(path::to::main); +//! +//! // expands into +//! +//! #[export_name = "main"] +//! pub extern "C" fn __impl_main() -> ! { +//! // validate the signature of the program entry point +//! let f: fn() -> ! = path::to::main; +//! +//! f() +//! } +//! ``` +//! +//! The unmangled `main` symbol must have signature `extern "C" fn() -> !` or its invocation from +//! `Reset` will result in undefined behavior. +//! +//! ## Incorporating device specific interrupts //! //! This section covers how an external crate can insert device specific interrupt handlers into the //! vector table. Most users don't need to concern themselves with these details, but if you are @@ -226,7 +261,7 @@ //! //! The information in this section applies when the `"device"` feature has been enabled. //! -//! ## `__INTERRUPTS` +//! ### `__INTERRUPTS` //! //! The external crate must provide the interrupts portion of the vector table via a `static` //! variable named`__INTERRUPTS` (unmangled) that must be placed in the `.vector_table.interrupts` @@ -273,7 +308,7 @@ //! ]; //! ``` //! -//! ## `device.x` +//! ### `device.x` //! //! Linking in `__INTERRUPTS` creates a bunch of undefined references. If the user doesn't set a //! handler for *all* the device specific interrupts then linking will fail with `"undefined @@ -425,9 +460,12 @@ pub unsafe extern "C" fn Reset() -> ! { } } -/// Macro to define the user entry point of a program +/// Macro to define the entry point of the program /// -/// Usage: `entry!($path::to::user::entry)` +/// **NOTE** This macro must be invoked once and must be invoked from an accessible module, ideally +/// from the root of the crate. +/// +/// Usage: `entry!(path::to::entry::point)` /// /// The specified function will be called by the reset handler *after* RAM has been initialized. In /// the case of the `thumbv7em-none-eabihf` target the FPU will also be enabled before the function @@ -439,7 +477,7 @@ macro_rules! entry { ($path:path) => { #[export_name = "main"] pub extern "C" fn __impl_main() -> ! { - // validate the signature of the user provide `main` + // validate the signature of the program entry point let f: fn() -> ! = $path; f() @@ -561,10 +599,7 @@ pub static __EXCEPTIONS: [Vector; 14] = [ // 13: Reserved Vector { reserved: 0 }, // Exception 14: Pend SV Interrupt [not on Cortex-M0 variants]. - #[cfg(not(armv6m))] Vector { handler: PendSV }, - #[cfg(armv6m)] - Vector { reserved: 0 }, // Exception 15: System Tick Interrupt. Vector { handler: SysTick }, ]; @@ -598,6 +633,9 @@ pub static __INTERRUPTS: [unsafe extern "C" fn(); 32] = [{ /// Macro to set or override a processor core exception handler /// +/// **NOTE** This macro must be invoked from an accessible module, ideally from the root of the +/// crate. +/// /// # Syntax /// /// ``` ignore @@ -613,7 +651,7 @@ pub static __INTERRUPTS: [unsafe extern "C" fn(); 32] = [{ /// ); /// ``` /// -/// `$Name` can be one of: +/// where `$Name` can be one of: /// /// - `*` /// - `NonMaskableInt` @@ -701,9 +739,9 @@ pub static __INTERRUPTS: [unsafe extern "C" fn(); 32] = [{ macro_rules! exception { (* , $handler:path) => { #[allow(unsafe_code)] - #[allow(non_snake_case)] - #[export_name = "DefaultHandler"] - pub unsafe extern "C" fn __impl_DefaultHandler() { + #[deny(private_no_mangle_fns)] // raise an error if this item is not accessible + #[no_mangle] + pub unsafe extern "C" fn DefaultHandler() { extern crate core; // validate the signature of the user provided handler @@ -719,9 +757,9 @@ macro_rules! exception { (HardFault, $handler:path) => { #[allow(unsafe_code)] - #[allow(non_snake_case)] - #[export_name = "UserHardFault"] - pub unsafe extern "C" fn __impl_UserHardFault(ef: &$crate::ExceptionFrame) { + #[deny(private_no_mangle_fns)] // raise an error if this item is not accessible + #[no_mangle] + pub unsafe extern "C" fn UserHardFault(ef: &$crate::ExceptionFrame) { // validate the signature of the user provided handler let f: fn(&$crate::ExceptionFrame) -> ! = $handler; @@ -731,6 +769,7 @@ macro_rules! exception { ($Name:ident, $handler:path,state: $State:ty = $initial_state:expr) => { #[allow(unsafe_code)] + #[deny(private_no_mangle_fns)] // raise an error if this item is not accessible #[no_mangle] pub unsafe extern "C" fn $Name() { static mut STATE: $State = $initial_state; @@ -747,6 +786,7 @@ macro_rules! exception { ($Name:ident, $handler:path) => { #[allow(unsafe_code)] + #[deny(private_no_mangle_fns)] // raise an error if this item is not accessible #[no_mangle] pub unsafe extern "C" fn $Name() { // check that this exception exists -- cgit v1.2.3 From 022d2d7df13156a1dc5d0e0385f2c26e7e26f118 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 11 May 2018 22:51:49 +0200 Subject: document vector table symbols --- cortex-m-rt/src/lib.rs | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index e9aacf7..c499f7e 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -10,9 +10,9 @@ //! - The memory layout of the program. In particular, it populates the vector table so the device //! can boot correctly, and properly dispatch exceptions and interrupts. //! -//! - Initializing `static` variables before the user entry point. +//! - Initializing `static` variables before the program entry point. //! -//! - Enabling the FPU before the user entry point if the target is `thumbv7em-none-eabihf`. +//! - Enabling the FPU before the program entry point if the target is `thumbv7em-none-eabihf`. //! //! This crate also provides a mechanism to set exception handlers: see the [`exception!`] macro. //! @@ -215,6 +215,22 @@ //! - `UserHardFault`. This is the user defined hard fault handler. This function will contain, or //! call, the function you declared in the second argument of `exception!(HardFault, ..)` //! +//! - `__STACK_START`. This is the first entry in the `.vector_table` section. This symbol contains +//! the initial value of the stack pointer; this is where the stack will be located -- the stack +//! grows downwards towards smaller addresses. +//! +//! - `__RESET_VECTOR`. This is the reset vector, a pointer into the `Reset` handler. This vector is +//! located in the `.vector_table` section after `__STACK_START`. +//! +//! - `__EXCEPTIONS`. This is the core exceptions portion of the vector table; it's an array of 14 +//! exception vectors, which includes exceptions like `HardFault` and `SysTick`. This array is +//! located after `__RESET_VECTOR` in the `.vector_table` section. +//! +//! - `__EXCEPTIONS`. This is the device specific interrupt portion of the vector table; its exact +//! size depends on the target device but if the `"device"` feature has not been enabled it will +//! have a size of 32 vectors (on ARMv6-M) or 240 vectors (on ARMv7-M). This array is located after +//! `__EXCEPTIONS` in the `.vector_table` section. +//! //! If you override any exception handler you'll find it as an unmangled symbol, e.g. `SysTick` or //! `SVCall`, in the output of `objdump`, //! @@ -669,6 +685,8 @@ pub static __INTERRUPTS: [unsafe extern "C" fn(); 32] = [{ /// /// (b) Only available on ARMv8-M /// +/// # Usage +/// /// `exception!(HardFault, ..)` sets the hard fault handler. The handler must have signature /// `fn(&ExceptionFrame) -> !`. This handler is not allowed to return as that can cause undefined /// behavior. It's mandatory to set the `HardFault` handler somewhere in the dependency graph of an @@ -686,7 +704,7 @@ pub static __INTERRUPTS: [unsafe extern "C" fn(); 32] = [{ /// /// # Examples /// -/// Setting the `HardFault` handler +/// - Setting the `HardFault` handler /// /// ``` /// #[macro_use(exception)] @@ -704,7 +722,7 @@ pub static __INTERRUPTS: [unsafe extern "C" fn(); 32] = [{ /// # fn main() {} /// ``` /// -/// Setting the default handler +/// - Setting the default handler /// /// ``` /// #[macro_use(exception)] @@ -719,7 +737,7 @@ pub static __INTERRUPTS: [unsafe extern "C" fn(); 32] = [{ /// # fn main() {} /// ``` /// -/// Overriding the `SysTick` handler +/// - Overriding the `SysTick` handler /// /// ``` /// #[macro_use(exception)] -- cgit v1.2.3 From 955c87207da97174ee5dd9b9d66e0466a991984f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 12 May 2018 14:48:43 +0200 Subject: truncate ICSR --- cortex-m-rt/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index c499f7e..d548e08 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -769,7 +769,7 @@ macro_rules! exception { // NOTE not volatile so the compiler can opt the load operation away if the value is // unused - f(core::ptr::read(SCB_ICSR) as i16 - 16) + f(core::ptr::read(SCB_ICSR) as u8 as i16 - 16) } }; -- cgit v1.2.3 From 351b06c0781ad775b3edba44c16144f98f0eba2d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 12 May 2018 14:54:34 +0200 Subject: ExceptionFrame: make fmt::Debug print address in hex --- cortex-m-rt/src/lib.rs | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index d548e08..f800a86 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -384,28 +384,58 @@ extern crate r0; +use core::fmt; + /// Registers stacked (pushed into the stack) during an exception -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy)] #[repr(C)] pub struct ExceptionFrame { /// (General purpose) Register 0 pub r0: u32, + /// (General purpose) Register 1 pub r1: u32, + /// (General purpose) Register 2 pub r2: u32, + /// (General purpose) Register 3 pub r3: u32, + /// (General purpose) Register 12 pub r12: u32, + /// Linker Register pub lr: u32, + /// Program Counter pub pc: u32, + /// Program Status Register pub xpsr: u32, } +impl fmt::Debug for ExceptionFrame { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + struct Hex(u32); + impl fmt::Debug for Hex { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "0x{:08x}", self.0) + } + } + f.debug_struct("ExceptionFrame") + .field("r0", &Hex(self.r0)) + .field("r1", &Hex(self.r1)) + .field("r2", &Hex(self.r2)) + .field("r3", &Hex(self.r3)) + .field("r12", &Hex(self.r12)) + .field("lr", &Hex(self.lr)) + .field("pc", &Hex(self.pc)) + .field("xpsr", &Hex(self.xpsr)) + .finish() + } +} + /// Returns a pointer into which the heap can be placed /// /// The start of the heap is guaranteed to be 4-byte aligned; that is the pointer returned by this -- cgit v1.2.3 From 09013442e31a44634b44fa92c48f2134bf1388e9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 12 May 2018 17:53:20 +0200 Subject: update the CHANGELOG --- cortex-m-rt/CHANGELOG.md | 37 +++++++++++++++++++++++++++++++++++++ cortex-m-rt/link.x.in | 2 +- cortex-m-rt/src/lib.rs | 21 +++++++++++++-------- 3 files changed, 51 insertions(+), 9 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/CHANGELOG.md b/cortex-m-rt/CHANGELOG.md index 3dbed87..dc07408 100644 --- a/cortex-m-rt/CHANGELOG.md +++ b/cortex-m-rt/CHANGELOG.md @@ -7,6 +7,43 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.5.0] - 2018-05-12 + +### Added + +- An `entry!` macro to set the entry point of the program. + +- A `heap_start` function that returns a pointer into the start of the heap region. + +- A `device` feature. When disabled this crate provides the interrupt vectors; when enabled the + interrupt vectors are expected to be provided by another crate. Read the documentation for + details. + +### Changed + +- This crate now compiles on the beta and stable channels. + +- [breaking-change] this crate now requires `arm-none-eabi-gcc` to be installed and available in + `$PATH` to compile. + +- [breaking-change] the `start` lang item has been removed. The standard `main` interface won't + work. Instead use `#![no_main]` and the `entry!` macro. See documentation for details. + +- [breaking-change] the `default_handler!` macro has been merged into the `exception!` macro. Use + `exception!(*, ..)` to set the default exception handler. + +- [breaking-change] there's no weak default handler so a default handler must be defined by the + application, or one of its dependencies. + +- [breaking-change] the syntax of the third argument of the `exception!` handler has changed. See + the documentation of the macro for details. + +- [breaking-change] the exception names that the `exception!` macro accepts has changed to match the + CMSIS specification. See the documentation of the macro for the list of names it accepts. + +- [breaking-change] The number of symbol interfaces has been reduced. Check the advanced section of + the documentation for details. + ## [v0.4.0] - 2018-04-09 ### Added diff --git a/cortex-m-rt/link.x.in b/cortex-m-rt/link.x.in index 3f91693..9b99427 100644 --- a/cortex-m-rt/link.x.in +++ b/cortex-m-rt/link.x.in @@ -183,7 +183,7 @@ cortex-m-rt: The '.text' section can't be placed inside the '.vector_table' sect '_stext' to an address greater than '__einterrupts' (cf. `nm` output)"); ASSERT(_stext < ORIGIN(FLASH) + LENGTH(FLASH), " -cortex-m-rt The '.text' section must be placed inside the FLASH memory.Set '_stext' to an +cortex-m-rt The '.text' section must be placed inside the FLASH memory. Set '_stext' to an address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)"); /* This has been temporarily omitted because it's not supported by LLD */ diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index f800a86..eaefbbc 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -18,12 +18,18 @@ //! //! [`exception!`]: macro.exception.html //! -//! # `memory.x` +//! # Requirements +//! +//! ## `arm-none-eabi-gcc` +//! +//! This crate requires `arm-none-eabi-gcc` to be installed and available in `$PATH`. +//! +//! ## `memory.x` //! //! This crate expects the user, or some other crate, to provide the memory layout of the target //! device via a linker script named `memory.x`. This section covers the contents of `memory.x` //! -//! ## `MEMORY` +//! ### `MEMORY` //! //! The linker script must specify the memory available in the device as, at least, two `MEMORY` //! regions: one named `FLASH` and one named `RAM`. The `.text` and `.rodata` sections of the @@ -39,7 +45,7 @@ //! } //! ``` //! -//! ## `_stack_start` +//! ### `_stack_start` //! //! This optional symbol can be used to indicate where the call stack of the program should be //! placed. If this symbol is not used then the stack will be placed at the *end* of the `RAM` @@ -62,7 +68,7 @@ //! _stack_start = ORIGIN(CCRAM) + LENGTH(CCRAM); //! ``` //! -//! ## `_stext` +//! ### `_stext` //! //! This optional symbol can be used to control where the `.text` section is placed. If omitted the //! `.text` section will be placed right after the vector table, which is placed at the beginning of @@ -80,7 +86,7 @@ //! _stext = ORIGIN(FLASH) + 0x40C //! ``` //! -//! # Example +//! # An example //! //! This section presents a minimal application built on top of `cortex-m-rt`. Apart from the //! mandatory `memory.x` linker script describing the memory layout of the device, the hard fault @@ -436,10 +442,9 @@ impl fmt::Debug for ExceptionFrame { } } -/// Returns a pointer into which the heap can be placed +/// Returns a pointer to the start of the heap /// -/// The start of the heap is guaranteed to be 4-byte aligned; that is the pointer returned by this -/// function is a multiple of 4. +/// The returned pointer is guaranteed to be 4-byte aligned. #[inline] pub fn heap_start() -> *mut u32 { extern "C" { -- cgit v1.2.3 From 21c205462686554d0d639834fc7d38e84608f11a Mon Sep 17 00:00:00 2001 From: Stephen Roe Date: Wed, 13 Jun 2018 23:22:12 +0100 Subject: Modified the entry and exception macros to accept a closure. This allows: entry!(|| { let mut x = 1; loop { x = x + 1; } }); as well as allowing the original usage: entry!(main); fn main() -> ! { let mut x = 1; loop { x = x + 1; } } The same is true for exceptions: exception!(*, |irqn: i16| { panic!("Unhandled exception (IRQn = {})", irqn); }); --- cortex-m-rt/src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index eaefbbc..e55171a 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -525,7 +525,7 @@ pub unsafe extern "C" fn Reset() -> ! { /// The signature of the specified function must be `fn() -> !` (never ending function) #[macro_export] macro_rules! entry { - ($path:path) => { + ($path:expr) => { #[export_name = "main"] pub extern "C" fn __impl_main() -> ! { // validate the signature of the program entry point @@ -695,7 +695,7 @@ pub static __INTERRUPTS: [unsafe extern "C" fn(); 32] = [{ /// $Name:ident, /// /// // Path to the exception handler (a function) -/// $handler:path, +/// $handler:expr, /// /// // Optional, state preserved across invocations of the handler /// state: $State:ty = $initial_state:expr, @@ -790,7 +790,7 @@ pub static __INTERRUPTS: [unsafe extern "C" fn(); 32] = [{ /// ``` #[macro_export] macro_rules! exception { - (* , $handler:path) => { + (* , $handler:expr) => { #[allow(unsafe_code)] #[deny(private_no_mangle_fns)] // raise an error if this item is not accessible #[no_mangle] @@ -808,7 +808,7 @@ macro_rules! exception { } }; - (HardFault, $handler:path) => { + (HardFault, $handler:expr) => { #[allow(unsafe_code)] #[deny(private_no_mangle_fns)] // raise an error if this item is not accessible #[no_mangle] @@ -820,7 +820,7 @@ macro_rules! exception { } }; - ($Name:ident, $handler:path,state: $State:ty = $initial_state:expr) => { + ($Name:ident, $handler:expr,state: $State:ty = $initial_state:expr) => { #[allow(unsafe_code)] #[deny(private_no_mangle_fns)] // raise an error if this item is not accessible #[no_mangle] @@ -837,7 +837,7 @@ macro_rules! exception { } }; - ($Name:ident, $handler:path) => { + ($Name:ident, $handler:expr) => { #[allow(unsafe_code)] #[deny(private_no_mangle_fns)] // raise an error if this item is not accessible #[no_mangle] -- cgit v1.2.3 From 335856a05a9cd4d78b3dd4e2348fdd5702edb9ba Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 7 Aug 2018 18:57:41 -0500 Subject: [WIP] provide defaults for DefaultHandler and HardFault `exception!(HardFault, ..)` and `exception!(*, ..)` can now be omitted from programs to pick up the default behavior of an infinite loop. Existing programs that define these exception handlers will continue to work w/o any functional change. closes #72 --- cortex-m-rt/link.x.in | 3 +++ cortex-m-rt/src/lib.rs | 22 +++++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/link.x.in b/cortex-m-rt/link.x.in index 5df965a..5fa7dbf 100644 --- a/cortex-m-rt/link.x.in +++ b/cortex-m-rt/link.x.in @@ -45,6 +45,9 @@ PROVIDE(DebugMonitor = DefaultHandler); PROVIDE(PendSV = DefaultHandler); PROVIDE(SysTick = DefaultHandler); +PROVIDE(DefaultHandler = DefaultDefaultHandler); +PROVIDE(UserHardFault = DefaultUserHardFault); + /* # Interrupt vectors */ EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index e55171a..60c8034 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -390,7 +390,7 @@ extern crate r0; -use core::fmt; +use core::{fmt, ptr}; /// Registers stacked (pushed into the stack) during an exception #[derive(Clone, Copy)] @@ -511,6 +511,26 @@ pub unsafe extern "C" fn Reset() -> ! { } } +#[doc(hidden)] +#[no_mangle] +pub unsafe extern "C" fn DefaultDefaultHandler() { + loop { + // add some side effect to prevent this from turning into a UDF instruction + // see rust-lang/rust#28728 + ptr::read_volatile(&0u8); + } +} + +#[doc(hidden)] +#[no_mangle] +pub unsafe extern "C" fn DefaultUserHardFault() { + loop { + // add some side effect to prevent this from turning into a UDF instruction + // see rust-lang/rust#28728 + ptr::read_volatile(&0u8); + } +} + /// Macro to define the entry point of the program /// /// **NOTE** This macro must be invoked once and must be invoked from an accessible module, ideally -- cgit v1.2.3 From e6a6769166922299937f490669590096f86dc298 Mon Sep 17 00:00:00 2001 From: Jonathan Soo Date: Fri, 20 Jul 2018 03:10:26 -0400 Subject: Add a __pre_init function to be called at the start of the reset handler The call to the function and the macro to set it are both gated behind the `pre_init` feature flag. Signed-off-by: Gabriel Smith --- cortex-m-rt/Cargo.toml | 1 + cortex-m-rt/src/lib.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 9cd9d19..d22c5df 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -21,3 +21,4 @@ panic-abort = "0.2.0" [features] device = [] +pre_init = [] diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 60c8034..7b023ed 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -169,6 +169,13 @@ //! conjunction with crates generated using `svd2rust`. Those *device crates* will populate the //! missing part of the vector table when their `"rt"` feature is enabled. //! +//! ## `pre_init` +//! +//! If this feature is enabled then a user-defined function will be run at the start of the reset +//! handler, before RAM is initialized. If this feature is enabled then the macro `pre_init!` needs +//! to be called to set the function to be run. This feature is intended to perform actions that +//! cannot wait the time it takes for RAM to be initialized, such as disabling a watchdog. +//! //! # Inspection //! //! This section covers how to inspect a binary that builds on top of `cortex-m-rt`. @@ -474,8 +481,14 @@ pub unsafe extern "C" fn Reset() -> ! { static mut __sdata: u32; static mut __edata: u32; static __sidata: u32; + + #[cfg(feature = "pre_init")] + fn _pre_init(); } + #[cfg(feature = "pre_init")] + _pre_init(); + // Initialize RAM r0::zero_bss(&mut __sbss, &mut __ebss); r0::init_data(&mut __sdata, &mut __edata, &__sidata); @@ -872,3 +885,36 @@ macro_rules! exception { } }; } + +/// Macro to set the function to be called at the beginning of the reset handler. +/// +/// The function must have the signature of `unsafe fn()`. +/// +/// The function passed will be called before static variables are initialized. Any access of static +/// variables will result in undefined behavior. +/// +/// # Examples +/// +/// ``` ignore +/// pre_init!(foo::bar); +/// +/// mod foo { +/// pub unsafe fn bar() { +/// // do something here +/// } +/// } +/// ``` +#[cfg(feature = "pre_init")] +#[macro_export] +macro_rules! pre_init { + ($handler:path) => { + #[allow(unsafe_code)] + #[deny(private_no_mangle_fns)] // raise an error if this item is not accessible + #[no_mangle] + pub unsafe extern "C" fn _pre_init() { + // validate user handler + let f: unsafe fn() = $handler; + f(); + } + } +} -- cgit v1.2.3 From 06ce316ad44f6eaac497d43c392703e326b50944 Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Sat, 4 Aug 2018 01:04:36 -0400 Subject: Remove the pre-init feature and provide a default for the __pre_init symbol Signed-off-by: Gabriel Smith --- cortex-m-rt/Cargo.toml | 1 - cortex-m-rt/link.x.in | 5 +++++ cortex-m-rt/src/lib.rs | 31 ++++++++++++++++++------------- 3 files changed, 23 insertions(+), 14 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index d22c5df..9cd9d19 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -21,4 +21,3 @@ panic-abort = "0.2.0" [features] device = [] -pre_init = [] diff --git a/cortex-m-rt/link.x.in b/cortex-m-rt/link.x.in index dfcf262..02cdb32 100644 --- a/cortex-m-rt/link.x.in +++ b/cortex-m-rt/link.x.in @@ -51,6 +51,11 @@ PROVIDE(UserHardFault = DefaultUserHardFault); /* # Interrupt vectors */ EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ +/* # Pre-initialization function */ +/* If the user overrides this using the `pre_init!` macro or by creating a `__pre_init` function, + then the function this points to will be called before the RAM is initialized. */ +PROVIDE(__pre_init = 0); + /* # Sections */ SECTIONS { diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 7b023ed..d73dc4f 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -169,13 +169,6 @@ //! conjunction with crates generated using `svd2rust`. Those *device crates* will populate the //! missing part of the vector table when their `"rt"` feature is enabled. //! -//! ## `pre_init` -//! -//! If this feature is enabled then a user-defined function will be run at the start of the reset -//! handler, before RAM is initialized. If this feature is enabled then the macro `pre_init!` needs -//! to be called to set the function to be run. This feature is intended to perform actions that -//! cannot wait the time it takes for RAM to be initialized, such as disabling a watchdog. -//! //! # Inspection //! //! This section covers how to inspect a binary that builds on top of `cortex-m-rt`. @@ -244,6 +237,10 @@ //! have a size of 32 vectors (on ARMv6-M) or 240 vectors (on ARMv7-M). This array is located after //! `__EXCEPTIONS` in the `.vector_table` section. //! +//! - `__pre_init`. This is a function to be run before RAM is initialized. It defaults pointing at +//! `0` and if not changed to point to another address, usually by calling the `pre_init!` macro, +//! the `_pre_init` function is skipped. +//! //! If you override any exception handler you'll find it as an unmangled symbol, e.g. `SysTick` or //! `SVCall`, in the output of `objdump`, //! @@ -385,6 +382,14 @@ //! println!("cargo:rustc-link-search={}", out.display()); //! } //! ``` +//! +//! ## `pre_init!` +//! +//! A user-defined function can be run at the start of the reset handler, before RAM is +//! initialized. The macro `pre_init!` can be called to set the function to be run. The function is +//! intended to perform actions that cannot wait the time it takes for RAM to be initialized, such +//! as disabling a watchdog. As the function is called before RAM is initialized, any access of +//! static variables will result in undefined behavior. // # Developer notes // @@ -482,12 +487,13 @@ pub unsafe extern "C" fn Reset() -> ! { static mut __edata: u32; static __sidata: u32; - #[cfg(feature = "pre_init")] - fn _pre_init(); + fn __pre_init(); } - #[cfg(feature = "pre_init")] - _pre_init(); + let pre_init: unsafe extern "C" fn() = __pre_init; + if pre_init as usize != 0 { + pre_init(); + } // Initialize RAM r0::zero_bss(&mut __sbss, &mut __ebss); @@ -904,14 +910,13 @@ macro_rules! exception { /// } /// } /// ``` -#[cfg(feature = "pre_init")] #[macro_export] macro_rules! pre_init { ($handler:path) => { #[allow(unsafe_code)] #[deny(private_no_mangle_fns)] // raise an error if this item is not accessible #[no_mangle] - pub unsafe extern "C" fn _pre_init() { + pub unsafe extern "C" fn __pre_init() { // validate user handler let f: unsafe fn() = $handler; f(); -- cgit v1.2.3 From f3fa545b978a6d5d29d0bcdc78aca03518183bdc Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Sun, 12 Aug 2018 15:23:49 -0400 Subject: Change the sentinel value for __pre_init to something other than 1 The sentinel value of 0, while nice, was being optimized out as the compiler assumed that the function pointer would never be 0. Signed-off-by: Gabriel Smith --- cortex-m-rt/link.x.in | 2 +- cortex-m-rt/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/link.x.in b/cortex-m-rt/link.x.in index 02cdb32..c2511f7 100644 --- a/cortex-m-rt/link.x.in +++ b/cortex-m-rt/link.x.in @@ -54,7 +54,7 @@ EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ /* # Pre-initialization function */ /* If the user overrides this using the `pre_init!` macro or by creating a `__pre_init` function, then the function this points to will be called before the RAM is initialized. */ -PROVIDE(__pre_init = 0); +PROVIDE(__pre_init = 1); /* # Sections */ SECTIONS diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index d73dc4f..31e4ea3 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -491,7 +491,7 @@ pub unsafe extern "C" fn Reset() -> ! { } let pre_init: unsafe extern "C" fn() = __pre_init; - if pre_init as usize != 0 { + if pre_init as usize != 1 { pre_init(); } -- cgit v1.2.3 From 61c19330d5dd8b58ebd57f2e064ced4ccc4faad2 Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Sun, 12 Aug 2018 16:11:09 -0400 Subject: Correct docs for __pre_init Signed-off-by: Gabriel Smith --- cortex-m-rt/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 31e4ea3..04d5b9e 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -238,8 +238,10 @@ //! `__EXCEPTIONS` in the `.vector_table` section. //! //! - `__pre_init`. This is a function to be run before RAM is initialized. It defaults pointing at -//! `0` and if not changed to point to another address, usually by calling the `pre_init!` macro, -//! the `_pre_init` function is skipped. +//! `1` and if not changed to point to another address, usually by calling the `pre_init!` macro, +//! the `_pre_init` function is skipped. The function cannot default to `0` as the compiler +//! optimizes out the check for `0` under the assumption that a function pointer cannot point to +//! `0`. //! //! If you override any exception handler you'll find it as an unmangled symbol, e.g. `SysTick` or //! `SVCall`, in the output of `objdump`, -- cgit v1.2.3 From 73e0b2a25d1766debe4f603dd13a732de2f1993d Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Sun, 12 Aug 2018 18:46:50 -0400 Subject: Change pre-init to use an empty function that is overwridden instead of a sentinel Using a sentinel creates a conditional branch that cannot be optimized out whereas an empty default function keeps the codepath linear and can be optimized out in the best case. Signed-off-by: Gabriel Smith --- cortex-m-rt/link.x.in | 2 +- cortex-m-rt/src/lib.rs | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/link.x.in b/cortex-m-rt/link.x.in index c2511f7..23f406d 100644 --- a/cortex-m-rt/link.x.in +++ b/cortex-m-rt/link.x.in @@ -54,7 +54,7 @@ EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ /* # Pre-initialization function */ /* If the user overrides this using the `pre_init!` macro or by creating a `__pre_init` function, then the function this points to will be called before the RAM is initialized. */ -PROVIDE(__pre_init = 1); +PROVIDE(__pre_init = DefaultPreInit); /* # Sections */ SECTIONS diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 04d5b9e..cecb5f8 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -237,11 +237,10 @@ //! have a size of 32 vectors (on ARMv6-M) or 240 vectors (on ARMv7-M). This array is located after //! `__EXCEPTIONS` in the `.vector_table` section. //! -//! - `__pre_init`. This is a function to be run before RAM is initialized. It defaults pointing at -//! `1` and if not changed to point to another address, usually by calling the `pre_init!` macro, -//! the `_pre_init` function is skipped. The function cannot default to `0` as the compiler -//! optimizes out the check for `0` under the assumption that a function pointer cannot point to -//! `0`. +//! - `__pre_init`. This is a function to be run before RAM is initialized. It defaults to an empty +//! function. The function called can be changed by calling the `pre_init!` macro. The empty +//! function is not optimized out by default, but if an empty function is passed to `pre_init!` the +//! function call will be optimized out. //! //! If you override any exception handler you'll find it as an unmangled symbol, e.g. `SysTick` or //! `SVCall`, in the output of `objdump`, @@ -493,9 +492,7 @@ pub unsafe extern "C" fn Reset() -> ! { } let pre_init: unsafe extern "C" fn() = __pre_init; - if pre_init as usize != 1 { - pre_init(); - } + pre_init(); // Initialize RAM r0::zero_bss(&mut __sbss, &mut __ebss); @@ -552,6 +549,10 @@ pub unsafe extern "C" fn DefaultUserHardFault() { } } +#[doc(hidden)] +#[no_mangle] +pub unsafe extern "C" fn DefaultPreInit() {} + /// Macro to define the entry point of the program /// /// **NOTE** This macro must be invoked once and must be invoked from an accessible module, ideally -- cgit v1.2.3 From 2557ac432eb3645671c093e3ace8787444180537 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 25 Aug 2018 19:10:36 +0200 Subject: reduce the size of default handlers this commit replaces the two default handler (DefaultDefaultHandler and DefaultUserHardFault) by a single handler named `EndlessLoop`. This results in one less symbol being generated. Also this new handler uses `compiler_fence` to avoid the "infinite loops w/o side effects are undef values" bug in LLVM. `compiler_fence` is guaranteed to generate no code so this reduces the size of the handler (when compiler in release). --- cortex-m-rt/link.x.in | 4 ++-- cortex-m-rt/src/lib.rs | 21 ++++++--------------- 2 files changed, 8 insertions(+), 17 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/link.x.in b/cortex-m-rt/link.x.in index 23f406d..b9436ca 100644 --- a/cortex-m-rt/link.x.in +++ b/cortex-m-rt/link.x.in @@ -45,8 +45,8 @@ PROVIDE(DebugMonitor = DefaultHandler); PROVIDE(PendSV = DefaultHandler); PROVIDE(SysTick = DefaultHandler); -PROVIDE(DefaultHandler = DefaultDefaultHandler); -PROVIDE(UserHardFault = DefaultUserHardFault); +PROVIDE(DefaultHandler = EndlessLoop); +PROVIDE(UserHardFault = EndlessLoop); /* # Interrupt vectors */ EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index cecb5f8..3c2dd89 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -403,7 +403,8 @@ extern crate r0; -use core::{fmt, ptr}; +use core::fmt; +use core::sync::atomic::{self, Ordering}; /// Registers stacked (pushed into the stack) during an exception #[derive(Clone, Copy)] @@ -531,21 +532,11 @@ pub unsafe extern "C" fn Reset() -> ! { #[doc(hidden)] #[no_mangle] -pub unsafe extern "C" fn DefaultDefaultHandler() { +pub unsafe extern "C" fn EndlessLoop() -> ! { loop { // add some side effect to prevent this from turning into a UDF instruction - // see rust-lang/rust#28728 - ptr::read_volatile(&0u8); - } -} - -#[doc(hidden)] -#[no_mangle] -pub unsafe extern "C" fn DefaultUserHardFault() { - loop { - // add some side effect to prevent this from turning into a UDF instruction - // see rust-lang/rust#28728 - ptr::read_volatile(&0u8); + // see rust-lang/rust#28728 for details + atomic::compiler_fence(Ordering::SeqCst); } } @@ -924,5 +915,5 @@ macro_rules! pre_init { let f: unsafe fn() = $handler; f(); } - } + }; } -- cgit v1.2.3 From 4c7169fa65f0c34c5461379e10f38f32c723507b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 25 Aug 2018 19:53:13 +0200 Subject: two separate default handlers --- cortex-m-rt/link.x.in | 4 ++-- cortex-m-rt/src/lib.rs | 13 ++++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/link.x.in b/cortex-m-rt/link.x.in index b9436ca..3d71811 100644 --- a/cortex-m-rt/link.x.in +++ b/cortex-m-rt/link.x.in @@ -45,8 +45,8 @@ PROVIDE(DebugMonitor = DefaultHandler); PROVIDE(PendSV = DefaultHandler); PROVIDE(SysTick = DefaultHandler); -PROVIDE(DefaultHandler = EndlessLoop); -PROVIDE(UserHardFault = EndlessLoop); +PROVIDE(DefaultHandler = DefaultHandler_); +PROVIDE(UserHardFault = UserHardFault_); /* # Interrupt vectors */ EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 3c2dd89..599ae06 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -530,9 +530,20 @@ pub unsafe extern "C" fn Reset() -> ! { } } +#[allow(unused_variables)] #[doc(hidden)] #[no_mangle] -pub unsafe extern "C" fn EndlessLoop() -> ! { +pub unsafe extern "C" fn UserHardFault_(ef: &ExceptionFrame) -> ! { + loop { + // add some side effect to prevent this from turning into a UDF instruction + // see rust-lang/rust#28728 for details + atomic::compiler_fence(Ordering::SeqCst); + } +} + +#[doc(hidden)] +#[no_mangle] +pub unsafe extern "C" fn DefaultHandler_() -> ! { loop { // add some side effect to prevent this from turning into a UDF instruction // see rust-lang/rust#28728 for details -- cgit v1.2.3 From e5b9974886f452d6a0889842c82a5a2b69d4b941 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 27 Aug 2018 15:03:18 +0200 Subject: v0.5.3 --- cortex-m-rt/CHANGELOG.md | 11 +++++++++-- cortex-m-rt/Cargo.toml | 2 +- cortex-m-rt/src/lib.rs | 4 ---- 3 files changed, 10 insertions(+), 7 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/CHANGELOG.md b/cortex-m-rt/CHANGELOG.md index 23a4b9a..7027d5a 100644 --- a/cortex-m-rt/CHANGELOG.md +++ b/cortex-m-rt/CHANGELOG.md @@ -7,11 +7,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.5.3] - 2018-08-27 + +### Changed + +- This crate no longer depends on `arm-none-eabi-gcc`. + ## [v0.5.2] - 2018-08-11 ### Added -* A `pre_init!` macro and related functionality to run a function immediately +* A `pre_init!` macro and related functionality to run a function immediately after reset, before memory initialisation ### Changed @@ -336,7 +342,8 @@ section size addr Initial release -[Unreleased]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.5.2...HEAD +[Unreleased]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.5.3...HEAD +[v0.5.3]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.5.2...v0.5.3 [v0.5.2]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.5.1...v0.5.2 [v0.5.1]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.5.0...v0.5.1 [v0.5.0]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.4.0...v0.5.0 diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 1cd9aaa..0dfbaf7 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -8,7 +8,7 @@ keywords = ["arm", "cortex-m", "runtime", "startup"] license = "MIT OR Apache-2.0" name = "cortex-m-rt" repository = "https://github.com/japaric/cortex-m-rt" -version = "0.5.2" +version = "0.5.3" [dependencies] r0 = "0.2.1" diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 599ae06..10f60f6 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -20,10 +20,6 @@ //! //! # Requirements //! -//! ## `arm-none-eabi-gcc` -//! -//! This crate requires `arm-none-eabi-gcc` to be installed and available in `$PATH`. -//! //! ## `memory.x` //! //! This crate expects the user, or some other crate, to provide the memory layout of the target -- cgit v1.2.3 From f2a155a0715cb99cbace2eca7ab5fcfa93d106d2 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 18 Aug 2018 22:45:13 +0200 Subject: turn macros into attributes --- cortex-m-rt/.gitignore | 1 + cortex-m-rt/Cargo.toml | 1 + cortex-m-rt/ci/script.sh | 2 + cortex-m-rt/examples/alignment.rs | 4 +- cortex-m-rt/examples/data_overflow.rs | 4 +- cortex-m-rt/examples/device.rs | 5 +- cortex-m-rt/examples/minimal.rs | 6 +- cortex-m-rt/examples/override-exception.rs | 13 +- cortex-m-rt/examples/pre_init.rs | 8 +- cortex-m-rt/examples/state.rs | 12 +- cortex-m-rt/macros/Cargo.toml | 17 ++ cortex-m-rt/macros/src/lib.rs | 462 +++++++++++++++++++++++++++++ cortex-m-rt/src/lib.rs | 263 +--------------- 13 files changed, 517 insertions(+), 281 deletions(-) create mode 100644 cortex-m-rt/macros/Cargo.toml create mode 100644 cortex-m-rt/macros/src/lib.rs (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/.gitignore b/cortex-m-rt/.gitignore index c71d6db..d8748d6 100644 --- a/cortex-m-rt/.gitignore +++ b/cortex-m-rt/.gitignore @@ -1,4 +1,5 @@ **/*.rs.bk +.#* Cargo.lock bin/*.after bin/*.before diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 0dfbaf7..016cdc9 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -12,6 +12,7 @@ version = "0.5.3" [dependencies] r0 = "0.2.1" +cortex-m-rt-macros = { path = "macros", version = "0.1.0" } [dev-dependencies] panic-semihosting = "0.3.0" diff --git a/cortex-m-rt/ci/script.sh b/cortex-m-rt/ci/script.sh index 7d1cc67..242a546 100644 --- a/cortex-m-rt/ci/script.sh +++ b/cortex-m-rt/ci/script.sh @@ -5,6 +5,8 @@ main() { cargo check --target $TARGET --features device + ( cd macros && cargo check && cargo test ) + local examples=( alignment minimal diff --git a/cortex-m-rt/examples/alignment.rs b/cortex-m-rt/examples/alignment.rs index 5635851..25d755d 100644 --- a/cortex-m-rt/examples/alignment.rs +++ b/cortex-m-rt/examples/alignment.rs @@ -4,13 +4,12 @@ #![no_main] #![no_std] -#[macro_use(entry)] extern crate cortex_m_rt as rt; extern crate panic_abort; use core::ptr; -entry!(main); +use rt::entry; static mut BSS1: u16 = 0; static mut BSS2: u8 = 0; @@ -19,6 +18,7 @@ static mut DATA2: u16 = 1; static RODATA1: &[u8; 3] = b"012"; static RODATA2: &[u8; 2] = b"34"; +#[entry] fn main() -> ! { unsafe { let _bss1 = ptr::read_volatile(&BSS1); diff --git a/cortex-m-rt/examples/data_overflow.rs b/cortex-m-rt/examples/data_overflow.rs index 396f1c8..ceec18b 100644 --- a/cortex-m-rt/examples/data_overflow.rs +++ b/cortex-m-rt/examples/data_overflow.rs @@ -5,13 +5,12 @@ #![no_main] #![no_std] -#[macro_use(entry)] extern crate cortex_m_rt as rt; extern crate panic_abort; use core::ptr; -entry!(main); +use rt::entry; // This large static array uses most of .rodata static RODATA: [u8; 48*1024] = [1u8; 48*1024]; @@ -20,6 +19,7 @@ static RODATA: [u8; 48*1024] = [1u8; 48*1024]; // without also overflowing RAM. static mut DATA: [u8; 16*1024] = [1u8; 16*1024]; +#[entry] fn main() -> ! { unsafe { let _bigdata = ptr::read_volatile(&RODATA as *const u8); diff --git a/cortex-m-rt/examples/device.rs b/cortex-m-rt/examples/device.rs index 4395db2..950a564 100644 --- a/cortex-m-rt/examples/device.rs +++ b/cortex-m-rt/examples/device.rs @@ -5,13 +5,12 @@ #![no_main] #![no_std] -#[macro_use(entry)] extern crate cortex_m_rt as rt; extern crate panic_semihosting; -// the program entry point -entry!(main); +use rt::entry; +#[entry] fn main() -> ! { loop {} } diff --git a/cortex-m-rt/examples/minimal.rs b/cortex-m-rt/examples/minimal.rs index a036046..6f60180 100644 --- a/cortex-m-rt/examples/minimal.rs +++ b/cortex-m-rt/examples/minimal.rs @@ -5,13 +5,13 @@ #![no_main] #![no_std] -#[macro_use(entry)] extern crate cortex_m_rt as rt; extern crate panic_semihosting; -// the program entry point -entry!(main); +use rt::entry; +// the program entry point +#[entry] fn main() -> ! { loop {} } diff --git a/cortex-m-rt/examples/override-exception.rs b/cortex-m-rt/examples/override-exception.rs index 2f100a2..dca31e6 100644 --- a/cortex-m-rt/examples/override-exception.rs +++ b/cortex-m-rt/examples/override-exception.rs @@ -6,28 +6,23 @@ #![no_std] extern crate cortex_m; -#[macro_use(entry, exception)] extern crate cortex_m_rt as rt; extern crate panic_semihosting; use cortex_m::asm; -use rt::ExceptionFrame; - -// the program entry point -entry!(main); +use rt::{entry, exception, ExceptionFrame}; +#[entry] fn main() -> ! { loop {} } -exception!(*, default_handler); - +#[exception(DefaultHandler)] fn default_handler(_irqn: i16) { asm::bkpt(); } -exception!(HardFault, hard_fault); - +#[exception(HardFault)] fn hard_fault(_ef: &ExceptionFrame) -> ! { asm::bkpt(); diff --git a/cortex-m-rt/examples/pre_init.rs b/cortex-m-rt/examples/pre_init.rs index 7258936..00e2f2c 100644 --- a/cortex-m-rt/examples/pre_init.rs +++ b/cortex-m-rt/examples/pre_init.rs @@ -4,19 +4,17 @@ #![no_main] #![no_std] -#[macro_use(entry, pre_init)] extern crate cortex_m_rt as rt; extern crate panic_semihosting; -pre_init!(disable_watchdog); +use rt::{entry, pre_init}; +#[pre_init] unsafe fn disable_watchdog() { // Do what you need to disable the watchdog. } -// the program entry point -entry!(main); - +#[entry] fn main() -> ! { loop {} } diff --git a/cortex-m-rt/examples/state.rs b/cortex-m-rt/examples/state.rs index dbacdaf..72ca194 100644 --- a/cortex-m-rt/examples/state.rs +++ b/cortex-m-rt/examples/state.rs @@ -5,20 +5,18 @@ #![no_main] #![no_std] -#[macro_use(entry, exception)] extern crate cortex_m_rt as rt; extern crate panic_semihosting; -// the program entry point -entry!(main); +use rt::{entry, exception}; +#[entry] fn main() -> ! { loop {} } // exception handler with state -exception!(SysTick, sys_tick, state: u32 = 0); - -fn sys_tick(state: &mut u32) { - *state += 1; +#[exception(SysTick, static STATE: u32 = 0)] +fn sys_tick() { + *STATE += 1; } diff --git a/cortex-m-rt/macros/Cargo.toml b/cortex-m-rt/macros/Cargo.toml new file mode 100644 index 0000000..85e8cd1 --- /dev/null +++ b/cortex-m-rt/macros/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "cortex-m-rt-macros" +version = "0.1.0" +authors = ["Jorge Aparicio "] + +[lib] +proc-macro = true + +[dependencies] +quote = "0.6.6" + +[dependencies.syn] +features = ["extra-traits", "full"] +version = "0.14.8" + +[dev-dependencies] +cortex-m-rt = { path = ".." } diff --git a/cortex-m-rt/macros/src/lib.rs b/cortex-m-rt/macros/src/lib.rs new file mode 100644 index 0000000..3aa494d --- /dev/null +++ b/cortex-m-rt/macros/src/lib.rs @@ -0,0 +1,462 @@ +#![deny(warnings)] + +extern crate proc_macro; +#[macro_use] +extern crate quote; +#[macro_use] +extern crate syn; + +use syn::synom::Synom; +use syn::token::{Colon, Comma, Eq, Static}; +use syn::{Expr, FnArg, Ident, ItemFn, ReturnType, Type, Visibility}; + +use proc_macro::TokenStream; + +/// Attribute to declare the entry point of the program +/// +/// **NOTE** This macro must be invoked once and must be invoked from an accessible module, ideally +/// from the root of the crate. +/// +/// The specified function will be called by the reset handler *after* RAM has been initialized. In +/// the case of the `thumbv7em-none-eabihf` target the FPU will also be enabled before the function +/// is called. +/// +/// The type of the specified function must be `fn() -> !` (never ending function) +/// +/// # Examples +/// +/// ``` no_run +/// # #![no_main] +/// # use cortex_m_rt_macros::entry; +/// #[entry] +/// fn main() -> ! { +/// loop { +/// /* .. */ +/// } +/// } +/// ``` +#[proc_macro_attribute] +pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { + let f: ItemFn = syn::parse(input).expect("`#[entry]` must be applied to a function"); + + // check the function signature + assert!( + f.constness.is_none() + && f.vis == Visibility::Inherited + && f.unsafety.is_none() + && f.abi.is_none() + && f.decl.inputs.is_empty() + && f.decl.generics.params.is_empty() + && f.decl.generics.where_clause.is_none() + && f.decl.variadic.is_none() + && match f.decl.output { + ReturnType::Default => false, + ReturnType::Type(_, ref ty) => match **ty { + Type::Never(_) => true, + _ => false, + }, + }, + "`#[entry]` function must have signature `fn() -> !`" + ); + + assert_eq!( + args.to_string(), + "", + "`entry` attribute must have no arguments" + ); + + // XXX should we blacklist other attributes? + let attrs = f.attrs; + let ident = f.ident; + let block = f.block; + + quote!( + #[export_name = "main"] + #(#attrs)* + pub fn #ident() -> ! #block + ).into() +} + +struct ExceptionArgs { + first: Ident, + second: Option, +} + +impl Synom for ExceptionArgs { + named!(parse -> Self, do_parse!( + first: syn!(Ident) >> + second: option!(syn!(State)) >> ( + ExceptionArgs { first, second } + ) + )); +} + +struct State { + _comma: Comma, + _static: Static, + ident: Ident, + _colon: Colon, + ty: Type, + _eq: Eq, + expr: Expr, +} + +impl Synom for State { + named!(parse -> Self, do_parse!( + _comma: punct!(,) >> + _static: syn!(Static) >> + ident: syn!(Ident) >> + _colon: punct!(:) >> + ty: syn!(Type) >> + _eq: punct!(=) >> + expr: syn!(Expr) >> ( + State { _comma, _static, ident, _colon, ty, _eq, expr } + ) + )); +} + +/// Attribute to declare an exception handler +/// +/// **NOTE** This macro must be invoked from an accessible module, ideally from the root of the +/// crate. +/// +/// # Syntax +/// +/// ``` +/// # use cortex_m_rt_macros::exception; +/// #[exception(SysTick, static COUNT: u32 = 0)] +/// fn handler() { +/// // .. +/// } +/// +/// # fn main() {} +/// ``` +/// +/// where the first argument can be one of: +/// +/// - `DefaultHandler` +/// - `NonMaskableInt` +/// - `HardFault` +/// - `MemoryManagement` (a) +/// - `BusFault` (a) +/// - `UsageFault` (a) +/// - `SecureFault` (b) +/// - `SVCall` +/// - `DebugMonitor` (a) +/// - `PendSV` +/// - `SysTick` +/// +/// and the second is optional. +/// +/// (a) Not available on Cortex-M0 variants (`thumbv6m-none-eabi`) +/// +/// (b) Only available on ARMv8-M +/// +/// # Usage +/// +/// `#[exception(HardFault)]` sets the hard fault handler. The handler must have signature +/// `fn(&ExceptionFrame) -> !`. This handler is not allowed to return as that can cause undefined +/// behavior. +/// +/// `#[exception(DefaultHandler)]` sets the *default* handler. All exceptions which have not been +/// assigned a handler will be serviced by this handler. This handler must have signature `fn(irqn: +/// i16)`. `irqn` is the IRQ number (See CMSIS); `irqn` will be a negative number when the handler +/// is servicing a core exception; `irqn` will be a positive number when the handler is servicing a +/// device specific exception (interrupt). +/// +/// `#[exception(Name)]` overrides the default handler for the exception with the given `Name`. +/// +/// # Examples +/// +/// - Setting the `HardFault` handler +/// +/// ``` +/// # extern crate cortex_m_rt; +/// # extern crate cortex_m_rt_macros; +/// # use cortex_m_rt_macros::exception; +/// #[exception(HardFault)] +/// fn hard_fault(ef: &cortex_m_rt::ExceptionFrame) -> ! { +/// // prints the exception frame as a panic message +/// panic!("{:#?}", ef); +/// } +/// +/// # fn main() {} +/// ``` +/// +/// - Setting the default handler +/// +/// ``` +/// # use cortex_m_rt_macros::exception; +/// #[exception(DefaultHandler)] +/// fn default_handler(irqn: i16) { +/// println!("IRQn = {}", irqn); +/// } +/// +/// # fn main() {} +/// ``` +/// +/// - Overriding the `SysTick` handler +/// +/// ``` +/// extern crate cortex_m_rt as rt; +/// +/// use rt::exception; +/// +/// #[exception(SysTick, static COUNT: i32 = 0)] +/// fn sys_tick() { +/// *COUNT += 1; +/// +/// println!("{}", COUNT); +/// } +/// +/// # fn main() {} +/// ``` +#[proc_macro_attribute] +pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { + let f: ItemFn = syn::parse(input).expect("`#[exception]` must be applied to a function"); + let args: ExceptionArgs = syn::parse(args).expect( + "`exception` attribute expects the exception name as its argument. \ + e.g. `#[exception(HardFault)]`", + ); + let name = args.first; + let name_s = name.to_string(); + + enum Exception { + DefaultHandler, + HardFault, + Other, + } + + // first validation of the exception name + let exn = match &*name_s { + "DefaultHandler" => Exception::DefaultHandler, + "HardFault" => Exception::HardFault, + // NOTE that at this point we don't check if the exception is available on the target (e.g. + // MemoryManagement is not available on Cortex-M0) + "NonMaskableInt" | "MemoryManagement" | "BusFault" | "UsageFault" | "SecureFault" + | "SVCall" | "DebugMonitor" | "PendSV" | "SysTick" => Exception::Other, + _ => panic!("{} is not a valid exception name", name_s), + }; + + // XXX should we blacklist other attributes? + let attrs = f.attrs; + let ident = f.ident; + let block = f.block; + let stmts = &block.stmts; + + match exn { + Exception::DefaultHandler => { + assert!( + f.constness.is_none() + && f.vis == Visibility::Inherited + && f.unsafety.is_none() + && f.abi.is_none() + && f.decl.inputs.len() == 1 + && f.decl.generics.params.is_empty() + && f.decl.generics.where_clause.is_none() + && f.decl.variadic.is_none() + && match f.decl.output { + ReturnType::Default => true, + ReturnType::Type(_, ref ty) => match **ty { + Type::Tuple(ref tuple) => tuple.elems.is_empty(), + _ => false, + }, + }, + "`#[exception(DefaultHandler)]` function must have signature `fn(i16)`" + ); + + assert!( + args.second.is_none(), + "`#[exception(DefaultHandler)]` takes no additional arguments" + ); + + let arg = match f.decl.inputs[0] { + FnArg::Captured(ref arg) => arg, + _ => unreachable!(), + }; + + quote!( + #[export_name = #name_s] + #(#attrs)* + pub fn #ident() { + extern crate core; + + const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; + + let #arg = unsafe { core::ptr::read(SCB_ICSR) as u8 as i16 - 16 }; + + #(#stmts)* + } + ).into() + } + Exception::HardFault => { + assert!( + f.constness.is_none() + && f.vis == Visibility::Inherited + && f.unsafety.is_none() + && f.abi.is_none() + && f.decl.inputs.len() == 1 + && match f.decl.inputs[0] { + FnArg::Captured(ref arg) => match arg.ty { + Type::Reference(ref r) => { + r.lifetime.is_none() && r.mutability.is_none() + } + _ => false, + }, + _ => false, + } + && f.decl.generics.params.is_empty() + && f.decl.generics.where_clause.is_none() + && f.decl.variadic.is_none() + && match f.decl.output { + ReturnType::Default => false, + ReturnType::Type(_, ref ty) => match **ty { + Type::Never(_) => true, + _ => false, + }, + }, + "`#[exception(HardFault)]` function must have signature `fn(&ExceptionFrame) -> !`" + ); + + assert!( + args.second.is_none(), + "`#[exception(HardFault)]` takes no additional arguments" + ); + + let arg = match f.decl.inputs[0] { + FnArg::Captured(ref arg) => arg, + _ => unreachable!(), + }; + + let pat = &arg.pat; + + quote!( + #[export_name = "UserHardFault"] + #(#attrs)* + pub unsafe extern "C" fn #ident(#arg) -> ! { + extern crate cortex_m_rt; + + // further type check of the input argument + let #pat: &cortex_m_rt::ExceptionFrame = #pat; + + #(#stmts)* + } + ).into() + } + Exception::Other => { + assert!( + f.constness.is_none() + && f.vis == Visibility::Inherited + && f.unsafety.is_none() + && f.abi.is_none() + && f.decl.inputs.is_empty() + && f.decl.generics.params.is_empty() + && f.decl.generics.where_clause.is_none() + && f.decl.variadic.is_none() + && match f.decl.output { + ReturnType::Default => true, + ReturnType::Type(_, ref ty) => match **ty { + Type::Tuple(ref tuple) => tuple.elems.is_empty(), + _ => false, + }, + }, + "`#[exception]` functions must have signature `fn()`" + ); + + if let Some(second) = args.second { + let ty = second.ty; + let expr = second.expr; + let state = second.ident; + + quote!( + #[export_name = #name_s] + #(#attrs)* + pub fn #ident() { + extern crate cortex_m_rt; + + cortex_m_rt::Exception::#name; + + static mut __STATE__: #ty = #expr; + + #[allow(non_snake_case)] + let #state: &mut #ty = unsafe { &mut __STATE__ }; + + #(#stmts)* + } + ).into() + } else { + quote!( + #[export_name = #name_s] + #(#attrs)* + pub fn #ident() { + extern crate cortex_m_rt; + + cortex_m_rt::Exception::#name; + + #(#stmts)* + } + ).into() + } + } + } +} + +/// Attribute to mark which function will be called at the beginning of the reset handler. +/// +/// The function must have the signature of `unsafe fn()`. +/// +/// The function passed will be called before static variables are initialized. Any access of static +/// variables will result in undefined behavior. +/// +/// # Examples +/// +/// ``` +/// # use cortex_m_rt_macros::pre_init; +/// #[pre_init] +/// unsafe fn before_main() { +/// // do something here +/// } +/// +/// # fn main() {} +/// ``` +#[proc_macro_attribute] +pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream { + let f: ItemFn = syn::parse(input).expect("`#[pre_init]` must be applied to a function"); + + // check the function signature + assert!( + f.constness.is_none() + && f.vis == Visibility::Inherited + && f.unsafety.is_some() + && f.abi.is_none() + && f.decl.inputs.is_empty() + && f.decl.generics.params.is_empty() + && f.decl.generics.where_clause.is_none() + && f.decl.variadic.is_none() + && match f.decl.output { + ReturnType::Default => true, + ReturnType::Type(_, ref ty) => match **ty { + Type::Tuple(ref tuple) => tuple.elems.is_empty(), + _ => false, + }, + }, + "`#[pre_init]` function must have signature `unsafe fn()`" + ); + + assert_eq!( + args.to_string(), + "", + "`pre_init` attribute must have no arguments" + ); + + // XXX should we blacklist other attributes? + let attrs = f.attrs; + let ident = f.ident; + let block = f.block; + + quote!( + #[export_name = "__pre_init"] + #(#attrs)* + pub unsafe fn #ident() #block + ).into() +} diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 10f60f6..526b28b 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -94,18 +94,16 @@ //! #![no_main] //! #![no_std] //! -//! #[macro_use(entry, exception)] //! extern crate cortex_m_rt as rt; //! //! // makes `panic!` print messages to the host stderr using semihosting //! extern crate panic_semihosting; //! -//! use rt::ExceptionFrame; +//! use rt::entry; //! //! // use `main` as the entry point of this application -//! entry!(main); -//! //! // `main` is not allowed to return +//! #[entry] //! fn main() -> ! { //! // initialization //! @@ -113,20 +111,6 @@ //! // application logic //! } //! } -//! -//! // define the hard fault handler -//! exception!(HardFault, hard_fault); -//! -//! fn hard_fault(ef: &ExceptionFrame) -> ! { -//! panic!("{:#?}", ef); -//! } -//! -//! // define the default exception handler -//! exception!(*, default_handler); -//! -//! fn default_handler(irqn: i16) { -//! panic!("unhandled exception (IRQn={})", irqn); -//! } //! ``` //! //! To actually build this program you need to place a `memory.x` linker script somewhere the linker @@ -397,11 +381,14 @@ #![deny(warnings)] #![no_std] +extern crate cortex_m_rt_macros as macros; extern crate r0; use core::fmt; use core::sync::atomic::{self, Ordering}; +pub use macros::{entry, exception, pre_init}; + /// Registers stacked (pushed into the stack) during an exception #[derive(Clone, Copy)] #[repr(C)] @@ -474,8 +461,6 @@ pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = Reset; #[no_mangle] pub unsafe extern "C" fn Reset() -> ! { extern "C" { - // This symbol will be provided by the user via the `entry!` macro - fn main() -> !; // These symbols come from `link.x` static mut __sbss: u32; @@ -485,11 +470,17 @@ pub unsafe extern "C" fn Reset() -> ! { static mut __edata: u32; static __sidata: u32; + } + + extern "Rust" { + // This symbol will be provided by the user via `#[entry]` + fn main() -> !; + + // This symbol will be provided by the user via `#[pre_init]` fn __pre_init(); } - let pre_init: unsafe extern "C" fn() = __pre_init; - pre_init(); + __pre_init(); // Initialize RAM r0::zero_bss(&mut __sbss, &mut __ebss); @@ -551,31 +542,6 @@ pub unsafe extern "C" fn DefaultHandler_() -> ! { #[no_mangle] pub unsafe extern "C" fn DefaultPreInit() {} -/// Macro to define the entry point of the program -/// -/// **NOTE** This macro must be invoked once and must be invoked from an accessible module, ideally -/// from the root of the crate. -/// -/// Usage: `entry!(path::to::entry::point)` -/// -/// The specified function will be called by the reset handler *after* RAM has been initialized. In -/// the case of the `thumbv7em-none-eabihf` target the FPU will also be enabled before the function -/// is called. -/// -/// The signature of the specified function must be `fn() -> !` (never ending function) -#[macro_export] -macro_rules! entry { - ($path:expr) => { - #[export_name = "main"] - pub extern "C" fn __impl_main() -> ! { - // validate the signature of the program entry point - let f: fn() -> ! = $path; - - f() - } - }; -} - /* Exceptions */ #[doc(hidden)] pub enum Exception { @@ -721,206 +687,3 @@ pub static __INTERRUPTS: [unsafe extern "C" fn(); 32] = [{ DefaultHandler }; 32]; - -/// Macro to set or override a processor core exception handler -/// -/// **NOTE** This macro must be invoked from an accessible module, ideally from the root of the -/// crate. -/// -/// # Syntax -/// -/// ``` ignore -/// exception!( -/// // Name of the exception -/// $Name:ident, -/// -/// // Path to the exception handler (a function) -/// $handler:expr, -/// -/// // Optional, state preserved across invocations of the handler -/// state: $State:ty = $initial_state:expr, -/// ); -/// ``` -/// -/// where `$Name` can be one of: -/// -/// - `*` -/// - `NonMaskableInt` -/// - `HardFault` -/// - `MemoryManagement` (a) -/// - `BusFault` (a) -/// - `UsageFault` (a) -/// - `SecureFault` (b) -/// - `SVCall` -/// - `DebugMonitor` (a) -/// - `PendSV` -/// - `SysTick` -/// -/// (a) Not available on Cortex-M0 variants (`thumbv6m-none-eabi`) -/// -/// (b) Only available on ARMv8-M -/// -/// # Usage -/// -/// `exception!(HardFault, ..)` sets the hard fault handler. The handler must have signature -/// `fn(&ExceptionFrame) -> !`. This handler is not allowed to return as that can cause undefined -/// behavior. It's mandatory to set the `HardFault` handler somewhere in the dependency graph of an -/// application. -/// -/// `exception!(*, ..)` sets the *default* handler. All exceptions which have not been assigned a -/// handler will be serviced by this handler. This handler must have signature `fn(irqn: i16)`. -/// `irqn` is the IRQ number (cf. CMSIS); `irqn` will be a negative number when the handler is -/// servicing a core exception; `irqn` will be a positive number when the handler is servicing a -/// device specific exception (interrupt). It's mandatory to set the default handler somewhere -/// in the dependency graph of an application. -/// -/// `exception!($Exception, ..)` overrides the default handler for `$Exception`. All exceptions, -/// except for `HardFault`, can be assigned some `$State`. -/// -/// # Examples -/// -/// - Setting the `HardFault` handler -/// -/// ``` -/// #[macro_use(exception)] -/// extern crate cortex_m_rt as rt; -/// -/// use rt::ExceptionFrame; -/// -/// exception!(HardFault, hard_fault); -/// -/// fn hard_fault(ef: &ExceptionFrame) -> ! { -/// // prints the exception frame as a panic message -/// panic!("{:#?}", ef); -/// } -/// -/// # fn main() {} -/// ``` -/// -/// - Setting the default handler -/// -/// ``` -/// #[macro_use(exception)] -/// extern crate cortex_m_rt as rt; -/// -/// exception!(*, default_handler); -/// -/// fn default_handler(irqn: i16) { -/// println!("IRQn = {}", irqn); -/// } -/// -/// # fn main() {} -/// ``` -/// -/// - Overriding the `SysTick` handler -/// -/// ``` -/// #[macro_use(exception)] -/// extern crate cortex_m_rt as rt; -/// -/// exception!(SysTick, sys_tick, state: u32 = 0); -/// -/// fn sys_tick(count: &mut u32) { -/// println!("count = {}", *count); -/// -/// *count += 1; -/// } -/// -/// # fn main() {} -/// ``` -#[macro_export] -macro_rules! exception { - (* , $handler:expr) => { - #[allow(unsafe_code)] - #[deny(private_no_mangle_fns)] // raise an error if this item is not accessible - #[no_mangle] - pub unsafe extern "C" fn DefaultHandler() { - extern crate core; - - // validate the signature of the user provided handler - let f: fn(i16) = $handler; - - const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; - - // NOTE not volatile so the compiler can opt the load operation away if the value is - // unused - f(core::ptr::read(SCB_ICSR) as u8 as i16 - 16) - } - }; - - (HardFault, $handler:expr) => { - #[allow(unsafe_code)] - #[deny(private_no_mangle_fns)] // raise an error if this item is not accessible - #[no_mangle] - pub unsafe extern "C" fn UserHardFault(ef: &$crate::ExceptionFrame) { - // validate the signature of the user provided handler - let f: fn(&$crate::ExceptionFrame) -> ! = $handler; - - f(ef) - } - }; - - ($Name:ident, $handler:expr,state: $State:ty = $initial_state:expr) => { - #[allow(unsafe_code)] - #[deny(private_no_mangle_fns)] // raise an error if this item is not accessible - #[no_mangle] - pub unsafe extern "C" fn $Name() { - static mut STATE: $State = $initial_state; - - // check that this exception exists - let _ = $crate::Exception::$Name; - - // validate the signature of the user provided handler - let f: fn(&mut $State) = $handler; - - f(&mut STATE) - } - }; - - ($Name:ident, $handler:expr) => { - #[allow(unsafe_code)] - #[deny(private_no_mangle_fns)] // raise an error if this item is not accessible - #[no_mangle] - pub unsafe extern "C" fn $Name() { - // check that this exception exists - let _ = $crate::Exception::$Name; - - // validate the signature of the user provided handler - let f: fn() = $handler; - - f() - } - }; -} - -/// Macro to set the function to be called at the beginning of the reset handler. -/// -/// The function must have the signature of `unsafe fn()`. -/// -/// The function passed will be called before static variables are initialized. Any access of static -/// variables will result in undefined behavior. -/// -/// # Examples -/// -/// ``` ignore -/// pre_init!(foo::bar); -/// -/// mod foo { -/// pub unsafe fn bar() { -/// // do something here -/// } -/// } -/// ``` -#[macro_export] -macro_rules! pre_init { - ($handler:path) => { - #[allow(unsafe_code)] - #[deny(private_no_mangle_fns)] // raise an error if this item is not accessible - #[no_mangle] - pub unsafe extern "C" fn __pre_init() { - // validate user handler - let f: unsafe fn() = $handler; - f(); - } - }; -} -- cgit v1.2.3 From fc592e4960d99ca8f33c6414ca9903bf0cb6df73 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 3 Sep 2018 20:41:41 +0200 Subject: make `static mut` variables safe to access in the entry point extend / update documentation --- cortex-m-rt/macros/src/lib.rs | 146 +++++++++++++++++++++++++++++++----------- cortex-m-rt/src/lib.rs | 29 +++++---- 2 files changed, 128 insertions(+), 47 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/macros/src/lib.rs b/cortex-m-rt/macros/src/lib.rs index 82457f1..5d6a603 100644 --- a/cortex-m-rt/macros/src/lib.rs +++ b/cortex-m-rt/macros/src/lib.rs @@ -9,7 +9,7 @@ extern crate syn; use proc_macro2::Span; use rand::Rng; -use syn::{FnArg, Ident, Item, ItemFn, ReturnType, Stmt, Type, Visibility}; +use syn::{FnArg, Ident, Item, ItemFn, ItemStatic, ReturnType, Stmt, Type, Visibility}; use proc_macro::TokenStream; @@ -24,13 +24,45 @@ use proc_macro::TokenStream; /// /// The type of the specified function must be `fn() -> !` (never ending function) /// +/// # Properties +/// +/// The entry point will be called by the reset handler. The program can't reference to the entry +/// point, much less invoke it. +/// +/// `static mut` variables declared within the entry point are safe to access. The compiler can't +/// prove this is safe so the attribute will help by making a transformation to the source code: for +/// this reason a variable like `static mut FOO: u32` will become `let FOO: &'static mut u32;`. Note +/// that `&'static mut` references have move semantics. +/// /// # Examples /// +/// - Simple entry point +/// +/// ``` no_run +/// # #![no_main] +/// # use cortex_m_rt_macros::entry; +/// #[entry] +/// fn main() -> ! { +/// loop { +/// /* .. */ +/// } +/// } +/// ``` +/// +/// - `static mut` variables local to the entry point are safe to modify. +/// /// ``` no_run /// # #![no_main] /// # use cortex_m_rt_macros::entry; /// #[entry] /// fn main() -> ! { +/// static mut FOO: u32 = 0; +/// +/// let foo: &'static mut u32 = FOO; +/// assert_eq!(*foo, 0); +/// *foo = 1; +/// assert_eq!(*foo, 1); +/// /// loop { /// /* .. */ /// } @@ -69,12 +101,36 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { // XXX should we blacklist other attributes? let attrs = f.attrs; let ident = f.ident; - let block = f.block; + let (statics, stmts) = extract_static_muts(f.block.stmts); + + let vars = statics + .into_iter() + .map(|var| { + let ident = var.ident; + // `let` can't shadow a `static mut` so we must give the `static` a different + // name. We'll create a new name by appending an underscore to the original name + // of the `static`. + let mut ident_ = ident.to_string(); + ident_.push('_'); + let ident_ = Ident::new(&ident_, Span::call_site()); + let ty = var.ty; + let expr = var.expr; + + quote!( + static mut #ident_: #ty = #expr; + #[allow(non_snake_case, unsafe_code)] + let #ident: &'static mut #ty = unsafe { &mut #ident_ }; + ) + }).collect::>(); quote!( #[export_name = "main"] #(#attrs)* - pub fn #ident() -> ! #block + pub fn #ident() -> ! { + #(#vars)* + + #(#stmts)* + } ).into() } @@ -130,8 +186,15 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { /// mut` variables at the beginning of the body of the function. These variables will be safe to /// access from the function body. /// +/// # Properties +/// /// Exception handlers can only be called by the hardware. Other parts of the program can't refer to -/// the exception handler much less invoke them as if they were functions. +/// the exception handlers, much less invoke them as if they were functions. +/// +/// `static mut` variables declared within an exception handler are safe to access and can be used +/// to preserve state across invocations of the handler. The compiler can't prove this is safe so +/// the attribute will help by making a transformation to the source code: for this reason a +/// variable like `static mut FOO: u32` will become `let FOO: &mut u32;`. /// /// # Examples /// @@ -215,17 +278,7 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { let block = f.block; let stmts = block.stmts; - let mut rng = rand::thread_rng(); - let hash = (0..16) - .map(|i| { - if i == 0 || rng.gen() { - ('a' as u8 + rng.gen::() % 25) as char - } else { - ('0' as u8 + rng.gen::() % 10) as char - } - }).collect::(); - let hash = Ident::new(&hash, Span::call_site()); - + let hash = random_ident(); match exn { Exception::DefaultHandler => { assert!( @@ -336,27 +389,7 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { have signature `fn()`" ); - // Collect all the `static mut` at the beginning of the function body. We'll make them - // safe - let mut istmts = stmts.into_iter(); - - let mut statics = vec![]; - let mut stmts = vec![]; - while let Some(stmt) = istmts.next() { - match stmt { - Stmt::Item(Item::Static(var)) => if var.mutability.is_some() { - statics.push(var); - } else { - stmts.push(Stmt::Item(Item::Static(var))); - }, - _ => { - stmts.push(stmt); - break; - } - } - } - - stmts.extend(istmts); + let (statics, stmts) = extract_static_muts(stmts); let vars = statics .into_iter() @@ -455,3 +488,44 @@ pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream { pub unsafe fn #ident() #block ).into() } + +// Creates a random identifier +fn random_ident() -> Ident { + let mut rng = rand::thread_rng(); + Ident::new( + &(0..16) + .map(|i| { + if i == 0 || rng.gen() { + ('a' as u8 + rng.gen::() % 25) as char + } else { + ('0' as u8 + rng.gen::() % 10) as char + } + }).collect::(), + Span::call_site(), + ) +} + +/// Extracts `static mut` vars from the beginning of the given statements +fn extract_static_muts(stmts: Vec) -> (Vec, Vec) { + let mut istmts = stmts.into_iter(); + + let mut statics = vec![]; + let mut stmts = vec![]; + while let Some(stmt) = istmts.next() { + match stmt { + Stmt::Item(Item::Static(var)) => if var.mutability.is_some() { + statics.push(var); + } else { + stmts.push(Stmt::Item(Item::Static(var))); + }, + _ => { + stmts.push(stmt); + break; + } + } + } + + stmts.extend(istmts); + + (statics, stmts) +} diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 526b28b..17c4a63 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -14,9 +14,16 @@ //! //! - Enabling the FPU before the program entry point if the target is `thumbv7em-none-eabihf`. //! -//! This crate also provides a mechanism to set exception handlers: see the [`exception!`] macro. +//! This crate also provides the following attributes: //! -//! [`exception!`]: macro.exception.html +//! - [`#[entry]`] to declare the entry point of the program +//! - [`#[exception]`] to override an exception handler. If not overridden all exception handlers +//! default to an infinite loop. +//! - [`#[pre_init]`] to run code *before* `static` variables are initialized +//! +//! [`#[entry]`]: ../cortex_m_rt_macros/fn.entry.html +//! [`#[exception]`]: ../cortex_m_rt_macros/fn.exception.html +//! [`#[pre_init]`]: ../cortex_m_rt_macros/fn.pre_init.html //! //! # Requirements //! @@ -87,7 +94,7 @@ //! This section presents a minimal application built on top of `cortex-m-rt`. Apart from the //! mandatory `memory.x` linker script describing the memory layout of the device, the hard fault //! handler and the default exception handler must also be defined somewhere in the dependency -//! graph (cf. [`exception!`]). In this example we define them in the binary crate: +//! graph (see [`#[exception]`]). In this example we define them in the binary crate: //! //! ``` ignore //! // IMPORTANT the standard `main` interface is not used because it requires nightly @@ -191,15 +198,15 @@ //! //! [`entry!`]: macro.entry.html //! -//! - `DefaultHandler`. This is the default handler. This function will contain, or call, the -//! function you declared in the second argument of `exception!(*, ..)`. +//! - `DefaultHandler`. This is the default handler. If not overridden using `#[exception] fn +//! DefaultHandler(..` this will be an infinite loop. //! //! - `HardFault`. This is the hard fault handler. This function is simply a trampoline that jumps -//! into the user defined hard fault handler: `UserHardFault`. The trampoline is required to set up -//! the pointer to the stacked exception frame. +//! into the user defined hard fault handler named `UserHardFault`. The trampoline is required to +//! set up the pointer to the stacked exception frame. //! -//! - `UserHardFault`. This is the user defined hard fault handler. This function will contain, or -//! call, the function you declared in the second argument of `exception!(HardFault, ..)` +//! - `UserHardFault`. This is the user defined hard fault handler. If not overridden using +//! `#[exception] fn HardFault(..` this will be an infinite loop. //! //! - `__STACK_START`. This is the first entry in the `.vector_table` section. This symbol contains //! the initial value of the stack pointer; this is where the stack will be located -- the stack @@ -340,8 +347,8 @@ //! PROVIDE(Bar = DefaultHandler); //! ``` //! -//! This weakly aliases both `Foo` and `Bar`. `DefaultHandler` is the default exception handler that -//! the user provides via `exception!(*, ..)` and that the core exceptions use unless overridden. +//! This weakly aliases both `Foo` and `Bar`. `DefaultHandler` is the default exception handler and +//! that the core exceptions use unless overridden. //! //! Because this linker script is provided by a dependency of the final application the dependency //! must contain build script that puts `device.x` somewhere the linker can find. An example of such -- cgit v1.2.3 From 5975c99f34c2621422589d9e317592e693c5f2b9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 6 Sep 2018 22:38:23 +0200 Subject: error during compilation if two copies of cortex-m-rt are being linked linking two copies into the final binary produces a confusing linker error message. This improves the situation by producing an error at compile time. This will have to be backported into the v0.5.x series or you won't get the new error message. --- cortex-m-rt/CHANGELOG.md | 11 ++++++++++- cortex-m-rt/Cargo.toml | 2 +- cortex-m-rt/src/lib.rs | 4 ++++ 3 files changed, 15 insertions(+), 2 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/CHANGELOG.md b/cortex-m-rt/CHANGELOG.md index dce4dfc..7721d91 100644 --- a/cortex-m-rt/CHANGELOG.md +++ b/cortex-m-rt/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.6.1] - 2018-09-06 + +### Changed + +- Produce a better error message if two (or more) copies of `cortex-m-rt` are + going to be linked into a binary. + ## [v0.6.0] - 2018-09-06 ### Changed @@ -351,7 +358,9 @@ section size addr Initial release -[Unreleased]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.5.3...HEAD +[Unreleased]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.1...HEAD +[v0.6.1]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.6.0...v0.6.1 +[v0.6.0]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.5.3...v0.6.0 [v0.5.3]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.5.2...v0.5.3 [v0.5.2]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.5.1...v0.5.2 [v0.5.1]: https://github.com/rust-embedded/cortex-m-rt/compare/v0.5.0...v0.5.1 diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 2035bf4..c8c84cf 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" name = "cortex-m-rt" readme = "README.md" repository = "https://github.com/japaric/cortex-m-rt" -version = "0.6.0" +version = "0.6.1" [dependencies] r0 = "0.2.1" diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 17c4a63..ad36400 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -396,6 +396,10 @@ use core::sync::atomic::{self, Ordering}; pub use macros::{entry, exception, pre_init}; +#[export_name = "error: cortex-m-rt appears more than once in the dependency graph"] +#[doc(hidden)] +pub static __ONCE__: () = (); + /// Registers stacked (pushed into the stack) during an exception #[derive(Clone, Copy)] #[repr(C)] -- cgit v1.2.3 From 33ebd5ded7bd3f31641c997684bd5608bbcc2098 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Sep 2018 13:58:45 +0200 Subject: README: update the documentation link because we have `readme = "README.md"` set in Cargo.toml the crates.io page renders the README which contains a big "Documentation" link that points to docs.rs which is broken. This commit makes that link point to our GH pages. --- cortex-m-rt/Cargo.toml | 2 +- cortex-m-rt/README.md | 4 ++-- cortex-m-rt/src/lib.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index c8c84cf..276f33c 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["arm", "cortex-m", "runtime", "startup"] license = "MIT OR Apache-2.0" name = "cortex-m-rt" readme = "README.md" -repository = "https://github.com/japaric/cortex-m-rt" +repository = "https://github.com/rust-embedded/cortex-m-rt" version = "0.6.1" [dependencies] diff --git a/cortex-m-rt/README.md b/cortex-m-rt/README.md index 01c2243..d74fa51 100644 --- a/cortex-m-rt/README.md +++ b/cortex-m-rt/README.md @@ -3,11 +3,11 @@ # `cortex-m-rt` -> Minimal runtime / startup for Cortex-M microcontrollers +> Startup code and minimal runtime for Cortex-M microcontrollers This project is developed and maintained by the [Cortex-M team][team]. -# [Documentation](https://docs.rs/cortex-m-rt) +# [Documentation](https://rust-embedded.github.io/cortex-m-rt) # License diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index ad36400..f3e58d0 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -1,4 +1,4 @@ -//! Minimal startup / runtime for Cortex-M microcontrollers +//! Startup code and minimal runtime for Cortex-M microcontrollers //! //! This crate contains all the required parts to build a `no_std` application (binary crate) that //! targets a Cortex-M microcontroller. -- cgit v1.2.3 From fb7368e658ed175a35cdf4a33a02b356aa139523 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 17 Sep 2018 20:12:25 +0200 Subject: implement `#[interrupt]` --- cortex-m-rt/Cargo.toml | 1 + cortex-m-rt/ci/script.sh | 2 +- cortex-m-rt/macros/src/lib.rs | 147 ++++++++++++++++++++- cortex-m-rt/src/lib.rs | 4 +- cortex-m-rt/tests/compile-fail/interrupt-args.rs | 20 +++ .../compile-fail/interrupt-bad-signature-1.rs | 20 +++ .../compile-fail/interrupt-bad-signature-2.rs | 22 +++ .../tests/compile-fail/interrupt-invalid.rs | 21 +++ .../tests/compile-fail/interrupt-not-reexported.rs | 15 +++ .../tests/compile-fail/interrupt-soundness.rs | 33 +++++ cortex-m-rt/tests/compile-fail/interrupt-twice.rs | 31 +++++ 11 files changed, 310 insertions(+), 6 deletions(-) create mode 100644 cortex-m-rt/tests/compile-fail/interrupt-args.rs create mode 100644 cortex-m-rt/tests/compile-fail/interrupt-bad-signature-1.rs create mode 100644 cortex-m-rt/tests/compile-fail/interrupt-bad-signature-2.rs create mode 100644 cortex-m-rt/tests/compile-fail/interrupt-invalid.rs create mode 100644 cortex-m-rt/tests/compile-fail/interrupt-not-reexported.rs create mode 100644 cortex-m-rt/tests/compile-fail/interrupt-soundness.rs create mode 100644 cortex-m-rt/tests/compile-fail/interrupt-twice.rs (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 41a958d..0123750 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -18,6 +18,7 @@ cortex-m-rt-macros = { path = "macros", version = "0.1.1" } cortex-m = "0.5.4" panic-abort = "0.3.0" panic-semihosting = "0.4.0" +panic-halt = "0.2.0" [dev-dependencies.rand] default-features = false diff --git a/cortex-m-rt/ci/script.sh b/cortex-m-rt/ci/script.sh index 9933372..3cffcad 100644 --- a/cortex-m-rt/ci/script.sh +++ b/cortex-m-rt/ci/script.sh @@ -8,7 +8,7 @@ main() { if [ $TARGET = x86_64-unknown-linux-gnu ]; then ( cd macros && cargo check && cargo test ) - cargo test --test compiletest + cargo test --features device --test compiletest fi local examples=( diff --git a/cortex-m-rt/macros/src/lib.rs b/cortex-m-rt/macros/src/lib.rs index 804dd64..711cf0b 100644 --- a/cortex-m-rt/macros/src/lib.rs +++ b/cortex-m-rt/macros/src/lib.rs @@ -411,10 +411,10 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { let expr = var.expr; quote!( - static mut #ident_: #ty = #expr; - #[allow(non_snake_case)] - let #ident: &mut #ty = unsafe { &mut #ident_ }; - ) + static mut #ident_: #ty = #expr; + #[allow(non_snake_case)] + let #ident: &mut #ty = unsafe { &mut #ident_ }; + ) }).collect::>(); quote!( @@ -435,6 +435,145 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { } } +/// Attribute to declare an interrupt (AKA device-specific exception) handler +/// +/// **IMPORTANT**: This attribute must be used on reachable items (i.e. there must be no private +/// modules between the item and the root of the crate). If the item is in the root of the crate +/// you'll be fine. +/// +/// **NOTE**: This attribute is exposed by `cortex-m-rt` only when the `device` feature is enabled. +/// However, that export is not meant to be used directly -- using it will result in a compilation +/// error. You should instead use the device crate (usually generated using `svd2rust`) re-export of +/// that attribute. You need to use the re-export to have the compiler check that the interrupt +/// exists on the target device. +/// +/// # Syntax +/// +/// ``` ignore +/// extern crate device; +/// +/// // the attribute comes from the device crate not from cortex-m-rt +/// use device::interrupt; +/// +/// #[interrupt] +/// fn USART1() { +/// // .. +/// } +/// ``` +/// +/// where the name of the function must be one of the device interrupts. +/// +/// # Usage +/// +/// `#[interrupt] fn Name(..` overrides the default handler for the interrupt with the given `Name`. +/// These handlers must have signature `[unsafe] fn() [-> !]`. It's possible to add state to these +/// handlers by declaring `static mut` variables at the beginning of the body of the function. These +/// variables will be safe to access from the function body. +/// +/// If the interrupt handler has not been overridden it will be dispatched by the default exception +/// handler (`DefaultHandler`). +/// +/// # Properties +/// +/// Interrupts handlers can only be called by the hardware. Other parts of the program can't refer +/// to the interrupt handlers, much less invoke them as if they were functions. +/// +/// `static mut` variables declared within an interrupt handler are safe to access and can be used +/// to preserve state across invocations of the handler. The compiler can't prove this is safe so +/// the attribute will help by making a transformation to the source code: for this reason a +/// variable like `static mut FOO: u32` will become `let FOO: &mut u32;`. +/// +/// # Examples +/// +/// - Using state within an interrupt handler +/// +/// ``` ignore +/// extern crate device; +/// +/// use device::interrupt; +/// +/// #[interrupt] +/// fn TIM2() { +/// static mut COUNT: i32 = 0; +/// +/// // `COUNT` is safe to access and has type `&mut i32` +/// *COUNT += 1; +/// +/// println!("{}", COUNT); +/// } +/// ``` +#[proc_macro_attribute] +pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { + let f: ItemFn = syn::parse(input).expect("`#[interrupt]` must be applied to a function"); + + assert!( + args.to_string() == "", + "`interrupt` attribute must have no arguments" + ); + + let ident = f.ident; + let ident_s = ident.to_string(); + + // XXX should we blacklist other attributes? + let attrs = f.attrs; + let block = f.block; + let stmts = block.stmts; + + assert!( + f.constness.is_none() + && f.vis == Visibility::Inherited + && f.abi.is_none() + && f.decl.inputs.is_empty() + && f.decl.generics.params.is_empty() + && f.decl.generics.where_clause.is_none() + && f.decl.variadic.is_none() + && match f.decl.output { + ReturnType::Default => true, + ReturnType::Type(_, ref ty) => match **ty { + Type::Tuple(ref tuple) => tuple.elems.is_empty(), + Type::Never(..) => true, + _ => false, + }, + }, + "`#[interrupt]` functions must have signature `[unsafe] fn() [-> !]`" + ); + + let (statics, stmts) = extract_static_muts(stmts); + + let vars = statics + .into_iter() + .map(|var| { + let ident = var.ident; + // `let` can't shadow a `static mut` so we must give the `static` a different + // name. We'll create a new name by appending an underscore to the original name + // of the `static`. + let mut ident_ = ident.to_string(); + ident_.push('_'); + let ident_ = Ident::new(&ident_, Span::call_site()); + let ty = var.ty; + let expr = var.expr; + + quote!( + static mut #ident_: #ty = #expr; + #[allow(non_snake_case)] + let #ident: &mut #ty = unsafe { &mut #ident_ }; + ) + }).collect::>(); + + let hash = random_ident(); + quote!( + #[export_name = #ident_s] + #(#attrs)* + pub extern "C" fn #hash() { + interrupt::#ident; + + #(#vars)* + + #(#stmts)* + } + ).into() +} + /// Attribute to mark which function will be called at the beginning of the reset handler. /// /// **IMPORTANT**: This attribute must be used once in the dependency graph and must be used on a diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index f3e58d0..7488cc9 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -394,6 +394,8 @@ extern crate r0; use core::fmt; use core::sync::atomic::{self, Ordering}; +#[cfg(feature = "device")] +pub use macros::interrupt; pub use macros::{entry, exception, pre_init}; #[export_name = "error: cortex-m-rt appears more than once in the dependency graph"] @@ -674,7 +676,7 @@ pub static __EXCEPTIONS: [Vector; 14] = [ // If we are not targeting a specific device we bind all the potential device specific interrupts // to the default handler -#[cfg(all(not(feature = "device"), not(armv6m)))] +#[cfg(all(any(not(feature = "device"), test), not(armv6m)))] #[doc(hidden)] #[link_section = ".vector_table.interrupts"] #[no_mangle] diff --git a/cortex-m-rt/tests/compile-fail/interrupt-args.rs b/cortex-m-rt/tests/compile-fail/interrupt-args.rs new file mode 100644 index 0000000..36af388 --- /dev/null +++ b/cortex-m-rt/tests/compile-fail/interrupt-args.rs @@ -0,0 +1,20 @@ +#![no_main] +#![no_std] + +extern crate cortex_m_rt; +extern crate panic_halt; + +use cortex_m_rt::{entry, interrupt}; + +#[entry] +fn foo() -> ! { + loop {} +} + +enum interrupt { + USART1, +} + +#[interrupt(true)] //~ ERROR custom attribute panicked +//~^ HELP `interrupt` attribute must have no arguments +fn USART1() {} diff --git a/cortex-m-rt/tests/compile-fail/interrupt-bad-signature-1.rs b/cortex-m-rt/tests/compile-fail/interrupt-bad-signature-1.rs new file mode 100644 index 0000000..0222413 --- /dev/null +++ b/cortex-m-rt/tests/compile-fail/interrupt-bad-signature-1.rs @@ -0,0 +1,20 @@ +#![no_main] +#![no_std] + +extern crate cortex_m_rt; +extern crate panic_halt; + +use cortex_m_rt::{entry, interrupt}; + +#[entry] +fn foo() -> ! { + loop {} +} + +enum interrupt { + USART1, +} + +#[interrupt] //~ ERROR custom attribute panicked +//~^ HELP `#[interrupt]` functions must have signature `[unsafe] fn() [-> !]` +fn USART1(undef: i32) {} diff --git a/cortex-m-rt/tests/compile-fail/interrupt-bad-signature-2.rs b/cortex-m-rt/tests/compile-fail/interrupt-bad-signature-2.rs new file mode 100644 index 0000000..0c9000b --- /dev/null +++ b/cortex-m-rt/tests/compile-fail/interrupt-bad-signature-2.rs @@ -0,0 +1,22 @@ +#![no_main] +#![no_std] + +extern crate cortex_m_rt; +extern crate panic_halt; + +use cortex_m_rt::{entry, interrupt}; + +#[entry] +fn foo() -> ! { + loop {} +} + +enum interrupt { + USART1, +} + +#[interrupt] //~ ERROR custom attribute panicked +//~^ HELP `#[interrupt]` functions must have signature `[unsafe] fn() [-> !]` +fn USART1() -> i32 { + 0 +} diff --git a/cortex-m-rt/tests/compile-fail/interrupt-invalid.rs b/cortex-m-rt/tests/compile-fail/interrupt-invalid.rs new file mode 100644 index 0000000..4e79e7d --- /dev/null +++ b/cortex-m-rt/tests/compile-fail/interrupt-invalid.rs @@ -0,0 +1,21 @@ +#![no_main] +#![no_std] + +extern crate cortex_m_rt; +extern crate panic_halt; + +use cortex_m_rt::{entry, interrupt}; + +#[entry] +fn foo() -> ! { + loop {} +} + +enum interrupt { + USART1, +} + +// NOTE this looks a bit better when using a device crate: +// "no variant named `foo` found for type `stm32f30x::Interrupt` in the current scope" +#[interrupt] //~ ERROR no variant named `foo` found for type `interrupt` in the current scope +fn foo() {} diff --git a/cortex-m-rt/tests/compile-fail/interrupt-not-reexported.rs b/cortex-m-rt/tests/compile-fail/interrupt-not-reexported.rs new file mode 100644 index 0000000..9530cf4 --- /dev/null +++ b/cortex-m-rt/tests/compile-fail/interrupt-not-reexported.rs @@ -0,0 +1,15 @@ +#![no_main] +#![no_std] + +extern crate cortex_m_rt; +extern crate panic_halt; + +use cortex_m_rt::{entry, interrupt}; + +#[entry] +fn foo() -> ! { + loop {} +} + +#[interrupt] //~ ERROR failed to resolve. Use of undeclared type or module `interrupt` +fn USART1() {} diff --git a/cortex-m-rt/tests/compile-fail/interrupt-soundness.rs b/cortex-m-rt/tests/compile-fail/interrupt-soundness.rs new file mode 100644 index 0000000..b473a94 --- /dev/null +++ b/cortex-m-rt/tests/compile-fail/interrupt-soundness.rs @@ -0,0 +1,33 @@ +#![no_main] +#![no_std] + +extern crate cortex_m_rt; +extern crate panic_halt; + +use cortex_m_rt::{entry, interrupt}; + +#[entry] +fn foo() -> ! { + loop {} +} + +enum interrupt { + USART1, + USART2, +} + +#[interrupt] +fn USART1() { + static mut COUNT: u64 = 0; + + if *COUNT % 2 == 0 { + *COUNT += 1; + } else { + *COUNT *= 2; + } +} + +#[interrupt] +fn USART2() { + USART1(); //~ ERROR cannot find function `USART1` in this scope +} diff --git a/cortex-m-rt/tests/compile-fail/interrupt-twice.rs b/cortex-m-rt/tests/compile-fail/interrupt-twice.rs new file mode 100644 index 0000000..b59aea9 --- /dev/null +++ b/cortex-m-rt/tests/compile-fail/interrupt-twice.rs @@ -0,0 +1,31 @@ +#![allow(non_camel_case_types)] +#![no_main] +#![no_std] + +extern crate cortex_m_rt; +extern crate panic_halt; + +use cortex_m_rt::{entry, interrupt}; + +#[entry] +fn foo() -> ! { + loop {} +} + +enum interrupt { + USART1, +} + +#[interrupt] +fn USART1() {} + +pub mod reachable { + use cortex_m_rt::interrupt; + + enum interrupt { + USART1, + } + + #[interrupt] //~ ERROR symbol `USART1` is already defined + fn USART1() {} +} -- cgit v1.2.3 From 98eb7ea7816e17b38f03c39173804358adb15a7c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 26 Oct 2018 23:04:03 +0200 Subject: `b UserHardFault` this commit replaces the `bl UserHardFault` instruction in HardFault with `b UserHardFault`. This lets us drop the prologue (`push {r0,lr}`) while preserving the ability to unwind the stack using GDB. To prevent linker errors about relocations when UserHardFault and HardFault end up far away from each other and the target is ARMv6-M (where the `b` instruction only supports offsets of +/- 2KB) we use two *input* sections: .HardFault and .UserHardFault. HardFault is placed in the .HardFault section and UserHardFault is placed in the .UserHardFault section. The .HardFault input section is placed in the output .text section after all the input .text sections, and the .UserHardFault input section is placed after the .HardFault section. This causes the two symbols to always appear next to each other in the output binary, furthermore UserHardFault *always* appears after HardFault so the branch offset of `b UserHardFault` is always a few bytes. It should be noted that neither .HardFault or .UserHardFault will appear in the output of the `size -A` command as they are input sections that get merged into the output .text section. IOW, the sizes of HardFault and UserHardFault will continue to be reported under the .text section. --- cortex-m-rt/asm.s | 9 ++++++--- cortex-m-rt/bin/thumbv6m-none-eabi.a | Bin 920 -> 882 bytes cortex-m-rt/bin/thumbv7em-none-eabi.a | Bin 920 -> 882 bytes cortex-m-rt/bin/thumbv7em-none-eabihf.a | Bin 920 -> 882 bytes cortex-m-rt/bin/thumbv7m-none-eabi.a | Bin 920 -> 882 bytes cortex-m-rt/link.x.in | 2 ++ cortex-m-rt/macros/src/lib.rs | 1 + cortex-m-rt/src/lib.rs | 1 + 8 files changed, 10 insertions(+), 3 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/asm.s b/cortex-m-rt/asm.s index a5748a5..4636bc3 100644 --- a/cortex-m-rt/asm.s +++ b/cortex-m-rt/asm.s @@ -1,7 +1,10 @@ - .section .text.HardFault + # LLD requires that the section flags are explicitly set here + .section .HardFault, "ax" .global HardFault + # .type and .thumb_func are both required; otherwise its Thumb bit does not + # get set and an invalid vector table is generated + .type HardFault,%function .thumb_func HardFault: - push {r0, lr} mrs r0, MSP - bl UserHardFault + b UserHardFault diff --git a/cortex-m-rt/bin/thumbv6m-none-eabi.a b/cortex-m-rt/bin/thumbv6m-none-eabi.a index 4a2f178..9857abc 100644 Binary files a/cortex-m-rt/bin/thumbv6m-none-eabi.a and b/cortex-m-rt/bin/thumbv6m-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv7em-none-eabi.a b/cortex-m-rt/bin/thumbv7em-none-eabi.a index e5ffd6f..3f8b8fe 100644 Binary files a/cortex-m-rt/bin/thumbv7em-none-eabi.a and b/cortex-m-rt/bin/thumbv7em-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv7em-none-eabihf.a b/cortex-m-rt/bin/thumbv7em-none-eabihf.a index e5ffd6f..3f8b8fe 100644 Binary files a/cortex-m-rt/bin/thumbv7em-none-eabihf.a and b/cortex-m-rt/bin/thumbv7em-none-eabihf.a differ diff --git a/cortex-m-rt/bin/thumbv7m-none-eabi.a b/cortex-m-rt/bin/thumbv7m-none-eabi.a index d3cc07e..43c843e 100644 Binary files a/cortex-m-rt/bin/thumbv7m-none-eabi.a and b/cortex-m-rt/bin/thumbv7m-none-eabi.a differ diff --git a/cortex-m-rt/link.x.in b/cortex-m-rt/link.x.in index fde4e70..e6e0d3b 100644 --- a/cortex-m-rt/link.x.in +++ b/cortex-m-rt/link.x.in @@ -86,6 +86,8 @@ SECTIONS .text _stext : { *(.text .text.*); + *(.HardFault); + *(.UserHardFault); } > FLASH /* ### .rodata */ diff --git a/cortex-m-rt/macros/src/lib.rs b/cortex-m-rt/macros/src/lib.rs index 0d29f55..9ce80ad 100644 --- a/cortex-m-rt/macros/src/lib.rs +++ b/cortex-m-rt/macros/src/lib.rs @@ -365,6 +365,7 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { quote!( #[export_name = "UserHardFault"] + #[link_section = ".UserHardFault"] #(#attrs)* pub #unsafety extern "C" fn #hash(#arg) -> ! { extern crate cortex_m_rt; diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 7488cc9..5fb5057 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -532,6 +532,7 @@ pub unsafe extern "C" fn Reset() -> ! { #[allow(unused_variables)] #[doc(hidden)] +#[link_section = ".UserHardFault"] #[no_mangle] pub unsafe extern "C" fn UserHardFault_(ef: &ExceptionFrame) -> ! { loop { -- cgit v1.2.3 From 2f2ad09a0fd7e8fe6e76fafc8da15d5451609121 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 1 Nov 2018 19:05:57 +0100 Subject: Mention interrupt attribute in main crate docs Fixes #137 --- cortex-m-rt/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 5fb5057..4d9bf3f 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -25,6 +25,10 @@ //! [`#[exception]`]: ../cortex_m_rt_macros/fn.exception.html //! [`#[pre_init]`]: ../cortex_m_rt_macros/fn.pre_init.html //! +//! This crate also implements a related attribute called `#[interrupt]`, which allows you +//! to define interrupt handlers. However, since which interrupts are available depends on the +//! microcontroller in use, this attribute should be re-exported and used from a device crate. +//! //! # Requirements //! //! ## `memory.x` -- cgit v1.2.3 From a029b4864b49a9593abc96af4c7a22d4c99e0b6d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 11 Nov 2018 16:43:02 +0100 Subject: change attribute doc links to point to the "Reexports" section. The older links don't work correctly on docs.rs. The "Reexports" section always has valid links to the documentation of each attribute. --- cortex-m-rt/src/lib.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 4d9bf3f..e1b5e45 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -16,19 +16,18 @@ //! //! This crate also provides the following attributes: //! -//! - [`#[entry]`] to declare the entry point of the program -//! - [`#[exception]`] to override an exception handler. If not overridden all exception handlers +//! - `#[entry]` to declare the entry point of the program +//! - `#[exception]` to override an exception handler. If not overridden all exception handlers //! default to an infinite loop. -//! - [`#[pre_init]`] to run code *before* `static` variables are initialized -//! -//! [`#[entry]`]: ../cortex_m_rt_macros/fn.entry.html -//! [`#[exception]`]: ../cortex_m_rt_macros/fn.exception.html -//! [`#[pre_init]`]: ../cortex_m_rt_macros/fn.pre_init.html +//! default to an infinite loop. +//! - `#[pre_init]` to run code *before* `static` variables are initialized //! //! This crate also implements a related attribute called `#[interrupt]`, which allows you //! to define interrupt handlers. However, since which interrupts are available depends on the //! microcontroller in use, this attribute should be re-exported and used from a device crate. //! +//! The documentation for these attributes can be found in the [Reexports](#reexports) section. +//! //! # Requirements //! //! ## `memory.x` -- cgit v1.2.3 From 74976ae36b86f1d99531c8cdb60761f57f844e0e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 11 Nov 2018 17:12:22 +0100 Subject: remove duplicated line --- cortex-m-rt/src/lib.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index e1b5e45..f418e7f 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -19,7 +19,6 @@ //! - `#[entry]` to declare the entry point of the program //! - `#[exception]` to override an exception handler. If not overridden all exception handlers //! default to an infinite loop. -//! default to an infinite loop. //! - `#[pre_init]` to run code *before* `static` variables are initialized //! //! This crate also implements a related attribute called `#[interrupt]`, which allows you -- cgit v1.2.3 From e883c5e962dd7fb420554787010df7f1a10c9926 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 27 Oct 2018 14:19:28 +0200 Subject: rename UserHardFault to HardFault so it matches the exception name (`#[exception] fn HardFault(..`) --- cortex-m-rt/asm.s | 10 +++++----- cortex-m-rt/bin/thumbv6m-none-eabi.a | Bin 882 -> 920 bytes cortex-m-rt/bin/thumbv7em-none-eabi.a | Bin 882 -> 920 bytes cortex-m-rt/bin/thumbv7em-none-eabihf.a | Bin 882 -> 920 bytes cortex-m-rt/bin/thumbv7m-none-eabi.a | Bin 882 -> 920 bytes cortex-m-rt/link.x.in | 8 ++++---- cortex-m-rt/macros/src/lib.rs | 4 ++-- cortex-m-rt/src/lib.rs | 18 +++++++++--------- 8 files changed, 20 insertions(+), 20 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/asm.s b/cortex-m-rt/asm.s index 4636bc3..1f0e74d 100644 --- a/cortex-m-rt/asm.s +++ b/cortex-m-rt/asm.s @@ -1,10 +1,10 @@ # LLD requires that the section flags are explicitly set here - .section .HardFault, "ax" - .global HardFault + .section .HardFaultTrampoline, "ax" + .global HardFaultTrampoline # .type and .thumb_func are both required; otherwise its Thumb bit does not # get set and an invalid vector table is generated - .type HardFault,%function + .type HardFaultTrampoline,%function .thumb_func -HardFault: +HardFaultTrampoline: mrs r0, MSP - b UserHardFault + b HardFault diff --git a/cortex-m-rt/bin/thumbv6m-none-eabi.a b/cortex-m-rt/bin/thumbv6m-none-eabi.a index 9857abc..5938e99 100644 Binary files a/cortex-m-rt/bin/thumbv6m-none-eabi.a and b/cortex-m-rt/bin/thumbv6m-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv7em-none-eabi.a b/cortex-m-rt/bin/thumbv7em-none-eabi.a index 3f8b8fe..fc426f9 100644 Binary files a/cortex-m-rt/bin/thumbv7em-none-eabi.a and b/cortex-m-rt/bin/thumbv7em-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv7em-none-eabihf.a b/cortex-m-rt/bin/thumbv7em-none-eabihf.a index 3f8b8fe..fc426f9 100644 Binary files a/cortex-m-rt/bin/thumbv7em-none-eabihf.a and b/cortex-m-rt/bin/thumbv7em-none-eabihf.a differ diff --git a/cortex-m-rt/bin/thumbv7m-none-eabi.a b/cortex-m-rt/bin/thumbv7m-none-eabi.a index 43c843e..3359875 100644 Binary files a/cortex-m-rt/bin/thumbv7m-none-eabi.a and b/cortex-m-rt/bin/thumbv7m-none-eabi.a differ diff --git a/cortex-m-rt/link.x.in b/cortex-m-rt/link.x.in index e6e0d3b..dff43e0 100644 --- a/cortex-m-rt/link.x.in +++ b/cortex-m-rt/link.x.in @@ -35,7 +35,7 @@ EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */ EXTERN(DefaultHandler); PROVIDE(NonMaskableInt = DefaultHandler); -EXTERN(HardFault); +EXTERN(HardFaultTrampoline); PROVIDE(MemoryManagement = DefaultHandler); PROVIDE(BusFault = DefaultHandler); PROVIDE(UsageFault = DefaultHandler); @@ -46,7 +46,7 @@ PROVIDE(PendSV = DefaultHandler); PROVIDE(SysTick = DefaultHandler); PROVIDE(DefaultHandler = DefaultHandler_); -PROVIDE(UserHardFault = UserHardFault_); +PROVIDE(HardFault = HardFault_); /* # Interrupt vectors */ EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ @@ -86,8 +86,8 @@ SECTIONS .text _stext : { *(.text .text.*); - *(.HardFault); - *(.UserHardFault); + *(.HardFaultTrampoline); + *(.HardFault.*); } > FLASH /* ### .rodata */ diff --git a/cortex-m-rt/macros/src/lib.rs b/cortex-m-rt/macros/src/lib.rs index dfa936b..1013f5e 100644 --- a/cortex-m-rt/macros/src/lib.rs +++ b/cortex-m-rt/macros/src/lib.rs @@ -397,8 +397,8 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { let pat = &arg.pat; quote!( - #[export_name = "UserHardFault"] - #[link_section = ".UserHardFault"] + #[export_name = "HardFault"] + #[link_section = ".HardFault.user"] #(#attrs)* pub #unsafety extern "C" fn #hash(#arg) -> ! { extern crate cortex_m_rt; diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index f418e7f..9f2a20a 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -203,12 +203,12 @@ //! - `DefaultHandler`. This is the default handler. If not overridden using `#[exception] fn //! DefaultHandler(..` this will be an infinite loop. //! -//! - `HardFault`. This is the hard fault handler. This function is simply a trampoline that jumps -//! into the user defined hard fault handler named `UserHardFault`. The trampoline is required to -//! set up the pointer to the stacked exception frame. +//! - `HardFaultTrampoline`. This is the real hard fault handler. This function is simply a +//! trampoline that jumps into the user defined hard fault handler named `HardFault`. The +//! trampoline is required to set up the pointer to the stacked exception frame. //! -//! - `UserHardFault`. This is the user defined hard fault handler. If not overridden using -//! `#[exception] fn HardFault(..` this will be an infinite loop. +//! - `HardFault`. This is the user defined hard fault handler. If not overridden using +//! `#[exception] fn HardFault(..` it will default to an infinite loop. //! //! - `__STACK_START`. This is the first entry in the `.vector_table` section. This symbol contains //! the initial value of the stack pointer; this is where the stack will be located -- the stack @@ -534,9 +534,9 @@ pub unsafe extern "C" fn Reset() -> ! { #[allow(unused_variables)] #[doc(hidden)] -#[link_section = ".UserHardFault"] +#[link_section = ".HardFault.default"] #[no_mangle] -pub unsafe extern "C" fn UserHardFault_(ef: &ExceptionFrame) -> ! { +pub unsafe extern "C" fn HardFault_(ef: &ExceptionFrame) -> ! { loop { // add some side effect to prevent this from turning into a UDF instruction // see rust-lang/rust#28728 for details @@ -590,7 +590,7 @@ pub enum Exception { extern "C" { fn NonMaskableInt(); - fn HardFault(); + fn HardFaultTrampoline(); #[cfg(not(armv6m))] fn MemoryManagement(); @@ -629,7 +629,7 @@ pub static __EXCEPTIONS: [Vector; 14] = [ handler: NonMaskableInt, }, // Exception 3: Hard Fault Interrupt. - Vector { handler: HardFault }, + Vector { handler: HardFaultTrampoline }, // Exception 4: Memory Management Interrupt [not on Cortex-M0 variants]. #[cfg(not(armv6m))] Vector { -- cgit v1.2.3 From 77d205c3209aa5e4ed8821374e43b6bd1657d547 Mon Sep 17 00:00:00 2001 From: chrysn Date: Thu, 24 Jan 2019 19:43:16 +0100 Subject: doc: Remove obsolete references to entry! --- cortex-m-rt/examples/main.rs | 2 +- cortex-m-rt/src/lib.rs | 27 +++++++-------------------- 2 files changed, 8 insertions(+), 21 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/examples/main.rs b/cortex-m-rt/examples/main.rs index b8ab66e..58e3cb4 100644 --- a/cortex-m-rt/examples/main.rs +++ b/cortex-m-rt/examples/main.rs @@ -1,4 +1,4 @@ -//! Directly plug a `main` symbol instead of using `entry!` +//! Directly plug a `main` symbol instead of using `#[entry]` #![deny(warnings)] #![no_main] diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 9f2a20a..1dd686f 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -194,11 +194,11 @@ //! One will always find the following (unmangled) symbols in `cortex-m-rt` applications: //! //! - `Reset`. This is the reset handler. The microcontroller will executed this function upon -//! booting. This function will call the user program entry point (cf. [`entry!`]) using the `main` +//! booting. This function will call the user program entry point (cf. [`#[entry]`]) using the `main` //! symbol so you may also find that symbol in your program; if you do, `main` will contain your //! application code. Some other times `main` gets inlined into `Reset` so you won't find it. //! -//! [`entry!`]: macro.entry.html +//! [`#[entry]`]: https://docs.rs/cortex-m-rt-macros/0.1.5/cortex_m_rt_macros/attr.entry.html //! //! - `DefaultHandler`. This is the default handler. If not overridden using `#[exception] fn //! DefaultHandler(..` this will be an infinite loop. @@ -245,26 +245,13 @@ //! //! ## Setting the program entry point //! -//! This section describes how `entry!` is implemented. This information is useful to developers who -//! want to provide an alternative to `entry!` that provides extra guarantees. +//! This section describes how `#[entry]` is implemented. This information is useful to developers who +//! want to provide an alternative to `#[entry]` that provides extra guarantees. //! //! The `Reset` handler will call a symbol named `main` (unmangled) *after* initializing `.bss` and -//! `.data`, and enabling the FPU (if the target is `thumbv7em-none-eabihf`). `entry!` provides this -//! symbol in its expansion: -//! -//! ``` ignore -//! entry!(path::to::main); -//! -//! // expands into -//! -//! #[export_name = "main"] -//! pub extern "C" fn __impl_main() -> ! { -//! // validate the signature of the program entry point -//! let f: fn() -> ! = path::to::main; -//! -//! f() -//! } -//! ``` +//! `.data`, and enabling the FPU (if the target is `thumbv7em-none-eabihf`). A function with the +//! `entry` attribute will be set to have the export name "`main`"; in addition, its mutable +//! statics are turned into safe mutable references (see [`#[entry]`] for details). //! //! The unmangled `main` symbol must have signature `extern "C" fn() -> !` or its invocation from //! `Reset` will result in undefined behavior. -- cgit v1.2.3 From 94b11bf3905dce22d9c0c6358d7c79ee45b54f01 Mon Sep 17 00:00:00 2001 From: Raz Aloni Date: Fri, 1 Mar 2019 22:12:46 -0800 Subject: Update lib.rs comment describing __INTERRUPTS variable to say __INTERRUPTS instead of __EXCEPTIONS --- cortex-m-rt/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 1dd686f..f7ecb91 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -221,7 +221,7 @@ //! exception vectors, which includes exceptions like `HardFault` and `SysTick`. This array is //! located after `__RESET_VECTOR` in the `.vector_table` section. //! -//! - `__EXCEPTIONS`. This is the device specific interrupt portion of the vector table; its exact +//! - `__INTERRUPTS`. This is the device specific interrupt portion of the vector table; its exact //! size depends on the target device but if the `"device"` feature has not been enabled it will //! have a size of 32 vectors (on ARMv6-M) or 240 vectors (on ARMv7-M). This array is located after //! `__EXCEPTIONS` in the `.vector_table` section. -- cgit v1.2.3 From 94fbbe01189f97aefa8d6a97cc7cd73e5c6f6ec9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 19 Jun 2019 07:12:06 +0200 Subject: add a .uninit section that contains static variables that will not be initialized by the runtime this implements only the linker section described in RFC #116 so that downstream libraries / framework can leverage it without (a) forking this crate or (b) requiring the end user to pass additional linker scripts to the linker when building their crate. This commit doesn't add the user interface described in RFC #116; instead it documents how to use this linker section in the advanced section of the crate level documentation --- cortex-m-rt/link.x.in | 11 +++++++++-- cortex-m-rt/src/lib.rs | 30 ++++++++++++++++++++++++------ 2 files changed, 33 insertions(+), 8 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/link.x.in b/cortex-m-rt/link.x.in index 7a31928..3382d26 100644 --- a/cortex-m-rt/link.x.in +++ b/cortex-m-rt/link.x.in @@ -112,7 +112,6 @@ SECTIONS __edata = .; } > RAM AT > FLASH - /* LMA of .data */ __sidata = LOADADDR(.data); @@ -126,7 +125,15 @@ SECTIONS __ebss = .; } > RAM - /* Place the heap right after `.bss` */ + /* ### .uninit */ + .uninit (NOLOAD) : ALIGN(4) + { + . = ALIGN(4); + *(.uninit .uninit.*); + . = ALIGN(4); + } > RAM + + /* Place the heap right after `.uninit` */ . = ALIGN(4); __sheap = .; diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index f7ecb91..d89df2a 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -360,13 +360,31 @@ //! } //! ``` //! -//! ## `pre_init!` +//! ## Uninitialized static variables //! -//! A user-defined function can be run at the start of the reset handler, before RAM is -//! initialized. The macro `pre_init!` can be called to set the function to be run. The function is -//! intended to perform actions that cannot wait the time it takes for RAM to be initialized, such -//! as disabling a watchdog. As the function is called before RAM is initialized, any access of -//! static variables will result in undefined behavior. +//! The `.uninit` linker section can be used to leave `static mut` variables uninitialized. One use +//! case of unitialized static variables is to avoid zeroing large statically allocated buffers (say +//! to be used as thread stacks) -- this can considerably reduce initialization time on devices that +//! operate at low frequencies. +//! +//! The only correct way to use this section is by placing `static mut` variables with type +//! [`MaybeUninit`] in it. +//! +//! [`MaybeUninit`]: https://doc.rust-lang.org/core/mem/union.MaybeUninit.html +//! +//! ``` ignore +//! use core::mem::MaybeUninit; +//! +//! const STACK_SIZE: usize = 8 * 1024; +//! const NTHREADS: usize = 4; +//! +//! #[link_section = ".uninit.STACKS"] +//! static mut STACKS: MaybeUninit<[[u8; STACK_SIZE]; NTHREADS]> = MaybeUninit::uninit(); +//! ``` +//! +//! Be very careful with the `link_section` attribute because it's easy to misuse in ways that cause +//! undefined behavior. At some point in the future we may add an attribute to safely place static +//! variables in this section. // # Developer notes // -- cgit v1.2.3 From c284d555b5ac3f6807be633e218302ba8cc3bbcf Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 26 Nov 2019 22:49:27 +0100 Subject: Inline attr. macro docs and fix links --- cortex-m-rt/macros/src/lib.rs | 4 ++++ cortex-m-rt/src/lib.rs | 39 +++++++++++++++++++++++---------------- 2 files changed, 27 insertions(+), 16 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/macros/src/lib.rs b/cortex-m-rt/macros/src/lib.rs index b6b0fe4..543130c 100644 --- a/cortex-m-rt/macros/src/lib.rs +++ b/cortex-m-rt/macros/src/lib.rs @@ -1,3 +1,7 @@ +//! Internal implementation details of `cortex-m-rt`. +//! +//! Do not use this crate directly. + #![deny(warnings)] extern crate proc_macro; diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index d89df2a..85d9496 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -16,16 +16,17 @@ //! //! This crate also provides the following attributes: //! -//! - `#[entry]` to declare the entry point of the program -//! - `#[exception]` to override an exception handler. If not overridden all exception handlers -//! default to an infinite loop. -//! - `#[pre_init]` to run code *before* `static` variables are initialized +//! - [`#[entry]`][attr-entry] to declare the entry point of the program +//! - [`#[exception]`][attr-exception] to override an exception handler. If not overridden all +//! exception handlers default to an infinite loop. +//! - [`#[pre_init]`][attr-pre_init] to run code *before* `static` variables are initialized //! //! This crate also implements a related attribute called `#[interrupt]`, which allows you //! to define interrupt handlers. However, since which interrupts are available depends on the //! microcontroller in use, this attribute should be re-exported and used from a device crate. //! -//! The documentation for these attributes can be found in the [Reexports](#reexports) section. +//! The documentation for these attributes can be found in the [Attribute Macros](#attributes) +//! section. //! //! # Requirements //! @@ -194,11 +195,10 @@ //! One will always find the following (unmangled) symbols in `cortex-m-rt` applications: //! //! - `Reset`. This is the reset handler. The microcontroller will executed this function upon -//! booting. This function will call the user program entry point (cf. [`#[entry]`]) using the `main` -//! symbol so you may also find that symbol in your program; if you do, `main` will contain your -//! application code. Some other times `main` gets inlined into `Reset` so you won't find it. -//! -//! [`#[entry]`]: https://docs.rs/cortex-m-rt-macros/0.1.5/cortex_m_rt_macros/attr.entry.html +//! booting. This function will call the user program entry point (cf. [`#[entry]`][attr-entry]) +//! using the `main` symbol so you may also find that symbol in your program; if you do, `main` +//! will contain your application code. Some other times `main` gets inlined into `Reset` so you +//! won't find it. //! //! - `DefaultHandler`. This is the default handler. If not overridden using `#[exception] fn //! DefaultHandler(..` this will be an infinite loop. @@ -227,9 +227,9 @@ //! `__EXCEPTIONS` in the `.vector_table` section. //! //! - `__pre_init`. This is a function to be run before RAM is initialized. It defaults to an empty -//! function. The function called can be changed by calling the `pre_init!` macro. The empty -//! function is not optimized out by default, but if an empty function is passed to `pre_init!` the -//! function call will be optimized out. +//! function. The function called can be changed by applying the [`#[pre_init]`][attr-pre_init] +//! attribute to a function. The empty function is not optimized out by default, but if an empty +//! function is passed to [`#[pre_init]`][attr-pre_init] the function call will be optimized out. //! //! If you override any exception handler you'll find it as an unmangled symbol, e.g. `SysTick` or //! `SVCall`, in the output of `objdump`, @@ -245,13 +245,14 @@ //! //! ## Setting the program entry point //! -//! This section describes how `#[entry]` is implemented. This information is useful to developers who -//! want to provide an alternative to `#[entry]` that provides extra guarantees. +//! This section describes how [`#[entry]`][attr-entry] is implemented. This information is useful +//! to developers who want to provide an alternative to [`#[entry]`][attr-entry] that provides extra +//! guarantees. //! //! The `Reset` handler will call a symbol named `main` (unmangled) *after* initializing `.bss` and //! `.data`, and enabling the FPU (if the target is `thumbv7em-none-eabihf`). A function with the //! `entry` attribute will be set to have the export name "`main`"; in addition, its mutable -//! statics are turned into safe mutable references (see [`#[entry]`] for details). +//! statics are turned into safe mutable references (see [`#[entry]`][attr-entry] for details). //! //! The unmangled `main` symbol must have signature `extern "C" fn() -> !` or its invocation from //! `Reset` will result in undefined behavior. @@ -385,6 +386,10 @@ //! Be very careful with the `link_section` attribute because it's easy to misuse in ways that cause //! undefined behavior. At some point in the future we may add an attribute to safely place static //! variables in this section. +//! +//! [attr-entry]: attr.entry.html +//! [attr-exception]: attr.exception.html +//! [attr-pre_init]: attr.pre_init.html // # Developer notes // @@ -402,7 +407,9 @@ use core::fmt; use core::sync::atomic::{self, Ordering}; #[cfg(feature = "device")] +#[doc(inline)] pub use macros::interrupt; +#[doc(inline)] pub use macros::{entry, exception, pre_init}; #[export_name = "error: cortex-m-rt appears more than once in the dependency graph"] -- cgit v1.2.3 From 43d43bd5c84631fc183f42bc9651e0a076a06f65 Mon Sep 17 00:00:00 2001 From: Ian McIntyre Date: Mon, 9 Dec 2019 20:24:44 -0500 Subject: Remove 'extern crate cortex_m_rt' from macros See justification on 519d46a. Using 'extern crate cortex_m_rt' inside of the macros limits our ability to use the macros crate in other contexts. As long as another crate publicly exports an enumeration of `interrupt` and an enumeration of `exception`, the macros crate may be used in other cortex-m-rt-like systems. --- cortex-m-rt/macros/src/lib.rs | 8 ++------ cortex-m-rt/src/lib.rs | 2 ++ 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/macros/src/lib.rs b/cortex-m-rt/macros/src/lib.rs index 543130c..a844305 100644 --- a/cortex-m-rt/macros/src/lib.rs +++ b/cortex-m-rt/macros/src/lib.rs @@ -173,7 +173,7 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { /// # Syntax /// /// ``` -/// # use cortex_m_rt_macros::exception; +/// # use cortex_m_rt::exception; /// #[exception] /// fn SysTick() { /// // .. @@ -449,10 +449,8 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { })); f.block.stmts = iter::once( syn::parse2(quote! {{ - extern crate cortex_m_rt; - // check that this exception actually exists - cortex_m_rt::Exception::#ident; + exception::#ident; }}) .unwrap(), ) @@ -619,8 +617,6 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { })); f.block.stmts = iter::once( syn::parse2(quote! {{ - extern crate cortex_m_rt; - // Check that this interrupt actually exists interrupt::#ident; }}) diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 85d9496..8bfdd69 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -599,6 +599,8 @@ pub enum Exception { SysTick, } +pub use self::Exception as exception; + extern "C" { fn NonMaskableInt(); -- cgit v1.2.3 From 4666507bfc483862fcadb6d1d5379549bfdd051e Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 11 Jan 2020 18:27:11 +0100 Subject: Make `ExceptionFrame`s fields private --- cortex-m-rt/src/lib.rs | 61 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 17 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 8bfdd69..e184fd2 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -416,33 +416,60 @@ pub use macros::{entry, exception, pre_init}; #[doc(hidden)] pub static __ONCE__: () = (); -/// Registers stacked (pushed into the stack) during an exception +/// Registers stacked (pushed into the stack) during an exception. #[derive(Clone, Copy)] #[repr(C)] pub struct ExceptionFrame { - /// (General purpose) Register 0 - pub r0: u32, + r0: u32, + r1: u32, + r2: u32, + r3: u32, + r12: u32, + lr: u32, + pc: u32, + xpsr: u32, +} - /// (General purpose) Register 1 - pub r1: u32, +impl ExceptionFrame { + /// Returns the value of (general purpose) register 0. + pub fn r0(&self) -> u32 { + self.r0 + } - /// (General purpose) Register 2 - pub r2: u32, + /// Returns the value of (general purpose) register 1. + pub fn r1(&self) -> u32 { + self.r1 + } + + /// Returns the value of (general purpose) register 2. + pub fn r2(&self) -> u32 { + self.r2 + } - /// (General purpose) Register 3 - pub r3: u32, + /// Returns the value of (general purpose) register 3. + pub fn r3(&self) -> u32 { + self.r3 + } - /// (General purpose) Register 12 - pub r12: u32, + /// Returns the value of (general purpose) register 12. + pub fn r12(&self) -> u32 { + self.r12 + } - /// Linker Register - pub lr: u32, + /// Returns the value of the Link Register. + pub fn lr(&self) -> u32 { + self.lr + } - /// Program Counter - pub pc: u32, + /// Returns the value of the Program Counter. + pub fn pc(&self) -> u32 { + self.pc + } - /// Program Status Register - pub xpsr: u32, + /// Returns the value of the Program Status Register. + pub fn xpsr(&self) -> u32 { + self.xpsr + } } impl fmt::Debug for ExceptionFrame { -- cgit v1.2.3 From 7b57c865cb7d61bb7c7d6d4a75770f8f693310df Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 11 Jan 2020 23:41:14 +0100 Subject: Add unsafe setters Otherwise this would be a regression in functionality --- cortex-m-rt/src/lib.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index e184fd2..67a182a 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -470,6 +470,46 @@ impl ExceptionFrame { pub fn xpsr(&self) -> u32 { self.xpsr } + + /// Sets the stacked value of (general purpose) register 0. + pub unsafe fn set_r0(&mut self, value: u32) { + self.r0 = value; + } + + /// Sets the stacked value of (general purpose) register 1. + pub unsafe fn set_r1(&mut self, value: u32) { + self.r1 = value; + } + + /// Sets the stacked value of (general purpose) register 2. + pub unsafe fn set_r2(&mut self, value: u32) { + self.r2 = value; + } + + /// Sets the stacked value of (general purpose) register 3. + pub unsafe fn set_r3(&mut self, value: u32) { + self.r3 = value; + } + + /// Sets the stacked value of (general purpose) register 12. + pub unsafe fn set_r12(&mut self, value: u32) { + self.r12 = value; + } + + /// Sets the stacked value of the Link Register. + pub unsafe fn set_lr(&mut self, value: u32) { + self.lr = value; + } + + /// Sets the stacked value of the Program Counter. + pub unsafe fn set_pc(&mut self, value: u32) { + self.pc = value; + } + + /// Sets the stacked value of the Program Status Register. + pub unsafe fn set_xpsr(&mut self, value: u32) { + self.xpsr = value; + } } impl fmt::Debug for ExceptionFrame { -- cgit v1.2.3 From 8b10534995d8e0285cc38339ab7495d848fe7b7f Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 11 Jan 2020 23:42:47 +0100 Subject: Fix typo --- cortex-m-rt/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 67a182a..bf3a458 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -416,7 +416,7 @@ pub use macros::{entry, exception, pre_init}; #[doc(hidden)] pub static __ONCE__: () = (); -/// Registers stacked (pushed into the stack) during an exception. +/// Registers stacked (pushed onto the stack) during an exception. #[derive(Clone, Copy)] #[repr(C)] pub struct ExceptionFrame { -- cgit v1.2.3 From c27910bca8f6835f843c85765fd50fa521c87f89 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 12 Jan 2020 04:15:08 +0100 Subject: Add safety docs --- cortex-m-rt/src/lib.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index bf3a458..9697843 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -472,41 +472,81 @@ impl ExceptionFrame { } /// Sets the stacked value of (general purpose) register 0. + /// + /// # Safety + /// + /// This affects the `r0` register of the preempted code, which must not rely on it getting + /// restored to its previous value. pub unsafe fn set_r0(&mut self, value: u32) { self.r0 = value; } /// Sets the stacked value of (general purpose) register 1. + /// + /// # Safety + /// + /// This affects the `r1` register of the preempted code, which must not rely on it getting + /// restored to its previous value. pub unsafe fn set_r1(&mut self, value: u32) { self.r1 = value; } /// Sets the stacked value of (general purpose) register 2. + /// + /// # Safety + /// + /// This affects the `r2` register of the preempted code, which must not rely on it getting + /// restored to its previous value. pub unsafe fn set_r2(&mut self, value: u32) { self.r2 = value; } /// Sets the stacked value of (general purpose) register 3. + /// + /// # Safety + /// + /// This affects the `r3` register of the preempted code, which must not rely on it getting + /// restored to its previous value. pub unsafe fn set_r3(&mut self, value: u32) { self.r3 = value; } /// Sets the stacked value of (general purpose) register 12. + /// + /// # Safety + /// + /// This affects the `r12` register of the preempted code, which must not rely on it getting + /// restored to its previous value. pub unsafe fn set_r12(&mut self, value: u32) { self.r12 = value; } /// Sets the stacked value of the Link Register. + /// + /// # Safety + /// + /// This affects the `lr` register of the preempted code, which must not rely on it getting + /// restored to its previous value. pub unsafe fn set_lr(&mut self, value: u32) { self.lr = value; } /// Sets the stacked value of the Program Counter. + /// + /// # Safety + /// + /// This affects the `pc` register of the preempted code, which must not rely on it getting + /// restored to its previous value. pub unsafe fn set_pc(&mut self, value: u32) { self.pc = value; } /// Sets the stacked value of the Program Status Register. + /// + /// # Safety + /// + /// This affects the `xPSR` registers (`IPSR`, `APSR`, and `EPSR`) of the preempted code, which + /// must not rely on them getting restored to their previous value. pub unsafe fn set_xpsr(&mut self, value: u32) { self.xpsr = value; } -- cgit v1.2.3 From a0319a5bb7cc10bdc34ccf818fad66edd2c95d52 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 14 Jan 2020 21:53:09 +0100 Subject: Make `ExceptionFrame` methods `#[inline(always)]` --- cortex-m-rt/src/lib.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 9697843..150ca8e 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -432,41 +432,49 @@ pub struct ExceptionFrame { impl ExceptionFrame { /// Returns the value of (general purpose) register 0. + #[inline(always)] pub fn r0(&self) -> u32 { self.r0 } /// Returns the value of (general purpose) register 1. + #[inline(always)] pub fn r1(&self) -> u32 { self.r1 } /// Returns the value of (general purpose) register 2. + #[inline(always)] pub fn r2(&self) -> u32 { self.r2 } /// Returns the value of (general purpose) register 3. + #[inline(always)] pub fn r3(&self) -> u32 { self.r3 } /// Returns the value of (general purpose) register 12. + #[inline(always)] pub fn r12(&self) -> u32 { self.r12 } /// Returns the value of the Link Register. + #[inline(always)] pub fn lr(&self) -> u32 { self.lr } /// Returns the value of the Program Counter. + #[inline(always)] pub fn pc(&self) -> u32 { self.pc } /// Returns the value of the Program Status Register. + #[inline(always)] pub fn xpsr(&self) -> u32 { self.xpsr } @@ -477,6 +485,7 @@ impl ExceptionFrame { /// /// This affects the `r0` register of the preempted code, which must not rely on it getting /// restored to its previous value. + #[inline(always)] pub unsafe fn set_r0(&mut self, value: u32) { self.r0 = value; } @@ -487,6 +496,7 @@ impl ExceptionFrame { /// /// This affects the `r1` register of the preempted code, which must not rely on it getting /// restored to its previous value. + #[inline(always)] pub unsafe fn set_r1(&mut self, value: u32) { self.r1 = value; } @@ -497,6 +507,7 @@ impl ExceptionFrame { /// /// This affects the `r2` register of the preempted code, which must not rely on it getting /// restored to its previous value. + #[inline(always)] pub unsafe fn set_r2(&mut self, value: u32) { self.r2 = value; } @@ -507,6 +518,7 @@ impl ExceptionFrame { /// /// This affects the `r3` register of the preempted code, which must not rely on it getting /// restored to its previous value. + #[inline(always)] pub unsafe fn set_r3(&mut self, value: u32) { self.r3 = value; } @@ -517,6 +529,7 @@ impl ExceptionFrame { /// /// This affects the `r12` register of the preempted code, which must not rely on it getting /// restored to its previous value. + #[inline(always)] pub unsafe fn set_r12(&mut self, value: u32) { self.r12 = value; } @@ -527,6 +540,7 @@ impl ExceptionFrame { /// /// This affects the `lr` register of the preempted code, which must not rely on it getting /// restored to its previous value. + #[inline(always)] pub unsafe fn set_lr(&mut self, value: u32) { self.lr = value; } @@ -537,6 +551,7 @@ impl ExceptionFrame { /// /// This affects the `pc` register of the preempted code, which must not rely on it getting /// restored to its previous value. + #[inline(always)] pub unsafe fn set_pc(&mut self, value: u32) { self.pc = value; } @@ -547,6 +562,7 @@ impl ExceptionFrame { /// /// This affects the `xPSR` registers (`IPSR`, `APSR`, and `EPSR`) of the preempted code, which /// must not rely on them getting restored to their previous value. + #[inline(always)] pub unsafe fn set_xpsr(&mut self, value: u32) { self.xpsr = value; } -- cgit v1.2.3 From d4a5321c914c49a82edcaac803b1ffa2210bf022 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 6 Feb 2020 00:54:41 +0100 Subject: Fix doctests and run them in CI --- cortex-m-rt/ci/script.sh | 2 + cortex-m-rt/macros/Cargo.toml | 3 - cortex-m-rt/macros/src/lib.rs | 261 ----------------------------------- cortex-m-rt/src/lib.rs | 307 +++++++++++++++++++++++++++++++++++++++--- 4 files changed, 288 insertions(+), 285 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/ci/script.sh b/cortex-m-rt/ci/script.sh index 40ff22a..69262f6 100755 --- a/cortex-m-rt/ci/script.sh +++ b/cortex-m-rt/ci/script.sh @@ -33,6 +33,8 @@ main() { data_overflow ) if [ "$TARGET" != x86_64-unknown-linux-gnu ]; then + RUSTDOCFLAGS="-Cpanic=abort" cargo test --doc + # linking with GNU LD for ex in "${examples[@]}"; do cargo rustc --target "$TARGET" --example "$ex" -- \ diff --git a/cortex-m-rt/macros/Cargo.toml b/cortex-m-rt/macros/Cargo.toml index 96dc22a..8c48e0d 100644 --- a/cortex-m-rt/macros/Cargo.toml +++ b/cortex-m-rt/macros/Cargo.toml @@ -20,6 +20,3 @@ proc-macro2 = "1.0" [dependencies.syn] features = ["extra-traits", "full"] version = "1.0" - -[dev-dependencies] -cortex-m-rt = { path = "..", version = "0.6" } diff --git a/cortex-m-rt/macros/src/lib.rs b/cortex-m-rt/macros/src/lib.rs index 8c1d182..09881b8 100644 --- a/cortex-m-rt/macros/src/lib.rs +++ b/cortex-m-rt/macros/src/lib.rs @@ -16,63 +16,6 @@ use syn::{ ItemStatic, ReturnType, Stmt, Type, Visibility, }; -/// Attribute to declare the entry point of the program -/// -/// **IMPORTANT**: This attribute must appear exactly *once* in the dependency graph. Also, if you -/// are using Rust 1.30 the attribute must be used on a reachable item (i.e. there must be no -/// private modules between the item and the root of the crate); if the item is in the root of the -/// crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 and newer releases. -/// -/// The specified function will be called by the reset handler *after* RAM has been initialized. In -/// the case of the `thumbv7em-none-eabihf` target the FPU will also be enabled before the function -/// is called. -/// -/// The type of the specified function must be `[unsafe] fn() -> !` (never ending function) -/// -/// # Properties -/// -/// The entry point will be called by the reset handler. The program can't reference to the entry -/// point, much less invoke it. -/// -/// `static mut` variables declared within the entry point are safe to access. The compiler can't -/// prove this is safe so the attribute will help by making a transformation to the source code: for -/// this reason a variable like `static mut FOO: u32` will become `let FOO: &'static mut u32;`. Note -/// that `&'static mut` references have move semantics. -/// -/// # Examples -/// -/// - Simple entry point -/// -/// ``` no_run -/// # #![no_main] -/// # use cortex_m_rt_macros::entry; -/// #[entry] -/// fn main() -> ! { -/// loop { -/// /* .. */ -/// } -/// } -/// ``` -/// -/// - `static mut` variables local to the entry point are safe to modify. -/// -/// ``` no_run -/// # #![no_main] -/// # use cortex_m_rt_macros::entry; -/// #[entry] -/// fn main() -> ! { -/// static mut FOO: u32 = 0; -/// -/// let foo: &'static mut u32 = FOO; -/// assert_eq!(*foo, 0); -/// *foo = 1; -/// assert_eq!(*foo, 1); -/// -/// loop { -/// /* .. */ -/// } -/// } -/// ``` #[proc_macro_attribute] pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { let mut f = parse_macro_input!(input as ItemFn); @@ -172,118 +115,6 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { .into() } -/// Attribute to declare an exception handler -/// -/// **IMPORTANT**: If you are using Rust 1.30 this attribute must be used on reachable items (i.e. -/// there must be no private modules between the item and the root of the crate); if the item is in -/// the root of the crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 -/// and newer releases. -/// -/// # Syntax -/// -/// ``` -/// # use cortex_m_rt::exception; -/// #[exception] -/// fn SysTick() { -/// // .. -/// } -/// -/// # fn main() {} -/// ``` -/// -/// where the name of the function must be one of: -/// -/// - `DefaultHandler` -/// - `NonMaskableInt` -/// - `HardFault` -/// - `MemoryManagement` (a) -/// - `BusFault` (a) -/// - `UsageFault` (a) -/// - `SecureFault` (b) -/// - `SVCall` -/// - `DebugMonitor` (a) -/// - `PendSV` -/// - `SysTick` -/// -/// (a) Not available on Cortex-M0 variants (`thumbv6m-none-eabi`) -/// -/// (b) Only available on ARMv8-M -/// -/// # Usage -/// -/// `#[exception] fn HardFault(..` sets the hard fault handler. The handler must have signature -/// `[unsafe] fn(&ExceptionFrame) -> !`. This handler is not allowed to return as that can cause -/// undefined behavior. -/// -/// `#[exception] fn DefaultHandler(..` sets the *default* handler. All exceptions which have not -/// been assigned a handler will be serviced by this handler. This handler must have signature -/// `[unsafe] fn(irqn: i16) [-> !]`. `irqn` is the IRQ number (See CMSIS); `irqn` will be a negative -/// number when the handler is servicing a core exception; `irqn` will be a positive number when the -/// handler is servicing a device specific exception (interrupt). -/// -/// `#[exception] fn Name(..` overrides the default handler for the exception with the given `Name`. -/// These handlers must have signature `[unsafe] fn() [-> !]`. When overriding these other exception -/// it's possible to add state to them by declaring `static mut` variables at the beginning of the -/// body of the function. These variables will be safe to access from the function body. -/// -/// # Properties -/// -/// Exception handlers can only be called by the hardware. Other parts of the program can't refer to -/// the exception handlers, much less invoke them as if they were functions. -/// -/// `static mut` variables declared within an exception handler are safe to access and can be used -/// to preserve state across invocations of the handler. The compiler can't prove this is safe so -/// the attribute will help by making a transformation to the source code: for this reason a -/// variable like `static mut FOO: u32` will become `let FOO: &mut u32;`. -/// -/// # Examples -/// -/// - Setting the `HardFault` handler -/// -/// ``` -/// # extern crate cortex_m_rt; -/// # extern crate cortex_m_rt_macros; -/// # use cortex_m_rt_macros::exception; -/// #[exception] -/// fn HardFault(ef: &cortex_m_rt::ExceptionFrame) -> ! { -/// // prints the exception frame as a panic message -/// panic!("{:#?}", ef); -/// } -/// -/// # fn main() {} -/// ``` -/// -/// - Setting the default handler -/// -/// ``` -/// # use cortex_m_rt_macros::exception; -/// #[exception] -/// fn DefaultHandler(irqn: i16) { -/// println!("IRQn = {}", irqn); -/// } -/// -/// # fn main() {} -/// ``` -/// -/// - Overriding the `SysTick` handler -/// -/// ``` -/// extern crate cortex_m_rt as rt; -/// -/// use rt::exception; -/// -/// #[exception] -/// fn SysTick() { -/// static mut COUNT: i32 = 0; -/// -/// // `COUNT` is safe to access and has type `&mut i32` -/// *COUNT += 1; -/// -/// println!("{}", COUNT); -/// } -/// -/// # fn main() {} -/// ``` #[proc_macro_attribute] pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { let mut f = parse_macro_input!(input as ItemFn); @@ -521,74 +352,6 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { } } -/// Attribute to declare an interrupt (AKA device-specific exception) handler -/// -/// **IMPORTANT**: If you are using Rust 1.30 this attribute must be used on reachable items (i.e. -/// there must be no private modules between the item and the root of the crate); if the item is in -/// the root of the crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 -/// and newer releases. -/// -/// **NOTE**: This attribute is exposed by `cortex-m-rt` only when the `device` feature is enabled. -/// However, that export is not meant to be used directly -- using it will result in a compilation -/// error. You should instead use the device crate (usually generated using `svd2rust`) re-export of -/// that attribute. You need to use the re-export to have the compiler check that the interrupt -/// exists on the target device. -/// -/// # Syntax -/// -/// ``` ignore -/// extern crate device; -/// -/// // the attribute comes from the device crate not from cortex-m-rt -/// use device::interrupt; -/// -/// #[interrupt] -/// fn USART1() { -/// // .. -/// } -/// ``` -/// -/// where the name of the function must be one of the device interrupts. -/// -/// # Usage -/// -/// `#[interrupt] fn Name(..` overrides the default handler for the interrupt with the given `Name`. -/// These handlers must have signature `[unsafe] fn() [-> !]`. It's possible to add state to these -/// handlers by declaring `static mut` variables at the beginning of the body of the function. These -/// variables will be safe to access from the function body. -/// -/// If the interrupt handler has not been overridden it will be dispatched by the default exception -/// handler (`DefaultHandler`). -/// -/// # Properties -/// -/// Interrupts handlers can only be called by the hardware. Other parts of the program can't refer -/// to the interrupt handlers, much less invoke them as if they were functions. -/// -/// `static mut` variables declared within an interrupt handler are safe to access and can be used -/// to preserve state across invocations of the handler. The compiler can't prove this is safe so -/// the attribute will help by making a transformation to the source code: for this reason a -/// variable like `static mut FOO: u32` will become `let FOO: &mut u32;`. -/// -/// # Examples -/// -/// - Using state within an interrupt handler -/// -/// ``` ignore -/// extern crate device; -/// -/// use device::interrupt; -/// -/// #[interrupt] -/// fn TIM2() { -/// static mut COUNT: i32 = 0; -/// -/// // `COUNT` is safe to access and has type `&mut i32` -/// *COUNT += 1; -/// -/// println!("{}", COUNT); -/// } -/// ``` #[proc_macro_attribute] pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { let mut f: ItemFn = syn::parse(input).expect("`#[interrupt]` must be applied to a function"); @@ -696,30 +459,6 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { .into() } -/// Attribute to mark which function will be called at the beginning of the reset handler. -/// -/// **IMPORTANT**: This attribute can appear at most *once* in the dependency graph. Also, if you -/// are using Rust 1.30 the attribute must be used on a reachable item (i.e. there must be no -/// private modules between the item and the root of the crate); if the item is in the root of the -/// crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 and newer -/// releases. -/// -/// The function must have the signature of `unsafe fn()`. -/// -/// The function passed will be called before static variables are initialized. Any access of static -/// variables will result in undefined behavior. -/// -/// # Examples -/// -/// ``` -/// # use cortex_m_rt_macros::pre_init; -/// #[pre_init] -/// unsafe fn before_main() { -/// // do something here -/// } -/// -/// # fn main() {} -/// ``` #[proc_macro_attribute] pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream { let f = parse_macro_input!(input as ItemFn); diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 150ca8e..40b10dc 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -42,7 +42,7 @@ //! program will be placed in the `FLASH` region, whereas the `.bss` and `.data` sections, as well //! as the heap,will be placed in the `RAM` region. //! -//! ``` text +//! ```text //! /* Linker script for the STM32F103C8T6 */ //! MEMORY //! { @@ -58,7 +58,7 @@ //! region -- the stack grows downwards towards smaller address. This symbol can be used to place //! the stack in a different memory region, for example: //! -//! ``` text +//! ```text //! /* Linker script for the STM32F303VCT6 */ //! MEMORY //! { @@ -82,7 +82,7 @@ //! for these devices one must place the `.text` section after this configuration section -- //! `_stext` can be used for this purpose. //! -//! ``` text +//! ```text //! MEMORY //! { //! /* .. */ @@ -99,17 +99,15 @@ //! handler and the default exception handler must also be defined somewhere in the dependency //! graph (see [`#[exception]`]). In this example we define them in the binary crate: //! -//! ``` ignore +//! ```no_run //! // IMPORTANT the standard `main` interface is not used because it requires nightly //! #![no_main] //! #![no_std] //! -//! extern crate cortex_m_rt as rt; +//! // Some panic handler needs to be included. This one halts the processor on panic. +//! extern crate panic_halt; //! -//! // makes `panic!` print messages to the host stderr using semihosting -//! extern crate panic_semihosting; -//! -//! use rt::entry; +//! use cortex_m_rt::entry; //! //! // use `main` as the entry point of this application //! // `main` is not allowed to return @@ -127,7 +125,7 @@ //! can find it, e.g. in the current directory; and then link the program using `cortex-m-rt`'s //! linker script: `link.x`. The required steps are shown below: //! -//! ``` text +//! ```text //! $ cat > memory.x < !]`. It's possible to add state to these +/// handlers by declaring `static mut` variables at the beginning of the body of the function. These +/// variables will be safe to access from the function body. +/// +/// If the interrupt handler has not been overridden it will be dispatched by the default exception +/// handler (`DefaultHandler`). +/// +/// # Properties +/// +/// Interrupts handlers can only be called by the hardware. Other parts of the program can't refer +/// to the interrupt handlers, much less invoke them as if they were functions. +/// +/// `static mut` variables declared within an interrupt handler are safe to access and can be used +/// to preserve state across invocations of the handler. The compiler can't prove this is safe so +/// the attribute will help by making a transformation to the source code: for this reason a +/// variable like `static mut FOO: u32` will become `let FOO: &mut u32;`. +/// +/// # Examples +/// +/// - Using state within an interrupt handler +/// +/// ``` ignore +/// extern crate device; +/// +/// use device::interrupt; +/// +/// #[interrupt] +/// fn TIM2() { +/// static mut COUNT: i32 = 0; +/// +/// // `COUNT` is safe to access and has type `&mut i32` +/// *COUNT += 1; +/// +/// println!("{}", COUNT); +/// } +/// ``` #[cfg(feature = "device")] -#[doc(inline)] pub use macros::interrupt; -#[doc(inline)] -pub use macros::{entry, exception, pre_init}; + +/// Attribute to declare the entry point of the program +/// +/// **IMPORTANT**: This attribute must appear exactly *once* in the dependency graph. Also, if you +/// are using Rust 1.30 the attribute must be used on a reachable item (i.e. there must be no +/// private modules between the item and the root of the crate); if the item is in the root of the +/// crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 and newer releases. +/// +/// The specified function will be called by the reset handler *after* RAM has been initialized. In +/// the case of the `thumbv7em-none-eabihf` target the FPU will also be enabled before the function +/// is called. +/// +/// The type of the specified function must be `[unsafe] fn() -> !` (never ending function) +/// +/// # Properties +/// +/// The entry point will be called by the reset handler. The program can't reference to the entry +/// point, much less invoke it. +/// +/// `static mut` variables declared within the entry point are safe to access. The compiler can't +/// prove this is safe so the attribute will help by making a transformation to the source code: for +/// this reason a variable like `static mut FOO: u32` will become `let FOO: &'static mut u32;`. Note +/// that `&'static mut` references have move semantics. +/// +/// # Examples +/// +/// - Simple entry point +/// +/// ``` no_run +/// # #![no_main] +/// # use cortex_m_rt::entry; +/// #[entry] +/// fn main() -> ! { +/// loop { +/// /* .. */ +/// } +/// } +/// ``` +/// +/// - `static mut` variables local to the entry point are safe to modify. +/// +/// ``` no_run +/// # #![no_main] +/// # use cortex_m_rt::entry; +/// #[entry] +/// fn main() -> ! { +/// static mut FOO: u32 = 0; +/// +/// let foo: &'static mut u32 = FOO; +/// assert_eq!(*foo, 0); +/// *foo = 1; +/// assert_eq!(*foo, 1); +/// +/// loop { +/// /* .. */ +/// } +/// } +/// ``` +pub use macros::entry; + +/// Attribute to declare an exception handler +/// +/// **IMPORTANT**: If you are using Rust 1.30 this attribute must be used on reachable items (i.e. +/// there must be no private modules between the item and the root of the crate); if the item is in +/// the root of the crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 +/// and newer releases. +/// +/// # Syntax +/// +/// ``` +/// # use cortex_m_rt::exception; +/// #[exception] +/// fn SysTick() { +/// // .. +/// } +/// +/// # fn main() {} +/// ``` +/// +/// where the name of the function must be one of: +/// +/// - `DefaultHandler` +/// - `NonMaskableInt` +/// - `HardFault` +/// - `MemoryManagement` (a) +/// - `BusFault` (a) +/// - `UsageFault` (a) +/// - `SecureFault` (b) +/// - `SVCall` +/// - `DebugMonitor` (a) +/// - `PendSV` +/// - `SysTick` +/// +/// (a) Not available on Cortex-M0 variants (`thumbv6m-none-eabi`) +/// +/// (b) Only available on ARMv8-M +/// +/// # Usage +/// +/// `#[exception] fn HardFault(..` sets the hard fault handler. The handler must have signature +/// `[unsafe] fn(&ExceptionFrame) -> !`. This handler is not allowed to return as that can cause +/// undefined behavior. +/// +/// `#[exception] fn DefaultHandler(..` sets the *default* handler. All exceptions which have not +/// been assigned a handler will be serviced by this handler. This handler must have signature +/// `[unsafe] fn(irqn: i16) [-> !]`. `irqn` is the IRQ number (See CMSIS); `irqn` will be a negative +/// number when the handler is servicing a core exception; `irqn` will be a positive number when the +/// handler is servicing a device specific exception (interrupt). +/// +/// `#[exception] fn Name(..` overrides the default handler for the exception with the given `Name`. +/// These handlers must have signature `[unsafe] fn() [-> !]`. When overriding these other exception +/// it's possible to add state to them by declaring `static mut` variables at the beginning of the +/// body of the function. These variables will be safe to access from the function body. +/// +/// # Properties +/// +/// Exception handlers can only be called by the hardware. Other parts of the program can't refer to +/// the exception handlers, much less invoke them as if they were functions. +/// +/// `static mut` variables declared within an exception handler are safe to access and can be used +/// to preserve state across invocations of the handler. The compiler can't prove this is safe so +/// the attribute will help by making a transformation to the source code: for this reason a +/// variable like `static mut FOO: u32` will become `let FOO: &mut u32;`. +/// +/// # Examples +/// +/// - Setting the `HardFault` handler +/// +/// ``` +/// # extern crate cortex_m_rt; +/// # extern crate cortex_m_rt_macros; +/// use cortex_m_rt::{ExceptionFrame, exception}; +/// +/// #[exception] +/// fn HardFault(ef: &ExceptionFrame) -> ! { +/// // prints the exception frame as a panic message +/// panic!("{:#?}", ef); +/// } +/// +/// # fn main() {} +/// ``` +/// +/// - Setting the default handler +/// +/// ``` +/// use cortex_m_rt::exception; +/// +/// #[exception] +/// fn DefaultHandler(irqn: i16) { +/// println!("IRQn = {}", irqn); +/// } +/// +/// # fn main() {} +/// ``` +/// +/// - Overriding the `SysTick` handler +/// +/// ``` +/// use cortex_m_rt::exception; +/// +/// #[exception] +/// fn SysTick() { +/// static mut COUNT: i32 = 0; +/// +/// // `COUNT` is safe to access and has type `&mut i32` +/// *COUNT += 1; +/// +/// println!("{}", COUNT); +/// } +/// +/// # fn main() {} +/// ``` +pub use macros::exception; + +/// Attribute to mark which function will be called at the beginning of the reset handler. +/// +/// **IMPORTANT**: This attribute can appear at most *once* in the dependency graph. Also, if you +/// are using Rust 1.30 the attribute must be used on a reachable item (i.e. there must be no +/// private modules between the item and the root of the crate); if the item is in the root of the +/// crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 and newer +/// releases. +/// +/// The function must have the signature of `unsafe fn()`. +/// +/// The function passed will be called before static variables are initialized. Any access of static +/// variables will result in undefined behavior. +/// +/// # Examples +/// +/// ``` +/// # use cortex_m_rt::pre_init; +/// #[pre_init] +/// unsafe fn before_main() { +/// // do something here +/// } +/// +/// # fn main() {} +/// ``` +pub use macros::pre_init; #[export_name = "error: cortex-m-rt appears more than once in the dependency graph"] #[doc(hidden)] @@ -722,6 +984,7 @@ pub enum Exception { SysTick, } +#[doc(hidden)] pub use self::Exception as exception; extern "C" { @@ -766,7 +1029,9 @@ pub static __EXCEPTIONS: [Vector; 14] = [ handler: NonMaskableInt, }, // Exception 3: Hard Fault Interrupt. - Vector { handler: HardFaultTrampoline }, + Vector { + handler: HardFaultTrampoline, + }, // Exception 4: Memory Management Interrupt [not on Cortex-M0 variants]. #[cfg(not(armv6m))] Vector { -- cgit v1.2.3 From 670dfe9738c38e670f2f750f5573b6649c86feae Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 17 Feb 2020 00:18:33 +0100 Subject: Expand #[pre_init] safety docs, discourage its use --- cortex-m-rt/src/lib.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 40b10dc..3522476 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -658,9 +658,18 @@ pub use macros::exception; /// /// The function must have the signature of `unsafe fn()`. /// -/// The function passed will be called before static variables are initialized. Any access of static +/// # Safety +/// +/// The function will be called before static variables are initialized. Any access of static /// variables will result in undefined behavior. /// +/// **Warning**: Due to [rvalue static promotion][rfc1414] static variables may be accessed whenever +/// taking a reference to a constant. This means that even trivial expressions such as `&1` in the +/// `#[pre_init]` function *or any code called by it* will cause **immediate undefined behavior**. +/// +/// Users are advised to only use the `#[pre_init]` feature when absolutely necessary as these +/// constraints make safe usage difficult. +/// /// # Examples /// /// ``` @@ -672,6 +681,8 @@ pub use macros::exception; /// /// # fn main() {} /// ``` +/// +/// [rfc1414]: https://github.com/rust-lang/rfcs/blob/master/text/1414-rvalue_static_promotion.md pub use macros::pre_init; #[export_name = "error: cortex-m-rt appears more than once in the dependency graph"] -- cgit v1.2.3 From 39b21be089a20ea7617dff97becfe61c191f3eb2 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 17 Feb 2020 00:48:19 +0100 Subject: Ignore a doctest again I accidentally typoed `no_run`, but compiling the test fails since the `device.x` path is wrong. I don't think this can be fixed, so ignore the test instead. --- cortex-m-rt/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 40b10dc..f269532 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -342,7 +342,7 @@ //! must contain build script that puts `device.x` somewhere the linker can find. An example of such //! build script is shown below: //! -//! ```no_ruin +//! ```ignore //! use std::env; //! use std::fs::File; //! use std::io::Write; -- cgit v1.2.3 From ffffb7b3aaef1d9bb4e4b81347ed8f1d50e50ea4 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Mon, 30 Mar 2020 10:02:16 +0200 Subject: Changed Hardfault's and DefaultHander's default implementations to panic --- cortex-m-rt/src/lib.rs | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 0d62d47..06e945d 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -199,14 +199,15 @@ //! won't find it. //! //! - `DefaultHandler`. This is the default handler. If not overridden using `#[exception] fn -//! DefaultHandler(..` this will be an infinite loop. +//! DefaultHandler(..` this will cause a panic with the message "DefaultHandler #`i`", where `i` is +//! the number of the interrupt handler. //! //! - `HardFaultTrampoline`. This is the real hard fault handler. This function is simply a //! trampoline that jumps into the user defined hard fault handler named `HardFault`. The //! trampoline is required to set up the pointer to the stacked exception frame. //! //! - `HardFault`. This is the user defined hard fault handler. If not overridden using -//! `#[exception] fn HardFault(..` it will default to an infinite loop. +//! `#[exception] fn HardFault(..` it will default to a panic with message "Hardfault". //! //! - `__STACK_START`. This is the first entry in the `.vector_table` section. This symbol contains //! the initial value of the stack pointer; this is where the stack will be located -- the stack @@ -402,7 +403,6 @@ extern crate cortex_m_rt_macros as macros; extern crate r0; use core::fmt; -use core::sync::atomic::{self, Ordering}; /// Attribute to declare an interrupt (AKA device-specific exception) handler /// @@ -945,21 +945,17 @@ pub unsafe extern "C" fn Reset() -> ! { #[link_section = ".HardFault.default"] #[no_mangle] pub unsafe extern "C" fn HardFault_(ef: &ExceptionFrame) -> ! { - loop { - // add some side effect to prevent this from turning into a UDF instruction - // see rust-lang/rust#28728 for details - atomic::compiler_fence(Ordering::SeqCst); - } + panic!("Hardfault"); } #[doc(hidden)] #[no_mangle] pub unsafe extern "C" fn DefaultHandler_() -> ! { - loop { - // add some side effect to prevent this from turning into a UDF instruction - // see rust-lang/rust#28728 for details - atomic::compiler_fence(Ordering::SeqCst); - } + const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; + + let irqn = core::ptr::read(SCB_ICSR) as u8 as i16 - 16; + + panic!("DefaultHandler #{}", irqn); } #[doc(hidden)] -- cgit v1.2.3 From 853a47fbf5cf76367a99f1d347dfc71a330f240e Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Mon, 30 Mar 2020 10:06:55 +0200 Subject: New compile-fail string for interrupt-invalid --- cortex-m-rt/src/lib.rs | 4 ++-- cortex-m-rt/tests/compile-fail/interrupt-invalid.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 06e945d..8b43c52 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -207,7 +207,7 @@ //! trampoline is required to set up the pointer to the stacked exception frame. //! //! - `HardFault`. This is the user defined hard fault handler. If not overridden using -//! `#[exception] fn HardFault(..` it will default to a panic with message "Hardfault". +//! `#[exception] fn HardFault(..` it will default to a panic with message "HardFault". //! //! - `__STACK_START`. This is the first entry in the `.vector_table` section. This symbol contains //! the initial value of the stack pointer; this is where the stack will be located -- the stack @@ -945,7 +945,7 @@ pub unsafe extern "C" fn Reset() -> ! { #[link_section = ".HardFault.default"] #[no_mangle] pub unsafe extern "C" fn HardFault_(ef: &ExceptionFrame) -> ! { - panic!("Hardfault"); + panic!("HardFault"); } #[doc(hidden)] diff --git a/cortex-m-rt/tests/compile-fail/interrupt-invalid.rs b/cortex-m-rt/tests/compile-fail/interrupt-invalid.rs index e915518..f2ec718 100644 --- a/cortex-m-rt/tests/compile-fail/interrupt-invalid.rs +++ b/cortex-m-rt/tests/compile-fail/interrupt-invalid.rs @@ -19,4 +19,4 @@ enum interrupt { // NOTE this looks a bit better when using a device crate: // "no variant named `foo` found for type `stm32f30x::Interrupt` in the current scope" #[interrupt] -fn foo() {} //~ ERROR no variant or associated item named `foo` found for type `interrupt` in the current scope +fn foo() {} //~ ERROR no variant or associated item named `foo` found for enum `interrupt` in the current scope [E0599] -- cgit v1.2.3 From b731402e5e7da107be6f2eafd91b20aad3095a8e Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Sat, 4 Apr 2020 19:05:56 +0100 Subject: Add statement of MSRV to docs --- cortex-m-rt/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 0d62d47..867d671 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -388,6 +388,10 @@ //! [attr-entry]: attr.entry.html //! [attr-exception]: attr.exception.html //! [attr-pre_init]: attr.pre_init.html +//! +//! # Minimum Supported Rust Version (MSRV) +//! +//! The MSRV of this release is Rust 1.32.0. // # Developer notes // -- cgit v1.2.3 From 36033333a4e99983cf58110707ec1e8133c2914b Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Sun, 5 Apr 2020 15:53:34 +0100 Subject: Update MSRV to 1.39.0, fix doc test that fails <1.41.0. --- cortex-m-rt/.travis.yml | 14 +++++++------- cortex-m-rt/src/lib.rs | 3 ++- 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/.travis.yml b/cortex-m-rt/.travis.yml index 2e4be47..4043e4a 100644 --- a/cortex-m-rt/.travis.yml +++ b/cortex-m-rt/.travis.yml @@ -4,24 +4,24 @@ matrix: allow_failures: - rust: nightly include: - # MSRV 1.32.0 ############################################################# + # MSRV 1.39.0 ############################################################# - env: TARGET=x86_64-unknown-linux-gnu - rust: 1.32.0 + rust: 1.39.0 - env: TARGET=thumbv6m-none-eabi - rust: 1.32.0 + rust: 1.39.0 - env: TARGET=thumbv7m-none-eabi - rust: 1.32.0 + rust: 1.39.0 - env: TARGET=thumbv7em-none-eabi - rust: 1.32.0 + rust: 1.39.0 - env: TARGET=thumbv7em-none-eabihf - rust: 1.32.0 + rust: 1.39.0 - env: TARGET=thumbv8m.main-none-eabi - rust: 1.32.0 + rust: 1.39.0 # Stable ################################################################## - env: TARGET=x86_64-unknown-linux-gnu diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 867d671..4dabad6 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -372,6 +372,7 @@ //! [`MaybeUninit`]: https://doc.rust-lang.org/core/mem/union.MaybeUninit.html //! //! ```no_run,edition2018 +//! # extern crate core; //! use core::mem::MaybeUninit; //! //! const STACK_SIZE: usize = 8 * 1024; @@ -391,7 +392,7 @@ //! //! # Minimum Supported Rust Version (MSRV) //! -//! The MSRV of this release is Rust 1.32.0. +//! The MSRV of this release is Rust 1.39.0. // # Developer notes // -- cgit v1.2.3 From 169328090dbbfd6e792f994d337958ee4e53e0a6 Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Tue, 19 May 2020 19:56:58 +0200 Subject: Get rid of #[deny(warnings)] This is considered harmful as the warnings may change with any compiler release. Signed-off-by: Daniel Egger --- cortex-m-rt/macros/src/lib.rs | 2 -- cortex-m-rt/src/lib.rs | 1 - 2 files changed, 3 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/macros/src/lib.rs b/cortex-m-rt/macros/src/lib.rs index 09881b8..3c532c0 100644 --- a/cortex-m-rt/macros/src/lib.rs +++ b/cortex-m-rt/macros/src/lib.rs @@ -2,8 +2,6 @@ //! //! Do not use this crate directly. -#![deny(warnings)] - extern crate proc_macro; use proc_macro::TokenStream; diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index d680b6d..1988df6 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -401,7 +401,6 @@ // here will appear in the linker script (`link.x`) in conjunction with the `KEEP` command. #![deny(missing_docs)] -#![deny(warnings)] #![no_std] extern crate cortex_m_rt_macros as macros; -- cgit v1.2.3 From f10a81030055d85c49d7cc5c9124942debbc949e Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Fri, 3 Jul 2020 15:05:07 +0100 Subject: Replace __ONCE__ with Cargo links key --- cortex-m-rt/Cargo.toml | 1 + cortex-m-rt/src/lib.rs | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 8fd075f..f8f8342 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -14,6 +14,7 @@ readme = "README.md" repository = "https://github.com/rust-embedded/cortex-m-rt" version = "0.6.11" autoexamples = true +links = "cortex-m-rt" # Prevent multiple versions of cortex-m-rt being linked [dependencies] r0 = "1.0" diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 1988df6..08037d2 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -689,10 +689,6 @@ pub use macros::exception; /// [rfc1414]: https://github.com/rust-lang/rfcs/blob/master/text/1414-rvalue_static_promotion.md pub use macros::pre_init; -#[export_name = "error: cortex-m-rt appears more than once in the dependency graph"] -#[doc(hidden)] -pub static __ONCE__: () = (); - /// Registers stacked (pushed onto the stack) during an exception. #[derive(Clone, Copy)] #[repr(C)] -- cgit v1.2.3 From 434d4af0ebc3b3f409a6c1707f80506144fce63d Mon Sep 17 00:00:00 2001 From: Ian McIntyre Date: Sun, 5 Jul 2020 09:51:17 -0400 Subject: Mark main() with a C ABI The documentation says that main() should have a C ABI. Additionally, the #[entry] macro will create a main() function that has a C ABI. Marking main() as 'extern "Rust"' is inconsistent with its calling convention. --- cortex-m-rt/src/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 1988df6..4dabb29 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -897,12 +897,11 @@ pub unsafe extern "C" fn Reset() -> ! { static mut __edata: u32; static __sidata: u32; - } - - extern "Rust" { // This symbol will be provided by the user via `#[entry]` fn main() -> !; + } + extern "Rust" { // This symbol will be provided by the user via `#[pre_init]` fn __pre_init(); } -- cgit v1.2.3 From 37f58d93e707c458d8a3f19d34335e349dd6d9fb Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Thu, 9 Jul 2020 02:34:47 +0100 Subject: Keep __ONCE__ for backcompat --- cortex-m-rt/src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 08037d2..13f41f4 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -689,6 +689,14 @@ pub use macros::exception; /// [rfc1414]: https://github.com/rust-lang/rfcs/blob/master/text/1414-rvalue_static_promotion.md pub use macros::pre_init; +// We export this static with an informative name so that if an application attempts to link +// two copies of cortex-m-rt together, linking will fail. We also declare a links key in +// Cargo.toml which is the more modern way to solve the same problem, but we have to keep +// __ONCE__ around to prevent linking with versions before the links key was added. +#[export_name = "error: cortex-m-rt appears more than once in the dependency graph"] +#[doc(hidden)] +pub static __ONCE__: () = (); + /// Registers stacked (pushed onto the stack) during an exception. #[derive(Clone, Copy)] #[repr(C)] -- cgit v1.2.3 From cdc02c64d92bb7fdc8efb5e66c67f90c1dc8ec94 Mon Sep 17 00:00:00 2001 From: Thales Fragoso Date: Sun, 12 Jul 2020 15:36:23 -0300 Subject: Add barriers after FPU enabling --- cortex-m-rt/Cargo.toml | 2 +- cortex-m-rt/src/lib.rs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index f8f8342..1a62ab6 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -19,9 +19,9 @@ links = "cortex-m-rt" # Prevent multiple versions of cortex-m-rt being linked [dependencies] r0 = "1.0" cortex-m-rt-macros = { path = "macros", version = "=0.6.11" } +cortex-m = "0.6" [dev-dependencies] -cortex-m = "0.6" panic-halt = "0.2.0" cortex-m-semihosting = "0.3" diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index ba50572..47bc1f7 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -916,12 +916,12 @@ pub unsafe extern "C" fn Reset() -> ! { r0::zero_bss(&mut __sbss, &mut __ebss); r0::init_data(&mut __sdata, &mut __edata, &__sidata); + #[allow(clippy::match_single_binding)] match () { #[cfg(not(has_fpu))] () => main(), #[cfg(has_fpu)] () => { - // We redefine these here to avoid pulling the `cortex-m` crate as a dependency const SCB_CPACR: *mut u32 = 0xE000_ED88 as *mut u32; const SCB_CPACR_FPU_ENABLE: u32 = 0b01_01 << 20; const SCB_CPACR_FPU_USER: u32 = 0b10_10 << 20; @@ -932,6 +932,9 @@ pub unsafe extern "C" fn Reset() -> ! { *SCB_CPACR | SCB_CPACR_FPU_ENABLE | SCB_CPACR_FPU_USER, ); + cortex_m::asm::dsb(); + cortex_m::asm::isb(); + // this is used to prevent the compiler from inlining the user `main` into the reset // handler. Inlining can cause the FPU instructions in the user `main` to be executed // before enabling the FPU, and that would produce a hard to diagnose hard fault at -- cgit v1.2.3 From e7c72973c5a59d3a6245560a4892fd56966debe4 Mon Sep 17 00:00:00 2001 From: Dominik Boehi Date: Wed, 22 Jul 2020 19:42:36 +0200 Subject: Make Vector public in interrupt example If the `Vector`union is not public, the example code leads to a compilation error because `pub static __INTERRUPTS` leaks the private type `Vector`. --- cortex-m-rt/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 47bc1f7..bab2844 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -283,7 +283,7 @@ //! IRQ number = 2, and `Bar`, with IRQ number = 4. //! //! ```no_run -//! union Vector { +//! pub union Vector { //! handler: unsafe extern "C" fn(), //! reserved: usize, //! } -- cgit v1.2.3 From 44c56187772e88f7c38e0b68824a9d163958fd49 Mon Sep 17 00:00:00 2001 From: Todd Stellanova Date: Thu, 30 Jul 2020 17:09:09 -0700 Subject: Doc adding memory sections in memory.x --- cortex-m-rt/src/lib.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 47bc1f7..8139e7f 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -92,6 +92,7 @@ //! _stext = ORIGIN(FLASH) + 0x40C //! ``` //! +//! //! # An example //! //! This section presents a minimal application built on top of `cortex-m-rt`. Apart from the @@ -387,6 +388,39 @@ //! undefined behavior. At some point in the future we may add an attribute to safely place static //! variables in this section. //! +//! ## Extra Sections +//! +//! Some microcontrollers provide additional memory regions beyond RAM and FLASH. +//! For example, some STM32 devices provide "CCM" or core-coupled RAM that is +//! only accessible from the core. In order to access these using +//! `#[link_section=".foo"]` from your code, you need to modify `memory.x` +//! to declare the additional sections: +//! +//! ```text +//! MEMORY +//! { +//! FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K +//! RAM (rw) : ORIGIN = 0x20000000, LENGTH = 128K +//! CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K +//! } +//! +//! SECTIONS +//! { +//! .ccmram (NOLOAD) : ALIGN(4) +//! { +//! *(.ccmram .ccmram.*); +//! . = ALIGN(4); +//! } > CCMRAM +//! } INSERT AFTER .bss; +//! ``` +//! +//! You can then use something like this to place a variable into this specific section of memory: +//! +//! ```no_run,edition2018 +//! #[link_section=".ccmram.BUFFERS"] +//! static mut BUF: [u8; 1024] = [0u8; 1024]; +//! ``` +//! //! [attr-entry]: attr.entry.html //! [attr-exception]: attr.exception.html //! [attr-pre_init]: attr.pre_init.html -- cgit v1.2.3 From 0fdefc9e729f5d039d6cfbcbc099105e9b40f902 Mon Sep 17 00:00:00 2001 From: Todd Stellanova Date: Thu, 30 Jul 2020 17:13:50 -0700 Subject: remove unintended edit --- cortex-m-rt/src/lib.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 8139e7f..d078a91 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -92,7 +92,6 @@ //! _stext = ORIGIN(FLASH) + 0x40C //! ``` //! -//! //! # An example //! //! This section presents a minimal application built on top of `cortex-m-rt`. Apart from the -- cgit v1.2.3 From d1ddbce570e6b5d68036a7f2d33b749c70452fc4 Mon Sep 17 00:00:00 2001 From: Todd Stellanova Date: Thu, 30 Jul 2020 22:26:35 -0700 Subject: more specific ref to link_section attributes --- cortex-m-rt/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index d078a91..fe4ee20 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -392,9 +392,11 @@ //! Some microcontrollers provide additional memory regions beyond RAM and FLASH. //! For example, some STM32 devices provide "CCM" or core-coupled RAM that is //! only accessible from the core. In order to access these using -//! `#[link_section=".foo"]` from your code, you need to modify `memory.x` +//! [`link_section`] attributes from your code, you need to modify `memory.x` //! to declare the additional sections: //! +//! [`link_section`]: https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute +//! //! ```text //! MEMORY //! { -- cgit v1.2.3 From ac74bff1e91b1042a906343e30cb685754fb6c82 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 23 Aug 2020 21:59:01 +0200 Subject: Revert "Changed Hardfault's and DefaultHander's default implementations to panic" This reverts commit ffffb7b3aaef1d9bb4e4b81347ed8f1d50e50ea4. --- cortex-m-rt/src/lib.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index fe4ee20..335a357 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -199,15 +199,14 @@ //! won't find it. //! //! - `DefaultHandler`. This is the default handler. If not overridden using `#[exception] fn -//! DefaultHandler(..` this will cause a panic with the message "DefaultHandler #`i`", where `i` is -//! the number of the interrupt handler. +//! DefaultHandler(..` this will be an infinite loop. //! //! - `HardFaultTrampoline`. This is the real hard fault handler. This function is simply a //! trampoline that jumps into the user defined hard fault handler named `HardFault`. The //! trampoline is required to set up the pointer to the stacked exception frame. //! //! - `HardFault`. This is the user defined hard fault handler. If not overridden using -//! `#[exception] fn HardFault(..` it will default to a panic with message "HardFault". +//! `#[exception] fn HardFault(..` it will default to an infinite loop. //! //! - `__STACK_START`. This is the first entry in the `.vector_table` section. This symbol contains //! the initial value of the stack pointer; this is where the stack will be located -- the stack @@ -442,6 +441,7 @@ extern crate cortex_m_rt_macros as macros; extern crate r0; use core::fmt; +use core::sync::atomic::{self, Ordering}; /// Attribute to declare an interrupt (AKA device-specific exception) handler /// @@ -990,17 +990,21 @@ pub unsafe extern "C" fn Reset() -> ! { #[link_section = ".HardFault.default"] #[no_mangle] pub unsafe extern "C" fn HardFault_(ef: &ExceptionFrame) -> ! { - panic!("HardFault"); + loop { + // add some side effect to prevent this from turning into a UDF instruction + // see rust-lang/rust#28728 for details + atomic::compiler_fence(Ordering::SeqCst); + } } #[doc(hidden)] #[no_mangle] pub unsafe extern "C" fn DefaultHandler_() -> ! { - const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; - - let irqn = core::ptr::read(SCB_ICSR) as u8 as i16 - 16; - - panic!("DefaultHandler #{}", irqn); + loop { + // add some side effect to prevent this from turning into a UDF instruction + // see rust-lang/rust#28728 for details + atomic::compiler_fence(Ordering::SeqCst); + } } #[doc(hidden)] -- cgit v1.2.3 From 7d19e64be310c7c91e9e3773ef0ddf155a93959f Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 23 Aug 2020 22:11:18 +0200 Subject: Document NMI handler unsafety --- cortex-m-rt/src/lib.rs | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 335a357..fe56477 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -612,13 +612,13 @@ pub use macros::entry; /// /// # Usage /// -/// `#[exception] fn HardFault(..` sets the hard fault handler. The handler must have signature -/// `[unsafe] fn(&ExceptionFrame) -> !`. This handler is not allowed to return as that can cause -/// undefined behavior. +/// `#[exception] unsafe fn HardFault(..` sets the hard fault handler. The handler must have +/// signature `unsafe fn(&ExceptionFrame) -> !`. This handler is not allowed to return as that can +/// cause undefined behavior. /// -/// `#[exception] fn DefaultHandler(..` sets the *default* handler. All exceptions which have not -/// been assigned a handler will be serviced by this handler. This handler must have signature -/// `[unsafe] fn(irqn: i16) [-> !]`. `irqn` is the IRQ number (See CMSIS); `irqn` will be a negative +/// `#[exception] unsafe fn DefaultHandler(..` sets the *default* handler. All exceptions which have +/// not been assigned a handler will be serviced by this handler. This handler must have signature +/// `unsafe fn(irqn: i16) [-> !]`. `irqn` is the IRQ number (See CMSIS); `irqn` will be a negative /// number when the handler is servicing a core exception; `irqn` will be a positive number when the /// handler is servicing a device specific exception (interrupt). /// @@ -637,6 +637,24 @@ pub use macros::entry; /// the attribute will help by making a transformation to the source code: for this reason a /// variable like `static mut FOO: u32` will become `let FOO: &mut u32;`. /// +/// # Safety +/// +/// It is not generally safe to register handlers for non-maskable interrupts. On Cortex-M, +/// `HardFault` is non-maskable (at least in general), and there is an explicitly non-maskable +/// interrupt `NonMaskableInt`. +/// +/// The reason for that is that non-maskable interrupts will preempt any currently running function, +/// even if that function executes within a critical section. Thus, if it was safe to define NMI +/// handlers, critical sections wouldn't work safely anymore. +/// +/// This also means that defining a `DefaultHandler` must be unsafe, as that will catch +/// `NonMaskableInt` and `HardFault` if no handlers for those are defined. +/// +/// The safety requirements on those handlers is as follows: The handler must not access any data +/// that is protected via a critical section and shared with other interrupts that may be preempted +/// by the NMI while holding the critical section. As long as this requirement is fulfilled, it is +/// safe to handle NMIs. +/// /// # Examples /// /// - Setting the `HardFault` handler -- cgit v1.2.3 From c3851d8928c1f0b402a2144a157081a6e2c7dc5b Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 23 Aug 2020 22:13:32 +0200 Subject: Remove broken doctest/example This is unsound unless you control the panic handler implementation. --- cortex-m-rt/src/lib.rs | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index fe56477..65dee34 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -657,29 +657,13 @@ pub use macros::entry; /// /// # Examples /// -/// - Setting the `HardFault` handler -/// -/// ``` -/// # extern crate cortex_m_rt; -/// # extern crate cortex_m_rt_macros; -/// use cortex_m_rt::{ExceptionFrame, exception}; -/// -/// #[exception] -/// fn HardFault(ef: &ExceptionFrame) -> ! { -/// // prints the exception frame as a panic message -/// panic!("{:#?}", ef); -/// } -/// -/// # fn main() {} -/// ``` -/// /// - Setting the default handler /// /// ``` /// use cortex_m_rt::exception; /// /// #[exception] -/// fn DefaultHandler(irqn: i16) { +/// unsafe fn DefaultHandler(irqn: i16) { /// println!("IRQn = {}", irqn); /// } /// -- cgit v1.2.3 From e9eae4ded99c6f1f3a62bf379664e1503798c11f Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 30 Aug 2020 00:29:59 +0200 Subject: Avoid depending on `cortex-m` --- cortex-m-rt/.cargo/config | 15 +++++++----- cortex-m-rt/Cargo.toml | 4 +++- cortex-m-rt/asm.s | 23 ++++++++++++++++++ cortex-m-rt/bin/thumbv6m-none-eabi.a | Bin 940 -> 1218 bytes cortex-m-rt/bin/thumbv7em-none-eabi.a | Bin 940 -> 1198 bytes cortex-m-rt/bin/thumbv7em-none-eabihf.a | Bin 940 -> 1198 bytes cortex-m-rt/bin/thumbv7m-none-eabi.a | Bin 940 -> 1198 bytes cortex-m-rt/bin/thumbv8m.base-none-eabi.a | Bin 944 -> 1222 bytes cortex-m-rt/bin/thumbv8m.main-none-eabi.a | Bin 944 -> 1202 bytes cortex-m-rt/bin/thumbv8m.main-none-eabihf.a | Bin 944 -> 1202 bytes cortex-m-rt/src/lib.rs | 36 ++++++++-------------------- 11 files changed, 45 insertions(+), 33 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/.cargo/config b/cortex-m-rt/.cargo/config index 0d6b19c..1662bc6 100644 --- a/cortex-m-rt/.cargo/config +++ b/cortex-m-rt/.cargo/config @@ -1,11 +1,14 @@ +[target.thumbv6m-none-eabi] +runner = "qemu-system-arm -cpu cortex-m0 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel" + [target.thumbv7m-none-eabi] -# uncomment this to make `cargo run` execute programs on QEMU runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel" -[target.thumbv6m-none-eabi] -# uncomment this to make `cargo run` execute programs on QEMU -# For now, we use cortex-m3 instead of cortex-m0 which are not supported by QEMU -runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel" +[target.thumbv7em-none-eabi] +runner = "qemu-system-arm -cpu cortex-m4 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel" + +[target.thumbv7em-none-eabihf] +runner = "qemu-system-arm -cpu cortex-m4 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel" [target.'cfg(all(target_arch = "arm", target_os = "none"))'] # uncomment ONE of these three option to make `cargo run` start a GDB session @@ -28,4 +31,4 @@ rustflags = [ # "-C", "linker=arm-none-eabi-gcc", # "-C", "link-arg=-Wl,-Tlink.x", # "-C", "link-arg=-nostartfiles", -] \ No newline at end of file +] diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 1a62ab6..fa5e775 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -19,9 +19,11 @@ links = "cortex-m-rt" # Prevent multiple versions of cortex-m-rt being linked [dependencies] r0 = "1.0" cortex-m-rt-macros = { path = "macros", version = "=0.6.11" } -cortex-m = "0.6" +# Note: Do not depend on `cortex-m` here. This crate is used for testing `cortex-m`, so we need to +# avoid pulling in multiple versions of `cortex-m`. [dev-dependencies] +cortex-m = "0.6" panic-halt = "0.2.0" cortex-m-semihosting = "0.3" diff --git a/cortex-m-rt/asm.s b/cortex-m-rt/asm.s index 50a3fa5..1be4a02 100644 --- a/cortex-m-rt/asm.s +++ b/cortex-m-rt/asm.s @@ -17,3 +17,26 @@ HardFaultTrampoline: 0: mrs r0, PSP b HardFault + + .section .text.FpuTrampoline, "ax" + .global FpuTrampoline + # .type and .thumb_func are both required; otherwise its Thumb bit does not + # get set and an invalid vector table is generated + .type FpuTrampoline,%function + .thumb_func + # This enables the FPU and jumps to the main function. +FpuTrampoline: + # Address of SCB.CPACR. + ldr r0, =0xE000ED88 + # Enable access to CP10 and CP11 from both privileged and unprivileged mode. + ldr r1, =(0b1111 << 20) + # RMW. + ldr r2, [r0] + orr r2, r2, r1 + str r2, [r0] + # Barrier is required on some processors. + dsb + isb + # Hand execution over to `main`. + bl main + # Note: `main` must not return. `bl` is used only because it has a wider range than `b`. diff --git a/cortex-m-rt/bin/thumbv6m-none-eabi.a b/cortex-m-rt/bin/thumbv6m-none-eabi.a index 6a6a547..99f1b1a 100644 Binary files a/cortex-m-rt/bin/thumbv6m-none-eabi.a and b/cortex-m-rt/bin/thumbv6m-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv7em-none-eabi.a b/cortex-m-rt/bin/thumbv7em-none-eabi.a index 51d9aef..020b796 100644 Binary files a/cortex-m-rt/bin/thumbv7em-none-eabi.a and b/cortex-m-rt/bin/thumbv7em-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv7em-none-eabihf.a b/cortex-m-rt/bin/thumbv7em-none-eabihf.a index 51d9aef..020b796 100644 Binary files a/cortex-m-rt/bin/thumbv7em-none-eabihf.a and b/cortex-m-rt/bin/thumbv7em-none-eabihf.a differ diff --git a/cortex-m-rt/bin/thumbv7m-none-eabi.a b/cortex-m-rt/bin/thumbv7m-none-eabi.a index dc37fbf..16ade10 100644 Binary files a/cortex-m-rt/bin/thumbv7m-none-eabi.a and b/cortex-m-rt/bin/thumbv7m-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv8m.base-none-eabi.a b/cortex-m-rt/bin/thumbv8m.base-none-eabi.a index dda8dcc..264b029 100644 Binary files a/cortex-m-rt/bin/thumbv8m.base-none-eabi.a and b/cortex-m-rt/bin/thumbv8m.base-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv8m.main-none-eabi.a b/cortex-m-rt/bin/thumbv8m.main-none-eabi.a index ab500f4..01b343f 100644 Binary files a/cortex-m-rt/bin/thumbv8m.main-none-eabi.a and b/cortex-m-rt/bin/thumbv8m.main-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a b/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a index ab500f4..01b343f 100644 Binary files a/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a and b/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a differ diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 524b161..e2dd667 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -937,9 +937,6 @@ pub unsafe extern "C" fn Reset() -> ! { static mut __sdata: u32; static mut __edata: u32; static __sidata: u32; - - // This symbol will be provided by the user via `#[entry]` - fn main() -> !; } extern "Rust" { @@ -956,33 +953,20 @@ pub unsafe extern "C" fn Reset() -> ! { #[allow(clippy::match_single_binding)] match () { #[cfg(not(has_fpu))] - () => main(), + () => { + extern "C" { + // This symbol will be provided by the user via `#[entry]` + fn main() -> !; + } + main() + } #[cfg(has_fpu)] () => { - const SCB_CPACR: *mut u32 = 0xE000_ED88 as *mut u32; - const SCB_CPACR_FPU_ENABLE: u32 = 0b01_01 << 20; - const SCB_CPACR_FPU_USER: u32 = 0b10_10 << 20; - - // enable the FPU - core::ptr::write_volatile( - SCB_CPACR, - *SCB_CPACR | SCB_CPACR_FPU_ENABLE | SCB_CPACR_FPU_USER, - ); - - cortex_m::asm::dsb(); - cortex_m::asm::isb(); - - // this is used to prevent the compiler from inlining the user `main` into the reset - // handler. Inlining can cause the FPU instructions in the user `main` to be executed - // before enabling the FPU, and that would produce a hard to diagnose hard fault at - // runtime. - #[inline(never)] - #[export_name = "ResetTrampoline"] - fn trampoline() -> ! { - unsafe { main() } + extern "C" { + fn FpuTrampoline() -> !; } - trampoline() + FpuTrampoline() } } } -- cgit v1.2.3 From 965a6d22eae9cb2c83fc7da06be09dc769b791b5 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 2 Sep 2020 15:52:17 +0200 Subject: [ARMv6-M] initialize the LR register the ARMv6-M Architecture Reference Manual (ARM DDI 0419D) indicates in section B1.5.5 "Reset behavior" that the LR (Link Register) starts in an unknown state when the Reset handler is taken and that its "Value must be initialised by software" So this PR does that: it initializes the LR register to 0xFFFF_FFFF (-1) first thing in the Reset handler (only for v6). The manual doesn't say which value to use so I decided to use the value used by the ARMv7-M (v7 sets LR to 0xFFFF_FFFF before invoking the Reset handler; see its Architecture Manual for details). The values of LR (these are pushed onto the stack in function preludes) are used to unwind the stack (e.g. GDB's `backtrace` or a future `cortex_m_panic_unwind` handler). Having the initial stack frame use a known value on all Cortex-M variants makes it easier to implement `panic_unwind` and avoids virtual unwinders like GDB `backtrace` trying to unwind beyond the `Reset` handler Note that this implementation uses a trampoline that runs before `Reset` to set LR on v6. This is required because the prelude of the `Reset` routine will push LR onto the stack; we want that LR value to be -1. Calling `register::lr::write` from `Reset` would perform the write after LR has been pushed onto the stack and that's too late --- cortex-m-rt/asm.s | 14 ++++++++++++++ cortex-m-rt/bin/thumbv6m-none-eabi.a | Bin 1218 -> 1490 bytes cortex-m-rt/bin/thumbv7em-none-eabi.a | Bin 1198 -> 1434 bytes cortex-m-rt/bin/thumbv7em-none-eabihf.a | Bin 1198 -> 1434 bytes cortex-m-rt/bin/thumbv7m-none-eabi.a | Bin 1198 -> 1434 bytes cortex-m-rt/bin/thumbv8m.base-none-eabi.a | Bin 1222 -> 1494 bytes cortex-m-rt/bin/thumbv8m.main-none-eabi.a | Bin 1202 -> 1438 bytes cortex-m-rt/bin/thumbv8m.main-none-eabihf.a | Bin 1202 -> 1438 bytes cortex-m-rt/link.x.in | 4 ++++ cortex-m-rt/src/lib.rs | 11 +++++++++++ 10 files changed, 29 insertions(+) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/asm.s b/cortex-m-rt/asm.s index 1be4a02..37dedbd 100644 --- a/cortex-m-rt/asm.s +++ b/cortex-m-rt/asm.s @@ -40,3 +40,17 @@ FpuTrampoline: # Hand execution over to `main`. bl main # Note: `main` must not return. `bl` is used only because it has a wider range than `b`. + + # ARMv6-M leaves LR in an unknown state on Reset + # this trampoline sets LR before it's pushed onto the stack by Reset + .section .PreResetTrampoline, "ax" + .global PreResetTrampoline + # .type and .thumb_func are both required; otherwise its Thumb bit does not + # get set and an invalid vector table is generated + .type PreResetTrampoline,%function + .thumb_func +PreResetTrampoline: + # set LR to the initial value used by the ARMv7-M (0xFFFF_FFFF) + ldr r0,=0xffffffff + mov lr,r0 + b Reset diff --git a/cortex-m-rt/bin/thumbv6m-none-eabi.a b/cortex-m-rt/bin/thumbv6m-none-eabi.a index 99f1b1a..65684da 100644 Binary files a/cortex-m-rt/bin/thumbv6m-none-eabi.a and b/cortex-m-rt/bin/thumbv6m-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv7em-none-eabi.a b/cortex-m-rt/bin/thumbv7em-none-eabi.a index 020b796..c4e1f47 100644 Binary files a/cortex-m-rt/bin/thumbv7em-none-eabi.a and b/cortex-m-rt/bin/thumbv7em-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv7em-none-eabihf.a b/cortex-m-rt/bin/thumbv7em-none-eabihf.a index 020b796..c4e1f47 100644 Binary files a/cortex-m-rt/bin/thumbv7em-none-eabihf.a and b/cortex-m-rt/bin/thumbv7em-none-eabihf.a differ diff --git a/cortex-m-rt/bin/thumbv7m-none-eabi.a b/cortex-m-rt/bin/thumbv7m-none-eabi.a index 16ade10..ed96942 100644 Binary files a/cortex-m-rt/bin/thumbv7m-none-eabi.a and b/cortex-m-rt/bin/thumbv7m-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv8m.base-none-eabi.a b/cortex-m-rt/bin/thumbv8m.base-none-eabi.a index 264b029..f1c7734 100644 Binary files a/cortex-m-rt/bin/thumbv8m.base-none-eabi.a and b/cortex-m-rt/bin/thumbv8m.base-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv8m.main-none-eabi.a b/cortex-m-rt/bin/thumbv8m.main-none-eabi.a index 01b343f..cb216dc 100644 Binary files a/cortex-m-rt/bin/thumbv8m.main-none-eabi.a and b/cortex-m-rt/bin/thumbv8m.main-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a b/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a index 01b343f..cb216dc 100644 Binary files a/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a and b/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a differ diff --git a/cortex-m-rt/link.x.in b/cortex-m-rt/link.x.in index f5e582e..f4f4959 100644 --- a/cortex-m-rt/link.x.in +++ b/cortex-m-rt/link.x.in @@ -85,6 +85,10 @@ SECTIONS /* ### .text */ .text _stext : { + /* place these 2 close to each other or the `b` instruction will fail to link */ + *(.PreResetTrampoline); + *(.Reset); + *(.text .text.*); *(.HardFaultTrampoline); *(.HardFault.*); diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index e2dd667..ab4bc3f 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -923,9 +923,17 @@ pub fn heap_start() -> *mut u32 { #[doc(hidden)] #[link_section = ".vector_table.reset_vector"] #[no_mangle] +#[cfg(not(armv6m))] pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = Reset; #[doc(hidden)] +#[link_section = ".vector_table.reset_vector"] +#[no_mangle] +#[cfg(armv6m)] +pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = PreResetTrampoline; + +#[doc(hidden)] +#[link_section = ".Reset"] #[no_mangle] pub unsafe extern "C" fn Reset() -> ! { extern "C" { @@ -1030,6 +1038,9 @@ pub enum Exception { pub use self::Exception as exception; extern "C" { + #[cfg(armv6m)] + fn PreResetTrampoline() -> !; + fn NonMaskableInt(); fn HardFaultTrampoline(); -- cgit v1.2.3 From 319076c14fed9a749af24d3f0c6e324f08715e68 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 25 Nov 2020 01:21:50 +0100 Subject: Initialize RAM in assembly --- cortex-m-rt/Cargo.toml | 1 - cortex-m-rt/asm.s | 32 ++++++++++++++++++++++++++++ cortex-m-rt/bin/thumbv6m-none-eabi.a | Bin 1490 -> 1946 bytes cortex-m-rt/bin/thumbv7em-none-eabi.a | Bin 1434 -> 1922 bytes cortex-m-rt/bin/thumbv7em-none-eabihf.a | Bin 1434 -> 1922 bytes cortex-m-rt/bin/thumbv7m-none-eabi.a | Bin 1434 -> 1922 bytes cortex-m-rt/bin/thumbv8m.base-none-eabi.a | Bin 1494 -> 1966 bytes cortex-m-rt/bin/thumbv8m.main-none-eabi.a | Bin 1438 -> 1926 bytes cortex-m-rt/bin/thumbv8m.main-none-eabihf.a | Bin 1438 -> 1926 bytes cortex-m-rt/src/lib.rs | 31 --------------------------- 10 files changed, 32 insertions(+), 32 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index fa5e775..bbb6254 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -17,7 +17,6 @@ autoexamples = true links = "cortex-m-rt" # Prevent multiple versions of cortex-m-rt being linked [dependencies] -r0 = "1.0" cortex-m-rt-macros = { path = "macros", version = "=0.6.11" } # Note: Do not depend on `cortex-m` here. This crate is used for testing `cortex-m`, so we need to # avoid pulling in multiple versions of `cortex-m`. diff --git a/cortex-m-rt/asm.s b/cortex-m-rt/asm.s index 58ed274..7a36197 100644 --- a/cortex-m-rt/asm.s +++ b/cortex-m-rt/asm.s @@ -62,6 +62,38 @@ PreResetTrampoline: # set LR to the initial value used by the ARMv7-M (0xFFFF_FFFF) ldr r0,=0xffffffff mov lr,r0 + + # run the pre-init code + bl __pre_init + + # initialize .data and .bss memory + ldr r0,=__sbss + ldr r1,=__ebss + ldr r2,=0 +0: + cmp r1, r0 + beq 1f + stm r0!, {r2} + b 0b +1: + + # copy to here + ldr r0,=__sdata + # ...up to here + ldr r1,=__edata + # copy from here + ldr r2,=__sidata +2: + cmp r1, r0 + beq 3f + # load 1 word from r2 to r3, inc r2 + ldm r2!, {r3} + # store 1 word from r3 to r0, inc r0 + stm r0!, {r3} + b 2b +3: + + # jump to Rust b Reset .cfi_endproc .size PreResetTrampoline, . - PreResetTrampoline diff --git a/cortex-m-rt/bin/thumbv6m-none-eabi.a b/cortex-m-rt/bin/thumbv6m-none-eabi.a index 65684da..674b34a 100644 Binary files a/cortex-m-rt/bin/thumbv6m-none-eabi.a and b/cortex-m-rt/bin/thumbv6m-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv7em-none-eabi.a b/cortex-m-rt/bin/thumbv7em-none-eabi.a index c4e1f47..a0302b1 100644 Binary files a/cortex-m-rt/bin/thumbv7em-none-eabi.a and b/cortex-m-rt/bin/thumbv7em-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv7em-none-eabihf.a b/cortex-m-rt/bin/thumbv7em-none-eabihf.a index c4e1f47..a0302b1 100644 Binary files a/cortex-m-rt/bin/thumbv7em-none-eabihf.a and b/cortex-m-rt/bin/thumbv7em-none-eabihf.a differ diff --git a/cortex-m-rt/bin/thumbv7m-none-eabi.a b/cortex-m-rt/bin/thumbv7m-none-eabi.a index ed96942..0298e64 100644 Binary files a/cortex-m-rt/bin/thumbv7m-none-eabi.a and b/cortex-m-rt/bin/thumbv7m-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv8m.base-none-eabi.a b/cortex-m-rt/bin/thumbv8m.base-none-eabi.a index f1c7734..8a3cfcf 100644 Binary files a/cortex-m-rt/bin/thumbv8m.base-none-eabi.a and b/cortex-m-rt/bin/thumbv8m.base-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv8m.main-none-eabi.a b/cortex-m-rt/bin/thumbv8m.main-none-eabi.a index cb216dc..02bcf02 100644 Binary files a/cortex-m-rt/bin/thumbv8m.main-none-eabi.a and b/cortex-m-rt/bin/thumbv8m.main-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a b/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a index cb216dc..02bcf02 100644 Binary files a/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a and b/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a differ diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index ab4bc3f..5285bd1 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -438,7 +438,6 @@ #![no_std] extern crate cortex_m_rt_macros as macros; -extern crate r0; use core::fmt; use core::sync::atomic::{self, Ordering}; @@ -923,41 +922,12 @@ pub fn heap_start() -> *mut u32 { #[doc(hidden)] #[link_section = ".vector_table.reset_vector"] #[no_mangle] -#[cfg(not(armv6m))] -pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = Reset; - -#[doc(hidden)] -#[link_section = ".vector_table.reset_vector"] -#[no_mangle] -#[cfg(armv6m)] pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = PreResetTrampoline; #[doc(hidden)] #[link_section = ".Reset"] #[no_mangle] pub unsafe extern "C" fn Reset() -> ! { - extern "C" { - - // These symbols come from `link.x` - static mut __sbss: u32; - static mut __ebss: u32; - - static mut __sdata: u32; - static mut __edata: u32; - static __sidata: u32; - } - - extern "Rust" { - // This symbol will be provided by the user via `#[pre_init]` - fn __pre_init(); - } - - __pre_init(); - - // Initialize RAM - r0::zero_bss(&mut __sbss, &mut __ebss); - r0::init_data(&mut __sdata, &mut __edata, &__sidata); - #[allow(clippy::match_single_binding)] match () { #[cfg(not(has_fpu))] @@ -1038,7 +1008,6 @@ pub enum Exception { pub use self::Exception as exception; extern "C" { - #[cfg(armv6m)] fn PreResetTrampoline() -> !; fn NonMaskableInt(); -- cgit v1.2.3 From 4426f26ab0aed70ae2cc433f55ee48f62d7eb46b Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Thu, 21 Jan 2021 02:39:12 +0000 Subject: Update Reset-in-asm. * Use arm-none-eabi-gcc to assemble, allowing use of preprocessor to conditionally enable the FPU for eabihf targets. * Remove has_fpu configuration from build.rs. * Remove FpuTrampoline as no longer required. * Remove the Rust Reset method entirely, since the asm Reset can now enable FPU and jump to user main. --- cortex-m-rt/asm.S | 105 +++++++++++++++++++++++++++ cortex-m-rt/asm.s | 108 ---------------------------- cortex-m-rt/assemble.sh | 14 ++-- cortex-m-rt/bin/thumbv6m-none-eabi.a | Bin 1966 -> 1618 bytes cortex-m-rt/bin/thumbv7em-none-eabi.a | Bin 1942 -> 1598 bytes cortex-m-rt/bin/thumbv7em-none-eabihf.a | Bin 1942 -> 1622 bytes cortex-m-rt/bin/thumbv7m-none-eabi.a | Bin 1942 -> 1598 bytes cortex-m-rt/bin/thumbv8m.base-none-eabi.a | Bin 1950 -> 1622 bytes cortex-m-rt/bin/thumbv8m.main-none-eabi.a | Bin 1946 -> 1602 bytes cortex-m-rt/bin/thumbv8m.main-none-eabihf.a | Bin 1946 -> 1626 bytes cortex-m-rt/build.rs | 8 --- cortex-m-rt/link.x.in | 9 ++- cortex-m-rt/src/lib.rs | 63 ++++------------ 13 files changed, 134 insertions(+), 173 deletions(-) create mode 100644 cortex-m-rt/asm.S delete mode 100644 cortex-m-rt/asm.s (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/asm.S b/cortex-m-rt/asm.S new file mode 100644 index 0000000..6254129 --- /dev/null +++ b/cortex-m-rt/asm.S @@ -0,0 +1,105 @@ + .cfi_sections .debug_frame + + # Notes for function attributes: + # .type and .thumb_func are _both_ required, otherwise the Thumb mode bit + # will not be set and an invalid vector table is generated. + # LLD requires that section flags are set explicitly. + + .section .HardFaultTrampoline, "ax" + .global HardFaultTrampoline + .type HardFaultTrampoline,%function + .thumb_func + .cfi_startproc + # HardFault exceptions are bounced through this trampoline which grabs the + # stack pointer at the time of the exception and passes it to the user's + # HardFault handler in r0. +HardFaultTrampoline: + # Depending on the stack mode in EXC_RETURN, fetch stack pointer from + # PSP or MSP. + mov r0, lr + mov r1, #4 + tst r0, r1 + bne 0f + mrs r0, MSP + b HardFault +0: + mrs r0, PSP + b HardFault + .cfi_endproc + .size HardFaultTrampoline, . - HardFaultTrampoline + + .section .Reset, "ax" + .global Reset + .type Reset,%function + .thumb_func + .cfi_startproc + # Main entry point after reset. This jumps to the user __pre_init function, + # which cannot be called from Rust code without invoking UB, then + # initialises RAM. If the target has an FPU, it is enabled. Finally, jumps + # to the user main function. +Reset: + # ARMv6-M does not initialise LR, but many tools expect it to be 0xFFFF_FFFF + # when reaching the first call frame, so we set it at startup. + # ARMv7-M and above initialise LR to 0xFFFF_FFFF at reset. + ldr r4,=0xffffffff + mov lr,r4 + + # Run user pre-init code, which must be executed immediately after startup, + # before the potentially time-consuming memory initialisation takes place. + # Example use cases include disabling default watchdogs or enabling RAM. + bl __pre_init + + # Restore LR after calling __pre_init (r4 is preserved by subroutines). + mov lr,r4 + + # Initialise .bss memory. `__sbss` and `__ebss` come from the linker script. + ldr r0,=__sbss + ldr r1,=__ebss + mov r2,#0 +0: + cmp r1, r0 + beq 1f + stm r0!, {r2} + b 0b +1: + + # Initialise .data memory. `__sdata`, `__sidata`, and `__edata` come from the + # linker script. Copy from r2 into r0 until r0 reaches r1. + ldr r0,=__sdata + ldr r1,=__edata + ldr r2,=__sidata +2: + cmp r1, r0 + beq 3f + # load 1 word from r2 to r3, inc r2 + ldm r2!, {r3} + # store 1 word from r3 to r0, inc r0 + stm r0!, {r3} + b 2b +3: + +#ifdef HAS_FPU + # Conditionally enable the FPU. + # Address of SCB.CPACR. + ldr r0, =0xE000ED88 + # Enable access to CP10 and CP11 from both privileged and unprivileged mode. + ldr r1, =(0b1111 << 20) + # RMW. + ldr r2, [r0] + orr r2, r2, r1 + str r2, [r0] + # Barrier is required on some processors. + dsb + isb +#endif + +4: + # Jump to user main function. We use bl for the extended range, but the + # user main function may not return. + bl main + + # Trap on return. + udf + + .cfi_endproc + .size Reset, . - Reset diff --git a/cortex-m-rt/asm.s b/cortex-m-rt/asm.s deleted file mode 100644 index 6cae842..0000000 --- a/cortex-m-rt/asm.s +++ /dev/null @@ -1,108 +0,0 @@ - .cfi_sections .debug_frame - - # LLD requires that the section flags are explicitly set here - .section .HardFaultTrampoline, "ax" - .global HardFaultTrampoline - # .type and .thumb_func are both required; otherwise its Thumb bit does not - # get set and an invalid vector table is generated - .type HardFaultTrampoline,%function - .thumb_func - .cfi_startproc -HardFaultTrampoline: - # depending on the stack mode in EXC_RETURN, fetch stack pointer from - # PSP or MSP - mov r0, lr - mov r1, #4 - tst r0, r1 - bne 0f - mrs r0, MSP - b HardFault -0: - mrs r0, PSP - b HardFault - .cfi_endproc - .size HardFaultTrampoline, . - HardFaultTrampoline - - .section .text.FpuTrampoline, "ax" - .global FpuTrampoline - # .type and .thumb_func are both required; otherwise its Thumb bit does not - # get set and an invalid vector table is generated - .type FpuTrampoline,%function - .thumb_func - .cfi_startproc - # This enables the FPU and jumps to the main function. -FpuTrampoline: - # Address of SCB.CPACR. - ldr r0, =0xE000ED88 - # Enable access to CP10 and CP11 from both privileged and unprivileged mode. - ldr r1, =(0b1111 << 20) - # RMW. - ldr r2, [r0] - orr r2, r2, r1 - str r2, [r0] - # Barrier is required on some processors. - dsb - isb - # Hand execution over to `main`. - bl main - # Note: `main` must not return. `bl` is used only because it has a wider range than `b`. - .cfi_endproc - .size FpuTrampoline, . - FpuTrampoline - - .section .PreResetTrampoline, "ax" - .global PreResetTrampoline - # .type and .thumb_func are both required; otherwise its Thumb bit does not - # get set and an invalid vector table is generated - .type PreResetTrampoline,%function - .thumb_func - .cfi_startproc - # Main entry point. This initializes RAM and invokes __pre_init, which cannot be done in Rust code - # without invoking UB. It then jumps to the Rust `Reset` function. -PreResetTrampoline: - # set LR to the initial value used by the ARMv7-M (0xFFFF_FFFF) - ldr r4,=0xffffffff - mov lr,r4 - - # run the pre-init code - # use cases of __pre_init include - # a) disabling an on-by-default watchdog and - # b) enabling off-by-default RAM - # this means it must be done before the potentially slow RAM init code below is executed, and RAM - # must not be accessed before this call - bl __pre_init - - # the call above clobbers LR, but tools may expect LR to be 0xFFFFFFFF when reaching the first - # call frame, so we restore it to its previous value (r4 is preserved by subroutines) - mov lr,r4 - - # initialize .data and .bss memory - ldr r0,=__sbss - ldr r1,=__ebss - ldr r2,=0 -0: - cmp r1, r0 - beq 1f - stm r0!, {r2} - b 0b -1: - - # copy to here - ldr r0,=__sdata - # ...up to here - ldr r1,=__edata - # copy from here - ldr r2,=__sidata -2: - cmp r1, r0 - beq 3f - # load 1 word from r2 to r3, inc r2 - ldm r2!, {r3} - # store 1 word from r3 to r0, inc r0 - stm r0!, {r3} - b 2b -3: - - # jump to Rust - b Reset - .cfi_endproc - .size PreResetTrampoline, . - PreResetTrampoline diff --git a/cortex-m-rt/assemble.sh b/cortex-m-rt/assemble.sh index cdb3205..b914fed 100755 --- a/cortex-m-rt/assemble.sh +++ b/cortex-m-rt/assemble.sh @@ -9,21 +9,25 @@ crate=cortex-m-rt # remove existing blobs because otherwise this will append object files to the old blobs rm -f bin/*.a -arm-none-eabi-as -march=armv6s-m asm.s -o bin/$crate.o +arm-none-eabi-gcc -c -march=armv6s-m asm.S -o bin/$crate.o ar crs bin/thumbv6m-none-eabi.a bin/$crate.o -arm-none-eabi-as -march=armv7-m asm.s -o bin/$crate.o +arm-none-eabi-gcc -c -march=armv7-m asm.S -o bin/$crate.o ar crs bin/thumbv7m-none-eabi.a bin/$crate.o -arm-none-eabi-as -march=armv7e-m asm.s -o bin/$crate.o +arm-none-eabi-gcc -c -march=armv7e-m asm.S -o bin/$crate.o ar crs bin/thumbv7em-none-eabi.a bin/$crate.o + +arm-none-eabi-gcc -c -march=armv7e-m asm.S -DHAS_FPU -o bin/$crate.o ar crs bin/thumbv7em-none-eabihf.a bin/$crate.o -arm-none-eabi-as -march=armv8-m.base asm.s -o bin/$crate.o +arm-none-eabi-gcc -c -march=armv8-m.base asm.S -o bin/$crate.o ar crs bin/thumbv8m.base-none-eabi.a bin/$crate.o -arm-none-eabi-as -march=armv8-m.main asm.s -o bin/$crate.o +arm-none-eabi-gcc -c -march=armv8-m.main asm.S -o bin/$crate.o ar crs bin/thumbv8m.main-none-eabi.a bin/$crate.o + +arm-none-eabi-gcc -c -march=armv8-m.main -DHAS_FPU asm.S -o bin/$crate.o ar crs bin/thumbv8m.main-none-eabihf.a bin/$crate.o rm bin/$crate.o diff --git a/cortex-m-rt/bin/thumbv6m-none-eabi.a b/cortex-m-rt/bin/thumbv6m-none-eabi.a index 263f15a..3ac0777 100644 Binary files a/cortex-m-rt/bin/thumbv6m-none-eabi.a and b/cortex-m-rt/bin/thumbv6m-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv7em-none-eabi.a b/cortex-m-rt/bin/thumbv7em-none-eabi.a index 56c3c06..d38ee46 100644 Binary files a/cortex-m-rt/bin/thumbv7em-none-eabi.a and b/cortex-m-rt/bin/thumbv7em-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv7em-none-eabihf.a b/cortex-m-rt/bin/thumbv7em-none-eabihf.a index 56c3c06..a782dce 100644 Binary files a/cortex-m-rt/bin/thumbv7em-none-eabihf.a and b/cortex-m-rt/bin/thumbv7em-none-eabihf.a differ diff --git a/cortex-m-rt/bin/thumbv7m-none-eabi.a b/cortex-m-rt/bin/thumbv7m-none-eabi.a index 1680a5b..038af9f 100644 Binary files a/cortex-m-rt/bin/thumbv7m-none-eabi.a and b/cortex-m-rt/bin/thumbv7m-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv8m.base-none-eabi.a b/cortex-m-rt/bin/thumbv8m.base-none-eabi.a index 3128cf0..ad383aa 100644 Binary files a/cortex-m-rt/bin/thumbv8m.base-none-eabi.a and b/cortex-m-rt/bin/thumbv8m.base-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv8m.main-none-eabi.a b/cortex-m-rt/bin/thumbv8m.main-none-eabi.a index 691a095..ef6e77a 100644 Binary files a/cortex-m-rt/bin/thumbv8m.main-none-eabi.a and b/cortex-m-rt/bin/thumbv8m.main-none-eabi.a differ diff --git a/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a b/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a index 691a095..44380fb 100644 Binary files a/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a and b/cortex-m-rt/bin/thumbv8m.main-none-eabihf.a differ diff --git a/cortex-m-rt/build.rs b/cortex-m-rt/build.rs index 67cdfab..c56f14c 100644 --- a/cortex-m-rt/build.rs +++ b/cortex-m-rt/build.rs @@ -7,8 +7,6 @@ fn main() { let target = env::var("TARGET").unwrap(); let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - has_fpu(&target); - if target.starts_with("thumbv") { fs::copy( format!("bin/{}.a", target), @@ -81,9 +79,3 @@ handlers."); println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=link.x.in"); } - -fn has_fpu(target: &str) { - if target.ends_with("eabihf") { - println!("cargo:rustc-cfg=has_fpu"); - } -} diff --git a/cortex-m-rt/link.x.in b/cortex-m-rt/link.x.in index f1a921d..78fa825 100644 --- a/cortex-m-rt/link.x.in +++ b/cortex-m-rt/link.x.in @@ -23,8 +23,9 @@ INCLUDE memory.x /* # Entry point = reset vector */ +EXTERN(__RESET_VECTOR); +EXTERN(Reset); ENTRY(Reset); -EXTERN(__RESET_VECTOR); /* depends on the `Reset` symbol */ /* # Exception vectors */ /* This is effectively weak aliasing at the linker level */ @@ -85,13 +86,15 @@ SECTIONS /* ### .text */ .text _stext : { - /* place these 2 close to each other or the `b` instruction will fail to link */ - *(.PreResetTrampoline); *(.Reset); *(.text .text.*); + + /* The HardFaultTrampoline uses the `b` instruction to enter `HardFault`, + so must be placed close to it. */ *(.HardFaultTrampoline); *(.HardFault.*); + . = ALIGN(4); /* Pad .text to the alignment to workaround overlapping load section bug in old lld */ } > FLASH . = ALIGN(4); /* Ensure __etext is aligned if something unaligned is inserted after .text */ diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 5285bd1..e5e290d 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -192,11 +192,9 @@ //! //! One will always find the following (unmangled) symbols in `cortex-m-rt` applications: //! -//! - `Reset`. This is the reset handler. The microcontroller will executed this function upon +//! - `Reset`. This is the reset handler. The microcontroller will execute this function upon //! booting. This function will call the user program entry point (cf. [`#[entry]`][attr-entry]) -//! using the `main` symbol so you may also find that symbol in your program; if you do, `main` -//! will contain your application code. Some other times `main` gets inlined into `Reset` so you -//! won't find it. +//! using the `main` symbol so you will also find that symbol in your program. //! //! - `DefaultHandler`. This is the default handler. If not overridden using `#[exception] fn //! DefaultHandler(..` this will be an infinite loop. @@ -212,8 +210,8 @@ //! the initial value of the stack pointer; this is where the stack will be located -- the stack //! grows downwards towards smaller addresses. //! -//! - `__RESET_VECTOR`. This is the reset vector, a pointer into the `Reset` handler. This vector is -//! located in the `.vector_table` section after `__STACK_START`. +//! - `__RESET_VECTOR`. This is the reset vector, a pointer to the `Reset` function. This vector +//! is located in the `.vector_table` section after `__STACK_START`. //! //! - `__EXCEPTIONS`. This is the core exceptions portion of the vector table; it's an array of 14 //! exception vectors, which includes exceptions like `HardFault` and `SysTick`. This array is @@ -226,19 +224,11 @@ //! //! - `__pre_init`. This is a function to be run before RAM is initialized. It defaults to an empty //! function. The function called can be changed by applying the [`#[pre_init]`][attr-pre_init] -//! attribute to a function. The empty function is not optimized out by default, but if an empty -//! function is passed to [`#[pre_init]`][attr-pre_init] the function call will be optimized out. +//! attribute to a function. //! //! If you override any exception handler you'll find it as an unmangled symbol, e.g. `SysTick` or //! `SVCall`, in the output of `objdump`, //! -//! If you are targeting the `thumbv7em-none-eabihf` target you'll also see a `ResetTrampoline` -//! symbol in the output. To avoid the compiler placing FPU instructions before the FPU has been -//! enabled (cf. `vpush`) `Reset` calls the function `ResetTrampoline` which is marked as -//! `#[inline(never)]` and `ResetTrampoline` calls `main`. The compiler is free to inline `main` -//! into `ResetTrampoline` but it can't inline `ResetTrampoline` into `Reset` -- the FPU is enabled -//! in `Reset`. -//! //! # Advanced usage //! //! ## Setting the program entry point @@ -248,9 +238,9 @@ //! guarantees. //! //! The `Reset` handler will call a symbol named `main` (unmangled) *after* initializing `.bss` and -//! `.data`, and enabling the FPU (if the target is `thumbv7em-none-eabihf`). A function with the -//! `entry` attribute will be set to have the export name "`main`"; in addition, its mutable -//! statics are turned into safe mutable references (see [`#[entry]`][attr-entry] for details). +//! `.data`, and enabling the FPU (if the target has an FPU). A function with the `entry` attribute +//! will be set to have the export name "`main`"; in addition, its mutable statics are turned into +//! safe mutable references (see [`#[entry]`][attr-entry] for details). //! //! The unmangled `main` symbol must have signature `extern "C" fn() -> !` or its invocation from //! `Reset` will result in undefined behavior. @@ -411,7 +401,7 @@ //! *(.ccmram .ccmram.*); //! . = ALIGN(4); //! } > CCMRAM -//! } INSERT AFTER .bss; +//! } //! ``` //! //! You can then use something like this to place a variable into this specific section of memory: @@ -700,8 +690,8 @@ pub use macros::exception; /// /// # Safety /// -/// The function will be called before static variables are initialized. Any access of static -/// variables will result in undefined behavior. +/// The function will be called before memory is initialized, as soon as possible after reset. Any +/// access of memory, including any static variables, will result in undefined behavior. /// /// **Warning**: Due to [rvalue static promotion][rfc1414] static variables may be accessed whenever /// taking a reference to a constant. This means that even trivial expressions such as `&1` in the @@ -918,36 +908,11 @@ pub fn heap_start() -> *mut u32 { unsafe { &mut __sheap } } -/* Entry point */ +// Entry point is Reset. #[doc(hidden)] #[link_section = ".vector_table.reset_vector"] #[no_mangle] -pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = PreResetTrampoline; - -#[doc(hidden)] -#[link_section = ".Reset"] -#[no_mangle] -pub unsafe extern "C" fn Reset() -> ! { - #[allow(clippy::match_single_binding)] - match () { - #[cfg(not(has_fpu))] - () => { - extern "C" { - // This symbol will be provided by the user via `#[entry]` - fn main() -> !; - } - main() - } - #[cfg(has_fpu)] - () => { - extern "C" { - fn FpuTrampoline() -> !; - } - - FpuTrampoline() - } - } -} +pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = Reset; #[allow(unused_variables)] #[doc(hidden)] @@ -1008,7 +973,7 @@ pub enum Exception { pub use self::Exception as exception; extern "C" { - fn PreResetTrampoline() -> !; + fn Reset() -> !; fn NonMaskableInt(); -- cgit v1.2.3 From 95b28372d743be9dbe35f23f6c31a4f1d5340d60 Mon Sep 17 00:00:00 2001 From: Anatol Ulrich Date: Mon, 25 Jan 2021 22:25:08 +0100 Subject: fix #74 --- cortex-m-rt/src/lib.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index e5e290d..93125b7 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -910,13 +910,15 @@ pub fn heap_start() -> *mut u32 { // Entry point is Reset. #[doc(hidden)] -#[link_section = ".vector_table.reset_vector"] +#[cfg_attr(target_os = "macos", link_section = ".vector_table,reset_vector")] +#[cfg_attr(not(target_os = "macos"), link_section = ".vector_table.reset_vector")] #[no_mangle] pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = Reset; #[allow(unused_variables)] #[doc(hidden)] -#[link_section = ".HardFault.default"] +#[cfg_attr(target_os = "macos", link_section = ".HardFault,default")] +#[cfg_attr(not(target_os = "macos"), link_section = ".HardFault.default")] #[no_mangle] pub unsafe extern "C" fn HardFault_(ef: &ExceptionFrame) -> ! { loop { @@ -1008,7 +1010,8 @@ pub union Vector { } #[doc(hidden)] -#[link_section = ".vector_table.exceptions"] +#[cfg_attr(target_os = "macos", link_section = ".vector_table,exceptions")] +#[cfg_attr(not(target_os = "macos"), link_section = ".vector_table.exceptions")] #[no_mangle] pub static __EXCEPTIONS: [Vector; 14] = [ // Exception 2: Non Maskable Interrupt. @@ -1070,7 +1073,8 @@ pub static __EXCEPTIONS: [Vector; 14] = [ // to the default handler #[cfg(all(any(not(feature = "device"), test), not(armv6m)))] #[doc(hidden)] -#[link_section = ".vector_table.interrupts"] +#[cfg_attr(target_os = "macos", link_section = ".vector_table,interrupts")] +#[cfg_attr(not(target_os = "macos"), link_section = ".vector_table.interrupts")] #[no_mangle] pub static __INTERRUPTS: [unsafe extern "C" fn(); 240] = [{ extern "C" { -- cgit v1.2.3 From f0e2218330adcffe7dc8a05869dac0e5399058c3 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Wed, 27 Jan 2021 11:14:20 +0000 Subject: Only emit link_section for cortex-m. Previously we always emitted link_section, even though it only had an effect when our linker script was being used (and only made sense on cortex-m targets). This breaks building the code for a MacOS target, which is occasionally useful for running `cargo check` etc. In the macros crate we don't have the target information available, so instead we continue to emit link_section except specifically on MacOS. --- cortex-m-rt/macros/src/lib.rs | 6 ++++-- cortex-m-rt/src/lib.rs | 12 ++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/macros/src/lib.rs b/cortex-m-rt/macros/src/lib.rs index 74041ef..fe0264f 100644 --- a/cortex-m-rt/macros/src/lib.rs +++ b/cortex-m-rt/macros/src/lib.rs @@ -278,8 +278,10 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream { #(#attrs)* #[doc(hidden)] #[export_name = "HardFault"] - #[cfg_attr(target_os = "macos", link_section = ".HardFault,user")] - #[cfg_attr(not(target_os = "macos"), link_section = ".HardFault.user")] + // Only emit link_section when building for embedded targets, + // because some hosted platforms (used to check the build) + // cannot handle the long link section names. + #[cfg_attr(target_os = "none", link_section = ".HardFault.user")] pub unsafe extern "C" fn #tramp_ident(frame: &::cortex_m_rt::ExceptionFrame) { #ident(frame) } diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 93125b7..cb1b5f7 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -910,15 +910,13 @@ pub fn heap_start() -> *mut u32 { // Entry point is Reset. #[doc(hidden)] -#[cfg_attr(target_os = "macos", link_section = ".vector_table,reset_vector")] -#[cfg_attr(not(target_os = "macos"), link_section = ".vector_table.reset_vector")] +#[cfg_attr(cortex_m, link_section = ".vector_table.reset_vector")] #[no_mangle] pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = Reset; #[allow(unused_variables)] #[doc(hidden)] -#[cfg_attr(target_os = "macos", link_section = ".HardFault,default")] -#[cfg_attr(not(target_os = "macos"), link_section = ".HardFault.default")] +#[cfg_attr(cortex_m, link_section = ".HardFault.default")] #[no_mangle] pub unsafe extern "C" fn HardFault_(ef: &ExceptionFrame) -> ! { loop { @@ -1010,8 +1008,7 @@ pub union Vector { } #[doc(hidden)] -#[cfg_attr(target_os = "macos", link_section = ".vector_table,exceptions")] -#[cfg_attr(not(target_os = "macos"), link_section = ".vector_table.exceptions")] +#[cfg_attr(cortex_m, link_section = ".vector_table.exceptions")] #[no_mangle] pub static __EXCEPTIONS: [Vector; 14] = [ // Exception 2: Non Maskable Interrupt. @@ -1073,8 +1070,7 @@ pub static __EXCEPTIONS: [Vector; 14] = [ // to the default handler #[cfg(all(any(not(feature = "device"), test), not(armv6m)))] #[doc(hidden)] -#[cfg_attr(target_os = "macos", link_section = ".vector_table,interrupts")] -#[cfg_attr(not(target_os = "macos"), link_section = ".vector_table.interrupts")] +#[cfg_attr(cortex_m, link_section = ".vector_table.interrupts")] #[no_mangle] pub static __INTERRUPTS: [unsafe extern "C" fn(); 240] = [{ extern "C" { -- cgit v1.2.3 From 68c02e42549d40fc459c8c0600fdfb2e43eec185 Mon Sep 17 00:00:00 2001 From: Jakub Duchniewicz Date: Thu, 1 Apr 2021 19:49:58 +0300 Subject: Minor documentation fix. --- cortex-m-rt/src/lib.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'cortex-m-rt/src') diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index cb1b5f7..43c8090 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -34,6 +34,7 @@ //! //! This crate expects the user, or some other crate, to provide the memory layout of the target //! device via a linker script named `memory.x`. This section covers the contents of `memory.x` +//! The `memory.x` file is used by during linking by the `link.x` script provided by this crate. //! //! ### `MEMORY` //! -- cgit v1.2.3 From 38897fa7a2ecd726c63291822cc259ffee73d698 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Wed, 12 Jan 2022 01:18:34 +0000 Subject: Bump cortex-m-rt MSRV 1.39->1.40 to support non_exhaustive in cortex-m --- .github/bors.toml | 2 +- .github/workflows/rt-ci.yml | 2 +- cortex-m-rt/README.md | 2 +- cortex-m-rt/src/lib.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'cortex-m-rt/src') diff --git a/.github/bors.toml b/.github/bors.toml index 2bfc949..a398b4a 100644 --- a/.github/bors.toml +++ b/.github/bors.toml @@ -5,7 +5,7 @@ status = [ "ci-linux (stable)", "ci-linux (1.40.0)", "rt-ci-linux (stable)", - "rt-ci-linux (1.39.0)", + "rt-ci-linux (1.40.0)", "rt-ci-other-os (macOS-latest)", "rt-ci-other-os (windows-latest)", "rustfmt", diff --git a/.github/workflows/rt-ci.yml b/.github/workflows/rt-ci.yml index 5b1b6c9..0e48b6b 100644 --- a/.github/workflows/rt-ci.yml +++ b/.github/workflows/rt-ci.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: # All generated code should be running on stable now - rust: [nightly, stable, 1.39.0] + rust: [nightly, stable, 1.40.0] include: # Nightly is only for reference and allowed to fail diff --git a/cortex-m-rt/README.md b/cortex-m-rt/README.md index a305373..9857720 100644 --- a/cortex-m-rt/README.md +++ b/cortex-m-rt/README.md @@ -11,7 +11,7 @@ This project is developed and maintained by the [Cortex-M team][team]. # Minimum Supported Rust Version (MSRV) -This crate is guaranteed to compile on stable Rust 1.39.0 and up. It *might* +This crate is guaranteed to compile on stable Rust 1.40.0 and up. It *might* compile with older versions but that may change in any new patch release. # License diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs index 43c8090..8003326 100644 --- a/cortex-m-rt/src/lib.rs +++ b/cortex-m-rt/src/lib.rs @@ -418,7 +418,7 @@ //! //! # Minimum Supported Rust Version (MSRV) //! -//! The MSRV of this release is Rust 1.39.0. +//! The MSRV of this release is Rust 1.40.0. // # Developer notes // -- cgit v1.2.3