feat(kernel): object lifetimes via slot generations

- SlotGenerations per table, never wraps, retires exhausted slots
- caps to dead/reused process, endpoint, region rejected
- endpoints owned, die w/ owner, waiters woken w/ error
- DropCap syscall + libkos wrapper
- irq table bounds-checked, routes dropped w/ thread
- self-kill terminates caller, exit_thread full cleanup
- sched run_now: switch to named thread, not queue head
- lifetime tests, fuzz kills/recreates, kani gen proofs
This commit is contained in:
2026-10-26 19:54:23 +01:00
parent 8d2c40cb1e
commit d43421e33e
32 changed files with 790 additions and 207 deletions

View File

@@ -20,20 +20,35 @@ impl IrqRoutingTable {
}
pub fn register(&mut self, irq: IrqId, thread: ThreadId) -> Result<(), KernelError> {
let idx = irq.raw() as usize;
if self.owners[idx].is_some() {
let slot = self
.owners
.get_mut(irq.raw() as usize)
.ok_or(KernelError::InvalidIrq(irq))?;
if slot.is_some() {
return Err(KernelError::IrqAlreadyOwned(irq));
}
self.owners[idx] = Some(thread);
*slot = Some(thread);
Ok(())
}
pub fn unregister(&mut self, irq: IrqId) {
self.owners[irq.raw() as usize] = None;
if let Some(slot) = self.owners.get_mut(irq.raw() as usize) {
*slot = None;
}
}
/// Drops every route to `thread`, e.g. when it dies.
pub fn unregister_thread(&mut self, thread: ThreadId) {
for slot in &mut self.owners {
if *slot == Some(thread) {
*slot = None;
}
}
}
/// The thread an interrupt is routed to; `None` for unknown lines.
pub fn owner(&self, irq: IrqId) -> Option<ThreadId> {
self.owners[irq.raw() as usize]
*self.owners.get(irq.raw() as usize)?
}
}