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}