feat(kernel): ipc cap transfer drops Delegate; one owner per irq line, freed when owner dies

This commit is contained in:
2026-10-27 14:42:28 +01:00
parent 37c482c36c
commit 33e1c849d1
7 changed files with 175 additions and 11 deletions

View File

@@ -46,10 +46,15 @@ impl<P: Platform> Kernel<P> {
if !grant {
return None;
}
let copy: Capability = self
.check_cap(from, slot, Permission::Delegate)
.ok()?
.clone();
// The receiver gets the capability but not the right to pass it
// on; a sender that wants that uses Delegate with explicit rights.
let source = self.check_cap(from, slot, Permission::Delegate).ok()?;
let copy = Capability::new(
*source.resource(),
source.permissions().without(Permission::Delegate),
*source.generation(),
)
.with_badge(source.badge());
let parent = self.cap_ref(from, slot);
self.insert_derived(to, copy, parent).ok()
}

View File

@@ -27,10 +27,14 @@ impl<P: Platform> Kernel<P> {
let irq = self.interrupt_cap(pid, irq_slot)?;
let (notification, badge, generation) =
self.notification_cap(pid, ntfn_slot, Permission::Write)?;
if self.irq_owner(irq).is_some_and(|owner| owner != pid) {
return Err(KernelError::IrqAlreadyOwned(irq));
}
let route = domain::irq::IrqRoute {
notification,
generation,
badge,
owner: pid,
};
if self.irqs.set(irq, route) {
Ok(())
@@ -45,10 +49,22 @@ impl<P: Platform> Kernel<P> {
slot: CapSlot,
) -> Result<(), KernelError> {
let irq = self.interrupt_cap(pid, slot)?;
if self.irq_owner(irq).is_some_and(|owner| owner != pid) {
return Err(KernelError::IrqAlreadyOwned(irq));
}
self.platform.unmask_irq(irq);
Ok(())
}
/// The process that routed `irq`, while its route still leads to a
/// live notification. One owner per line: other holders of the IRQ
/// capability cannot take it over.
fn irq_owner(&self, irq: IrqId) -> Option<ProcessId> {
let route = self.irqs.route(irq)?;
(self.notifications.generation(route.notification) == Some(route.generation))
.then_some(route.owner)
}
/// An interrupt fired: mask the line and signal its notification. The
/// line stays masked until the handler acknowledges it.
pub fn handle_interrupt(&mut self, irq: IrqId) {