blob: 2070efa3a647b709f11e4f50f7b9ac52ae65df41 [file] [log] [blame]
//! 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 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.
//!
//! For Cortex-M, the `_stack_start` must always be aligned to 8 bytes, which is enforced by
//! the linker script. If you override it, ensure that whatever value you set is a multiple
//! of 8 bytes.
//!
//! 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.
//!
//! ## `set-sp`
//!
//! If this feature is enabled, the stack pointer (SP) is initialised in the reset handler to the
//! `_stack_start` value from the linker script. This is not usually required, but some debuggers
//! do not initialise SP when performing a soft reset, which can lead to stack corruption.
//!
//! ## `set-vtor`
//!
//! If this feature is enabled, the vector table offset register (VTOR) is initialised in the reset
//! handler to the start of the vector table defined in the linker script. This is not usually
//! required, but some bootloaders do not set VTOR before jumping to application code, leading to
//! your main function executing but interrupt handlers not being used.
//!
//! # Inspection
//!
//! This section covers how to inspect a binary that builds on top of `cortex-m-rt`.
//!
//! ## 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. We use a similar solution via the `PROVIDE`
//! command in the linker script: when the `"device"` feature is enabled, `cortex-m-rt`'s linker
//! script (`link.x`) includes a linker script named `device.x`, which must be provided by
//! whichever crate provides `__INTERRUPTS`.
//!
//! For our running example the `device.x` linker script looks like this:
//!
//! ```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 a build script that puts `device.x` somewhere the linker can find. An example of
//! such build script is shown below:
//!
//! ```ignore
//! use std::env;
//! 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.59.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;
#[cfg(cortex_m)]
use core::arch::global_asm;
use core::fmt;
// HardFault exceptions are bounced through this trampoline which grabs the stack pointer at
// the time of the exception and passes it to the user's HardFault handler in r0.
// Depending on the stack mode in EXC_RETURN, fetches stack from either MSP or PSP.
#[cfg(cortex_m)]
global_asm!(
".cfi_sections .debug_frame
.section .HardFaultTrampoline, \"ax\"
.global HardFaultTrampline
.type HardFaultTrampline,%function
.thumb_func
.cfi_startproc
HardFaultTrampoline:",
"mov r0, lr
movs r1, #4
tst r0, r1
bne 0f
mrs r0, MSP
b HardFault
0:
mrs r0, PSP
b HardFault",
".cfi_endproc
.size HardFaultTrampoline, . - HardFaultTrampoline",
);
/// Parse cfg attributes inside a global_asm call.
#[cfg(cortex_m)]
macro_rules! cfg_global_asm {
{@inner, [$($x:tt)*], } => {
global_asm!{$($x)*}
};
(@inner, [$($x:tt)*], #[cfg($meta:meta)] $asm:literal, $($rest:tt)*) => {
#[cfg($meta)]
cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
#[cfg(not($meta))]
cfg_global_asm!{@inner, [$($x)*], $($rest)*}
};
{@inner, [$($x:tt)*], $asm:literal, $($rest:tt)*} => {
cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
};
{$($asms:tt)*} => {
cfg_global_asm!{@inner, [], $($asms)*}
};
}
// This reset vector is the initial entry point after a system reset.
// Calls an optional user-provided __pre_init and then initialises RAM.
// If the target has an FPU, it is enabled.
// Finally jumps to the user main function.
#[cfg(cortex_m)]
cfg_global_asm! {
".cfi_sections .debug_frame
.section .Reset, \"ax\"
.global Reset
.type Reset,%function
.thumb_func",
".cfi_startproc
Reset:",
// If enabled, initialise the SP. This is normally initialised by the CPU itself or by a
// bootloader, but some debuggers fail to set it when resetting the target, leading to
// stack corruptions.
#[cfg(feature = "set-sp")]
"ldr r0, =_stack_start
msr msp, r0",
// If enabled, initialise VTOR to the start of the vector table. This is normally initialised
// by a bootloader when the non-reset value is required, but some bootloaders do not set it,
// leading to frustrating issues where everything seems to work but interrupts are never
// handled. The VTOR register is optional on ARMv6-M, but when not present is RAZ,WI and
// therefore safe to write to.
#[cfg(feature = "set-vtor")]
"ldr r0, =0xe000ed08
ldr r1, =__vector_table
str r1, [r0]",
// Run user pre-init code which must be executed immediately after startup, before the
// potentially time-consuming memory initialisation takes place.
// Example use cases include disabling default watchdogs or enabling RAM.
"bl __pre_init",
// Initialise .bss memory. `__sbss` and `__ebss` come from the linker script.
"ldr r0, =__sbss
ldr r1, =__ebss
movs r2, #0
0:
cmp r1, r0
beq 1f
stm r0!, {{r2}}
b 0b
1:",
// Initialise .data memory. `__sdata`, `__sidata`, and `__edata` come from the linker script.
"ldr r0, =__sdata
ldr r1, =__edata
ldr r2, =__sidata
2:
cmp r1, r0
beq 3f
ldm r2!, {{r3}}
stm r0!, {{r3}}
b 2b
3:",
// Potentially enable an FPU.
// SCB.CPACR is 0xE000_ED88.
// We enable access to CP10 and CP11 from priviliged and unprivileged mode.
#[cfg(has_fpu)]
"ldr r0, =0xE000ED88
ldr r1, =(0b1111 << 20)
ldr r2, [r0]
orr r2, r2, r1
str r2, [r0]
dsb
isb",
// Jump to user main function.
// `bl` is used for the extended range, but the user main function should not return,
// so trap on any unexpected return.
"bl main
udf #0",
".cfi_endproc
.size Reset, . - Reset",
}
/// Attribute to declare an interrupt (AKA device-specific exception) handler
///
/// **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
///
/// 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
///
/// # 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.
///
/// 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) -> ! {
#[allow(clippy::empty_loop)]
loop {}
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn DefaultHandler_() -> ! {
#[allow(clippy::empty_loop)]
loop {}
}
#[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];