From 27d52597d026fced3e78a45fbedd590a600de270 Mon Sep 17 00:00:00 2001 From: Hugues de Valon Date: Sun, 12 Apr 2020 18:55:03 +0100 Subject: [PATCH 1/2] Add SCB methods to enable/disable exceptions Some exceptions might be disabled by default which means that the HardFault handler will be called instead of the exception handler. This commit adds methods on the SCB peripheral that use the SHCSR register to enable/disable exceptions. Signed-off-by: Hugues de Valon --- src/peripheral/scb.rs | 94 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/src/peripheral/scb.rs b/src/peripheral/scb.rs index 940809e1..d33a1108 100644 --- a/src/peripheral/scb.rs +++ b/src/peripheral/scb.rs @@ -1,6 +1,8 @@ //! System Control Block use core::ptr; +#[cfg(not(any(armv6m, armv8m_base)))] +use crate::interrupt; use volatile_register::RW; @@ -1011,4 +1013,96 @@ impl SCB { }); } } + + /// Enable the exception + /// + /// If the exception is enabled, when the exception is triggered, the exception handler will be executed instead of the + /// HardFault handler. + /// This function is only allowed on the following exceptions: + /// * `MemoryManagement` + /// * `BusFault` + /// * `UsageFault` + /// * `SecureFault` (can only be enabled from Secure state) + /// + /// Calling this function with any other exception will do nothing. + #[inline] + #[cfg(not(any(armv6m, armv8m_base)))] + pub fn enable(&mut self, exception: Exception) { + if self.is_enabled(exception) { + return; + } + + // Make sure that the read-modify-write sequence happens during a critical section to avoid + // modifying pending and active interrupts. + interrupt::free(|_| { + let shift = match exception { + Exception::MemoryManagement => 16, + Exception::BusFault => 17, + Exception::UsageFault => 18, + #[cfg(armv8m_main)] + Exception::SecureFault => 19, + _ => return, + }; + + unsafe { self.shcsr.modify(|value| value | (1 << shift)) } + }) + } + + /// Disable the exception + /// + /// If the exception is disabled, when the exception is triggered, the HardFault handler will be executed instead of the + /// exception handler. + /// This function is only allowed on the following exceptions: + /// * `MemoryManagement` + /// * `BusFault` + /// * `UsageFault` + /// * `SecureFault` (can not be changed from Non-secure state) + /// + /// Calling this function with any other exception will do nothing. + #[inline] + #[cfg(not(any(armv6m, armv8m_base)))] + pub fn disable(&mut self, exception: Exception) { + if !self.is_enabled(exception) { + return; + } + + // Make sure that the read-modify-write sequence happens during a critical section to avoid + // modifying pending and active interrupts. + interrupt::free(|_| { + let shift = match exception { + Exception::MemoryManagement => 16, + Exception::BusFault => 17, + Exception::UsageFault => 18, + #[cfg(armv8m_main)] + Exception::SecureFault => 19, + _ => return, + }; + + unsafe { self.shcsr.modify(|value| value & !(1 << shift)) } + }) + } + + /// Check if an exception is enabled + /// + /// This function is only allowed on the following exception: + /// * `MemoryManagement` + /// * `BusFault` + /// * `UsageFault` + /// * `SecureFault` (can not be read from Non-secure state) + /// + /// Calling this function with any other exception will read `false`. + #[inline] + #[cfg(not(any(armv6m, armv8m_base)))] + pub fn is_enabled(&mut self, exception: Exception) -> bool { + let shift = match exception { + Exception::MemoryManagement => 16, + Exception::BusFault => 17, + Exception::UsageFault => 18, + #[cfg(armv8m_main)] + Exception::SecureFault => 19, + _ => return false, + }; + + (self.shcsr.read() & (1 << shift)) > 0 + } } From 08f2a69abeac6d681c2e59b0b0b62e1d803389eb Mon Sep 17 00:00:00 2001 From: Hugues de Valon Date: Wed, 15 Apr 2020 09:52:01 +0100 Subject: [PATCH 2/2] Add a function to get SHCSR enable bit positions This removes the duplication of the look-up table and enforces some safety checks with the match statement. Signed-off-by: Hugues de Valon --- src/peripheral/scb.rs | 75 ++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 47 deletions(-) diff --git a/src/peripheral/scb.rs b/src/peripheral/scb.rs index d33a1108..7fb4505d 100644 --- a/src/peripheral/scb.rs +++ b/src/peripheral/scb.rs @@ -1,8 +1,6 @@ //! System Control Block use core::ptr; -#[cfg(not(any(armv6m, armv8m_base)))] -use crate::interrupt; use volatile_register::RW; @@ -1014,6 +1012,20 @@ impl SCB { } } + /// Return the bit position of the exception enable bit in the SHCSR register + #[inline] + #[cfg(not(any(armv6m, armv8m_base)))] + fn shcsr_enable_shift(exception: Exception) -> Option { + match exception { + Exception::MemoryManagement => Some(16), + Exception::BusFault => Some(17), + Exception::UsageFault => Some(18), + #[cfg(armv8m_main)] + Exception::SecureFault => Some(19), + _ => None, + } + } + /// Enable the exception /// /// If the exception is enabled, when the exception is triggered, the exception handler will be executed instead of the @@ -1028,24 +1040,11 @@ impl SCB { #[inline] #[cfg(not(any(armv6m, armv8m_base)))] pub fn enable(&mut self, exception: Exception) { - if self.is_enabled(exception) { - return; - } - - // Make sure that the read-modify-write sequence happens during a critical section to avoid - // modifying pending and active interrupts. - interrupt::free(|_| { - let shift = match exception { - Exception::MemoryManagement => 16, - Exception::BusFault => 17, - Exception::UsageFault => 18, - #[cfg(armv8m_main)] - Exception::SecureFault => 19, - _ => return, - }; - + if let Some(shift) = SCB::shcsr_enable_shift(exception) { + // The mutable reference to SCB makes sure that only this code is currently modifying + // the register. unsafe { self.shcsr.modify(|value| value | (1 << shift)) } - }) + } } /// Disable the exception @@ -1062,24 +1061,11 @@ impl SCB { #[inline] #[cfg(not(any(armv6m, armv8m_base)))] pub fn disable(&mut self, exception: Exception) { - if !self.is_enabled(exception) { - return; - } - - // Make sure that the read-modify-write sequence happens during a critical section to avoid - // modifying pending and active interrupts. - interrupt::free(|_| { - let shift = match exception { - Exception::MemoryManagement => 16, - Exception::BusFault => 17, - Exception::UsageFault => 18, - #[cfg(armv8m_main)] - Exception::SecureFault => 19, - _ => return, - }; - + if let Some(shift) = SCB::shcsr_enable_shift(exception) { + // The mutable reference to SCB makes sure that only this code is currently modifying + // the register. unsafe { self.shcsr.modify(|value| value & !(1 << shift)) } - }) + } } /// Check if an exception is enabled @@ -1093,16 +1079,11 @@ impl SCB { /// Calling this function with any other exception will read `false`. #[inline] #[cfg(not(any(armv6m, armv8m_base)))] - pub fn is_enabled(&mut self, exception: Exception) -> bool { - let shift = match exception { - Exception::MemoryManagement => 16, - Exception::BusFault => 17, - Exception::UsageFault => 18, - #[cfg(armv8m_main)] - Exception::SecureFault => 19, - _ => return false, - }; - - (self.shcsr.read() & (1 << shift)) > 0 + pub fn is_enabled(&self, exception: Exception) -> bool { + if let Some(shift) = SCB::shcsr_enable_shift(exception) { + (self.shcsr.read() & (1 << shift)) > 0 + } else { + false + } } }