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