//! 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 < !` 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`) 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; use core::fmt; #[cfg(cortex_m)] use core::arch::global_asm; // HardFault exceptions are bounced through this trampoline which grabs the stack pointer at // the time of the exception and passes it to th euser'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 jumsp 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 r0, 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];