sel4/
cptr.rs

1//
2// Copyright 2023, Colias Group, LLC
3// Copyright (c) 2020 Arm Limited
4//
5// SPDX-License-Identifier: MIT
6//
7
8use core::fmt;
9use core::hash::Hash;
10use core::marker::PhantomData;
11
12use crate::{sys, InvocationContext, IpcBuffer, NoExplicitInvocationContext, WORD_SIZE};
13
14/// The raw bits of a capability pointer.
15pub type CPtrBits = sys::seL4_CPtr;
16
17/// A capability pointer.
18#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
19pub struct CPtr {
20    bits: CPtrBits,
21}
22
23impl CPtr {
24    pub const fn bits(self) -> CPtrBits {
25        self.bits
26    }
27
28    pub const fn from_bits(bits: CPtrBits) -> Self {
29        Self { bits }
30    }
31
32    pub const fn cast<T: CapType>(self) -> Cap<T> {
33        Cap::from_cptr(self)
34    }
35}
36
37/// A capability pointer with a number of bits to resolve.
38#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
39pub struct CPtrWithDepth {
40    bits: CPtrBits,
41    depth: usize,
42}
43
44impl CPtrWithDepth {
45    pub const fn from_bits_with_depth(bits: CPtrBits, depth: usize) -> Self {
46        Self { bits, depth }
47    }
48
49    pub const fn bits(&self) -> CPtrBits {
50        self.bits
51    }
52
53    pub const fn depth(&self) -> usize {
54        self.depth
55    }
56
57    /// The [`CPtrWithDepth`] with a depth of 0.
58    pub const fn empty() -> Self {
59        Self::from_bits_with_depth(0, 0)
60    }
61
62    // convenience
63    pub(crate) fn depth_for_kernel(&self) -> u8 {
64        self.depth().try_into().unwrap()
65    }
66}
67
68impl From<CPtr> for CPtrWithDepth {
69    fn from(cptr: CPtr) -> Self {
70        Self::from_bits_with_depth(cptr.bits(), WORD_SIZE)
71    }
72}
73
74/// A capability pointer to be resolved in the current CSpace.
75///
76/// - The `T` parameter is a [`CapType`] marking the type of the pointed-to capability.
77/// - The `C` parameter is a strategy for discovering the current thread's IPC buffer. When the
78///   `"state"` feature is enabled, [`NoExplicitInvocationContext`] is an alias for
79///   [`ImplicitInvocationContext`](crate::ImplicitInvocationContext), which uses the [`IpcBuffer`]
80///   set by [`set_ipc_buffer`](crate::set_ipc_buffer). Otherwise, it is an alias for
81///   [`NoInvocationContext`](crate::NoInvocationContext), which does not implement
82///   [`InvocationContext`]. In such cases, the [`with`](Cap::with) method is used to specify an
83///   invocation context before the capability is invoked.
84///
85/// The most general way to construct a [`Cap`] is with [`CPtr::cast`].
86///
87/// Note that `seL4_CNode_*` capability invocations are methods of [`AbsoluteCPtr`] rather than
88/// [`Cap`].
89#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
90pub struct Cap<T: CapType, C = NoExplicitInvocationContext> {
91    cptr: CPtr,
92    invocation_context: C,
93    _phantom: PhantomData<T>,
94}
95
96impl<T: CapType, C> Cap<T, C> {
97    pub const fn cptr(&self) -> CPtr {
98        self.cptr
99    }
100
101    pub const fn bits(&self) -> CPtrBits {
102        self.cptr().bits()
103    }
104
105    pub fn cast<T1: CapType>(self) -> Cap<T1, C> {
106        Cap {
107            cptr: self.cptr,
108            invocation_context: self.invocation_context,
109            _phantom: PhantomData,
110        }
111    }
112
113    pub fn with<C1>(self, context: C1) -> Cap<T, C1> {
114        Cap {
115            cptr: self.cptr,
116            invocation_context: context,
117            _phantom: PhantomData,
118        }
119    }
120
121    pub fn without_context(self) -> Cap<T> {
122        self.with(NoExplicitInvocationContext::new())
123    }
124
125    pub fn into_invocation_context(self) -> C {
126        self.invocation_context
127    }
128}
129
130impl<T: CapType> Cap<T> {
131    pub const fn from_cptr(cptr: CPtr) -> Self {
132        Self {
133            cptr,
134            invocation_context: NoExplicitInvocationContext::new(),
135            _phantom: PhantomData,
136        }
137    }
138
139    pub const fn from_bits(bits: CPtrBits) -> Self {
140        CPtr::from_bits(bits).cast()
141    }
142}
143
144impl<T: CapType, C: InvocationContext> Cap<T, C> {
145    // TODO
146    // Consider the tradeoffs of taking &mut self here, and switching all object invocations to take
147    // &mut self too.
148    pub(crate) fn invoke<R>(self, f: impl FnOnce(CPtr, &mut IpcBuffer) -> R) -> R {
149        let cptr = self.cptr();
150        self.into_invocation_context()
151            .with_context(|ipc_buffer| f(cptr, ipc_buffer))
152    }
153}
154
155impl<T: CapType, C> fmt::Debug for Cap<T, C> {
156    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157        f.debug_tuple(T::NAME).field(&self.cptr().bits()).finish()
158    }
159}
160
161/// Trait for marker types corresponding to capability types in the seL4 API.
162///
163/// Implementors are used to mark instantiations of [`Cap`].
164// NOTE require derivable traits for convenience to make up for limitations of automatic trait
165// derivation
166pub trait CapType: Copy + Clone + Eq + PartialEq + Ord + PartialOrd + Hash {
167    const NAME: &'static str;
168}
169
170pub mod cap_type {
171    //! Markers corresponding to capability types and classes of capability types.
172    //!
173    //! These types are used for marking [`Cap`](crate::Cap).
174
175    use sel4_config::sel4_cfg_if;
176
177    use crate::{
178        declare_cap_type, declare_cap_type_for_object_of_fixed_size,
179        declare_cap_type_for_object_of_variable_size,
180    };
181
182    pub use crate::arch::cap_type_arch::*;
183
184    declare_cap_type_for_object_of_variable_size! {
185        /// Corresponds to `seL4_Untyped`.
186        Untyped { ObjectType, ObjectBlueprint }
187    }
188
189    declare_cap_type_for_object_of_fixed_size! {
190        /// Corresponds to the endpoint capability type.
191        Endpoint { ObjectType, ObjectBlueprint }
192    }
193
194    declare_cap_type_for_object_of_fixed_size! {
195        /// Corresponds to the notification capability type.
196        Notification { ObjectType, ObjectBlueprint }
197    }
198
199    declare_cap_type_for_object_of_fixed_size! {
200        /// Corresponds to `seL4_TCB`.
201        Tcb { ObjectType, ObjectBlueprint }
202    }
203
204    declare_cap_type_for_object_of_variable_size! {
205        /// Corresponds to `seL4_CNode`.
206        CNode { ObjectType, ObjectBlueprint }
207    }
208
209    declare_cap_type! {
210        /// Corresponds to `seL4_IRQControl`.
211        IrqControl
212    }
213
214    declare_cap_type! {
215        /// Corresponds to `seL4_IRQHandler`.
216        IrqHandler
217    }
218
219    declare_cap_type! {
220        /// Corresponds to `seL4_ASIDControl`.
221        AsidControl
222    }
223
224    declare_cap_type! {
225        /// Corresponds to `seL4_ASIDPool`.
226        AsidPool
227    }
228
229    declare_cap_type! {
230        /// Corresponds to the null capability.
231        Null
232    }
233
234    declare_cap_type! {
235        /// Any capability.
236        Unspecified
237    }
238
239    declare_cap_type! {
240        /// Any page capability.
241        UnspecifiedPage
242    }
243
244    declare_cap_type! {
245        /// Any intermediate translation table capability.
246        UnspecifiedIntermediateTranslationTable
247    }
248
249    sel4_cfg_if! {
250        if #[sel4_cfg(KERNEL_MCS)] {
251            declare_cap_type! {
252                /// Corresponds to the reply capability type (MCS only).
253                Reply
254            }
255
256            declare_cap_type_for_object_of_variable_size! {
257                /// Corresponds to the scheduling context capability type (MCS only).
258                SchedContext { ObjectType, ObjectBlueprint }
259            }
260
261            declare_cap_type! {
262                /// Corresponds to `seL4_SchedControl`.
263                SchedControl
264            }
265        }
266    }
267}
268
269use cap::*;
270
271pub mod cap {
272    //! Marked aliases of [`Cap`](crate::Cap).
273    //!
274    //! Each type `$t<C = NoExplicitInvocationContext>` in this module is an alias for `Cap<$t, C>`.
275
276    use sel4_config::sel4_cfg_if;
277
278    use crate::declare_cap_alias;
279
280    pub use crate::arch::cap_arch::*;
281
282    declare_cap_alias!(Untyped);
283    declare_cap_alias!(Endpoint);
284    declare_cap_alias!(Notification);
285    declare_cap_alias!(Tcb);
286    declare_cap_alias!(CNode);
287    declare_cap_alias!(IrqControl);
288    declare_cap_alias!(IrqHandler);
289    declare_cap_alias!(AsidControl);
290    declare_cap_alias!(AsidPool);
291
292    declare_cap_alias!(Null);
293    declare_cap_alias!(Unspecified);
294    declare_cap_alias!(UnspecifiedPage);
295    declare_cap_alias!(UnspecifiedIntermediateTranslationTable);
296
297    declare_cap_alias!(VSpace);
298    declare_cap_alias!(Granule);
299
300    sel4_cfg_if! {
301        if #[sel4_cfg(KERNEL_MCS)] {
302            declare_cap_alias!(Reply);
303            declare_cap_alias!(SchedContext);
304            declare_cap_alias!(SchedControl);
305        }
306    }
307}
308
309impl<T: CapType, C> Cap<T, C> {
310    pub fn upcast(self) -> Unspecified<C> {
311        self.cast()
312    }
313}
314
315impl<C> Unspecified<C> {
316    pub fn downcast<T: CapType>(self) -> Cap<T, C> {
317        self.cast()
318    }
319}
320
321/// A [`CPtrWithDepth`] to be resolved in the context of a particular [`CNode`].
322///
323/// [`AbsoluteCPtr`] addresses capability slots in a more general way than [`Cap`]. It allows one to
324/// address any capability slot that is directly addressable from any CNode that is directly
325/// addressible in the current thread's CSpace. Furthermore, it allows one to address capability
326/// slots that contain CNodes by limiting the lookup depth to prevent the kernel's lookup procedure
327/// from descending into the CNode contained in that slot.
328///
329/// `seL4_CNode_*` capability invocations are methods of [`AbsoluteCPtr`] rather than [`Cap`].
330///
331/// In addition to [`AbsoluteCPtr::new`], the following methods can be used to construct an
332/// [`AbsoluteCPtr`]:
333/// - [`CNode::absolute_cptr`]
334/// - [`CNode::absolute_cptr_from_bits_with_depth`]
335/// - [`CNode::absolute_cptr_for_self`]
336#[derive(Copy, Clone, Debug, Eq, PartialEq)]
337pub struct AbsoluteCPtr<C = NoExplicitInvocationContext> {
338    root: CNode<C>,
339    path: CPtrWithDepth,
340}
341
342impl<C> AbsoluteCPtr<C> {
343    pub const fn new(root: CNode<C>, path: CPtrWithDepth) -> Self {
344        Self { root, path }
345    }
346
347    pub const fn root(&self) -> &CNode<C> {
348        &self.root
349    }
350
351    pub fn into_root(self) -> CNode<C> {
352        self.root
353    }
354
355    pub const fn path(&self) -> &CPtrWithDepth {
356        &self.path
357    }
358
359    pub fn with<C1>(self, context: C1) -> AbsoluteCPtr<C1> {
360        AbsoluteCPtr {
361            root: self.root.with(context),
362            path: self.path,
363        }
364    }
365
366    pub fn without_context(self) -> AbsoluteCPtr {
367        self.with(NoExplicitInvocationContext::new())
368    }
369}
370
371impl<C: InvocationContext> AbsoluteCPtr<C> {
372    pub(crate) fn invoke<R>(self, f: impl FnOnce(CPtr, CPtrWithDepth, &mut IpcBuffer) -> R) -> R {
373        let path = *self.path();
374        self.into_root()
375            .invoke(|cptr, ipc_buffer| f(cptr, path, ipc_buffer))
376    }
377}
378
379/// Trait for types whose members which logically contain a [`CPtrWithDepth`].
380///
381/// [`CPtr`] and [`Cap`] each logically contain a [`CPtrWithDepth`] with a depth of [`WORD_SIZE`].
382pub trait HasCPtrWithDepth {
383    /// Returns the logical [`CPtrWithDepth`] entailed by `self`.
384    fn cptr_with_depth(self) -> CPtrWithDepth;
385}
386
387impl HasCPtrWithDepth for CPtr {
388    fn cptr_with_depth(self) -> CPtrWithDepth {
389        self.into()
390    }
391}
392
393impl<T: CapType, C> HasCPtrWithDepth for Cap<T, C> {
394    fn cptr_with_depth(self) -> CPtrWithDepth {
395        self.cptr().into()
396    }
397}
398
399impl HasCPtrWithDepth for CPtrWithDepth {
400    fn cptr_with_depth(self) -> CPtrWithDepth {
401        self
402    }
403}
404
405impl<C> CNode<C> {
406    /// Returns the [`AbsoluteCPtr`] for `path` in the context of `self`.
407    pub fn absolute_cptr<T: HasCPtrWithDepth>(self, path: T) -> AbsoluteCPtr<C> {
408        AbsoluteCPtr {
409            root: self,
410            path: path.cptr_with_depth(),
411        }
412    }
413
414    /// Returns the [`AbsoluteCPtr`] for
415    /// [`CPtrWithDepth::from_bits_with_depth(bits, depth)`](CPtrWithDepth::from_bits_with_depth)
416    /// in the context of `self`.
417    pub fn absolute_cptr_from_bits_with_depth(
418        self,
419        bits: CPtrBits,
420        depth: usize,
421    ) -> AbsoluteCPtr<C> {
422        self.absolute_cptr(CPtrWithDepth::from_bits_with_depth(bits, depth))
423    }
424
425    /// Returns the [`AbsoluteCPtr`] for `self` in its own context.
426    ///
427    /// Currently implemented as:
428    /// ```rust
429    /// self.absolute_cptr(CPtrWithDepth::empty())
430    /// ```
431    pub fn absolute_cptr_for_self(self) -> AbsoluteCPtr<C> {
432        self.absolute_cptr(CPtrWithDepth::empty())
433    }
434}