kernel/
deferred_call.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Hardware-independent kernel interface for deferred calls.
6//!
7//! This allows any struct in the kernel which implements [`DeferredCallClient`]
8//! to set and receive deferred calls, Tock's version of software interrupts.
9//!
10//! These can be used to implement long-running in-kernel algorithms or software
11//! devices that are supposed to work like hardware devices. Essentially, this
12//! allows the chip to handle more important interrupts, and lets a kernel
13//! component return the function call stack up to the scheduler, automatically
14//! being called again.
15//!
16//! Usage
17//! -----
18//!
19//! The `DEFCALLS` array size determines how many [`DeferredCall`]s may be
20//! registered. By default this is set to 32. To support more deferred calls,
21//! this file would need to be modified to use a larger variable for `BITMASK`
22//! (e.g. `BITMASK` could be a u64 and the array size increased to 64). If more
23//! than 32 deferred calls are created, the kernel will panic at the beginning
24//! of the kernel loop.
25//!
26//! ```rust
27//! use kernel::deferred_call::{DeferredCall, DeferredCallClient};
28//! use kernel::static_init;
29//!
30//! struct SomeCapsule {
31//!     deferred_call: DeferredCall
32//! }
33//! impl SomeCapsule {
34//!     pub fn new() -> Self {
35//!         Self {
36//!             deferred_call: DeferredCall::new(),
37//!         }
38//!     }
39//! }
40//! impl DeferredCallClient for SomeCapsule {
41//!     fn handle_deferred_call(&self) {
42//!         // Your action here
43//!     }
44//!
45//!     fn register(&'static self) {
46//!         self.deferred_call.register(self);
47//!     }
48//! }
49//!
50//! // main.rs or your component must register the capsule with its deferred
51//! // call. This should look like:
52//! let some_capsule = unsafe { static_init!(SomeCapsule, SomeCapsule::new()) };
53//! some_capsule.register();
54//! ```
55
56use crate::utilities::cells::OptionalCell;
57use core::cell::Cell;
58use core::marker::Copy;
59use core::marker::PhantomData;
60use core::ptr::addr_of;
61
62/// This trait should be implemented by clients which need to receive
63/// [`DeferredCall`]s.
64// This trait is not intended to be used as a trait object; e.g. you should not
65// create a `&dyn DeferredCallClient`. The `Sized` supertrait prevents this.
66pub trait DeferredCallClient: Sized {
67    /// Software interrupt function that is called when the deferred call is
68    /// triggered.
69    fn handle_deferred_call(&self);
70
71    // This function should be implemented as
72    // `self.deferred_call.register(&self);`.
73    fn register(&'static self);
74}
75
76/// This struct serves as a lightweight alternative to the use of trait objects
77/// (e.g. `&dyn DeferredCall`). Using a trait object will include a 20 byte
78/// vtable per instance, but this alternative stores only the data and function
79/// pointers, 8 bytes per instance.
80#[derive(Copy, Clone)]
81struct DynDefCallRef<'a> {
82    data: *const (),
83    callback: fn(*const ()),
84    _lifetime: PhantomData<&'a ()>,
85}
86
87impl<'a> DynDefCallRef<'a> {
88    // SAFETY: We define the callback function as being a closure which casts
89    // the passed pointer to be the appropriate type (a pointer to `T`) and then
90    // calls `T::handle_deferred_call()`. In practice, the closure is optimized
91    // away by LLVM when the ABI of the closure and the underlying function are
92    // identical, making this zero-cost, but saving us from having to trust that
93    // `fn(*const ())` and `fn handle_deferred_call(&self)` will always have the
94    // same calling convention for any type.
95    fn new<T: DeferredCallClient>(x: &'a T) -> Self {
96        Self {
97            data: core::ptr::from_ref(x) as *const (),
98            callback: |p| unsafe { T::handle_deferred_call(&*p.cast()) },
99            _lifetime: PhantomData,
100        }
101    }
102}
103
104impl DynDefCallRef<'_> {
105    // More efficient to pass by `self` if we don't have to implement
106    // `DeferredCallClient` directly.
107    fn handle_deferred_call(self) {
108        (self.callback)(self.data)
109    }
110}
111
112// The below constant lets us get around Rust not allowing short array
113// initialization for non-default types.
114const EMPTY: OptionalCell<DynDefCallRef<'static>> = OptionalCell::empty();
115
116/// Counter for the number of deferred calls that have been created, this is
117/// used to track that no more than 32 deferred calls have been created.
118// All 3 of the below global statics are accessed only in this file, and all
119// accesses are via immutable references. Tock is single threaded, so each will
120// only ever be accessed via an immutable reference from the single kernel
121// thread. TODO: Once Tock decides on an approach to replace `static mut` with
122// some sort of `SyncCell`, migrate all three of these to that approach
123// (https://github.com/tock/tock/issues/1545).
124static mut CTR: Cell<usize> = Cell::new(0);
125
126/// This bitmask tracks which of the up to 32 existing deferred calls have been
127/// scheduled. Any bit that is set in that mask indicates the deferred call with
128/// its [`DeferredCall::idx`] field set to the index of that bit has been
129/// scheduled and not yet serviced.
130static mut BITMASK: Cell<u32> = Cell::new(0);
131
132/// An array that stores references to up to 32 `DeferredCall`s via the low-cost
133/// [`DynDefCallRef`].
134// This is a 256 byte array, but at least resides in `.bss`.
135static mut DEFCALLS: [OptionalCell<DynDefCallRef<'static>>; 32] = [EMPTY; 32];
136
137pub struct DeferredCall {
138    idx: usize,
139}
140
141impl DeferredCall {
142    /// Create a new deferred call with a unique ID.
143    pub fn new() -> Self {
144        // SAFETY: No accesses to CTR are via an &mut, and the Tock kernel is
145        // single-threaded so all accesses will occur from this thread.
146        let ctr = unsafe { &*addr_of!(CTR) };
147        let idx = ctr.get();
148        ctr.set(idx + 1);
149        DeferredCall { idx }
150    }
151
152    // To reduce monomorphization bloat, the non-generic portion of register is
153    // moved into this function without generic parameters.
154    #[inline(never)]
155    fn register_internal_non_generic(&self, handler: DynDefCallRef<'static>) {
156        // SAFETY: No accesses to DEFCALLS are via an &mut, and the Tock kernel
157        // is single-threaded so all accesses will occur from this thread.
158        let defcalls = unsafe { &*addr_of!(DEFCALLS) };
159        if self.idx >= defcalls.len() {
160            // This error will be caught by the scheduler at the beginning of
161            // the kernel loop, which is much better than panicking here, before
162            // the debug writer is setup. Also allows a single panic for
163            // creating too many deferred calls instead of NUM_DCS panics (this
164            // function is monomorphized).
165            return;
166        }
167        defcalls[self.idx].set(handler);
168    }
169
170    /// This function registers the passed client with this deferred call, such
171    /// that calls to [`DeferredCall::set()`] will schedule a callback on the
172    /// [`handle_deferred_call()`](DeferredCallClient::handle_deferred_call)
173    /// method of the passed client.
174    pub fn register<DC: DeferredCallClient>(&self, client: &'static DC) {
175        let handler = DynDefCallRef::new(client);
176        self.register_internal_non_generic(handler);
177    }
178
179    /// Schedule a deferred callback on the client associated with this deferred
180    /// call.
181    pub fn set(&self) {
182        // SAFETY: No accesses to BITMASK are via an &mut, and the Tock kernel
183        // is single-threaded so all accesses will occur from this thread.
184        let bitmask = unsafe { &*addr_of!(BITMASK) };
185        bitmask.set(bitmask.get() | (1 << self.idx));
186    }
187
188    /// Check if a deferred callback has been set and not yet serviced on this
189    /// deferred call.
190    pub fn is_pending(&self) -> bool {
191        // SAFETY: No accesses to BITMASK are via an &mut, and the Tock kernel
192        // is single-threaded so all accesses will occur from this thread.
193        let bitmask = unsafe { &*addr_of!(BITMASK) };
194        bitmask.get() & (1 << self.idx) == 1
195    }
196
197    /// Services and clears the next pending [`DeferredCall`], returns which
198    /// index was serviced.
199    pub fn service_next_pending() -> Option<usize> {
200        // SAFETY: No accesses to BITMASK/DEFCALLS are via an &mut, and the Tock
201        // kernel is single-threaded so all accesses will occur from this
202        // thread.
203        let bitmask = unsafe { &*addr_of!(BITMASK) };
204        let defcalls = unsafe { &*addr_of!(DEFCALLS) };
205        let val = bitmask.get();
206        if val == 0 {
207            None
208        } else {
209            let bit = val.trailing_zeros() as usize;
210            let new_val = val & !(1 << bit);
211            bitmask.set(new_val);
212            defcalls[bit].map(|dc| {
213                dc.handle_deferred_call();
214                bit
215            })
216        }
217    }
218
219    /// Returns true if any deferred calls are waiting to be serviced, false
220    /// otherwise.
221    pub fn has_tasks() -> bool {
222        // SAFETY: No accesses to BITMASK are via an &mut, and the Tock kernel
223        // is single-threaded so all accesses will occur from this thread.
224        let bitmask = unsafe { &*addr_of!(BITMASK) };
225        bitmask.get() != 0
226    }
227
228    /// This function should be called at the beginning of the kernel loop to
229    /// verify that deferred calls have been correctly initialized. This
230    /// function verifies two things:
231    ///
232    /// 1. That <= [`DEFCALLS.len()`] deferred calls have been created, which is
233    ///    the maximum this interface supports.
234    ///
235    /// 2. That exactly as many deferred calls were registered as were created,
236    ///    which helps to catch bugs if board maintainers forget to call
237    ///    [`register()`](DeferredCall::register) on a created [`DeferredCall`].
238    ///
239    /// Neither of these checks are necessary for soundness, but they are
240    /// necessary for confirming that [`DeferredCall`]s will actually be
241    /// delivered as expected. This function costs about 300 bytes, so you can
242    /// remove it if you are confident your setup will not exceed 32 deferred
243    /// calls, and that all of your components register their deferred calls.
244    // Ignore the clippy warning for using `.filter(|opt| opt.is_some())` since
245    // we don't actually have an Option (we have an OptionalCell) and
246    // IntoIterator is not implemented for OptionalCell.
247    #[allow(clippy::iter_filter_is_some)]
248    pub fn verify_setup() {
249        // SAFETY: No accesses to CTR/DEFCALLS are via an &mut, and the Tock
250        // kernel is single-threaded so all accesses will occur from this
251        // thread.
252        let ctr = unsafe { &*addr_of!(CTR) };
253        let defcalls = unsafe { &*addr_of!(DEFCALLS) };
254        let num_deferred_calls = ctr.get();
255        let num_registered_calls = defcalls.iter().filter(|opt| opt.is_some()).count();
256        if num_deferred_calls > defcalls.len() {
257            panic!("ERROR: too many deferred calls: {}", num_deferred_calls);
258        } else if num_deferred_calls != num_registered_calls {
259            panic!(
260                "ERROR: {} deferred calls, {} registered. A component may have forgotten to register a deferred call.",
261                num_deferred_calls, num_registered_calls
262            );
263        }
264    }
265}