use types::{ badge::Badge, generation::Generation, id::{IrqId, NotificationId, ProcessId}, }; #[cfg(test)] #[path = "tests.rs"] mod tests; const MAX_IRQS: usize = if cfg!(kani) { 2 } else { 256 }; /// Where an interrupt is delivered: a signal on a notification, through a /// capability snapshot (generation and badge) taken when the route was set. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct IrqRoute { pub notification: NotificationId, pub generation: Generation, pub badge: Badge, /// The process that set the route, and so owns the line. pub owner: ProcessId, } pub struct IrqRoutingTable { routes: [Option; MAX_IRQS], } impl IrqRoutingTable { pub fn new() -> Self { Self { routes: [None; MAX_IRQS], } } /// Whether `irq` is a line this table can route. pub fn is_valid(&self, irq: IrqId) -> bool { (irq.raw() as usize) < MAX_IRQS } /// Routes `irq`, replacing any previous route. Fails for lines beyond /// the table. pub fn set(&mut self, irq: IrqId, route: IrqRoute) -> bool { match self.routes.get_mut(irq.raw() as usize) { Some(slot) => { *slot = Some(route); true } None => false, } } pub fn clear(&mut self, irq: IrqId) { if let Some(slot) = self.routes.get_mut(irq.raw() as usize) { *slot = None; } } /// Drops every route `owner` set, when it dies. pub fn clear_owned_by(&mut self, owner: ProcessId) { for slot in self.routes.iter_mut() { if slot.is_some_and(|r| r.owner == owner) { *slot = None; } } } /// The route for `irq`; `None` for unknown or unrouted lines. pub fn route(&self, irq: IrqId) -> Option { *self.routes.get(irq.raw() as usize)? } } impl Default for IrqRoutingTable { fn default() -> Self { Self::new() } }