From ea9a50cea25644f58f60f465a7c0c965b65abd28 Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Mon, 24 Jun 2024 06:13:05 +0000 Subject: [PATCH] crates/sel4-microkit: Add support for PD hierarchy Signed-off-by: Nick Spinale --- crates/sel4-microkit/base/src/channel.rs | 18 ++++++++++++ crates/sel4-microkit/base/src/lib.rs | 2 +- crates/sel4-microkit/base/src/message.rs | 9 ++++++ crates/sel4-microkit/base/src/symbols.rs | 2 +- crates/sel4-microkit/src/handler.rs | 21 ++++++++++---- crates/sel4-microkit/src/ipc.rs | 37 +++++++++++++++++------- 6 files changed, 70 insertions(+), 19 deletions(-) diff --git a/crates/sel4-microkit/base/src/channel.rs b/crates/sel4-microkit/base/src/channel.rs index e44af0e35..654c15c76 100644 --- a/crates/sel4-microkit/base/src/channel.rs +++ b/crates/sel4-microkit/base/src/channel.rs @@ -11,6 +11,7 @@ use crate::MessageInfo; const BASE_OUTPUT_NOTIFICATION_SLOT: usize = 10; const BASE_ENDPOINT_SLOT: usize = BASE_OUTPUT_NOTIFICATION_SLOT + 64; const BASE_IRQ_SLOT: usize = BASE_ENDPOINT_SLOT + 64; +const BASE_TCB_SLOT: usize = BASE_IRQ_SLOT + 64; const MAX_CHANNELS: usize = 63; @@ -79,3 +80,20 @@ impl fmt::Display for IrqAckError { write!(f, "irq ack error: {:?}", self.inner()) } } + +/// A handle to a child protection domain, identified by a child protection domain index. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct ProtectionDomain { + index: usize, +} + +impl ProtectionDomain { + pub const fn new(index: usize) -> Self { + Self { index } + } + + #[doc(hidden)] + pub fn tcb(&self) -> sel4::cap::Tcb { + sel4::Cap::from_bits((BASE_TCB_SLOT + self.index) as sel4::CPtrBits) + } +} diff --git a/crates/sel4-microkit/base/src/lib.rs b/crates/sel4-microkit/base/src/lib.rs index 01a95f995..e45bcbab0 100644 --- a/crates/sel4-microkit/base/src/lib.rs +++ b/crates/sel4-microkit/base/src/lib.rs @@ -11,7 +11,7 @@ mod channel; mod message; mod symbols; -pub use channel::{Channel, IrqAckError}; +pub use channel::{Channel, IrqAckError, ProtectionDomain}; pub use message::{ get_mr, set_mr, with_msg_bytes, with_msg_bytes_mut, with_msg_regs, with_msg_regs_mut, MessageInfo, MessageLabel, MessageRegisterValue, diff --git a/crates/sel4-microkit/base/src/message.rs b/crates/sel4-microkit/base/src/message.rs index ca9ff5a54..182b8f525 100644 --- a/crates/sel4-microkit/base/src/message.rs +++ b/crates/sel4-microkit/base/src/message.rs @@ -18,6 +18,11 @@ impl MessageInfo { Self { inner } } + #[doc(hidden)] + pub fn inner(&self) -> &sel4::MessageInfo { + &self.inner + } + #[doc(hidden)] pub fn into_inner(self) -> sel4::MessageInfo { self.inner @@ -38,6 +43,10 @@ impl MessageInfo { pub fn count(&self) -> usize { self.inner.length() } + + pub fn fault(&self) -> sel4::Fault { + sel4::with_ipc_buffer(|ipc_buffer| sel4::Fault::new(ipc_buffer, self.inner())) + } } impl Default for MessageInfo { diff --git a/crates/sel4-microkit/base/src/symbols.rs b/crates/sel4-microkit/base/src/symbols.rs index 8a5bff70e..d92de2867 100644 --- a/crates/sel4-microkit/base/src/symbols.rs +++ b/crates/sel4-microkit/base/src/symbols.rs @@ -117,7 +117,7 @@ macro_rules! maybe_extern_var { /// Returns whether this projection domain is a passive server. pub fn pd_is_passive() -> bool { - *maybe_extern_var!(passive: bool = false) + *maybe_extern_var!(microkit_passive: bool = false) } /// Returns the name of this projection domain without converting to unicode. diff --git a/crates/sel4-microkit/src/handler.rs b/crates/sel4-microkit/src/handler.rs index 745d2b743..deb2c014f 100644 --- a/crates/sel4-microkit/src/handler.rs +++ b/crates/sel4-microkit/src/handler.rs @@ -6,12 +6,10 @@ use core::fmt; -use sel4_microkit_base::MessageInfo; - use crate::{ defer::{DeferredAction, PreparedDeferredAction}, ipc::{self, Event}, - pd_is_passive, Channel, + pd_is_passive, Channel, MessageInfo, ProtectionDomain, }; pub use core::convert::Infallible; @@ -39,6 +37,14 @@ pub trait Handler { panic!("unexpected protected procedure call from channel {channel:?} with msg_info={msg_info:?}") } + fn fault( + &mut self, + pd: ProtectionDomain, + msg_info: MessageInfo, + ) -> Result { + panic!("unexpected fault from protection domain {pd:?} with msg_info={msg_info:?}") + } + /// An advanced feature for use by protection domains which seek to coalesce syscalls when /// possible. /// @@ -67,14 +73,17 @@ pub trait Handler { }; match event { - Event::Protected(channel, msg_info) => { - reply_tag = Some(self.protected(channel, msg_info)?); - } 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(pd, msg_info) => { + reply_tag = Some(self.fault(pd, msg_info)?); + } }; prepared_deferred_action = self diff --git a/crates/sel4-microkit/src/ipc.rs b/crates/sel4-microkit/src/ipc.rs index ded2adfaa..1ab2539a7 100644 --- a/crates/sel4-microkit/src/ipc.rs +++ b/crates/sel4-microkit/src/ipc.rs @@ -6,31 +6,46 @@ use sel4_microkit_base::MessageInfo; -use crate::{defer::PreparedDeferredAction, Channel}; +use crate::{defer::PreparedDeferredAction, Channel, ProtectionDomain}; const INPUT_CAP: sel4::cap::Endpoint = sel4::Cap::from_bits(1); const REPLY_CAP: sel4::cap::Reply = sel4::Cap::from_bits(4); const MONITOR_EP_CAP: sel4::cap::Endpoint = sel4::Cap::from_bits(5); -const EVENT_TYPE_MASK: sel4::Word = 1 << (sel4::WORD_SIZE - 1); +const CHANNEL_BADGE_BIT: usize = 63; +const PD_BADGE_BIT: usize = 62; + +fn strip_flag(badge: sel4::Badge, bit: usize) -> Option { + let mask = 1 << bit; + if badge & mask != 0 { + Some(badge & !mask) + } else { + None + } +} #[doc(hidden)] #[derive(Debug, Clone)] pub enum Event { - Protected(Channel, MessageInfo), Notified(NotifiedEvent), + Protected(Channel, MessageInfo), + Fault(ProtectionDomain, MessageInfo), } impl Event { fn new(tag: sel4::MessageInfo, badge: sel4::Badge) -> Self { - match badge & EVENT_TYPE_MASK { - 0 => Self::Notified(NotifiedEvent(badge)), - _ => { - let channel_index = badge & (sel4::Word::try_from(sel4::WORD_SIZE).unwrap() - 1); - let channel = Channel::new(channel_index.try_into().unwrap()); - let tag = MessageInfo::from_inner(tag); - Self::Protected(channel, tag) - } + if let Some(channel_index) = strip_flag(badge, CHANNEL_BADGE_BIT) { + Self::Protected( + Channel::new(channel_index.try_into().unwrap()), + MessageInfo::from_inner(tag), + ) + } else if let Some(pd_index) = strip_flag(badge, PD_BADGE_BIT) { + Self::Fault( + ProtectionDomain::new(pd_index.try_into().unwrap()), + MessageInfo::from_inner(tag), + ) + } else { + Self::Notified(NotifiedEvent(badge)) } }