-
Notifications
You must be signed in to change notification settings - Fork 175
Cherrypick old cortex-m PRs #606
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
7bb5dbd
to
6d66f5a
Compare
Output of
The change is #422, where ITNS is added for armv8m targts, which required splitting |
b85e7fd
to
cbd8738
Compare
which the underscore tells them they aren't supposed to do, so I don't consider that breaking. Here's the diff against the old 0.7.x branch - it looks OK to me. diff --color -r cortex-m-subtree/src/asm.rs cortex-m/cortex-m/src/asm.rs
20,21c20,21
< /// This is implemented in assembly so its execution time is independent of the optimization
< /// level, however it is dependent on the specific architecture and core configuration.
---
> /// This is implemented in assembly as a fixed number of iterations of a loop, so that execution
> /// time is independent of the optimization level.
23,26c23,31
< /// NOTE that the delay can take much longer if interrupts are serviced during its execution
< /// and the execution time may vary with other factors. This delay is mainly useful for simple
< /// timer-less initialization of peripherals if and only if accurate timing is not essential. In
< /// any other case please use a more accurate method to produce a delay.
---
> /// The loop code is the same for all architectures, however the number of CPU cycles required for
> /// one iteration varies substantially between architectures. This means that with a 48MHz CPU
> /// clock, a call to `delay(48_000_000)` is guaranteed to take at least 1 second, but for example
> /// could take 2 seconds.
> ///
> /// NOTE that the delay can take much longer if interrupts are serviced during its execution and the
> /// execution time may vary with other factors. This delay is mainly useful for simple timer-less
> /// initialization of peripherals if and only if accurate timing is not essential. In any other case
> /// please use a more accurate method to produce a delay.
diff --color -r cortex-m-subtree/src/critical_section.rs cortex-m/cortex-m/src/critical_section.rs
1,3c1
< #[cfg(all(cortex_m, feature = "critical-section-single-core"))]
< mod single_core_critical_section {
< use critical_section::{set_impl, Impl, RawRestoreState};
---
> use critical_section::{set_impl, Impl, RawRestoreState};
5,6c3,4
< use crate::interrupt;
< use crate::register::primask;
---
> use crate::interrupt;
> use crate::register::primask;
8,9c6,7
< struct SingleCoreCriticalSection;
< set_impl!(SingleCoreCriticalSection);
---
> struct SingleCoreCriticalSection;
> set_impl!(SingleCoreCriticalSection);
11,16c9,18
< unsafe impl Impl for SingleCoreCriticalSection {
< unsafe fn acquire() -> RawRestoreState {
< let was_active = primask::read().is_active();
< interrupt::disable();
< was_active
< }
---
> unsafe impl Impl for SingleCoreCriticalSection {
> unsafe fn acquire() -> RawRestoreState {
> // Backup previous state of PRIMASK register. We access the entire register directly as a
> // u32 instead of using the primask::read() function to minimize the number of processor
> // cycles during which interrupts are disabled.
> let restore_state = primask::read_raw();
> // NOTE: Fence guarantees are provided by interrupt::disable(), which performs a `compiler_fence(SeqCst)`.
> interrupt::disable();
> restore_state
> }
18,23c20,22
< unsafe fn release(was_active: RawRestoreState) {
< // Only re-enable interrupts if they were enabled before the critical section.
< if was_active {
< interrupt::enable()
< }
< }
---
> unsafe fn release(restore_state: RawRestoreState) {
> // NOTE: Fence guarantees are provided by primask::write_raw(), which performs a `compiler_fence(SeqCst)`.
> primask::write_raw(restore_state);
diff --color -r cortex-m-subtree/src/delay.rs cortex-m/cortex-m/src/delay.rs
4c4
< use embedded_hal::blocking::delay::{DelayMs, DelayUs};
---
> use eh1::delay::DelayNs;
78c78
< impl DelayMs<u32> for Delay {
---
> impl eh0::blocking::delay::DelayMs<u32> for Delay {
86c86
< impl DelayMs<i32> for Delay {
---
> impl eh0::blocking::delay::DelayMs<i32> for Delay {
94c94
< impl DelayMs<u16> for Delay {
---
> impl eh0::blocking::delay::DelayMs<u16> for Delay {
101c101
< impl DelayMs<u8> for Delay {
---
> impl eh0::blocking::delay::DelayMs<u8> for Delay {
108c108
< impl DelayUs<u32> for Delay {
---
> impl eh0::blocking::delay::DelayUs<u32> for Delay {
116c116
< impl DelayUs<i32> for Delay {
---
> impl eh0::blocking::delay::DelayUs<i32> for Delay {
124c124
< impl DelayUs<u16> for Delay {
---
> impl eh0::blocking::delay::DelayUs<u16> for Delay {
131c131
< impl DelayUs<u8> for Delay {
---
> impl eh0::blocking::delay::DelayUs<u8> for Delay {
134a135,155
> }
> }
>
> impl DelayNs for Delay {
> #[inline]
> fn delay_ns(&mut self, ns: u32) {
> // from the rp2040-hal:
> let us = ns / 1000 + if ns % 1000 == 0 { 0 } else { 1 };
> // With rustc 1.73, this can be replaced by:
> // let us = ns.div_ceil(1000);
> Delay::delay_us(self, us)
> }
>
> #[inline]
> fn delay_us(&mut self, us: u32) {
> Delay::delay_us(self, us)
> }
>
> #[inline]
> fn delay_ms(&mut self, ms: u32) {
> Delay::delay_ms(self, ms)
diff --color -r cortex-m-subtree/src/interrupt.rs cortex-m/cortex-m/src/interrupt.rs
53a54
> #[cfg(cortex_m)]
59c60,63
< let primask = crate::register::primask::read();
---
> // Backup previous state of PRIMASK register. We access the entire register directly as a
> // u32 instead of using the primask::read() function to minimize the number of processor
> // cycles during which interrupts are disabled.
> let primask = crate::register::primask::read_raw();
66,69c70,71
< // If the interrupts were active before our `disable` call, then re-enable
< // them. Otherwise, keep them disabled
< if primask.is_active() {
< unsafe { enable() }
---
> unsafe {
> crate::register::primask::write_raw(primask);
72a75,88
> }
>
> // Make a `free()` function available on hosted platforms to allow checking dependencies without
> // specifying a target, but that will panic at runtime if executed.
> /// Execute closure `f` in an interrupt-free context.
> ///
> /// This as also known as a "critical section".
> #[cfg(not(cortex_m))]
> #[inline]
> pub fn free<F, R>(_: F) -> R
> where
> F: FnOnce(&CriticalSection) -> R,
> {
> panic!("cortex_m::interrupt::free() is only functional on cortex-m platforms");
diff --color -r cortex-m-subtree/src/lib.rs cortex-m/cortex-m/src/lib.rs
20c20
< //! function call overhead when `inline-asm` is not enabled.
---
> //! function call overhead when `inline-asm` is not enabled.
23c23
< //! API docs for details.
---
> //! API docs for details.
34c34
< //! and may cause functional problems in systems where some interrupts must be not be disabled
---
> //! and may cause functional problems in systems where some interrupts must not be disabled
37a38,42
> //! The critical section has been optimized to block interrupts for as few cycles as possible,
> //! but -- due to `critical-section` implementation details -- incurs branches in a normal build
> //! configuration. For minimal interrupt latency, you can achieve inlining by enabling
> //! [linker-plugin-based LTO](https://doc.rust-lang.org/rustc/linker-plugin-lto.html).
> //!
66c71
< //! This crate is guaranteed to compile on stable Rust 1.59 and up. It *might*
---
> //! This crate is guaranteed to compile on stable Rust 1.61 and up. It *might*
103d107
< mod critical_section;
112a117,126
>
> #[cfg(all(cortex_m, feature = "critical-section-single-core"))]
> mod critical_section;
>
> /// Used to reexport items for use in macros. Do not use directly.
> /// Not covered by semver guarantees.
> #[doc(hidden)]
> pub mod _export {
> pub use critical_section;
> }
diff --color -r cortex-m-subtree/src/macros.rs cortex-m/cortex-m/src/macros.rs
34d33
< /// This macro is unsound on multi core systems.
36,37c35,37
< /// For debuggability, you can set an explicit name for a singleton. This name only shows up the
< /// the debugger and is not referencable from other code. See example below.
---
> /// This macro requires a `critical-section` implementation to be set. For most single core systems,
> /// you can enable the `critical-section-single-core` feature for this crate. For other systems, you
> /// have to provide one from elsewhere, typically your chip's HAL crate.
38a39,41
> /// For debuggability, you can set an explicit name for a singleton. This name only shows up the
> /// debugger and is not referenceable from other code. See example below.
> ///
64,65c67,68
< ($name:ident: $ty:ty = $expr:expr) => {
< $crate::interrupt::free(|_| {
---
> ($(#[$meta:meta])* $name:ident: $ty:ty = $expr:expr) => {
> $crate::_export::critical_section::with(|_| {
68a72
> $(#[$meta])*
82,83c86
< $name.0 = ::core::mem::MaybeUninit::new(expr);
< Some(&mut *$name.0.as_mut_ptr())
---
> Some($name.0.write(expr))
88,89c91,92
< (: $ty:ty = $expr:expr) => {
< $crate::singleton!(VAR: $ty = $expr)
---
> ($(#[$meta:meta])* : $ty:ty = $expr:expr) => {
> $crate::singleton!($(#[$meta])* VAR: $ty = $expr)
114a118,129
>
> /// ```
> /// use cortex_m::singleton;
> ///
> /// fn foo() {
> /// // check that attributes are forwarded
> /// singleton!(#[link_section = ".bss"] FOO: u8 = 0);
> /// singleton!(#[link_section = ".bss"]: u8 = 1);
> /// }
> /// ```
> #[allow(dead_code)]
> const CPASS_ATTR: () = ();
diff --color -r cortex-m-subtree/src/peripheral/mod.rs cortex-m/cortex-m/src/peripheral/mod.rs
63,65c63
< use crate::interrupt;
<
< #[cfg(cm7)]
---
> #[cfg(feature = "cm7")]
99c97
< #[cfg(cm7)]
---
> #[cfg(feature = "cm7")]
168c166
< interrupt::free(|_| {
---
> crate::interrupt::free(|_| {
183c181
< #[cfg(cm7)]
---
> #[cfg(feature = "cm7")]
235c233
< #[cfg(cm7)]
---
> #[cfg(feature = "cm7")]
240c238
< #[cfg(cm7)]
---
> #[cfg(feature = "cm7")]
243c241
< #[cfg(cm7)]
---
> #[cfg(feature = "cm7")]
diff --color -r cortex-m-subtree/src/peripheral/nvic.rs cortex-m/cortex-m/src/peripheral/nvic.rs
39c39
< _reserved5: [u32; 48],
---
> _reserved5: [u32; 16],
40a41,48
> #[cfg(armv8m)]
> /// Interrupt Target Non-secure (only present on Arm v8-M)
> pub itns: [RW<u32>; 16],
> #[cfg(not(armv8m))]
> _reserved6: [u32; 16],
>
> _reserved7: [u32; 16],
>
70c78
< _reserved6: [u32; 580],
---
> _reserved8: [u32; 580],
diff --color -r cortex-m-subtree/src/peripheral/scb.rs cortex-m/cortex-m/src/peripheral/scb.rs
649,652c649
< self.invalidate_dcache_by_address(
< slice.as_ptr() as usize,
< slice.len() * core::mem::size_of::<T>(),
< );
---
> self.invalidate_dcache_by_address(slice.as_ptr() as usize, core::mem::size_of_val(slice));
735,738c732
< self.clean_dcache_by_address(
< slice.as_ptr() as usize,
< slice.len() * core::mem::size_of::<T>(),
< );
---
> self.clean_dcache_by_address(slice.as_ptr() as usize, core::mem::size_of_val(slice));
818a813,832
> }
> }
> }
>
> const SCB_SCR_SEVONPEND: u32 = 0x1 << 4;
>
> impl SCB {
> /// Set the SEVONPEND bit in the SCR register
> #[inline]
> pub fn set_sevonpend(&mut self) {
> unsafe {
> self.scr.modify(|scr| scr | SCB_SCR_SEVONPEND);
> }
> }
>
> /// Clear the SEVONPEND bit in the SCR register
> #[inline]
> pub fn clear_sevonpend(&mut self) {
> unsafe {
> self.scr.modify(|scr| scr & !SCB_SCR_SEVONPEND);
diff --color -r cortex-m-subtree/src/peripheral/syst.rs cortex-m/cortex-m/src/peripheral/syst.rs
1a2,15
> //!
> //! # Example
> //!
> //! ```no_run
> //! use cortex_m::peripheral::{Peripherals, SYST};
> //!
> //! let core_periph = cortex_m::peripheral::Peripherals::take().unwrap();
> //! let mut syst = core_periph.SYST;
> //! syst.set_reload(0xffffff);
> //! syst.clear_current();
> //! syst.enable_counter();
> //!
> //! let syst_value: u32 = SYST::get_current();
> //! ```
42c56
< /// After calling `clear_current()`, the next call to `has_wrapped()` will return `false`.
---
> /// After calling `clear_current()`, the next call to `has_wrapped()`, unless called after the reload time (if the counter is enabled), will return `false`.
diff --color -r cortex-m-subtree/src/prelude.rs cortex-m/cortex-m/src/prelude.rs
3c3
< pub use embedded_hal::prelude::*;
---
> pub use eh0::prelude::*;
diff --color -r cortex-m-subtree/src/register/primask.rs cortex-m/cortex-m/src/register/primask.rs
2a3,7
> #[cfg(cortex_m)]
> use core::arch::asm;
> #[cfg(cortex_m)]
> use core::sync::atomic::{compiler_fence, Ordering};
>
26c31
< /// Reads the CPU register
---
> /// Reads the prioritizable interrupt mask
29,30c34
< let r: u32 = call_asm!(__primask_r() -> u32);
< if r & (1 << 0) == (1 << 0) {
---
> if read_raw() & (1 << 0) == (1 << 0) {
34a39,75
> }
>
> /// Reads the entire PRIMASK register
> /// Note that bits [31:1] are reserved and UNK (Unknown)
> #[inline]
> #[cfg(cortex_m)]
> pub fn read_raw() -> u32 {
> let r: u32;
> unsafe { asm!("mrs {}, PRIMASK", out(reg) r, options(nomem, nostack, preserves_flags)) };
> r
> }
>
> /// Reads the entire PRIMASK register
> /// Note that bits [31:1] are reserved and UNK (Unknown)
> #[inline]
> #[cfg(not(cortex_m))]
> pub fn read_raw() -> u32 {
> panic!("cannot read PRIMASK on non-cortex-m platform");
> }
>
> /// Writes the entire PRIMASK register
> /// Note that bits [31:1] are reserved and SBZP (Should-Be-Zero-or-Preserved)
> ///
> /// # Safety
> ///
> /// This method is unsafe as other unsafe code may rely on interrupts remaining disabled, for
> /// example during a critical section, and being able to safely re-enable them would lead to
> /// undefined behaviour. Do not call this function in a context where interrupts are expected to
> /// remain disabled -- for example, in the midst of a critical section or `interrupt::free()` call.
> #[cfg(cortex_m)]
> #[inline]
> pub unsafe fn write_raw(r: u32) {
> // Ensure no preceeding memory accesses are reordered to after interrupts are possibly enabled.
> compiler_fence(Ordering::SeqCst);
> unsafe { asm!("msr PRIMASK, {}", in(reg) r, options(nomem, nostack, preserves_flags)) };
> // Ensure no subsequent memory accesses are reordered to before interrupts are possibly disabled.
> compiler_fence(Ordering::SeqCst); |
Optimize critical_section: use MSR instruction
422: Add ITNS field to NVIC peripheral r=adamgreig a=sphw This PR adds the ITNS (Interrupt Target Non-secure) field to the NIVC peripheral. This field is required to write a boot loader for TrustZone-M devices, since it allows the user to use interrupts from non-secure states. I believe I have maintained the correct padding for the next fields, but I have not tested these changes on a non M33 device. So a close review and test would be appreciated. Co-authored-by: Sascha Wise <[email protected]>
Signed-off-by: Ariel D'Alessandro <[email protected]>
singleton: forward attributes
451: Small critical-section-related fixes. r=adamgreig a=Dirbaio See individual commit messages. Co-authored-by: Dario Nieuwenhuis <[email protected]>
e3575c5
to
523cf3d
Compare
I've rebased onto master. |
PRs backported:
PRs that we should still backport in this PR but I haven't got to yet:
LocalTimestampOptions
, impl gatedTryFrom<u8>
#366PRs that are breaking and we will probably want one day but can't include in 0.7.x:
SCB.ICSR.VECTACTIVE
is 9 bits, not 8 #373&mut self
forrequest
. #472Besides those listed above I don't think there are any PRs to the old cortex-m master branch between when we split it to 0.7.x (#375) and when we recently reverted it (#605).