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
9use crate::{
10    defer::{DeferredAction, PreparedDeferredAction},
11    ipc::{self, Event},
12    pd_is_passive, Channel, Child, MessageInfo,
13};
14
15pub use core::convert::Infallible;
16
17/// Trait for the application-specific part of a protection domain's main loop.
18pub trait Handler {
19    /// Error type returned by this protection domain's entrypoints.
20    type Error: fmt::Display;
21
22    /// This method has the same meaning and type as its analog in `libmicrokit`.
23    ///
24    /// The default implementation just panics.
25    fn notified(&mut self, channel: Channel) -> Result<(), Self::Error> {
26        panic!("unexpected notification from channel {channel:?}")
27    }
28
29    /// This method has the same meaning and type as its analog in `libmicrokit`.
30    ///
31    /// The default implementation just panics.
32    fn protected(
33        &mut self,
34        channel: Channel,
35        msg_info: MessageInfo,
36    ) -> Result<MessageInfo, Self::Error> {
37        panic!("unexpected protected procedure call from channel {channel:?} with msg_info={msg_info:?}")
38    }
39
40    /// This method has the same meaning and type as its analog in `libmicrokit`.
41    ///
42    /// The default implementation just panics.
43    fn fault(
44        &mut self,
45        child: Child,
46        msg_info: MessageInfo,
47    ) -> Result<Option<MessageInfo>, Self::Error> {
48        panic!("unexpected fault from protection domain {child:?} with msg_info={msg_info:?}")
49    }
50
51    /// An advanced feature for use by protection domains which seek to coalesce syscalls when
52    /// possible.
53    ///
54    /// This method is used by the main loop to fuse a queued `seL4_Send` call with the next
55    /// `seL4_Recv` using `seL4_NBSendRecv`. Its default implementation just returns `None`.
56    fn take_deferred_action(&mut self) -> Option<DeferredAction> {
57        None
58    }
59
60    #[doc(hidden)]
61    fn run(&mut self) -> Result<Never, Self::Error> {
62        let mut reply_tag: Option<MessageInfo> = None;
63
64        let mut prepared_deferred_action: Option<PreparedDeferredAction> = if pd_is_passive() {
65            Some(ipc::forfeit_sc())
66        } else {
67            None
68        };
69
70        loop {
71            let event = match (reply_tag.take(), prepared_deferred_action.take()) {
72                (Some(msg_info), None) => ipc::reply_recv(msg_info),
73                (None, Some(action)) => ipc::nb_send_recv(action),
74                (None, None) => ipc::recv(),
75                _ => panic!("handler yielded deferred action after call to 'protected()'"),
76            };
77
78            match event {
79                Event::Notified(notified_event) => {
80                    for channel in notified_event.iter() {
81                        self.notified(channel)?;
82                    }
83                }
84                Event::Protected(channel, msg_info) => {
85                    reply_tag = Some(self.protected(channel, msg_info)?);
86                }
87                Event::Fault(child, msg_info) => {
88                    reply_tag = self.fault(child, msg_info)?;
89                }
90            };
91
92            prepared_deferred_action = self
93                .take_deferred_action()
94                .as_ref()
95                .map(DeferredAction::prepare);
96        }
97    }
98}
99
100#[doc(hidden)]
101pub enum Never {}
102
103impl Handler for Never {
104    type Error = Infallible;
105}
106
107/// A [`Handler`] implementation which does not override any of the default method implementations.
108pub struct NullHandler(());
109
110impl NullHandler {
111    #[allow(clippy::new_without_default)]
112    pub fn new() -> Self {
113        Self(())
114    }
115}
116
117impl Handler for NullHandler {
118    type Error = Infallible;
119}