feat(kernel): shared ABI decoder+proofs, no-panic gate, syscall storm, kani on shrunk kernel

This commit is contained in:
2026-10-26 23:44:09 +01:00
parent 154599e3af
commit 130a82f50d
41 changed files with 1583 additions and 404 deletions

View File

@@ -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(),
)

View File

@@ -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(())
}

View File

@@ -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,