Skip to main content

sel4_microkit_base/
handler.rs

1//
2// Copyright 2023, Colias Group, LLC
3//
4// SPDX-License-Identifier: BSD-2-Clause
5//
6
7use core::fmt;
8
9#[cfg(feature = "alloc")]
10use alloc::boxed::Box;
11
12use crate::{
13    Channel, Child, MessageInfo,
14    defer::{DeferredAction, PreparedDeferredAction},
15    ipc::{self, ChannelSet, Event},
16    pd_is_passive,
17};
18
19pub use core::convert::Infallible;
20
21/// Trait for the application-specific part of a protection domain's main loop.
22pub trait Handler {
23    /// Error type returned by this protection domain's entrypoints.
24    type Error: fmt::Display;
25
26    /// This method has the same meaning and type as its analog in `libmicrokit`.
27    ///
28    /// The default implementation just panics.
29    fn notified(&mut self, channels: ChannelSet) -> Result<(), Self::Error> {
30        panic!(
31            "unexpected notification from channels {}",
32            channels.display()
33        )
34    }
35
36    /// This method has the same meaning and type as its analog in `libmicrokit`.
37    ///
38    /// The default implementation just panics.
39    fn protected(
40        &mut self,
41        channel: Channel,
42        msg_info: MessageInfo,
43    ) -> Result<MessageInfo, Self::Error> {
44        panic!(
45            "unexpected protected procedure call from channel {channel:?} with msg_info={msg_info:?}"
46        )
47    }
48
49    /// This method has the same meaning and type as its analog in `libmicrokit`.
50    ///
51    /// The default implementation just panics.
52    fn fault(
53        &mut self,
54        child: Child,
55        msg_info: MessageInfo,
56    ) -> Result<Option<MessageInfo>, Self::Error> {
57        panic!("unexpected fault from protection domain {child:?} with msg_info={msg_info:?}")
58    }
59
60    /// An advanced feature for use by protection domains which seek to coalesce syscalls when
61    /// possible.
62    ///
63    /// This method is used by the main loop to fuse a queued `seL4_Send` call with the next
64    /// `seL4_Recv` using `seL4_NBSendRecv`. Its default implementation just returns `None`.
65    fn take_deferred_action(&mut self) -> Option<DeferredAction> {
66        None
67    }
68
69    #[doc(hidden)]
70    fn run(&mut self) -> Result<Never, Self::Error> {
71        let mut reply_tag: Option<MessageInfo> = None;
72
73        let mut prepared_deferred_action: Option<PreparedDeferredAction> = if pd_is_passive() {
74            Some(ipc::forfeit_sc())
75        } else {
76            None
77        };
78
79        loop {
80            let event = match (reply_tag.take(), prepared_deferred_action.take()) {
81                (Some(msg_info), None) => ipc::reply_recv(msg_info),
82                (None, Some(action)) => ipc::nb_send_recv(action),
83                (None, None) => ipc::recv(),
84                _ => panic!("handler yielded deferred action after call to 'protected()'"),
85            };
86
87            match event {
88                Event::Notified(channels) => {
89                    self.notified(channels)?;
90                }
91                Event::Protected(channel, msg_info) => {
92                    reply_tag = Some(self.protected(channel, msg_info)?);
93                }
94                Event::Fault(child, msg_info) => {
95                    reply_tag = self.fault(child, msg_info)?;
96                }
97            };
98
99            prepared_deferred_action = self
100                .take_deferred_action()
101                .as_ref()
102                .map(DeferredAction::prepare);
103        }
104    }
105}
106
107#[doc(hidden)]
108pub enum Never {}
109
110impl Handler for Never {
111    type Error = Infallible;
112}
113
114/// A [`Handler`] implementation which does not override any of the default method implementations.
115pub struct NullHandler(());
116
117impl NullHandler {
118    #[allow(clippy::new_without_default)]
119    pub fn new() -> Self {
120        Self(())
121    }
122}
123
124impl Handler for NullHandler {
125    type Error = Infallible;
126}
127
128#[cfg(feature = "alloc")]
129impl<T: Handler + ?Sized> Handler for Box<T> {
130    type Error = T::Error;
131
132    fn notified(&mut self, channels: ChannelSet) -> Result<(), Self::Error> {
133        (**self).notified(channels)
134    }
135
136    fn protected(
137        &mut self,
138        channel: Channel,
139        msg_info: MessageInfo,
140    ) -> Result<MessageInfo, Self::Error> {
141        (**self).protected(channel, msg_info)
142    }
143
144    fn fault(
145        &mut self,
146        child: Child,
147        msg_info: MessageInfo,
148    ) -> Result<Option<MessageInfo>, Self::Error> {
149        (**self).fault(child, msg_info)
150    }
151
152    fn take_deferred_action(&mut self) -> Option<DeferredAction> {
153        (**self).take_deferred_action()
154    }
155
156    #[doc(hidden)]
157    fn run(&mut self) -> Result<Never, Self::Error> {
158        (**self).run()
159    }
160}