1//
2// Copyright 2023, Colias Group, LLC
3//
4// SPDX-License-Identifier: BSD-2-Clause
5//
67use core::fmt;
89use crate::{
10 defer::{DeferredAction, PreparedDeferredAction},
11 ipc::{self, Event},
12 pd_is_passive, Channel, Child, MessageInfo,
13};
1415pub use core::convert::Infallible;
1617/// 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.
20type Error: fmt::Display;
2122/// This method has the same meaning and type as its analog in `libmicrokit`.
23 ///
24 /// The default implementation just panics.
25fn notified(&mut self, channel: Channel) -> Result<(), Self::Error> {
26panic!("unexpected notification from channel {channel:?}")
27 }
2829/// This method has the same meaning and type as its analog in `libmicrokit`.
30 ///
31 /// The default implementation just panics.
32fn protected(
33&mut self,
34 channel: Channel,
35 msg_info: MessageInfo,
36 ) -> Result<MessageInfo, Self::Error> {
37panic!("unexpected protected procedure call from channel {channel:?} with msg_info={msg_info:?}")
38 }
3940/// This method has the same meaning and type as its analog in `libmicrokit`.
41 ///
42 /// The default implementation just panics.
43fn fault(
44&mut self,
45 child: Child,
46 msg_info: MessageInfo,
47 ) -> Result<Option<MessageInfo>, Self::Error> {
48panic!("unexpected fault from protection domain {child:?} with msg_info={msg_info:?}")
49 }
5051/// 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`.
56fn take_deferred_action(&mut self) -> Option<DeferredAction> {
57None
58}
5960#[doc(hidden)]
61fn run(&mut self) -> Result<Never, Self::Error> {
62let mut reply_tag: Option<MessageInfo> = None;
6364let mut prepared_deferred_action: Option<PreparedDeferredAction> = if pd_is_passive() {
65Some(ipc::forfeit_sc())
66 } else {
67None
68};
6970loop {
71let 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 };
7778match event {
79 Event::Notified(notified_event) => {
80for channel in notified_event.iter() {
81self.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 };
9192 prepared_deferred_action = self
93.take_deferred_action()
94 .as_ref()
95 .map(DeferredAction::prepare);
96 }
97 }
98}
99100#[doc(hidden)]
101pub enum Never {}
102103impl Handler for Never {
104type Error = Infallible;
105}
106107/// A [`Handler`] implementation which does not override any of the default method implementations.
108pub struct NullHandler(());
109110impl NullHandler {
111#[allow(clippy::new_without_default)]
112pub fn new() -> Self {
113Self(())
114 }
115}
116117impl Handler for NullHandler {
118type Error = Infallible;
119}