diff --git a/Cargo.lock b/Cargo.lock index 4bacc2d68..c226554d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2326,9 +2326,8 @@ dependencies = [ "cfg-if", "sel4", "sel4-dlmalloc", - "sel4-externally-shared", "sel4-immediate-sync-once-cell", - "sel4-immutable-cell", + "sel4-microkit-base", "sel4-microkit-macros", "sel4-panicking", "sel4-panicking-env", @@ -2336,6 +2335,14 @@ dependencies = [ "sel4-sync", ] +[[package]] +name = "sel4-microkit-base" +version = "0.1.0" +dependencies = [ + "sel4", + "sel4-immutable-cell", +] + [[package]] name = "sel4-microkit-macros" version = "0.1.0" @@ -2349,7 +2356,7 @@ dependencies = [ name = "sel4-microkit-message" version = "0.1.0" dependencies = [ - "sel4-microkit", + "sel4-microkit-base", "sel4-microkit-message-types", "serde", ] diff --git a/Cargo.toml b/Cargo.toml index 0deab4829..66d0864e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -104,6 +104,7 @@ members = [ "crates/sel4-kernel-loader/payload-types", "crates/sel4-logging", "crates/sel4-microkit", + "crates/sel4-microkit/base", "crates/sel4-microkit/macros", "crates/sel4-microkit/message", "crates/sel4-microkit/message/types", diff --git a/crates/private/tests/microkit/passive-server-with-deferred-action/pds/server/src/bin/server.rs b/crates/private/tests/microkit/passive-server-with-deferred-action/pds/server/src/bin/server.rs index d604764ec..198158e7c 100644 --- a/crates/private/tests/microkit/passive-server-with-deferred-action/pds/server/src/bin/server.rs +++ b/crates/private/tests/microkit/passive-server-with-deferred-action/pds/server/src/bin/server.rs @@ -28,7 +28,7 @@ impl Handler for HandlerImpl { type Error = Infallible; fn notified(&mut self, _channel: Channel) -> Result<(), Self::Error> { - self.deferred_action.defer(CLIENT.defer_notify()).unwrap(); + self.deferred_action.defer_notify(CLIENT).unwrap(); Ok(()) } diff --git a/crates/sel4-microkit/Cargo.nix b/crates/sel4-microkit/Cargo.nix index 85134bf4c..05e6db5fd 100644 --- a/crates/sel4-microkit/Cargo.nix +++ b/crates/sel4-microkit/Cargo.nix @@ -11,14 +11,13 @@ mk { dependencies = { inherit (versions) cfg-if; inherit (localCrates) - sel4-panicking - sel4-panicking-env sel4-immediate-sync-once-cell - sel4-immutable-cell + sel4-panicking-env + sel4-panicking sel4-dlmalloc sel4-sync + sel4-microkit-base sel4-microkit-macros - sel4-externally-shared ; sel4-runtime-common = localCrates.sel4-runtime-common // { features = [ "tls" "unwinding" "start" ]; }; sel4 = localCrates.sel4 // { features = [ "single-threaded" ]; }; diff --git a/crates/sel4-microkit/Cargo.toml b/crates/sel4-microkit/Cargo.toml index 8d71b92b5..8b5906154 100644 --- a/crates/sel4-microkit/Cargo.toml +++ b/crates/sel4-microkit/Cargo.toml @@ -26,9 +26,8 @@ unwinding = ["sel4-panicking/unwinding"] cfg-if = "1.0.0" sel4 = { path = "../sel4", features = ["single-threaded"] } sel4-dlmalloc = { path = "../sel4-dlmalloc" } -sel4-externally-shared = { path = "../sel4-externally-shared" } sel4-immediate-sync-once-cell = { path = "../sel4-immediate-sync-once-cell" } -sel4-immutable-cell = { path = "../sel4-immutable-cell" } +sel4-microkit-base = { path = "base" } sel4-microkit-macros = { path = "macros" } sel4-panicking = { path = "../sel4-panicking" } sel4-panicking-env = { path = "../sel4-panicking/env" } diff --git a/crates/sel4-microkit/base/Cargo.nix b/crates/sel4-microkit/base/Cargo.nix new file mode 100644 index 000000000..202a81dc7 --- /dev/null +++ b/crates/sel4-microkit/base/Cargo.nix @@ -0,0 +1,20 @@ +# +# Copyright 2023, Colias Group, LLC +# +# SPDX-License-Identifier: BSD-2-Clause +# + +{ mk, localCrates }: + +mk { + package.name = "sel4-microkit-base"; + dependencies = { + inherit (localCrates) + sel4-immutable-cell + sel4 + ; + }; + features = { + extern-symbols = []; + }; +} diff --git a/crates/sel4-microkit/base/Cargo.toml b/crates/sel4-microkit/base/Cargo.toml new file mode 100644 index 000000000..c54297afd --- /dev/null +++ b/crates/sel4-microkit/base/Cargo.toml @@ -0,0 +1,24 @@ +# +# Copyright 2023, Colias Group, LLC +# +# SPDX-License-Identifier: BSD-2-Clause +# +# +# This file is generated from './Cargo.nix'. You can edit this file directly +# if you are not using this project's Cargo manifest management tools. +# See 'hacking/cargo-manifest-management/README.md' for more information. +# + +[package] +name = "sel4-microkit-base" +version = "0.1.0" +authors = ["Nick Spinale "] +edition = "2021" +license = "BSD-2-Clause" + +[features] +extern-symbols = [] + +[dependencies] +sel4 = { path = "../../sel4" } +sel4-immutable-cell = { path = "../../sel4-immutable-cell" } diff --git a/crates/sel4-microkit/base/src/channel.rs b/crates/sel4-microkit/base/src/channel.rs new file mode 100644 index 000000000..50924d7e6 --- /dev/null +++ b/crates/sel4-microkit/base/src/channel.rs @@ -0,0 +1,81 @@ +// +// Copyright 2023, Colias Group, LLC +// +// SPDX-License-Identifier: BSD-2-Clause +// + +use core::fmt; + +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 MAX_CHANNELS: usize = 63; + +/// A channel between this protection domain and another, identified by a channel index. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct Channel { + index: usize, +} + +impl Channel { + pub const fn new(index: usize) -> Self { + assert!(index < MAX_CHANNELS); + Self { index } + } + + fn cap(&self, base_slot: usize) -> sel4::Cap { + sel4::Cap::from_bits((base_slot + self.index) as sel4::CPtrBits) + } + + #[doc(hidden)] + pub fn notification(&self) -> sel4::Notification { + self.cap::(BASE_OUTPUT_NOTIFICATION_SLOT) + } + + #[doc(hidden)] + pub fn irq_handler(&self) -> sel4::IrqHandler { + self.cap::(BASE_IRQ_SLOT) + } + + #[doc(hidden)] + pub fn endpoint(&self) -> sel4::Endpoint { + self.cap::(BASE_ENDPOINT_SLOT) + } + + pub fn notify(&self) { + self.notification().signal() + } + + pub fn irq_ack(&self) -> Result<(), IrqAckError> { + self.irq_handler() + .irq_handler_ack() + .map_err(IrqAckError::from_inner) + } + + pub fn pp_call(&self, msg_info: MessageInfo) -> MessageInfo { + MessageInfo::from_inner(self.endpoint().call(msg_info.into_inner())) + } +} + +/// Error type returned by [`Channel::irq_ack`]. +#[derive(Debug, PartialEq, Eq)] +pub struct IrqAckError(sel4::Error); + +impl IrqAckError { + fn from_inner(inner: sel4::Error) -> Self { + Self(inner) + } + + fn inner(&self) -> &sel4::Error { + &self.0 + } +} + +impl fmt::Display for IrqAckError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "irq ack error: {:?}", self.inner()) + } +} diff --git a/crates/sel4-microkit/base/src/lib.rs b/crates/sel4-microkit/base/src/lib.rs new file mode 100644 index 000000000..01a95f995 --- /dev/null +++ b/crates/sel4-microkit/base/src/lib.rs @@ -0,0 +1,25 @@ +// +// Copyright 2024, Colias Group, LLC +// +// SPDX-License-Identifier: BSD-2-Clause +// + +#![no_std] +#![feature(used_with_arg)] + +mod channel; +mod message; +mod symbols; + +pub use channel::{Channel, IrqAckError}; +pub use message::{ + get_mr, set_mr, with_msg_bytes, with_msg_bytes_mut, with_msg_regs, with_msg_regs_mut, + MessageInfo, MessageLabel, MessageRegisterValue, +}; +pub use symbols::{ipc_buffer_ptr, pd_is_passive, pd_name}; + +// For macros +#[doc(hidden)] +pub mod _private { + pub use sel4_immutable_cell::ImmutableCell; +} diff --git a/crates/sel4-microkit/src/message.rs b/crates/sel4-microkit/base/src/message.rs similarity index 85% rename from crates/sel4-microkit/src/message.rs rename to crates/sel4-microkit/base/src/message.rs index acbb596f7..ca9ff5a54 100644 --- a/crates/sel4-microkit/src/message.rs +++ b/crates/sel4-microkit/base/src/message.rs @@ -4,8 +4,6 @@ // SPDX-License-Identifier: BSD-2-Clause // -//! Utilities for handling IPC messages for protected procedure calls. - pub type MessageLabel = sel4::Word; pub type MessageRegisterValue = sel4::Word; @@ -15,16 +13,18 @@ pub struct MessageInfo { } impl MessageInfo { - pub(crate) fn from_sel4(inner: sel4::MessageInfo) -> Self { + #[doc(hidden)] + pub fn from_inner(inner: sel4::MessageInfo) -> Self { Self { inner } } - pub(crate) fn into_sel4(self) -> sel4::MessageInfo { + #[doc(hidden)] + pub fn into_inner(self) -> sel4::MessageInfo { self.inner } pub fn new(label: MessageLabel, count: usize) -> Self { - Self::from_sel4(sel4::MessageInfo::new(label, 0, 0, count)) + Self::from_inner(sel4::MessageInfo::new(label, 0, 0, count)) } pub fn label(&self) -> MessageLabel { diff --git a/crates/sel4-microkit/base/src/symbols.rs b/crates/sel4-microkit/base/src/symbols.rs new file mode 100644 index 000000000..646b737df --- /dev/null +++ b/crates/sel4-microkit/base/src/symbols.rs @@ -0,0 +1,143 @@ +// +// Copyright 2023, Colias Group, LLC +// +// SPDX-License-Identifier: BSD-2-Clause +// + +use core::ptr; +use core::str::{self, Utf8Error}; + +#[macro_export] +macro_rules! var { + ($(#[$attrs:meta])* $symbol:ident: $ty:ty = $default:expr) => {{ + use $crate::_private::ImmutableCell; + + $(#[$attrs])* + #[no_mangle] + #[link_section = ".data"] + static $symbol: ImmutableCell<$ty> = ImmutableCell::new($default); + + $symbol.get() + }} +} + +/// Declares a symbol via which the `microkit` tool can inject a memory region's address, and +/// returns the memory region's address at runtime. +/// +/// For more detail, see its definition. +/// +/// The patching mechanism used by the `microkit` tool requires that the symbol be allocated space +/// in the protection domain's ELF file, so we delare the symbol as part of the `.data` section. +/// +/// # Examples +/// +/// ```rust +/// let region_1 = unsafe { +/// ExternallySharedRef::<'static, Foo>::new( +/// memory_region_symbol!(region_1_addr: *mut Foo), +/// ) +/// }; +/// +/// let region_2 = unsafe { +/// ExternallySharedRef::<'static, [u8]>::new_read_only( +/// memory_region_symbol!(region_2_addr: *mut [u8], n = REGION_2_SIZE), +/// ) +/// }; +/// ``` +/// +/// # Note +/// +/// The `microkit` tool requires memory region address symbols to be present in protection domain +/// binaries. To prevent Rust from optimizing them out in cases where it is not used, add the +/// unstable `#[used(linker)]` attribute. For example: +/// +/// ```rust +/// #![feature(used_with_arg)] +/// +/// // might be optimized away if not used +/// memory_region_symbol!(region_addr: *mut Foo) +/// +/// // won't be optimized away +/// memory_region_symbol! { +/// #[used(linker)] +/// region_addr: *mut Foo +/// } +/// ``` +#[macro_export] +macro_rules! memory_region_symbol { + ($(#[$attrs:meta])* $symbol:ident: *mut [$ty:ty], n = $n:expr, bytes = $bytes:expr $(,)?) => { + core::ptr::NonNull::slice_from_raw_parts( + $crate::memory_region_symbol!( + $(#[$attrs])* $symbol: *mut [$ty; $n], bytes = $bytes + ).cast::<$ty>(), + $n, + ) + }; + ($(#[$attrs:meta])* $symbol:ident: *mut [$ty:ty], n = $n:expr $(,)?) => { + core::ptr::NonNull::slice_from_raw_parts( + $crate::memory_region_symbol!( + $(#[$attrs])* $symbol: *mut [$ty; $n] + ).cast::<$ty>(), + $n, + ) + }; + ($(#[$attrs:meta])* $symbol:ident: *mut $ty:ty, bytes = $bytes:expr $(,)?) => {{ + const _: () = assert!($bytes == core::mem::size_of::<$ty>()); + $crate::memory_region_symbol!($(#[$attrs])* $symbol: *mut $ty) + }}; + ($(#[$attrs:meta])* $symbol:ident: *mut $ty:ty $(,)?) => { + core::ptr::NonNull::new( + *$crate::var!($(#[$attrs])* $symbol: usize = 0) as *mut $ty + ).unwrap_or_else(|| { + panic!("{} is null", stringify!($symbol)) + }) + }; +} + +#[cfg(not(feature = "extern-symbols"))] +macro_rules! maybe_extern_var { + ($symbol:ident: $ty:ty = $default:expr) => { + var! { + #[used(linker)] + $symbol: $ty = $default + } + }; +} + +#[cfg(feature = "extern-symbols")] +macro_rules! maybe_extern_var { + ($symbol:ident: $ty:ty = $default:expr) => {{ + extern "C" { + static $symbol: $ty; + } + + unsafe { &$symbol } + }}; +} + +/// Returns whether this projection domain is a passive server. +pub fn pd_is_passive() -> bool { + *maybe_extern_var!(passive: bool = false) +} + +/// Returns the name of this projection domain without converting to unicode. +pub fn pd_name_bytes() -> &'static [u8] { + let all_bytes = maybe_extern_var!(microkit_name: [u8; 16] = [0; 16]); + match core::ffi::CStr::from_bytes_until_nul(all_bytes) { + Ok(cstr) => cstr.to_bytes(), + Err(_) => all_bytes, + } +} + +/// Returns the name of this projection domain. +pub fn pd_name() -> Result<&'static str, Utf8Error> { + str::from_utf8(pd_name_bytes()) +} + +pub fn ipc_buffer_ptr() -> *mut sel4::IpcBuffer { + extern "C" { + static mut __sel4_ipc_buffer_obj: sel4::IpcBuffer; + } + + unsafe { ptr::addr_of_mut!(__sel4_ipc_buffer_obj) } +} diff --git a/crates/sel4-microkit/message/Cargo.nix b/crates/sel4-microkit/message/Cargo.nix index a4475c12e..20063bfd6 100644 --- a/crates/sel4-microkit/message/Cargo.nix +++ b/crates/sel4-microkit/message/Cargo.nix @@ -13,7 +13,7 @@ mk { optional = true; }; inherit (localCrates) - sel4-microkit + sel4-microkit-base sel4-microkit-message-types ; }; diff --git a/crates/sel4-microkit/message/Cargo.toml b/crates/sel4-microkit/message/Cargo.toml index a94acbeed..59cffff9a 100644 --- a/crates/sel4-microkit/message/Cargo.toml +++ b/crates/sel4-microkit/message/Cargo.toml @@ -21,6 +21,6 @@ default = ["postcard"] postcard = ["dep:serde", "sel4-microkit-message-types/postcard"] [dependencies] -sel4-microkit = { path = ".." } +sel4-microkit-base = { path = "../base" } sel4-microkit-message-types = { path = "types" } serde = { version = "1.0.147", default-features = false, optional = true } diff --git a/crates/sel4-microkit/message/src/lib.rs b/crates/sel4-microkit/message/src/lib.rs index a6d9a7123..f5f7757cd 100644 --- a/crates/sel4-microkit/message/src/lib.rs +++ b/crates/sel4-microkit/message/src/lib.rs @@ -12,7 +12,7 @@ use core::mem; #[cfg(feature = "postcard")] use serde::{Deserialize, Serialize}; -use sel4_microkit::{with_msg_bytes, with_msg_bytes_mut, MessageInfo, MessageRegisterValue}; +use sel4_microkit_base::{with_msg_bytes, with_msg_bytes_mut, MessageInfo, MessageRegisterValue}; use sel4_microkit_message_types::{ EmptyMessage, MessageLabel, MessageRecv, MessageSend, MessageValueRecv, MessageValueSend, diff --git a/crates/sel4-microkit/src/cspace.rs b/crates/sel4-microkit/src/cspace.rs deleted file mode 100644 index b342e5bc3..000000000 --- a/crates/sel4-microkit/src/cspace.rs +++ /dev/null @@ -1,199 +0,0 @@ -// -// Copyright 2023, Colias Group, LLC -// -// SPDX-License-Identifier: BSD-2-Clause -// - -use core::fmt; - -use crate::message::MessageInfo; - -// For rustdoc. -#[allow(unused_imports)] -use crate::Handler; - -pub(crate) type Slot = usize; - -pub(crate) const INPUT_CAP: sel4::Endpoint = slot_to_cap(1); -pub(crate) const REPLY_CAP: sel4::Reply = slot_to_cap(4); -pub(crate) const MONITOR_EP_CAP: sel4::Endpoint = slot_to_cap(5); - -const BASE_OUTPUT_NOTIFICATION_CAP: Slot = 10; -const BASE_ENDPOINT_CAP: Slot = BASE_OUTPUT_NOTIFICATION_CAP + 64; -const BASE_IRQ_CAP: Slot = BASE_ENDPOINT_CAP + 64; - -const MAX_CHANNELS: Slot = 63; - -const fn slot_to_cap(slot: Slot) -> sel4::Cap { - sel4::Cap::from_bits(slot as sel4::CPtrBits) -} - -/// A channel between this protection domain and another, identified by a channel index. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub struct Channel { - index: usize, -} - -impl Channel { - pub const fn new(index: usize) -> Self { - assert!(index < MAX_CHANNELS); - Self { index } - } - - fn cap(&self, offset: Slot) -> sel4::Cap { - slot_to_cap(offset + self.index) - } - - fn notification(&self) -> sel4::Notification { - self.cap::(BASE_OUTPUT_NOTIFICATION_CAP) - } - - fn irq_handler(&self) -> sel4::IrqHandler { - self.cap::(BASE_IRQ_CAP) - } - - fn endpoint(&self) -> sel4::Endpoint { - self.cap::(BASE_ENDPOINT_CAP) - } - - pub fn notify(&self) { - self.notification().signal() - } - - pub fn irq_ack(&self) -> Result<(), IrqAckError> { - self.irq_handler() - .irq_handler_ack() - .map_err(IrqAckError::from_sel4_error) - } - - pub fn pp_call(&self, msg_info: MessageInfo) -> MessageInfo { - MessageInfo::from_sel4(self.endpoint().call(msg_info.into_sel4())) - } - - /// Prepare a [`DeferredAction`] for syscall coalescing using [`Handler::take_deferred_action`]. - pub fn defer_notify(&self) -> DeferredAction { - DeferredAction::new(*self, DeferredActionInterface::Notify) - } - - /// Prepare a [`DeferredAction`] for syscall coalescing using [`Handler::take_deferred_action`]. - pub fn defer_irq_ack(&self) -> DeferredAction { - DeferredAction::new(*self, DeferredActionInterface::IrqAck) - } -} - -/// An action deferred for syscall coalescing using [`Handler::take_deferred_action`]. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub struct DeferredAction { - channel: Channel, - interface: DeferredActionInterface, -} - -/// A channel interface for which actions can be deferred. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum DeferredActionInterface { - Notify, - IrqAck, -} - -impl DeferredAction { - pub fn new(channel: Channel, interface: DeferredActionInterface) -> Self { - Self { channel, interface } - } - - pub fn channel(&self) -> Channel { - self.channel - } - - pub fn interface(&self) -> DeferredActionInterface { - self.interface - } - - pub fn execute_now(self) -> Result<(), IrqAckError> { - match self.interface() { - DeferredActionInterface::Notify => { - self.channel().notify(); - Ok(()) - } - DeferredActionInterface::IrqAck => self.channel().irq_ack(), - } - } - - pub(crate) fn prepare(&self) -> PreparedDeferredAction { - match self.interface() { - DeferredActionInterface::Notify => PreparedDeferredAction::new( - self.channel().notification().cast(), - sel4::MessageInfoBuilder::default().build(), - ), - DeferredActionInterface::IrqAck => PreparedDeferredAction::new( - self.channel().irq_handler().cast(), - sel4::MessageInfoBuilder::default() - .label(sel4::sys::invocation_label::IRQAckIRQ.into()) - .build(), - ), - } - } -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub(crate) struct PreparedDeferredAction { - cptr: sel4::Unspecified, - msg_info: sel4::MessageInfo, -} - -impl PreparedDeferredAction { - pub(crate) fn new(cptr: sel4::Unspecified, msg_info: sel4::MessageInfo) -> Self { - Self { cptr, msg_info } - } - - pub(crate) fn cptr(&self) -> sel4::Unspecified { - self.cptr - } - - pub(crate) fn msg_info(&self) -> sel4::MessageInfo { - self.msg_info.clone() // TODO - } -} - -// TODO maybe excessive. remove? -pub struct DeferredActionSlot { - inner: Option, -} - -impl DeferredActionSlot { - pub const fn new() -> Self { - Self { inner: None } - } - - pub fn take(&mut self) -> Option { - self.inner.take() - } - - pub fn defer(&mut self, action: DeferredAction) -> Result<(), IrqAckError> { - self.inner - .replace(action) - .map(DeferredAction::execute_now) - .unwrap_or(Ok(())) - } -} - -/// Error type returned by [`Channel::irq_ack`]. -#[derive(Debug, PartialEq, Eq)] -pub struct IrqAckError { - sel4_error: sel4::Error, -} - -impl IrqAckError { - fn from_sel4_error(sel4_error: sel4::Error) -> Self { - Self { sel4_error } - } - - fn as_sel4_error(&self) -> &sel4::Error { - &self.sel4_error - } -} - -impl fmt::Display for IrqAckError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "irq ack error: {:?}", self.as_sel4_error()) - } -} diff --git a/crates/sel4-microkit/src/defer.rs b/crates/sel4-microkit/src/defer.rs new file mode 100644 index 000000000..7b1288217 --- /dev/null +++ b/crates/sel4-microkit/src/defer.rs @@ -0,0 +1,118 @@ +// +// Copyright 2024, Colias Group, LLC +// +// SPDX-License-Identifier: BSD-2-Clause +// + +use crate::{Channel, IrqAckError}; + +/// An action deferred for syscall coalescing using [`Handler::take_deferred_action`]. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct DeferredAction { + channel: Channel, + interface: DeferredActionInterface, +} + +/// A channel interface for which actions can be deferred. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum DeferredActionInterface { + Notify, + IrqAck, +} + +impl DeferredAction { + pub fn new(channel: Channel, interface: DeferredActionInterface) -> Self { + Self { channel, interface } + } + + pub fn new_notify(channel: Channel) -> DeferredAction { + DeferredAction::new(channel, DeferredActionInterface::Notify) + } + + pub fn new_irq_ack(channel: Channel) -> DeferredAction { + DeferredAction::new(channel, DeferredActionInterface::IrqAck) + } + + pub fn channel(&self) -> Channel { + self.channel + } + + pub fn interface(&self) -> DeferredActionInterface { + self.interface + } + + pub fn execute_now(self) -> Result<(), IrqAckError> { + match self.interface() { + DeferredActionInterface::Notify => { + self.channel().notify(); + Ok(()) + } + DeferredActionInterface::IrqAck => self.channel().irq_ack(), + } + } + + pub(crate) fn prepare(&self) -> PreparedDeferredAction { + match self.interface() { + DeferredActionInterface::Notify => PreparedDeferredAction::new( + self.channel().notification().cast(), + sel4::MessageInfoBuilder::default().build(), + ), + DeferredActionInterface::IrqAck => PreparedDeferredAction::new( + self.channel().irq_handler().cast(), + sel4::MessageInfoBuilder::default() + .label(sel4::sys::invocation_label::IRQAckIRQ.into()) + .build(), + ), + } + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub(crate) struct PreparedDeferredAction { + cptr: sel4::Unspecified, + msg_info: sel4::MessageInfo, +} + +impl PreparedDeferredAction { + pub(crate) fn new(cptr: sel4::Unspecified, msg_info: sel4::MessageInfo) -> Self { + Self { cptr, msg_info } + } + + pub(crate) fn cptr(&self) -> sel4::Unspecified { + self.cptr + } + + pub(crate) fn msg_info(&self) -> sel4::MessageInfo { + self.msg_info.clone() // TODO + } +} + +// TODO maybe excessive. remove? +pub struct DeferredActionSlot { + inner: Option, +} + +impl DeferredActionSlot { + pub const fn new() -> Self { + Self { inner: None } + } + + pub fn take(&mut self) -> Option { + self.inner.take() + } + + pub fn defer(&mut self, action: DeferredAction) -> Result<(), IrqAckError> { + self.inner + .replace(action) + .map(DeferredAction::execute_now) + .unwrap_or(Ok(())) + } + + pub fn defer_notify(&mut self, channel: Channel) -> Result<(), IrqAckError> { + self.defer(DeferredAction::new_notify(channel)) + } + + pub fn defer_irq_ack(&mut self, channel: Channel) -> Result<(), IrqAckError> { + self.defer(DeferredAction::new_irq_ack(channel)) + } +} diff --git a/crates/sel4-microkit/src/entry.rs b/crates/sel4-microkit/src/entry.rs index d2578213c..f873463fc 100644 --- a/crates/sel4-microkit/src/entry.rs +++ b/crates/sel4-microkit/src/entry.rs @@ -6,12 +6,14 @@ use core::panic::UnwindSafe; -pub use sel4_panicking::catch_unwind; -pub use sel4_panicking_env::abort; +use sel4_microkit_base::ipc_buffer_ptr; +use sel4_panicking::catch_unwind; +use sel4_panicking_env::abort; -use crate::env::get_ipc_buffer; -use crate::handler::{run_handler, Handler}; -use crate::panicking::init_panicking; +use crate::{ + handler::{run_handler, Handler}, + panicking::init_panicking, +}; #[cfg(target_thread_local)] #[no_mangle] @@ -29,6 +31,7 @@ unsafe extern "C" fn sel4_runtime_rust_entry() -> ! { inner_entry() } +#[allow(unreachable_code)] fn inner_entry() -> ! { #[cfg(all(feature = "unwinding", panic = "unwind"))] { @@ -38,7 +41,7 @@ fn inner_entry() -> ! { init_panicking(); unsafe { - sel4::set_ipc_buffer(get_ipc_buffer().as_mut().unwrap()); + sel4::set_ipc_buffer(ipc_buffer_ptr().as_mut().unwrap()); sel4_runtime_common::run_ctors(); __sel4_microkit__main(); } @@ -47,7 +50,7 @@ fn inner_entry() -> ! { } extern "C" { - fn __sel4_microkit__main(); + fn __sel4_microkit__main() -> !; } #[doc(hidden)] @@ -55,14 +58,15 @@ extern "C" { macro_rules! declare_init { ($init:expr) => { #[no_mangle] - fn __sel4_microkit__main() { + fn __sel4_microkit__main() -> ! { $crate::_private::run_main($init); } }; } +#[doc(hidden)] #[allow(clippy::missing_safety_doc)] -pub fn run_main(init: impl FnOnce() -> T + UnwindSafe) { +pub fn run_main(init: impl FnOnce() -> T + UnwindSafe) -> ! { let result = catch_unwind(|| match run_handler(init()) { Ok(absurdity) => match absurdity {}, Err(err) => err, diff --git a/crates/sel4-microkit/src/env.rs b/crates/sel4-microkit/src/env.rs deleted file mode 100644 index ce24ab3b2..000000000 --- a/crates/sel4-microkit/src/env.rs +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copyright 2023, Colias Group, LLC -// -// SPDX-License-Identifier: BSD-2-Clause -// - -use core::ptr; -use core::str; - -use sel4_immutable_cell::ImmutableCell; - -use crate::abort; - -extern "C" { - static mut __sel4_ipc_buffer_obj: sel4::IpcBuffer; -} - -pub(crate) unsafe fn get_ipc_buffer() -> *mut sel4::IpcBuffer { - ptr::addr_of_mut!(__sel4_ipc_buffer_obj) -} - -#[no_mangle] -#[used(linker)] -#[link_section = ".data"] -static passive: ImmutableCell = ImmutableCell::new(false); // just a placeholder - -/// Returns whether this projection domain is a passive server. -pub fn pd_is_passive() -> bool { - *passive.get() -} - -#[no_mangle] -#[used(linker)] -#[link_section = ".data"] -static microkit_name: ImmutableCell<[u8; 16]> = ImmutableCell::new([0; 16]); - -/// Returns the name of this projection domain. -pub fn pd_name() -> &'static str { - let all_bytes = microkit_name.get(); - let bytes = match core::ffi::CStr::from_bytes_until_nul(all_bytes) { - Ok(cstr) => cstr.to_bytes(), - Err(_) => all_bytes, - }; - str::from_utf8(bytes).unwrap_or_else(|_| { - // abort to avoid recursive panic - abort!("invalid embedded protection domain name"); - }) -} - -#[macro_export] -macro_rules! var { - ($(#[$attrs:meta])* $symbol:ident: $ty:ty = $default:expr) => {{ - $(#[$attrs])* - #[no_mangle] - #[link_section = ".data"] - static $symbol: $crate::_private::ImmutableCell<$ty> = $crate::_private::ImmutableCell::new($default); - - $symbol.get() - }}; -} diff --git a/crates/sel4-microkit/src/handler.rs b/crates/sel4-microkit/src/handler.rs index 69d773758..e383b13e8 100644 --- a/crates/sel4-microkit/src/handler.rs +++ b/crates/sel4-microkit/src/handler.rs @@ -6,13 +6,18 @@ use core::fmt; -pub use core::convert::Infallible; +use sel4_microkit_base::MessageInfo; -use crate::cspace::{ - Channel, DeferredAction, PreparedDeferredAction, INPUT_CAP, MONITOR_EP_CAP, REPLY_CAP, +use crate::{ + defer::{DeferredAction, PreparedDeferredAction}, + pd_is_passive, Channel, }; -use crate::message::MessageInfo; -use crate::pd_is_passive; + +pub use core::convert::Infallible; + +const INPUT_CAP: sel4::Endpoint = sel4::Cap::from_bits(1); +const REPLY_CAP: sel4::Reply = sel4::Cap::from_bits(4); +const MONITOR_EP_CAP: sel4::Endpoint = sel4::Cap::from_bits(5); const EVENT_TYPE_MASK: sel4::Word = 1 << (sel4::WORD_SIZE - 1); @@ -66,7 +71,7 @@ pub(crate) fn run_handler(mut handler: T) -> Result loop { let (tag, badge) = match (reply_tag.take(), prepared_deferred_action.take()) { - (Some(tag), None) => INPUT_CAP.reply_recv(tag.into_sel4(), REPLY_CAP), + (Some(tag), None) => INPUT_CAP.reply_recv(tag.into_inner(), REPLY_CAP), (None, Some(action)) => action.cptr().nb_send_recv( action.msg_info(), INPUT_CAP.cast::(), @@ -76,7 +81,7 @@ pub(crate) fn run_handler(mut handler: T) -> Result _ => unreachable!(), }; - let tag = MessageInfo::from_sel4(tag); + let tag = MessageInfo::from_inner(tag); let is_endpoint = badge & EVENT_TYPE_MASK != 0; diff --git a/crates/sel4-microkit/src/lib.rs b/crates/sel4-microkit/src/lib.rs index 3e4da09df..3abd6a4c2 100644 --- a/crates/sel4-microkit/src/lib.rs +++ b/crates/sel4-microkit/src/lib.rs @@ -6,7 +6,6 @@ #![no_std] #![feature(cfg_target_thread_local)] -#![feature(used_with_arg)] //! A foundation for pure-Rust [seL4 Microkit](https://github.com/seL4/microkit) protection domains. //! @@ -36,31 +35,19 @@ #[cfg(feature = "alloc")] extern crate alloc; -use sel4_panicking_env::abort; - +pub use sel4_microkit_base::*; pub use sel4_microkit_macros::protection_domain; -mod cspace; +mod defer; mod entry; -mod env; mod handler; mod heap; -mod memory_region; -mod message; mod printing; pub mod panicking; -pub use cspace::{ - Channel, DeferredAction, DeferredActionInterface, DeferredActionSlot, IrqAckError, -}; -pub use env::{pd_is_passive, pd_name}; +pub use defer::{DeferredAction, DeferredActionInterface, DeferredActionSlot}; pub use handler::{Handler, Infallible, NullHandler}; -pub use memory_region::{cast_memory_region_checked, cast_memory_region_to_slice_checked}; -pub use message::{ - get_mr, set_mr, with_msg_bytes, with_msg_bytes_mut, with_msg_regs, with_msg_regs_mut, - MessageInfo, MessageLabel, MessageRegisterValue, -}; pub use printing::{debug_print, debug_println}; /// Declares the initialization function, stack size, and, optionally, heap and heap size. @@ -102,7 +89,6 @@ pub const DEFAULT_STACK_SIZE: usize = 0x10000; // For macros #[doc(hidden)] pub mod _private { - pub use sel4_immutable_cell::ImmutableCell; pub use sel4_runtime_common::declare_stack; pub use crate::heap::_private as heap; diff --git a/crates/sel4-microkit/src/memory_region.rs b/crates/sel4-microkit/src/memory_region.rs deleted file mode 100644 index e78a94ba1..000000000 --- a/crates/sel4-microkit/src/memory_region.rs +++ /dev/null @@ -1,93 +0,0 @@ -// -// Copyright 2023, Colias Group, LLC -// -// SPDX-License-Identifier: BSD-2-Clause -// - -//! Utilities for declaring and using share memory regions. - -use core::mem; -use core::ptr::NonNull; - -/// Declares a symbol via which the `microkit` tool can inject a memory region's address, and -/// returns the memory region's address at runtime. -/// -/// For more detail, see its definition. -/// -/// The patching mechanism used by the `microkit` tool requires that the symbol be allocated space -/// in the protection domain's ELF file, so we delare the symbol as part of the `.data` section. -/// -/// # Examples -/// -/// ```rust -/// let region_1 = unsafe { -/// ExternallySharedRef::<'static, Foo>::new( -/// memory_region_symbol!(region_1_addr: *mut Foo), -/// ) -/// }; -/// -/// let region_2 = unsafe { -/// ExternallySharedRef::<'static, [u8]>::new_read_only( -/// memory_region_symbol!(region_2_addr: *mut [u8], n = REGION_2_SIZE), -/// ) -/// }; -/// ``` -/// -/// # Note -/// -/// The `microkit` tool requires memory region address symbols to be present in protection domain -/// binaries. To prevent Rust from optimizing them out in cases where it is not used, add the -/// unstable `#[used(linker)]` attribute. For example: -/// -/// ```rust -/// #![feature(used_with_arg)] -/// -/// // might be optimized away if not used -/// memory_region_symbol!(region_addr: *mut Foo) -/// -/// // won't be optimized away -/// memory_region_symbol! { -/// #[used(linker)] -/// region_addr: *mut Foo -/// } -/// ``` -#[macro_export] -macro_rules! memory_region_symbol { - ($(#[$attrs:meta])* $symbol:ident: *mut [$ty:ty], n = $n:expr) => {{ - core::ptr::NonNull::slice_from_raw_parts( - $crate::memory_region_symbol!($(#[$attrs])* $symbol: *mut $ty), - $n, - ) - }}; - ($(#[$attrs:meta])* $symbol:ident: *mut $ty:ty) => {{ - $(#[$attrs])* - #[no_mangle] - #[link_section = ".data"] - static $symbol: $crate::_private::ImmutableCell = $crate::_private::ImmutableCell::new(0); - - core::ptr::NonNull::new( - *$symbol.get() as *mut $ty - ).unwrap_or_else(|| { - panic!("{} is null", stringify!($symbol)) - }) - }}; -} - -pub fn cast_memory_region_checked(bytes_ptr: NonNull<[u8]>) -> NonNull { - let ptr = bytes_ptr.cast::(); - assert!(is_aligned(ptr.as_ptr())); - assert!(mem::size_of::() <= bytes_ptr.len()); - ptr -} - -pub fn cast_memory_region_to_slice_checked(bytes_ptr: NonNull<[u8]>) -> NonNull<[T]> { - let ptr = bytes_ptr.cast::(); - assert!(is_aligned(ptr.as_ptr())); - assert!(bytes_ptr.len() % mem::size_of::() == 0); - let n = bytes_ptr.len() / mem::size_of::(); - NonNull::slice_from_raw_parts(ptr, n) -} - -fn is_aligned(p: *mut T) -> bool { - p.cast::<()>().align_offset(mem::align_of::()) == 0 -} diff --git a/crates/sel4-microkit/src/panicking.rs b/crates/sel4-microkit/src/panicking.rs index 2940ea7c3..a79f33c45 100644 --- a/crates/sel4-microkit/src/panicking.rs +++ b/crates/sel4-microkit/src/panicking.rs @@ -26,7 +26,7 @@ fn get_hook() -> &'static PanicHook { } fn default_hook(info: &ExternalPanicInfo) { - debug_println!("{}: {}", pd_name(), info); + debug_println!("{}: {}", pd_name().unwrap_or("?"), info); } fn outer_hook(info: &ExternalPanicInfo) { diff --git a/crates/sel4-microkit/src/printing.rs b/crates/sel4-microkit/src/printing.rs index 715c6c0f9..3a19fd126 100644 --- a/crates/sel4-microkit/src/printing.rs +++ b/crates/sel4-microkit/src/printing.rs @@ -1,3 +1,9 @@ +// +// Copyright 2024, Colias Group, LLC +// +// SPDX-License-Identifier: BSD-2-Clause +// + use sel4::config::sel4_cfg_if; sel4_cfg_if! {