diff options
Diffstat (limited to 'cortex-m-rt/src/lib.rs')
-rw-r--r-- | cortex-m-rt/src/lib.rs | 1095 |
1 files changed, 1095 insertions, 0 deletions
diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs new file mode 100644 index 0000000..8003326 --- /dev/null +++ b/cortex-m-rt/src/lib.rs @@ -0,0 +1,1095 @@ +//! 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. +//! +//! # 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 program entry point. +//! +//! - Enabling the FPU before the program entry point if the target is `thumbv7em-none-eabihf`. +//! +//! This crate also provides the following attributes: +//! +//! - [`#[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 [Attribute Macros](#attributes) +//! section. +//! +//! # Requirements +//! +//! ## `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` +//! The `memory.x` file is used by during linking by the `link.x` script provided by this crate. +//! +//! ### `MEMORY` +//! +//! The linker script must specify the memory available in the device as, at least, two `MEMORY` +//! regions: one named `FLASH` and one named `RAM`. The `.text` and `.rodata` sections of the +//! program will be placed in the `FLASH` region, whereas the `.bss` and `.data` sections, as well +//! as the heap,will be placed in the `RAM` region. +//! +//! ```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 +//! ``` +//! +//! # 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 +//! 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: +//! +//! ```no_run +//! // IMPORTANT the standard `main` interface is not used because it requires nightly +//! #![no_main] +//! #![no_std] +//! +//! // Some panic handler needs to be included. This one halts the processor on panic. +//! extern crate panic_halt; +//! +//! use cortex_m_rt::entry; +//! +//! // use `main` as the entry point of this application +//! // `main` is not allowed to return +//! #[entry] +//! fn main() -> ! { +//! // initialization +//! +//! loop { +//! // application logic +//! } +//! } +//! ``` +//! +//! 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 <<EOF +//! /* Linker script for the STM32F103C8T6 */ +//! MEMORY +//! { +//! FLASH : ORIGIN = 0x08000000, LENGTH = 64K +//! RAM : ORIGIN = 0x20000000, LENGTH = 20K +//! } +//! EOF +//! +//! $ cargo rustc --target thumbv7m-none-eabi -- \ +//! -C link-arg=-nostartfiles -C link-arg=-Tlink.x +//! +//! $ file target/thumbv7m-none-eabi/debug/app +//! app: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, (..) +//! ``` +//! +//! # Optional features +//! +//! ## `device` +//! +//! If this feature is disabled then this crate populates the whole vector table. All the interrupts +//! in the vector table, even the ones unused by the target device, will be bound to the default +//! exception handler. This makes the final application device agnostic: you will be able to run it +//! on any Cortex-M device -- provided that you correctly specified its memory layout in `memory.x` +//! -- without hitting undefined behavior. +//! +//! If this feature is enabled then the interrupts section of the vector table is left unpopulated +//! and some other crate, or the user, will have to populate it. This mode is meant to be used in +//! conjunction with crates generated using `svd2rust`. Those *device crates* will populate the +//! missing part of the vector table when their `"rt"` feature is enabled. +//! +//! # Inspection +//! +//! This section covers how to inspect a binary that builds on top of `cortex-m-rt`. +//! +//! ## Sections (`size`) +//! +//! `cortex-m-rt` uses standard sections like `.text`, `.rodata`, `.bss` and `.data` as one would +//! expect. `cortex-m-rt` separates the vector table in its own section, named `.vector_table`. This +//! lets you distinguish how much space is taking the vector table in Flash vs how much is being +//! used by actual instructions (`.text`) and constants (`.rodata`). +//! +//! ```text +//! $ size -Ax target/thumbv7m-none-eabi/examples/app +//! target/thumbv7m-none-eabi/release/examples/app : +//! section size addr +//! .vector_table 0x400 0x8000000 +//! .text 0x88 0x8000400 +//! .rodata 0x0 0x8000488 +//! .data 0x0 0x20000000 +//! .bss 0x0 0x20000000 +//! ``` +//! +//! Without the `-A` argument `size` reports the sum of the sizes of `.text`, `.rodata` and +//! `.vector_table` under "text". +//! +//! ```text +//! $ size target/thumbv7m-none-eabi/examples/app +//! text data bss dec hex filename +//! 1160 0 0 1660 67c target/thumbv7m-none-eabi/release/app +//! ``` +//! +//! ## Symbols (`objdump`, `nm`) +//! +//! One will always find the following (unmangled) symbols in `cortex-m-rt` applications: +//! +//! - `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 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. +//! +//! - `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. +//! +//! - `__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 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 +//! located after `__RESET_VECTOR` in the `.vector_table` section. +//! +//! - `__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. +//! +//! - `__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. +//! +//! If you override any exception handler you'll find it as an unmangled symbol, e.g. `SysTick` or +//! `SVCall`, in the output of `objdump`, +//! +//! # Advanced usage +//! +//! ## Setting the program entry point +//! +//! 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 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. +//! +//! ## 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 +//! interested in how device crates generated using `svd2rust` integrate with `cortex-m-rt` read on. +//! +//! The information in this section applies when the `"device"` feature has been enabled. +//! +//! ### `__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` +//! section of its object file. +//! +//! This `static` variable will be placed at `ORIGIN(FLASH) + 0x40`. This address corresponds to the +//! spot where IRQ0 (IRQ number 0) is located. +//! +//! To conform to the Cortex-M ABI `__INTERRUPTS` must be an array of function pointers; some spots +//! in this array may need to be set to 0 if they are marked as *reserved* in the data sheet / +//! reference manual. We recommend using a `union` to set the reserved spots to `0`; `None` +//! (`Option<fn()>`) 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. +//! +//! ```no_run +//! pub union Vector { +//! handler: unsafe 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); +//! ``` +//! +//! 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 +//! build script is shown below: +//! +//! ```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()); +//! } +//! ``` +//! +//! ## Uninitialized static variables +//! +//! 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 +//! +//! ```no_run,edition2018 +//! # extern crate core; +//! 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. +//! +//! ## 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`] 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 +//! { +//! 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 +//! } +//! ``` +//! +//! 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 +//! +//! # Minimum Supported Rust Version (MSRV) +//! +//! The MSRV of this release is Rust 1.40.0. + +// # Developer notes +// +// - `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)] +#![no_std] + +extern crate cortex_m_rt_macros as macros; + +use core::fmt; +use core::sync::atomic::{self, Ordering}; + +/// 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); +/// } +/// ``` +#[cfg(feature = "device")] +pub use macros::interrupt; + +/// Attribute to declare the entry point of the program +/// +/// **IMPORTANT**: This attribute must appear exactly *once* in the dependency graph. Also, if you +/// are using Rust 1.30 the attribute must be used on a reachable item (i.e. there must be no +/// private modules between the item and the root of the crate); if the item is in the root of the +/// crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 and newer releases. +/// +/// The specified function will be called by the reset handler *after* RAM has been initialized. In +/// the case of the `thumbv7em-none-eabihf` target the FPU will also be enabled before the function +/// is called. +/// +/// 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] 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] 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). +/// +/// `#[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;`. +/// +/// # 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 default handler +/// +/// ``` +/// use cortex_m_rt::exception; +/// +/// #[exception] +/// unsafe 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()`. +/// +/// # Safety +/// +/// 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 +/// `#[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 +/// +/// ``` +/// # use cortex_m_rt::pre_init; +/// #[pre_init] +/// unsafe fn before_main() { +/// // do something here +/// } +/// +/// # fn main() {} +/// ``` +/// +/// [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)] +pub struct ExceptionFrame { + r0: u32, + r1: u32, + r2: u32, + r3: u32, + r12: u32, + lr: u32, + pc: u32, + xpsr: u32, +} + +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 + } + + /// 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. + #[inline(always)] + 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. + #[inline(always)] + 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. + #[inline(always)] + 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. + #[inline(always)] + 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. + #[inline(always)] + 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. + #[inline(always)] + 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. + #[inline(always)] + 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. + #[inline(always)] + pub unsafe fn set_xpsr(&mut self, value: u32) { + self.xpsr = value; + } +} + +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 to the start of the heap +/// +/// The returned pointer is guaranteed to be 4-byte aligned. +#[inline] +pub fn heap_start() -> *mut u32 { + extern "C" { + static mut __sheap: u32; + } + + unsafe { &mut __sheap } +} + +// Entry point is Reset. +#[doc(hidden)] +#[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(cortex_m, link_section = ".HardFault.default")] +#[no_mangle] +pub unsafe extern "C" fn HardFault_(ef: &ExceptionFrame) -> ! { + loop { + // add some side effect to prevent this from turning into a UDF instruction + // see rust-lang/rust#28728 for details + atomic::compiler_fence(Ordering::SeqCst); + } +} + +#[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); + } +} + +#[doc(hidden)] +#[no_mangle] +pub unsafe extern "C" fn DefaultPreInit() {} + +/* Exceptions */ +#[doc(hidden)] +pub enum Exception { + NonMaskableInt, + + // Not overridable + // HardFault, + #[cfg(not(armv6m))] + MemoryManagement, + + #[cfg(not(armv6m))] + BusFault, + + #[cfg(not(armv6m))] + UsageFault, + + #[cfg(armv8m)] + SecureFault, + + SVCall, + + #[cfg(not(armv6m))] + DebugMonitor, + + PendSV, + + SysTick, +} + +#[doc(hidden)] +pub use self::Exception as exception; + +extern "C" { + fn Reset() -> !; + + fn NonMaskableInt(); + + fn HardFaultTrampoline(); + + #[cfg(not(armv6m))] + fn MemoryManagement(); + + #[cfg(not(armv6m))] + fn BusFault(); + + #[cfg(not(armv6m))] + fn UsageFault(); + + #[cfg(armv8m)] + fn SecureFault(); + + fn SVCall(); + + #[cfg(not(armv6m))] + fn DebugMonitor(); + + fn PendSV(); + + fn SysTick(); +} + +#[doc(hidden)] +pub union Vector { + handler: unsafe extern "C" fn(), + reserved: usize, +} + +#[doc(hidden)] +#[cfg_attr(cortex_m, link_section = ".vector_table.exceptions")] +#[no_mangle] +pub static __EXCEPTIONS: [Vector; 14] = [ + // Exception 2: Non Maskable Interrupt. + Vector { + handler: NonMaskableInt, + }, + // Exception 3: Hard Fault Interrupt. + Vector { + handler: HardFaultTrampoline, + }, + // 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)] + 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))] + Vector { + handler: DebugMonitor, + }, + #[cfg(armv6m)] + Vector { reserved: 0 }, + // 13: Reserved + Vector { reserved: 0 }, + // Exception 14: Pend SV Interrupt [not on Cortex-M0 variants]. + Vector { handler: PendSV }, + // Exception 15: System Tick Interrupt. + Vector { handler: SysTick }, +]; + +// If we are not targeting a specific device we bind all the potential device specific interrupts +// to the default handler +#[cfg(all(any(not(feature = "device"), test), not(armv6m)))] +#[doc(hidden)] +#[cfg_attr(cortex_m, link_section = ".vector_table.interrupts")] +#[no_mangle] +pub static __INTERRUPTS: [unsafe extern "C" fn(); 240] = [{ + extern "C" { + fn DefaultHandler(); + } + + 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]; |