sel4_microkit_base/
channel.rs

1//
2// Copyright 2023, Colias Group, LLC
3//
4// SPDX-License-Identifier: BSD-2-Clause
5//
6
7use core::fmt;
8
9use crate::{
10    symbols::{pd_irqs, pd_notifications, pd_pps},
11    MessageInfo,
12};
13
14const BASE_OUTPUT_NOTIFICATION_SLOT: usize = 10;
15const BASE_ENDPOINT_SLOT: usize = BASE_OUTPUT_NOTIFICATION_SLOT + 64;
16const BASE_IRQ_SLOT: usize = BASE_ENDPOINT_SLOT + 64;
17const BASE_TCB_SLOT: usize = BASE_IRQ_SLOT + 64;
18
19const MAX_CHANNELS: usize = 62;
20
21/// A channel between this protection domain and another, identified by a channel index.
22#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
23pub struct Channel {
24    index: usize,
25}
26
27impl Channel {
28    pub const fn new(index: usize) -> Self {
29        assert!(index < MAX_CHANNELS);
30        Self { index }
31    }
32
33    pub const fn index(&self) -> usize {
34        self.index
35    }
36
37    fn cap<T: ChannelFacet>(&self) -> sel4::Cap<T> {
38        if T::mask() & (1 << self.index) == 0 {
39            panic!("{}: not valid for channel '{}'", T::METHOD_NAME, self.index);
40        }
41        sel4::Cap::from_bits((T::BASE_SLOT + self.index) as sel4::CPtrBits)
42    }
43
44    #[doc(hidden)]
45    pub fn notification(&self) -> sel4::cap::Notification {
46        self.cap::<sel4::cap_type::Notification>()
47    }
48
49    #[doc(hidden)]
50    pub fn irq_handler(&self) -> sel4::cap::IrqHandler {
51        self.cap::<sel4::cap_type::IrqHandler>()
52    }
53
54    #[doc(hidden)]
55    pub fn endpoint(&self) -> sel4::cap::Endpoint {
56        self.cap::<sel4::cap_type::Endpoint>()
57    }
58
59    pub fn notify(&self) {
60        self.notification().signal()
61    }
62
63    pub fn irq_ack(&self) -> Result<(), IrqAckError> {
64        self.irq_handler()
65            .irq_handler_ack()
66            .map_err(IrqAckError::from_inner)
67    }
68
69    pub fn pp_call(&self, msg_info: MessageInfo) -> MessageInfo {
70        MessageInfo::from_inner(self.endpoint().call(msg_info.into_inner()))
71    }
72}
73
74trait ChannelFacet: sel4::CapType {
75    const METHOD_NAME: &str;
76    const BASE_SLOT: usize;
77
78    fn mask() -> usize;
79}
80
81impl ChannelFacet for sel4::cap_type::Notification {
82    const METHOD_NAME: &str = "pp_call";
83    const BASE_SLOT: usize = BASE_OUTPUT_NOTIFICATION_SLOT;
84
85    fn mask() -> usize {
86        pd_notifications()
87    }
88}
89
90impl ChannelFacet for sel4::cap_type::IrqHandler {
91    const METHOD_NAME: &str = "irq_ack";
92    const BASE_SLOT: usize = BASE_IRQ_SLOT;
93
94    fn mask() -> usize {
95        pd_irqs()
96    }
97}
98
99impl ChannelFacet for sel4::cap_type::Endpoint {
100    const METHOD_NAME: &str = "notify";
101    const BASE_SLOT: usize = BASE_ENDPOINT_SLOT;
102
103    fn mask() -> usize {
104        pd_pps()
105    }
106}
107
108/// Error type returned by [`Channel::irq_ack`].
109#[derive(Debug, PartialEq, Eq)]
110pub struct IrqAckError(sel4::Error);
111
112impl IrqAckError {
113    fn from_inner(inner: sel4::Error) -> Self {
114        Self(inner)
115    }
116
117    fn inner(&self) -> &sel4::Error {
118        &self.0
119    }
120}
121
122impl fmt::Display for IrqAckError {
123    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
124        write!(f, "irq ack error: {:?}", self.inner())
125    }
126}
127
128/// A handle to a child protection domain, identified by a child protection domain index.
129#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
130pub struct Child {
131    index: usize,
132}
133
134impl Child {
135    pub const fn new(index: usize) -> Self {
136        Self { index }
137    }
138
139    pub const fn index(&self) -> usize {
140        self.index
141    }
142
143    #[doc(hidden)]
144    pub fn tcb(&self) -> sel4::cap::Tcb {
145        sel4::Cap::from_bits((BASE_TCB_SLOT + self.index) as sel4::CPtrBits)
146    }
147}