Skip to main content

sel4/
syscalls.rs

1//
2// Copyright 2023, Colias Group, LLC
3//
4// SPDX-License-Identifier: MIT
5//
6
7use core::array;
8
9use sel4_config::{sel4_cfg, sel4_cfg_if};
10
11use crate::{
12    Cap, CapType, ConveysReplyAuthority, InvocationContext, MessageInfo,
13    NUM_FAST_MESSAGE_REGISTERS, Word, cap, const_helpers::u32_into_usize, sys,
14};
15
16#[sel4_cfg(not(KERNEL_MCS))]
17use crate::IpcBuffer;
18
19/// Number of message registers in the IPC buffer.
20pub const NUM_MESSAGE_REGISTERS: usize = u32_into_usize(sys::seL4_MsgLimits::seL4_MsgMaxLength);
21
22/// A capability badge.
23pub type Badge = Word;
24
25sel4_cfg_if! {
26    if #[sel4_cfg(KERNEL_MCS)] {
27        pub type WaitMessageInfo = MessageInfo;
28
29        fn wait_message_info_from_sys(info: sys::WaitMessageInfo) -> WaitMessageInfo {
30            MessageInfo::from_inner(info)
31        }
32    } else {
33        pub type WaitMessageInfo = ();
34
35        fn wait_message_info_from_sys(info: sys::WaitMessageInfo) -> WaitMessageInfo {
36            info
37        }
38    }
39}
40
41impl<T: CapType, C: InvocationContext> Cap<T, C> {
42    /// Corresponds to `seL4_Send`.
43    pub fn send(self, info: MessageInfo) {
44        self.invoke(|cptr, ipc_buffer| {
45            ipc_buffer
46                .inner_mut()
47                .seL4_Send(cptr.bits(), info.into_inner())
48        })
49    }
50
51    /// Corresponds to `seL4_NBSend`.
52    pub fn nb_send(self, info: MessageInfo) {
53        self.invoke(|cptr, ipc_buffer| {
54            ipc_buffer
55                .inner_mut()
56                .seL4_NBSend(cptr.bits(), info.into_inner())
57        })
58    }
59
60    /// Corresponds to `seL4_NBSendRecv`.
61    #[sel4_cfg(KERNEL_MCS)]
62    pub fn nb_send_recv<U: CapType>(
63        self,
64        info: MessageInfo,
65        src: Cap<U>,
66        reply_authority: impl ConveysReplyAuthority,
67    ) -> (MessageInfo, Badge) {
68        let (raw_msg_info, badge) = self.invoke(|cptr, ipc_buffer| {
69            ipc_buffer.inner_mut().seL4_NBSendRecv(
70                cptr.bits(),
71                info.into_inner(),
72                src.bits(),
73                reply_authority
74                    .into_reply_authority()
75                    .into_sys_reply_authority(),
76            )
77        });
78        (MessageInfo::from_inner(raw_msg_info), badge)
79    }
80
81    /// Corresponds to `seL4_Recv`.
82    pub fn recv(self, reply_authority: impl ConveysReplyAuthority) -> (MessageInfo, Badge) {
83        let (raw_msg_info, badge) = self.invoke(|cptr, ipc_buffer| {
84            ipc_buffer.inner_mut().seL4_Recv(
85                cptr.bits(),
86                reply_authority
87                    .into_reply_authority()
88                    .into_sys_reply_authority(),
89            )
90        });
91        (MessageInfo::from_inner(raw_msg_info), badge)
92    }
93
94    /// Corresponds to `seL4_NBRecv`.
95    pub fn nb_recv(self, reply_authority: impl ConveysReplyAuthority) -> (MessageInfo, Badge) {
96        let (raw_msg_info, badge) = self.invoke(|cptr, ipc_buffer| {
97            ipc_buffer.inner_mut().seL4_NBRecv(
98                cptr.bits(),
99                reply_authority
100                    .into_reply_authority()
101                    .into_sys_reply_authority(),
102            )
103        });
104        (MessageInfo::from_inner(raw_msg_info), badge)
105    }
106
107    /// Corresponds to `seL4_Call`.
108    pub fn call(self, info: MessageInfo) -> MessageInfo {
109        MessageInfo::from_inner(self.invoke(|cptr, ipc_buffer| {
110            ipc_buffer
111                .inner_mut()
112                .seL4_Call(cptr.bits(), info.into_inner())
113        }))
114    }
115
116    /// Corresponds to `seL4_ReplyRecv`.
117    pub fn reply_recv(
118        self,
119        info: MessageInfo,
120        reply_authority: impl ConveysReplyAuthority,
121    ) -> (MessageInfo, Badge) {
122        let (raw_msg_info, badge) = self.invoke(|cptr, ipc_buffer| {
123            ipc_buffer.inner_mut().seL4_ReplyRecv(
124                cptr.bits(),
125                info.into_inner(),
126                reply_authority
127                    .into_reply_authority()
128                    .into_sys_reply_authority(),
129            )
130        });
131        (MessageInfo::from_inner(raw_msg_info), badge)
132    }
133
134    pub fn send_with_mrs<M: FastMessages>(self, info: MessageInfo, messages: M) {
135        let [msg0, msg1, msg2, msg3] = messages.prepare_in();
136        self.invoke(|cptr, ipc_buffer| {
137            ipc_buffer.inner_mut().seL4_SendWithMRs(
138                cptr.bits(),
139                info.into_inner(),
140                msg0,
141                msg1,
142                msg2,
143                msg3,
144            )
145        })
146    }
147
148    pub fn recv_with_mrs(self, reply_authority: impl ConveysReplyAuthority) -> RecvWithMRs {
149        let mut msg = [0; NUM_FAST_MESSAGE_REGISTERS];
150        let [mr0, mr1, mr2, mr3] = &mut msg;
151        let (raw_msg_info, badge) = self.invoke(|cptr, ipc_buffer| {
152            ipc_buffer.inner_mut().seL4_RecvWithMRs(
153                cptr.bits(),
154                Some(mr0),
155                Some(mr1),
156                Some(mr2),
157                Some(mr3),
158                reply_authority
159                    .into_reply_authority()
160                    .into_sys_reply_authority(),
161            )
162        });
163        RecvWithMRs {
164            info: MessageInfo::from_inner(raw_msg_info),
165            badge,
166            msg,
167        }
168    }
169
170    pub fn call_with_mrs<M: FastMessages>(self, info: MessageInfo, messages: M) -> CallWithMRs {
171        let mut msg = messages.prepare_in_out();
172        let [mr0, mr1, mr2, mr3] = &mut msg;
173        let raw_msg_info = self.invoke(|cptr, ipc_buffer| {
174            ipc_buffer.inner_mut().seL4_CallWithMRs(
175                cptr.bits(),
176                info.into_inner(),
177                Some(mr0),
178                Some(mr1),
179                Some(mr2),
180                Some(mr3),
181            )
182        });
183        CallWithMRs {
184            info: MessageInfo::from_inner(raw_msg_info),
185            msg,
186        }
187    }
188}
189
190impl<C: InvocationContext> cap::Notification<C> {
191    /// Corresponds to `seL4_Signal`.
192    pub fn signal(self) {
193        self.invoke(|cptr, ipc_buffer| ipc_buffer.inner_mut().seL4_Signal(cptr.bits()))
194    }
195
196    /// Corresponds to `seL4_Wait`.
197    pub fn wait(self) -> (WaitMessageInfo, Badge) {
198        let (info, badge) =
199            self.invoke(|cptr, ipc_buffer| ipc_buffer.inner_mut().seL4_Wait(cptr.bits()));
200        (wait_message_info_from_sys(info), badge)
201    }
202
203    /// Corresponds to `seL4_Poll`.
204    pub fn poll(self) -> (MessageInfo, Badge) {
205        let (info, badge) =
206            self.invoke(|cptr, ipc_buffer| ipc_buffer.inner_mut().seL4_Poll(cptr.bits()));
207        (MessageInfo::from_inner(info), badge)
208    }
209}
210
211/// Corresponds to `seL4_Reply`.
212#[sel4_cfg(not(KERNEL_MCS))]
213pub fn reply(ipc_buffer: &mut IpcBuffer, info: MessageInfo) {
214    ipc_buffer.inner_mut().seL4_Reply(info.into_inner())
215}
216
217/// Corresponds to `seL4_Yield`.
218pub fn r#yield() {
219    sys::seL4_Yield()
220}
221
222/// Corresponds to `seL4_SetTLSBase`.
223#[sel4_cfg(SET_TLS_BASE_SELF)]
224pub fn set_tls_base(addr: usize) {
225    sys::seL4_SetTLSBase(addr.try_into().unwrap())
226}
227
228//
229
230const UNUSED_FOR_IN: Word = 0;
231
232/// The result of [`cap::Endpoint::recv_with_mrs`].
233pub struct RecvWithMRs {
234    pub info: MessageInfo,
235    pub badge: Badge,
236    pub msg: [Word; NUM_FAST_MESSAGE_REGISTERS],
237}
238
239/// The result of [`cap::Endpoint::call_with_mrs`].
240pub struct CallWithMRs {
241    pub info: MessageInfo,
242    pub msg: [Word; NUM_FAST_MESSAGE_REGISTERS],
243}
244
245type ConcreteFastMessagesForIn = [Option<Word>; NUM_FAST_MESSAGE_REGISTERS];
246
247type ConcreteFastMessagesForInOut = [Word; NUM_FAST_MESSAGE_REGISTERS];
248
249/// Trait for types which can hold the contents of a set of inline message registers.
250pub trait FastMessages: fast_messages_sealing::FastMessagesSealed {
251    fn prepare_in(self) -> ConcreteFastMessagesForIn;
252
253    fn prepare_in_out(self) -> ConcreteFastMessagesForInOut;
254}
255
256impl<const N: usize> FastMessages for [Word; N]
257where
258    [Word; N]: fast_messages_sealing::FastMessagesSealed,
259{
260    fn prepare_in(self) -> ConcreteFastMessagesForIn {
261        array::from_fn(|i| if i < self.len() { Some(self[i]) } else { None })
262    }
263
264    fn prepare_in_out(self) -> ConcreteFastMessagesForInOut {
265        array::from_fn(|i| {
266            if i < self.len() {
267                self[i]
268            } else {
269                UNUSED_FOR_IN
270            }
271        })
272    }
273}
274
275impl FastMessages for &[Word] {
276    fn prepare_in(self) -> ConcreteFastMessagesForIn {
277        assert!(self.len() <= NUM_FAST_MESSAGE_REGISTERS);
278        array::from_fn(|i| if i < self.len() { Some(self[i]) } else { None })
279    }
280
281    fn prepare_in_out(self) -> ConcreteFastMessagesForInOut {
282        assert!(self.len() <= NUM_FAST_MESSAGE_REGISTERS);
283        array::from_fn(|i| {
284            if i < self.len() {
285                self[i]
286            } else {
287                UNUSED_FOR_IN
288            }
289        })
290    }
291}
292
293mod fast_messages_sealing {
294    use super::Word;
295
296    pub trait FastMessagesSealed {}
297
298    impl FastMessagesSealed for [Word; 0] {}
299    impl FastMessagesSealed for [Word; 1] {}
300    impl FastMessagesSealed for [Word; 2] {}
301    impl FastMessagesSealed for [Word; 3] {}
302    impl FastMessagesSealed for [Word; 4] {}
303
304    impl FastMessagesSealed for &[Word] {}
305}
306
307#[allow(clippy::assertions_on_constants)]
308const _: () = assert!(NUM_FAST_MESSAGE_REGISTERS == 4);