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