Skip to main content

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::{InvocationContext, IpcBuffer, NoExplicitInvocationContext, WORD_SIZE, sys};
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 `seL4_DomainSet`
231        DomainSet
232    }
233
234    declare_cap_type! {
235        /// Corresponds to the null capability.
236        Null
237    }
238
239    declare_cap_type! {
240        /// Any capability.
241        Unspecified
242    }
243
244    declare_cap_type! {
245        /// Any page capability.
246        UnspecifiedPage
247    }
248
249    declare_cap_type! {
250        /// Any intermediate translation table capability.
251        UnspecifiedIntermediateTranslationTable
252    }
253
254    sel4_cfg_if! {
255        if #[sel4_cfg(KERNEL_MCS)] {
256            declare_cap_type! {
257                /// Corresponds to the reply capability type (MCS only).
258                Reply
259            }
260
261            declare_cap_type_for_object_of_variable_size! {
262                /// Corresponds to the scheduling context capability type (MCS only).
263                SchedContext { ObjectType, ObjectBlueprint }
264            }
265
266            declare_cap_type! {
267                /// Corresponds to `seL4_SchedControl`.
268                SchedControl
269            }
270        }
271    }
272}
273
274use cap::*;
275
276pub mod cap {
277    //! Marked aliases of [`Cap`](crate::Cap).
278    //!
279    //! Each type `$t<C = NoExplicitInvocationContext>` in this module is an alias for `Cap<$t, C>`.
280
281    use sel4_config::sel4_cfg_if;
282
283    use crate::declare_cap_alias;
284
285    pub use crate::arch::cap_arch::*;
286
287    declare_cap_alias!(Untyped);
288    declare_cap_alias!(Endpoint);
289    declare_cap_alias!(Notification);
290    declare_cap_alias!(Tcb);
291    declare_cap_alias!(CNode);
292    declare_cap_alias!(IrqControl);
293    declare_cap_alias!(IrqHandler);
294    declare_cap_alias!(DomainSet);
295    declare_cap_alias!(AsidControl);
296    declare_cap_alias!(AsidPool);
297
298    declare_cap_alias!(Null);
299    declare_cap_alias!(Unspecified);
300    declare_cap_alias!(UnspecifiedPage);
301    declare_cap_alias!(UnspecifiedIntermediateTranslationTable);
302
303    declare_cap_alias!(VSpace);
304    declare_cap_alias!(Granule);
305
306    sel4_cfg_if! {
307        if #[sel4_cfg(KERNEL_MCS)] {
308            declare_cap_alias!(Reply);
309            declare_cap_alias!(SchedContext);
310            declare_cap_alias!(SchedControl);
311        }
312    }
313}
314
315impl<T: CapType, C> Cap<T, C> {
316    pub fn upcast(self) -> Unspecified<C> {
317        self.cast()
318    }
319}
320
321impl<C> Unspecified<C> {
322    pub fn downcast<T: CapType>(self) -> Cap<T, C> {
323        self.cast()
324    }
325}
326
327/// A [`CPtrWithDepth`] to be resolved in the context of a particular [`CNode`].
328///
329/// [`AbsoluteCPtr`] addresses capability slots in a more general way than [`Cap`]. It allows one to
330/// address any capability slot that is directly addressable from any CNode that is directly
331/// addressible in the current thread's CSpace. Furthermore, it allows one to address capability
332/// slots that contain CNodes by limiting the lookup depth to prevent the kernel's lookup procedure
333/// from descending into the CNode contained in that slot.
334///
335/// `seL4_CNode_*` capability invocations are methods of [`AbsoluteCPtr`] rather than [`Cap`].
336///
337/// In addition to [`AbsoluteCPtr::new`], the following methods can be used to construct an
338/// [`AbsoluteCPtr`]:
339/// - [`CNode::absolute_cptr`]
340/// - [`CNode::absolute_cptr_from_bits_with_depth`]
341/// - [`CNode::absolute_cptr_for_self`]
342#[derive(Copy, Clone, Debug, Eq, PartialEq)]
343pub struct AbsoluteCPtr<C = NoExplicitInvocationContext> {
344    root: CNode<C>,
345    path: CPtrWithDepth,
346}
347
348impl<C> AbsoluteCPtr<C> {
349    pub const fn new(root: CNode<C>, path: CPtrWithDepth) -> Self {
350        Self { root, path }
351    }
352
353    pub const fn root(&self) -> &CNode<C> {
354        &self.root
355    }
356
357    pub fn into_root(self) -> CNode<C> {
358        self.root
359    }
360
361    pub const fn path(&self) -> &CPtrWithDepth {
362        &self.path
363    }
364
365    pub fn with<C1>(self, context: C1) -> AbsoluteCPtr<C1> {
366        AbsoluteCPtr {
367            root: self.root.with(context),
368            path: self.path,
369        }
370    }
371
372    pub fn without_context(self) -> AbsoluteCPtr {
373        self.with(NoExplicitInvocationContext::new())
374    }
375}
376
377impl<C: InvocationContext> AbsoluteCPtr<C> {
378    pub(crate) fn invoke<R>(self, f: impl FnOnce(CPtr, CPtrWithDepth, &mut IpcBuffer) -> R) -> R {
379        let path = *self.path();
380        self.into_root()
381            .invoke(|cptr, ipc_buffer| f(cptr, path, ipc_buffer))
382    }
383}
384
385/// Trait for types whose members which logically contain a [`CPtrWithDepth`].
386///
387/// [`CPtr`] and [`Cap`] each logically contain a [`CPtrWithDepth`] with a depth of [`WORD_SIZE`].
388pub trait HasCPtrWithDepth {
389    /// Returns the logical [`CPtrWithDepth`] entailed by `self`.
390    fn cptr_with_depth(self) -> CPtrWithDepth;
391}
392
393impl HasCPtrWithDepth for CPtr {
394    fn cptr_with_depth(self) -> CPtrWithDepth {
395        self.into()
396    }
397}
398
399impl<T: CapType, C> HasCPtrWithDepth for Cap<T, C> {
400    fn cptr_with_depth(self) -> CPtrWithDepth {
401        self.cptr().into()
402    }
403}
404
405impl HasCPtrWithDepth for CPtrWithDepth {
406    fn cptr_with_depth(self) -> CPtrWithDepth {
407        self
408    }
409}
410
411impl<C> CNode<C> {
412    /// Returns the [`AbsoluteCPtr`] for `path` in the context of `self`.
413    pub fn absolute_cptr<T: HasCPtrWithDepth>(self, path: T) -> AbsoluteCPtr<C> {
414        AbsoluteCPtr {
415            root: self,
416            path: path.cptr_with_depth(),
417        }
418    }
419
420    /// Returns the [`AbsoluteCPtr`] for
421    /// [`CPtrWithDepth::from_bits_with_depth(bits, depth)`](CPtrWithDepth::from_bits_with_depth)
422    /// in the context of `self`.
423    pub fn absolute_cptr_from_bits_with_depth(
424        self,
425        bits: CPtrBits,
426        depth: usize,
427    ) -> AbsoluteCPtr<C> {
428        self.absolute_cptr(CPtrWithDepth::from_bits_with_depth(bits, depth))
429    }
430
431    /// Returns the [`AbsoluteCPtr`] for `self` in its own context.
432    ///
433    /// Currently implemented as:
434    /// ```rust
435    /// self.absolute_cptr(CPtrWithDepth::empty())
436    /// ```
437    pub fn absolute_cptr_for_self(self) -> AbsoluteCPtr<C> {
438        self.absolute_cptr(CPtrWithDepth::empty())
439    }
440}