aboutsummaryrefslogtreecommitdiff
path: root/cortex-m-rt/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cortex-m-rt/src/lib.rs')
-rw-r--r--cortex-m-rt/src/lib.rs1095
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];