Files
yggdrasil/kernel/lib/device-api/src/interrupt.rs
T
2025-08-14 11:34:00 +03:00

222 lines
5.6 KiB
Rust

use alloc::sync::Arc;
use yggdrasil_abi::error::Error;
use crate::device::Device;
#[derive(Clone)]
pub struct IrqHandle {
pub irq: Irq,
pub options: IrqOptions,
pub intc: Arc<dyn ExternalInterruptController>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Irq {
Private(u32),
External(u32),
}
#[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
#[repr(u32)]
pub enum IrqLevel {
#[default]
Default,
ActiveHigh,
ActiveLow,
}
#[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
#[repr(u32)]
pub enum IrqTrigger {
#[default]
Default,
Edge,
Level,
}
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
pub struct IrqOptions {
pub level: IrqLevel,
pub trigger: IrqTrigger,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum IpiDeliveryTarget {
Specific(usize),
ThisCpu,
OtherCpus,
}
#[derive(Clone, Copy, Debug, Default)]
pub struct MsiInfo {
pub address: usize,
pub value: u32,
pub vector: usize,
pub affinity: InterruptAffinity,
}
#[derive(Clone, Copy, Debug, Default)]
pub enum InterruptAffinity {
#[default]
Any,
Specific(usize),
}
#[derive(Clone, Copy, Debug)]
pub enum IrqVector {
Msi(usize),
Irq(Irq),
}
/// Describes messages sent from some CPU to others
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(u64)]
pub enum IpiMessage {
/// Indicates that the sender CPU entered kernel panic and wants other CPUs to follow
Panic,
/// Indicates that the cores should either halt and wait for the caller to shut the system
/// down, or they should shut down by themselves, depending on the platform
Shutdown,
}
pub trait InterruptHandler: Device {
fn handle_irq(self: Arc<Self>, vector: IrqVector) -> bool;
}
pub trait InterruptTable: Sync {
fn handler(&self, index: usize) -> Option<&Arc<dyn InterruptHandler>>;
}
pub trait ExternalInterruptController: Device {
/// Performs IRQ delivery method configuration and registers a handler to execute when it is
/// fired
fn register_irq(
&self,
irq: Irq,
options: IrqOptions,
handler: Arc<dyn InterruptHandler>,
) -> Result<(), Error>;
/// Enables the specified IRQ (unmasks it)
fn enable_irq(&self, irq: Irq) -> Result<(), Error>;
/// Handles a single pending interrupt on this controller.
/// The function is intended for interrupt controllers which have internal registers to track
/// the IRQ index and the order of interrupt handling (if multiple are handled in sequence) is
/// platform/controller specific.
fn handle_pending_irqs(&self) {}
/// Handles a single pending interrupt with a known index on this controller.
/// The function is intended for interrupt controllers where vectors "know" their interrupt
/// index.
fn handle_specific_irq(&self, index: usize) {
let _ = index;
}
}
pub trait MessageInterruptController: Device {
fn register_msi(
self: Arc<Self>,
affinity: InterruptAffinity,
handler: Arc<dyn InterruptHandler>,
) -> Result<MsiInfo, Error> {
let mut range = [MsiInfo {
affinity,
..Default::default()
}];
self.register_msi_range(&mut range, handler)?;
Ok(range[0])
}
#[allow(unused)]
fn register_msi_range(
self: Arc<Self>,
range: &mut [MsiInfo],
handler: Arc<dyn InterruptHandler>,
) -> Result<(), Error> {
Err(Error::NotImplemented)
}
fn handle_msi(&self, #[allow(unused)] vector: usize) {}
}
pub trait LocalInterruptController: Device {
/// Initializes the local interrupt controller for an Application Processor instance.
///
/// # Safety
///
/// The caller must ensure this function is only called once per each AP (and only for APs).
unsafe fn init_ap(&self) -> Result<(), Error>;
fn send_ipi(&self, target: IpiDeliveryTarget, msg: IpiMessage) -> Result<(), Error>;
}
pub struct FixedInterruptTable<const N: usize> {
rows: [Option<Arc<dyn InterruptHandler>>; N],
}
impl IrqHandle {
pub fn register(&self, handler: Arc<dyn InterruptHandler>) -> Result<(), Error> {
self.intc.register_irq(self.irq, self.options, handler)
}
pub fn enable(&self) -> Result<(), Error> {
self.intc.enable_irq(self.irq)
}
}
impl<const N: usize> FixedInterruptTable<N> {
pub const fn new() -> Self {
Self {
rows: [const { None }; N],
}
}
pub fn insert(&mut self, index: usize, entry: Arc<dyn InterruptHandler>) -> Result<(), Error> {
let row = self.rows.get_mut(index).ok_or(Error::InvalidArgument)?;
if row.is_some() {
return Err(Error::AlreadyExists);
}
*row = Some(entry);
Ok(())
}
pub fn insert_least_loaded(
&mut self,
handler: Arc<dyn InterruptHandler>,
) -> Result<usize, Error> {
let index = self
.rows
.iter()
.position(|p| p.is_none())
.ok_or(Error::InvalidArgument)?;
self.rows[index].replace(handler);
Ok(index)
}
}
impl<const N: usize> InterruptTable for FixedInterruptTable<N> {
#[inline]
fn handler(&self, index: usize) -> Option<&Arc<dyn InterruptHandler>> {
self.rows.get(index).and_then(|p| p.as_ref())
}
}
impl IrqLevel {
pub fn override_default(self, value: IrqLevel) -> Self {
match self {
Self::Default => value,
_ => self,
}
}
}
impl IrqTrigger {
pub fn override_default(self, value: IrqTrigger) -> Self {
match self {
Self::Default => value,
_ => self,
}
}
}