Skip to main content

ax_kernel_guard/
lib.rs

1//! RAII wrappers to create a critical section with local IRQs or preemption
2//! disabled, used to implement spin locks in kernel.
3//!
4//! The critical section is created after the guard struct is created, and is
5//! ended when the guard falls out of scope.
6//!
7//! The crate user must implement the [`KernelGuardIf`] trait using
8//! [`ax_crate_interface::impl_interface`] to provide the low-level implementantion
9//! of how to enable/disable kernel preemption, if the feature `preempt` is
10//! enabled.
11//!
12//! Available guards:
13//!
14//! - [`NoOp`]: Does nothing around the critical section.
15//! - [`IrqSave`]: Disables/enables local IRQs around the critical section.
16//! - [`NoPreempt`]: Disables/enables kernel preemption around the critical
17//!   section.
18//! - [`NoPreemptIrqSave`]: Disables/enables both kernel preemption and local
19//!   IRQs around the critical section.
20//!
21//! # Crate features
22//!
23//! - `preempt`: Use in the preemptive system. If this feature is enabled, you
24//!   need to implement the [`KernelGuardIf`] trait in other crates. Otherwise
25//!   the preemption enable/disable operations will be no-ops. This feature is
26//!   disabled by default.
27//! - `host-test`: Avoid privileged IRQ instructions for host unit tests. This
28//!   feature is disabled by default.
29//!
30//! # Examples
31//!
32//! ```
33//! use ax_kernel_guard::{KernelGuardIf, NoPreempt};
34//!
35//! struct KernelGuardIfImpl;
36//!
37//! #[ax_crate_interface::impl_interface]
38//! impl KernelGuardIf for KernelGuardIfImpl {
39//!     fn enable_preempt() {
40//!         // Your implementation here
41//!     }
42//!     fn disable_preempt() {
43//!         // Your implementation here
44//!     }
45//! }
46//!
47//! let guard = NoPreempt::new();
48//! // The critical section starts here
49//! //
50//! // Do something that requires preemption to be disabled
51//! //
52//! // The critical section ends here
53//! drop(guard);
54//! ```
55
56#![no_std]
57
58mod arch;
59
60/// Low-level interfaces that must be implemented by the crate user.
61#[ax_crate_interface::def_interface]
62pub trait KernelGuardIf {
63    /// How to enable kernel preemption.
64    fn enable_preempt();
65
66    /// How to disable kernel preemption.
67    fn disable_preempt();
68}
69
70/// A base trait that all guards implement.
71pub trait BaseGuard {
72    /// The saved state when entering the critical section.
73    type State: Clone + Copy;
74
75    /// Something that must be done before entering the critical section.
76    fn acquire() -> Self::State;
77
78    /// Something that must be done after leaving the critical section.
79    fn release(state: Self::State);
80
81    /// Returns whether locks guarded by this type should participate in
82    /// lock dependency tracking.
83    fn lockdep_enabled() -> bool {
84        false
85    }
86}
87
88/// A no-op guard that does nothing around the critical section.
89pub struct NoOp;
90
91/// A guard that disables/enables local IRQs around the critical section.
92pub struct IrqSave(usize);
93
94/// A guard that disables/enables kernel preemption around the critical section.
95pub struct NoPreempt;
96
97/// A guard that disables/enables both kernel preemption and local IRQs around
98/// the critical section.
99///
100/// When entering the critical section, it disables kernel preemption first,
101/// followed by local IRQs. When leaving the critical section, it re-enables
102/// local IRQs first, followed by kernel preemption.
103pub struct NoPreemptIrqSave(usize);
104
105impl BaseGuard for NoOp {
106    type State = ();
107    fn acquire() -> Self::State {}
108    fn release(_state: Self::State) {}
109}
110
111impl NoOp {
112    /// Creates a new [`NoOp`] guard.
113    pub const fn new() -> Self {
114        Self
115    }
116}
117
118impl Default for NoOp {
119    fn default() -> Self {
120        Self::new()
121    }
122}
123
124impl Drop for NoOp {
125    fn drop(&mut self) {}
126}
127
128mod imp {
129    use super::*;
130
131    impl BaseGuard for IrqSave {
132        type State = usize;
133
134        #[inline]
135        fn acquire() -> Self::State {
136            super::arch::local_irq_save_and_disable()
137        }
138
139        #[inline]
140        fn release(state: Self::State) {
141            // restore IRQ states
142            super::arch::local_irq_restore(state);
143        }
144
145        fn lockdep_enabled() -> bool {
146            // Keep this disabled for now. The current task-only lockdep model
147            // no longer depends on per-CPU held-lock state, but the codebase
148            // does not currently expose any BaseSpinLock<IrqSave, _> aliases or
149            // real users, so there is no need to widen the tracked guard set
150            // until that use case is defined and tested.
151            false
152        }
153    }
154
155    impl BaseGuard for NoPreempt {
156        type State = ();
157        fn acquire() -> Self::State {
158            // disable preempt
159            #[cfg(feature = "preempt")]
160            ax_crate_interface::call_interface!(KernelGuardIf::disable_preempt);
161        }
162        fn release(_state: Self::State) {
163            // enable preempt
164            #[cfg(feature = "preempt")]
165            ax_crate_interface::call_interface!(KernelGuardIf::enable_preempt);
166        }
167
168        fn lockdep_enabled() -> bool {
169            true
170        }
171    }
172
173    impl BaseGuard for NoPreemptIrqSave {
174        type State = usize;
175        fn acquire() -> Self::State {
176            // disable preempt
177            #[cfg(feature = "preempt")]
178            ax_crate_interface::call_interface!(KernelGuardIf::disable_preempt);
179            // disable IRQs and save IRQ states
180            super::arch::local_irq_save_and_disable()
181        }
182        fn release(state: Self::State) {
183            // restore IRQ states
184            super::arch::local_irq_restore(state);
185            // enable preempt
186            #[cfg(feature = "preempt")]
187            ax_crate_interface::call_interface!(KernelGuardIf::enable_preempt);
188        }
189
190        fn lockdep_enabled() -> bool {
191            true
192        }
193    }
194
195    impl IrqSave {
196        /// Creates a new [`IrqSave`] guard.
197        pub fn new() -> Self {
198            Self(Self::acquire())
199        }
200    }
201
202    impl Drop for IrqSave {
203        fn drop(&mut self) {
204            Self::release(self.0)
205        }
206    }
207
208    impl Default for IrqSave {
209        fn default() -> Self {
210            Self::new()
211        }
212    }
213
214    impl NoPreempt {
215        /// Creates a new [`NoPreempt`] guard.
216        pub fn new() -> Self {
217            Self::acquire();
218            Self
219        }
220    }
221
222    impl Drop for NoPreempt {
223        fn drop(&mut self) {
224            Self::release(())
225        }
226    }
227
228    impl Default for NoPreempt {
229        fn default() -> Self {
230            Self::new()
231        }
232    }
233
234    impl NoPreemptIrqSave {
235        /// Creates a new [`NoPreemptIrqSave`] guard.
236        pub fn new() -> Self {
237            Self(Self::acquire())
238        }
239    }
240
241    impl Drop for NoPreemptIrqSave {
242        fn drop(&mut self) {
243            Self::release(self.0)
244        }
245    }
246
247    impl Default for NoPreemptIrqSave {
248        fn default() -> Self {
249            Self::new()
250        }
251    }
252}