feat(kernel): shared ABI decoder+proofs, no-panic gate, syscall storm, kani on shrunk kernel
This commit is contained in:
@@ -15,7 +15,7 @@ impl<P: Platform> Kernel<P> {
|
||||
// travel with it; only the permissions narrow.
|
||||
let copy = match self.check_cap(caller_pid, slot, types::permission::Permission::Delegate) {
|
||||
Ok(cap) => domain::capability::Capability::new(
|
||||
cap.resource().clone(),
|
||||
*cap.resource(),
|
||||
cap.permissions().restrict_to(&restrict),
|
||||
*cap.generation(),
|
||||
)
|
||||
|
||||
@@ -56,6 +56,20 @@ fn rw_delegate() -> PermissionSet {
|
||||
}
|
||||
|
||||
impl<P: Platform> Kernel<P> {
|
||||
pub(crate) fn ipc(&self, tid: ThreadId) -> Option<&IpcState> {
|
||||
self.ipc.get(tid.raw() as usize)
|
||||
}
|
||||
|
||||
pub(crate) fn ipc_mut(&mut self, tid: ThreadId) -> Option<&mut IpcState> {
|
||||
self.ipc.get_mut(tid.raw() as usize)
|
||||
}
|
||||
|
||||
pub(crate) fn set_pending_result(&mut self, tid: ThreadId, result: Option<SyscallResult>) {
|
||||
if let Some(r) = self.pending_results.get_mut(tid.raw() as usize) {
|
||||
*r = result;
|
||||
}
|
||||
}
|
||||
|
||||
fn thread_ref(&self, tid: ThreadId) -> Option<ThreadRef> {
|
||||
Some(ThreadRef {
|
||||
tid,
|
||||
@@ -87,7 +101,7 @@ impl<P: Platform> Kernel<P> {
|
||||
};
|
||||
let priority = thread.priority();
|
||||
if thread.unblock().is_ok() {
|
||||
self.pending_results[tid.raw() as usize] = Some(result);
|
||||
self.set_pending_result(tid, Some(result));
|
||||
let core = self.platform.core_id();
|
||||
self.scheduler.add(tid, priority, core);
|
||||
}
|
||||
@@ -170,7 +184,10 @@ impl<P: Platform> Kernel<P> {
|
||||
_ => None,
|
||||
};
|
||||
if kind == DeliveryKind::Call {
|
||||
self.ipc[receiver.raw() as usize].reply_to = self.thread_ref(sender);
|
||||
let caller = self.thread_ref(sender);
|
||||
if let Some(s) = self.ipc_mut(receiver) {
|
||||
s.reply_to = caller;
|
||||
}
|
||||
}
|
||||
Delivery {
|
||||
kind,
|
||||
@@ -237,7 +254,9 @@ impl<P: Platform> Kernel<P> {
|
||||
if !queued {
|
||||
return SyscallOutcome::Complete(SyscallResult::Error(KernelError::EndpointFull));
|
||||
}
|
||||
self.ipc[tid.raw() as usize].outgoing = Some(out);
|
||||
if let Some(s) = self.ipc_mut(tid) {
|
||||
s.outgoing = Some(out);
|
||||
}
|
||||
let reason = if is_call {
|
||||
BlockReason::Calling(ep)
|
||||
} else {
|
||||
@@ -258,11 +277,11 @@ impl<P: Platform> Kernel<P> {
|
||||
Ok(v) => v,
|
||||
Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)),
|
||||
};
|
||||
if drop_reply && let Some(pending) = self.ipc[tid.raw() as usize].reply_to.take() {
|
||||
if drop_reply && let Some(pending) = self.ipc_mut(tid).and_then(|s| s.reply_to.take()) {
|
||||
self.release_caller(pending);
|
||||
}
|
||||
|
||||
if let Some(n) = self.ipc[tid.raw() as usize].bound
|
||||
if let Some(n) = self.ipc(tid).and_then(|s| s.bound)
|
||||
&& let Some(ntfn) = self.notifications.get_mut(n)
|
||||
&& ntfn.has_bits()
|
||||
{
|
||||
@@ -273,7 +292,7 @@ impl<P: Platform> Kernel<P> {
|
||||
let sender = self.endpoints.get_mut(ep).and_then(|e| e.dequeue_sender());
|
||||
if let Some(sender) = sender {
|
||||
let is_call = self.is_blocked_as(sender, |r| matches!(r, BlockReason::Calling(_)));
|
||||
let Some(out) = self.ipc[sender.raw() as usize].outgoing.take() else {
|
||||
let Some(out) = self.ipc_mut(sender).and_then(|s| s.outgoing.take()) else {
|
||||
// A queued sender always has a message; treat a missing one
|
||||
// as a sender that vanished.
|
||||
return SyscallOutcome::Complete(SyscallResult::Error(KernelError::WouldBlock));
|
||||
@@ -310,9 +329,9 @@ impl<P: Platform> Kernel<P> {
|
||||
pid: ProcessId,
|
||||
message: Message,
|
||||
) -> Result<(), KernelError> {
|
||||
let caller = self.ipc[tid.raw() as usize]
|
||||
.reply_to
|
||||
.take()
|
||||
let caller = self
|
||||
.ipc_mut(tid)
|
||||
.and_then(|s| s.reply_to.take())
|
||||
.ok_or(KernelError::NoReply)?;
|
||||
let waiting = self.is_live(caller)
|
||||
&& self.is_blocked_as(caller.tid, |r| *r == BlockReason::AwaitingReply);
|
||||
@@ -343,7 +362,7 @@ impl<P: Platform> Kernel<P> {
|
||||
if let Err(e) = self.endpoint_cap(pid, slot, Permission::Read) {
|
||||
return SyscallOutcome::Complete(SyscallResult::Error(e));
|
||||
}
|
||||
if self.ipc[tid.raw() as usize].reply_to.is_some() {
|
||||
if self.ipc(tid).is_some_and(|s| s.reply_to.is_some()) {
|
||||
let _ = self.reply(tid, pid, message);
|
||||
}
|
||||
self.receive(tid, pid, slot, false)
|
||||
@@ -367,7 +386,7 @@ impl<P: Platform> Kernel<P> {
|
||||
return Err(KernelError::InvalidArgument);
|
||||
}
|
||||
let minted = Capability::new(
|
||||
source.resource().clone(),
|
||||
*source.resource(),
|
||||
source.permissions().restrict_to(&permissions),
|
||||
*source.generation(),
|
||||
)
|
||||
@@ -475,7 +494,7 @@ impl<P: Platform> Kernel<P> {
|
||||
slot: CapSlot,
|
||||
) -> Result<(), KernelError> {
|
||||
let (id, _, _) = self.notification_cap(pid, slot, Permission::Read)?;
|
||||
if self.ipc[tid.raw() as usize].bound.is_some() {
|
||||
if self.ipc(tid).is_none_or(|s| s.bound.is_some()) {
|
||||
return Err(KernelError::InvalidArgument);
|
||||
}
|
||||
let ntfn = self
|
||||
@@ -485,7 +504,9 @@ impl<P: Platform> Kernel<P> {
|
||||
if !ntfn.bind(tid) {
|
||||
return Err(KernelError::InvalidArgument);
|
||||
}
|
||||
self.ipc[tid.raw() as usize].bound = Some(id);
|
||||
if let Some(s) = self.ipc_mut(tid) {
|
||||
s.bound = Some(id);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ use types::{bounded::CapSlot, id::ThreadId, syscall_abi::ErrorCode};
|
||||
use crate::Kernel;
|
||||
|
||||
pub use ipc::{IpcState, ThreadRef};
|
||||
pub use types::syscall_abi::{Delivery, DeliveryKind};
|
||||
|
||||
pub enum SyscallOutcome {
|
||||
Complete(SyscallResult),
|
||||
@@ -21,38 +22,6 @@ pub enum SyscallOutcome {
|
||||
TerminateCaller,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum DeliveryKind {
|
||||
/// A `Send`; no reply expected.
|
||||
Message,
|
||||
/// A `Call`; the receiver's reply slot now names the caller.
|
||||
Call,
|
||||
/// Notification bits.
|
||||
Signal,
|
||||
}
|
||||
|
||||
/// What a receiving syscall hands back (docs/ipc.md, register ABI).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Delivery {
|
||||
pub kind: DeliveryKind,
|
||||
/// The sender's badge, or the signal bits.
|
||||
pub badge: usize,
|
||||
pub words: [usize; 4],
|
||||
/// Where a transferred capability landed in the receiver's table.
|
||||
pub cap: Option<CapSlot>,
|
||||
}
|
||||
|
||||
impl Delivery {
|
||||
pub fn signal(bits: usize) -> Self {
|
||||
Self {
|
||||
kind: DeliveryKind::Signal,
|
||||
badge: bits,
|
||||
words: [0; 4],
|
||||
cap: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SyscallResult {
|
||||
Ok,
|
||||
|
||||
Reference in New Issue
Block a user