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