aboutsummaryrefslogtreecommitdiff
path: root/cortex-m-rt/src
diff options
context:
space:
mode:
Diffstat (limited to 'cortex-m-rt/src')
-rw-r--r--cortex-m-rt/src/lib.rs99
1 files changed, 70 insertions, 29 deletions
diff --git a/cortex-m-rt/src/lib.rs b/cortex-m-rt/src/lib.rs
index bab2844..524b161 100644
--- a/cortex-m-rt/src/lib.rs
+++ b/cortex-m-rt/src/lib.rs
@@ -199,15 +199,14 @@
//! won't find it.
//!
//! - `DefaultHandler`. This is the default handler. If not overridden using `#[exception] fn
-//! DefaultHandler(..` this will cause a panic with the message "DefaultHandler #`i`", where `i` is
-//! the number of the interrupt handler.
+//! 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 a panic with message "HardFault".
+//! `#[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
@@ -387,6 +386,41 @@
//! 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
+//! } INSERT AFTER .bss;
+//! ```
+//!
+//! 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
@@ -407,6 +441,7 @@ extern crate cortex_m_rt_macros as macros;
extern crate r0;
use core::fmt;
+use core::sync::atomic::{self, Ordering};
/// Attribute to declare an interrupt (AKA device-specific exception) handler
///
@@ -577,13 +612,13 @@ pub use macros::entry;
///
/// # Usage
///
-/// `#[exception] 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 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] 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
+/// `#[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).
///
@@ -602,23 +637,25 @@ pub use macros::entry;
/// 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
+/// # Safety
///
-/// - Setting the `HardFault` handler
+/// 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`.
///
-/// ```
-/// # extern crate cortex_m_rt;
-/// # extern crate cortex_m_rt_macros;
-/// use cortex_m_rt::{ExceptionFrame, exception};
+/// 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.
///
-/// #[exception]
-/// fn HardFault(ef: &ExceptionFrame) -> ! {
-/// // prints the exception frame as a panic message
-/// panic!("{:#?}", ef);
-/// }
+/// This also means that defining a `DefaultHandler` must be unsafe, as that will catch
+/// `NonMaskableInt` and `HardFault` if no handlers for those are defined.
///
-/// # fn main() {}
-/// ```
+/// 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
///
@@ -626,7 +663,7 @@ pub use macros::entry;
/// use cortex_m_rt::exception;
///
/// #[exception]
-/// fn DefaultHandler(irqn: i16) {
+/// unsafe fn DefaultHandler(irqn: i16) {
/// println!("IRQn = {}", irqn);
/// }
///
@@ -955,17 +992,21 @@ pub unsafe extern "C" fn Reset() -> ! {
#[link_section = ".HardFault.default"]
#[no_mangle]
pub unsafe extern "C" fn HardFault_(ef: &ExceptionFrame) -> ! {
- panic!("HardFault");
+ loop {
+ // add some side effect to prevent this from turning into a UDF instruction
+ // see rust-lang/rust#28728 for details
+ atomic::compiler_fence(Ordering::SeqCst);
+ }
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn DefaultHandler_() -> ! {
- const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32;
-
- let irqn = core::ptr::read(SCB_ICSR) as u8 as i16 - 16;
-
- panic!("DefaultHandler #{}", irqn);
+ loop {
+ // add some side effect to prevent this from turning into a UDF instruction
+ // see rust-lang/rust#28728 for details
+ atomic::compiler_fence(Ordering::SeqCst);
+ }
}
#[doc(hidden)]