cortex-m-rt 0.7.2

Minimal runtime / startup for Cortex-M microcontrollers
Documentation
//! 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. 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:",

    // Ensure LR is loaded with 0xFFFF_FFFF at startup to help debuggers find the first call frame.
    // On ARMv6-M LR is not initialised at all, while other platforms should initialise it.
    "movs r4, #0
     mvns r4, r4
     mov lr, r4",

    // 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.
    // Reload LR after returning from pre-init (r4 is preserved by subroutines).
    "bl __pre_init
     mov lr, r4",

    // 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",

    // Push `lr` to the stack for debuggers, to prevent them unwinding past Reset.
    // See https://sourceware.org/binutils/docs/as/CFI-directives.html.
    ".cfi_def_cfa sp, 0
     push {{lr}}
     .cfi_offset lr, 0",

    // 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];