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
58#[cfg(all(axtest, feature = "axtest"))]
59/// Coverage tests for kernel guard state transitions.
60pub mod axtest;
61
62mod arch;
63
64/// Low-level interfaces that must be implemented by the crate user.
65#[ax_crate_interface::def_interface]
66pub trait KernelGuardIf {
67 /// How to enable kernel preemption.
68 fn enable_preempt();
69
70 /// How to disable kernel preemption.
71 fn disable_preempt();
72}
73
74/// A base trait that all guards implement.
75pub trait BaseGuard {
76 /// The saved state when entering the critical section.
77 type State: Clone + Copy;
78
79 /// Something that must be done before entering the critical section.
80 fn acquire() -> Self::State;
81
82 /// Something that must be done after leaving the critical section.
83 fn release(state: Self::State);
84
85 /// Returns whether locks guarded by this type should participate in
86 /// lock dependency tracking.
87 fn lockdep_enabled() -> bool {
88 false
89 }
90}
91
92/// A no-op guard that does nothing around the critical section.
93pub struct NoOp;
94
95/// A guard that disables/enables local IRQs around the critical section.
96pub struct IrqSave(usize);
97
98/// A guard that disables/enables kernel preemption around the critical section.
99pub struct NoPreempt;
100
101/// A guard that disables/enables both kernel preemption and local IRQs around
102/// the critical section.
103///
104/// When entering the critical section, it disables kernel preemption first,
105/// followed by local IRQs. When leaving the critical section, it re-enables
106/// local IRQs first, followed by kernel preemption.
107pub struct NoPreemptIrqSave(usize);
108
109impl BaseGuard for NoOp {
110 type State = ();
111 fn acquire() -> Self::State {}
112 fn release(_state: Self::State) {}
113}
114
115impl NoOp {
116 /// Creates a new [`NoOp`] guard.
117 pub const fn new() -> Self {
118 Self
119 }
120}
121
122impl Default for NoOp {
123 fn default() -> Self {
124 Self::new()
125 }
126}
127
128impl Drop for NoOp {
129 fn drop(&mut self) {}
130}
131
132mod imp {
133 use super::*;
134
135 impl BaseGuard for IrqSave {
136 type State = usize;
137
138 #[inline]
139 fn acquire() -> Self::State {
140 super::arch::local_irq_save_and_disable()
141 }
142
143 #[inline]
144 fn release(state: Self::State) {
145 // restore IRQ states
146 super::arch::local_irq_restore(state);
147 }
148
149 fn lockdep_enabled() -> bool {
150 // Keep this disabled for now. The current task-only lockdep model
151 // no longer depends on per-CPU held-lock state, but the codebase
152 // does not currently expose any BaseSpinLock<IrqSave, _> aliases or
153 // real users, so there is no need to widen the tracked guard set
154 // until that use case is defined and tested.
155 false
156 }
157 }
158
159 impl BaseGuard for NoPreempt {
160 type State = ();
161 fn acquire() -> Self::State {
162 // disable preempt
163 #[cfg(feature = "preempt")]
164 ax_crate_interface::call_interface!(KernelGuardIf::disable_preempt);
165 }
166 fn release(_state: Self::State) {
167 // enable preempt
168 #[cfg(feature = "preempt")]
169 ax_crate_interface::call_interface!(KernelGuardIf::enable_preempt);
170 }
171
172 fn lockdep_enabled() -> bool {
173 true
174 }
175 }
176
177 impl BaseGuard for NoPreemptIrqSave {
178 type State = usize;
179 fn acquire() -> Self::State {
180 // disable preempt
181 #[cfg(feature = "preempt")]
182 ax_crate_interface::call_interface!(KernelGuardIf::disable_preempt);
183 // disable IRQs and save IRQ states
184 super::arch::local_irq_save_and_disable()
185 }
186 fn release(state: Self::State) {
187 // restore IRQ states
188 super::arch::local_irq_restore(state);
189 // enable preempt
190 #[cfg(feature = "preempt")]
191 ax_crate_interface::call_interface!(KernelGuardIf::enable_preempt);
192 }
193
194 fn lockdep_enabled() -> bool {
195 true
196 }
197 }
198
199 impl IrqSave {
200 /// Creates a new [`IrqSave`] guard.
201 pub fn new() -> Self {
202 Self(Self::acquire())
203 }
204 }
205
206 impl Drop for IrqSave {
207 fn drop(&mut self) {
208 Self::release(self.0)
209 }
210 }
211
212 impl Default for IrqSave {
213 fn default() -> Self {
214 Self::new()
215 }
216 }
217
218 impl NoPreempt {
219 /// Creates a new [`NoPreempt`] guard.
220 pub fn new() -> Self {
221 Self::acquire();
222 Self
223 }
224 }
225
226 impl Drop for NoPreempt {
227 fn drop(&mut self) {
228 Self::release(())
229 }
230 }
231
232 impl Default for NoPreempt {
233 fn default() -> Self {
234 Self::new()
235 }
236 }
237
238 impl NoPreemptIrqSave {
239 /// Creates a new [`NoPreemptIrqSave`] guard.
240 pub fn new() -> Self {
241 Self(Self::acquire())
242 }
243 }
244
245 impl Drop for NoPreemptIrqSave {
246 fn drop(&mut self) {
247 Self::release(self.0)
248 }
249 }
250
251 impl Default for NoPreemptIrqSave {
252 fn default() -> Self {
253 Self::new()
254 }
255 }
256}