feat(kernel): seL4-style IPC, notifications, status ABI
- badges + Mint, Call/Reply/ReplyRecv w/ gen-checked reply slot - cap transfer (1/msg, copy, needs Delegate, rechecked at delivery) - notifications: signal/wait/poll/bind, irq -> notification routing - WaitAny/WaitForInterrupt removed; a0=status, ErrorCode - libkos: single ecall primitive, compat wrappers + typed new api - fix: trap return clobbered user t0 on every trap - fix: wait queues FIFO, delegate keeps badge, fault cap checked - docs/ipc.md spec, ipc tests, ipc fuzz, kani ntfn + waitqueue
This commit is contained in:
@@ -18,11 +18,10 @@ use domain::{
|
||||
error::KernelError,
|
||||
irq::IrqRoutingTable,
|
||||
memory::{RegionTable, frame::FrameTable, quota::Quota},
|
||||
message::Message,
|
||||
notification::{MAX_NOTIFICATIONS, NotificationTable},
|
||||
process::{MAX_PROCESSES, ProcessTable},
|
||||
resource::Resource,
|
||||
scheduler::{Scheduler, multi_core::MultiCoreScheduler},
|
||||
syscall::WaitSet,
|
||||
thread::{MAX_THREADS, ThreadState, ThreadTable},
|
||||
};
|
||||
use platform::Platform;
|
||||
@@ -45,9 +44,9 @@ pub struct Kernel<P: Platform> {
|
||||
quotas: [Quota; MAX_PROCESSES],
|
||||
regions: RegionTable,
|
||||
irqs: IrqRoutingTable,
|
||||
pending_messages: [Option<Message>; MAX_THREADS],
|
||||
notifications: NotificationTable,
|
||||
ipc: [syscall::IpcState; MAX_THREADS],
|
||||
pending_results: [Option<SyscallResult>; MAX_THREADS],
|
||||
wait_sets: [Option<WaitSet>; MAX_THREADS],
|
||||
}
|
||||
|
||||
impl<P: Platform> Kernel<P> {
|
||||
@@ -63,9 +62,9 @@ impl<P: Platform> Kernel<P> {
|
||||
quotas: [Quota::default(); MAX_PROCESSES],
|
||||
regions: RegionTable::new(),
|
||||
irqs: IrqRoutingTable::new(),
|
||||
pending_messages: [const { None }; MAX_THREADS],
|
||||
notifications: NotificationTable::new(),
|
||||
ipc: [syscall::IpcState::default(); MAX_THREADS],
|
||||
pending_results: [const { None }; MAX_THREADS],
|
||||
wait_sets: [const { None }; MAX_THREADS],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,9 +94,9 @@ impl<P: Platform> Kernel<P> {
|
||||
addr_of_mut!((*slot).quotas).write([Quota::default(); MAX_PROCESSES]);
|
||||
addr_of_mut!((*slot).regions).write(RegionTable::new());
|
||||
addr_of_mut!((*slot).irqs).write(IrqRoutingTable::new());
|
||||
addr_of_mut!((*slot).pending_messages).write([const { None }; MAX_THREADS]);
|
||||
addr_of_mut!((*slot).notifications).write(NotificationTable::new());
|
||||
addr_of_mut!((*slot).ipc).write([syscall::IpcState::default(); MAX_THREADS]);
|
||||
addr_of_mut!((*slot).pending_results).write([const { None }; MAX_THREADS]);
|
||||
addr_of_mut!((*slot).wait_sets).write([const { None }; MAX_THREADS]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,6 +279,7 @@ impl<P: Platform> Kernel<P> {
|
||||
|
||||
self.cleanup_threads(&thread_ids);
|
||||
self.destroy_endpoints_owned_by(pid);
|
||||
self.destroy_notifications_owned_by(pid);
|
||||
self.teardown_memory(pid);
|
||||
|
||||
let _ = self.processes.destroy(pid);
|
||||
@@ -289,10 +289,12 @@ impl<P: Platform> Kernel<P> {
|
||||
use domain::scheduler::Scheduler;
|
||||
for tid in thread_ids.iter().flatten() {
|
||||
self.endpoints.remove_thread_from_all(*tid);
|
||||
self.cleanup_wait_any(*tid);
|
||||
self.irqs.unregister_thread(*tid);
|
||||
self.notifications.remove_thread_from_all(*tid);
|
||||
let ipc = core::mem::take(&mut self.ipc[tid.raw() as usize]);
|
||||
if let Some(caller) = ipc.reply_to {
|
||||
self.release_caller(caller);
|
||||
}
|
||||
self.scheduler.remove(*tid);
|
||||
self.pending_messages[tid.raw() as usize] = None;
|
||||
self.pending_results[tid.raw() as usize] = None;
|
||||
let _ = self.threads.destroy(*tid);
|
||||
}
|
||||
@@ -315,28 +317,31 @@ impl<P: Platform> Kernel<P> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Makes a blocked thread runnable with `error` as its syscall result.
|
||||
fn wake_with_error(&mut self, tid: ThreadId, error: KernelError) {
|
||||
self.cleanup_wait_any(tid);
|
||||
self.pending_messages[tid.raw() as usize] = None;
|
||||
let Ok(thread) = self.threads.get_mut(tid) else {
|
||||
return;
|
||||
};
|
||||
if !matches!(thread.state(), ThreadState::Blocked(_)) {
|
||||
return;
|
||||
/// Destroys every notification `owner` created, waking its waiters
|
||||
/// with an error and unbinding its bound thread.
|
||||
pub(crate) fn destroy_notifications_owned_by(&mut self, owner: ProcessId) {
|
||||
let mut owned = [None; MAX_NOTIFICATIONS];
|
||||
for (slot, id) in owned.iter_mut().zip(self.notifications.ids_owned_by(owner)) {
|
||||
*slot = Some(id);
|
||||
}
|
||||
let priority = thread.priority();
|
||||
if thread.unblock().is_ok() {
|
||||
self.pending_results[tid.raw() as usize] = Some(SyscallResult::Error(error));
|
||||
let core = self.platform.core_id();
|
||||
self.scheduler.add(tid, priority, core);
|
||||
for id in owned.into_iter().flatten() {
|
||||
let Some(mut n) = self.notifications.destroy(id) else {
|
||||
continue;
|
||||
};
|
||||
if let Some(bound) = n.bound() {
|
||||
self.ipc[bound.raw() as usize].bound = None;
|
||||
}
|
||||
while let Some(tid) = n.pop_waiter() {
|
||||
self.wake_with_error(tid, KernelError::NoSuchObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn cleanup_wait_any(&mut self, tid: ThreadId) {
|
||||
if self.wait_sets[tid.raw() as usize].take().is_some() {
|
||||
self.endpoints.remove_thread_from_all(tid);
|
||||
}
|
||||
/// Makes a blocked thread runnable with `error` as its syscall result,
|
||||
/// dropping whatever it was about to send.
|
||||
fn wake_with_error(&mut self, tid: ThreadId, error: KernelError) {
|
||||
self.ipc[tid.raw() as usize].outgoing = None;
|
||||
self.wake(tid, SyscallResult::Error(error));
|
||||
}
|
||||
|
||||
fn check_cap(
|
||||
@@ -362,6 +367,7 @@ impl<P: Platform> Kernel<P> {
|
||||
match resource {
|
||||
Resource::Endpoint(id) => self.endpoints.generation(*id),
|
||||
Resource::Memory(id) => self.regions.generation(*id),
|
||||
Resource::Notification(id) => self.notifications.generation(*id),
|
||||
Resource::Process(pid) => self.processes.generation(*pid),
|
||||
Resource::Interrupt(_) | Resource::ProcessCreate => Some(Generation::initial()),
|
||||
}
|
||||
@@ -371,6 +377,7 @@ impl<P: Platform> Kernel<P> {
|
||||
match resource {
|
||||
Resource::Endpoint(id) => self.endpoints.revoke(*id),
|
||||
Resource::Memory(id) => self.regions.revoke(*id),
|
||||
Resource::Notification(id) => self.notifications.revoke(*id),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user