feat(kernel): ipc cap transfer drops Delegate; one owner per irq line, freed when owner dies
This commit is contained in:
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user