Browse Source

添加irqchip这一层的数据结构(尚未接入真实的芯片) (#520)

* 添加irqchip这一层的数据结构(尚未接入真实的芯片)
LoGin 1 year ago
parent
commit
ce5850adbf

+ 2 - 2
kernel/src/driver/net/e1000e/e1000e.rs

@@ -14,7 +14,7 @@ use crate::driver::pci::pci::{
     get_pci_device_structure_mut, PciDeviceStructure, PciDeviceStructureGeneralDevice, PciError,
     PCI_DEVICE_LINKEDLIST,
 };
-use crate::driver::pci::pci_irq::{IrqCommonMsg, IrqMsg, IrqSpecificMsg, PciInterrupt, IRQ};
+use crate::driver::pci::pci_irq::{IrqCommonMsg, IrqSpecificMsg, PciInterrupt, PciIrqMsg, IRQ};
 use crate::include::bindings::bindings::pt_regs;
 use crate::libs::volatile::{ReadOnly, Volatile, WriteOnly};
 use crate::net::net_core::poll_ifaces_try_lock_onetime;
@@ -227,7 +227,7 @@ impl E1000EDevice {
         let irq_vector = device.irq_vector_mut().unwrap();
         irq_vector.push(E1000E_RECV_VECTOR);
         device.irq_init(IRQ::PCI_IRQ_MSI).expect("IRQ Init Failed");
-        let msg = IrqMsg {
+        let msg = PciIrqMsg {
             irq_common_message: IrqCommonMsg::init_from(
                 0,
                 "E1000E_RECV_IRQ",

+ 177 - 0
kernel/src/driver/open_firmware/device_node.rs

@@ -0,0 +1,177 @@
+use crate::{
+    driver::base::{
+        kobject::{KObjType, KObject, KObjectState},
+        kset::KSet,
+    },
+    filesystem::{kernfs::KernFSInode, sysfs::BinAttribute},
+    libs::rwlock::{RwLockReadGuard, RwLockWriteGuard},
+    libs::spinlock::SpinLock,
+};
+use alloc::{
+    string::String,
+    sync::{Arc, Weak},
+    vec::Vec,
+};
+use core::fmt::Debug;
+
+/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/of.h#51
+#[allow(dead_code)]
+#[derive(Debug)]
+pub struct DeviceNode {
+    full_name: Option<&'static str>,
+    full_name_allocated: Option<String>,
+    inner: SpinLock<InnerDeviceNode>,
+}
+
+#[allow(dead_code)]
+#[derive(Debug)]
+struct InnerDeviceNode {
+    properties: Vec<Property>,
+    parent: Weak<DeviceNode>,
+    children: Vec<Arc<DeviceNode>>,
+    sibling: Option<Weak<DeviceNode>>,
+    private_data: Option<Arc<dyn DeviceNodePrivateData>>,
+}
+
+#[allow(dead_code)]
+impl DeviceNode {
+    pub fn new(
+        full_name: Option<&'static str>,
+        full_name_allocated: Option<String>,
+    ) -> Option<Arc<Self>> {
+        if full_name.is_none() && full_name_allocated.is_none() {
+            return None;
+        }
+
+        let x = DeviceNode {
+            full_name,
+            full_name_allocated,
+            inner: SpinLock::new(InnerDeviceNode {
+                properties: Vec::new(),
+                parent: Weak::new(),
+                children: Vec::new(),
+                sibling: None,
+                private_data: None,
+            }),
+        };
+
+        return Some(Arc::new(x));
+    }
+
+    pub fn add_property(&self, prop: Property) {
+        self.inner.lock().properties.push(prop);
+    }
+
+    pub fn properties(&self) -> Vec<Property> {
+        self.inner.lock().properties.clone()
+    }
+
+    pub fn parent(&self) -> Option<Arc<DeviceNode>> {
+        self.inner.lock().parent.upgrade()
+    }
+
+    pub fn set_parent(&self, parent: Arc<DeviceNode>) {
+        self.inner.lock().parent = Arc::downgrade(&parent);
+    }
+
+    pub fn children(&self) -> Vec<Arc<DeviceNode>> {
+        self.inner.lock().children.clone()
+    }
+
+    pub fn add_child(&self, child: Arc<DeviceNode>) {
+        self.inner.lock().children.push(child);
+    }
+
+    pub fn sibling(&self) -> Option<Arc<DeviceNode>> {
+        self.inner.lock().sibling.as_ref().and_then(|s| s.upgrade())
+    }
+
+    pub fn set_sibling(&self, sibling: Arc<DeviceNode>) {
+        self.inner.lock().sibling = Some(Arc::downgrade(&sibling));
+    }
+
+    pub fn private_data(&self) -> Option<Arc<dyn DeviceNodePrivateData>> {
+        self.inner.lock().private_data.clone()
+    }
+
+    pub fn set_private_data(&self, data: Arc<dyn DeviceNodePrivateData>) {
+        self.inner.lock().private_data = Some(data);
+    }
+}
+
+pub trait DeviceNodePrivateData: Send + Sync + Debug {}
+
+impl KObject for DeviceNode {
+    fn as_any_ref(&self) -> &dyn core::any::Any {
+        self
+    }
+
+    fn set_inode(&self, _inode: Option<Arc<KernFSInode>>) {
+        todo!()
+    }
+
+    fn inode(&self) -> Option<Arc<KernFSInode>> {
+        todo!()
+    }
+
+    fn parent(&self) -> Option<Weak<dyn KObject>> {
+        todo!()
+    }
+
+    fn set_parent(&self, _parent: Option<Weak<dyn KObject>>) {
+        todo!()
+    }
+
+    fn kset(&self) -> Option<Arc<KSet>> {
+        todo!()
+    }
+
+    fn set_kset(&self, _kset: Option<Arc<KSet>>) {
+        todo!()
+    }
+
+    fn kobj_type(&self) -> Option<&'static dyn KObjType> {
+        todo!()
+    }
+
+    fn set_kobj_type(&self, _ktype: Option<&'static dyn KObjType>) {
+        todo!()
+    }
+
+    fn name(&self) -> String {
+        todo!()
+    }
+
+    fn set_name(&self, _name: String) {}
+
+    fn kobj_state(&self) -> RwLockReadGuard<KObjectState> {
+        todo!()
+    }
+
+    fn kobj_state_mut(&self) -> RwLockWriteGuard<KObjectState> {
+        todo!()
+    }
+
+    fn set_kobj_state(&self, _state: KObjectState) {
+        todo!()
+    }
+}
+
+#[allow(dead_code)]
+#[derive(Debug, Clone)]
+pub struct Property {
+    name: String,
+    value: Vec<u8>,
+    bin_attr: Option<Arc<dyn BinAttribute>>,
+}
+
+impl Property {
+    #[allow(dead_code)]
+    pub const fn new(name: String, value: Vec<u8>, battr: Option<Arc<dyn BinAttribute>>) -> Self {
+        Property {
+            name,
+            value,
+            bin_attr: battr,
+        }
+    }
+}

+ 1 - 0
kernel/src/driver/open_firmware/mod.rs

@@ -1,2 +1,3 @@
 // #[cfg(target_arch = "riscv64")]
+pub mod device_node;
 pub mod fdt;

+ 4 - 4
kernel/src/driver/pci/pci_irq.rs

@@ -70,7 +70,7 @@ pub enum IrqType {
 
 // PCI设备install中断时需要传递的参数
 #[derive(Clone, Debug)]
-pub struct IrqMsg {
+pub struct PciIrqMsg {
     pub irq_common_message: IrqCommonMsg,
     pub irq_specific_message: IrqSpecificMsg,
 }
@@ -301,7 +301,7 @@ pub trait PciInterrupt: PciDeviceStructure {
     /// @param self PCI设备的可变引用
     /// @param msg PCI设备install中断时需要传递的共同参数
     /// @return 一切正常返回Ok(0),有错误返回对应错误原因
-    fn irq_install(&mut self, msg: IrqMsg) -> Result<u8, PciError> {
+    fn irq_install(&mut self, msg: PciIrqMsg) -> Result<u8, PciError> {
         if let Some(irq_vector) = self.irq_vector_mut() {
             if msg.irq_common_message.irq_index as usize > irq_vector.len() {
                 return Err(PciError::PciIrqError(PciIrqError::InvalidIrqIndex(
@@ -332,7 +332,7 @@ pub trait PciInterrupt: PciDeviceStructure {
     /// @param self PCI设备的可变引用
     /// @param msg PCI设备install中断时需要传递的共同参数
     /// @return 一切正常返回Ok(0),有错误返回对应错误原因
-    fn msi_install(&mut self, msg: IrqMsg) -> Result<u8, PciError> {
+    fn msi_install(&mut self, msg: PciIrqMsg) -> Result<u8, PciError> {
         if let Some(irq_type) = self.irq_type_mut() {
             match *irq_type {
                 IrqType::Msi {
@@ -482,7 +482,7 @@ pub trait PciInterrupt: PciDeviceStructure {
     /// @param self PCI设备的可变引用
     /// @param msg PCI设备install中断时需要传递的共同参数
     /// @return 一切正常返回Ok(0),有错误返回对应错误原因
-    fn msix_install(&mut self, msg: IrqMsg) -> Result<u8, PciError> {
+    fn msix_install(&mut self, msg: PciIrqMsg) -> Result<u8, PciError> {
         if let Some(irq_type) = self.irq_type_mut() {
             match *irq_type {
                 IrqType::Msix {

+ 2 - 2
kernel/src/driver/virtio/transport_pci.rs

@@ -5,7 +5,7 @@ use crate::driver::pci::pci::{
     PciStandardDeviceBar, PCI_CAP_ID_VNDR,
 };
 
-use crate::driver::pci::pci_irq::{IrqCommonMsg, IrqMsg, IrqSpecificMsg, PciInterrupt, IRQ};
+use crate::driver::pci::pci_irq::{IrqCommonMsg, IrqSpecificMsg, PciInterrupt, PciIrqMsg, IRQ};
 use crate::include::bindings::bindings::pt_regs;
 use crate::libs::volatile::{
     volread, volwrite, ReadOnly, Volatile, VolatileReadable, VolatileWritable, WriteOnly,
@@ -133,7 +133,7 @@ impl PciTransport {
             .irq_init(IRQ::PCI_IRQ_MSIX)
             .expect("IRQ init failed");
         // 中断相关信息
-        let msg = IrqMsg {
+        let msg = PciIrqMsg {
             irq_common_message: IrqCommonMsg::init_from(
                 0,
                 "Virtio_Recv_IRQ",

+ 239 - 0
kernel/src/exception/irqchip.rs

@@ -0,0 +1,239 @@
+use core::{any::Any, fmt::Debug};
+
+use alloc::{
+    sync::{Arc, Weak},
+    vec::Vec,
+};
+use system_error::SystemError;
+
+use crate::{libs::spinlock::SpinLock, mm::VirtAddr};
+
+use super::{
+    irqdata::{IrqData, IrqLineStatus},
+    irqdomain::IrqDomain,
+    msi::MsiMsg,
+};
+
+/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#506
+pub trait IrqChip: Sync + Send + Any + Debug {
+    fn name(&self) -> &'static str;
+    /// start up the interrupt (defaults to ->enable if ENOSYS)
+    fn irq_startup(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
+        Err(SystemError::ENOSYS)
+    }
+
+    /// shut down the interrupt (defaults to ->disable if ENOSYS)
+    fn irq_shutdown(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
+        Err(SystemError::ENOSYS)
+    }
+
+    /// enable the interrupt
+    ///
+    /// (defaults to ->unmask if ENOSYS)
+    fn irq_enable(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
+        Err(SystemError::ENOSYS)
+    }
+
+    /// disable the interrupt
+    fn irq_disable(&self, irq: &Arc<IrqData>);
+
+    /// start of a new interrupt
+    fn irq_ack(&self, irq: &Arc<IrqData>);
+
+    /// mask an interrupt source
+    fn irq_mask(&self, irq: &Arc<IrqData>);
+    /// ack and mask an interrupt source
+    fn irq_mask_ack(&self, irq: &Arc<IrqData>);
+    /// unmask an interrupt source
+    fn irq_unmask(&self, irq: &Arc<IrqData>);
+    /// end of interrupt
+    fn irq_eoi(&self, irq: &Arc<IrqData>);
+
+    // todo: set affinity
+
+    /// retrigger an IRQ to the CPU
+    fn retrigger(&self, irq: &Arc<IrqData>);
+
+    /// set the flow type of an interrupt
+    ///
+    /// flow_type: the flow type to set
+    ///
+    fn irq_set_type(
+        &self,
+        _irq: &Arc<IrqData>,
+        _flow_type: IrqLineStatus,
+    ) -> Result<(), SystemError> {
+        Err(SystemError::ENOSYS)
+    }
+
+    /// enable/disable power management wake-on of an interrupt
+    fn irq_set_wake(&self, _irq: &Arc<IrqData>, _on: bool) -> Result<(), SystemError> {
+        Err(SystemError::ENOSYS)
+    }
+
+    /// function to lock access to slow bus (i2c) chips
+    fn irq_bus_lock(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
+        Ok(())
+    }
+
+    /// function to sync and unlock slow bus (i2c) chips
+    fn irq_bus_sync_unlock(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
+        Ok(())
+    }
+
+    /// function called from core code on suspend once per
+    /// chip, when one or more interrupts are installed
+    fn irq_suspend(&self, irq: &Arc<IrqData>);
+
+    /// function called from core code on resume once per chip,
+    /// when one ore more interrupts are installed
+    fn irq_resume(&self, irq: &Arc<IrqData>);
+
+    /// function called from core code on shutdown once per chip
+    fn irq_pm_shutdown(&self, irq: &Arc<IrqData>);
+
+    /// Optional function to set irq_data.mask for special cases
+    fn irq_calc_mask(&self, _irq: &Arc<IrqData>) {}
+
+    // todo: print chip
+
+    /// optional to request resources before calling
+    /// any other callback related to this irq
+    fn irq_request_resources(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
+        Ok(())
+    }
+
+    /// optional to release resources acquired with
+    /// irq_request_resources
+    fn irq_release_resources(&self, _irq: &Arc<IrqData>) {}
+
+    /// optional to compose message content for MSI
+    fn irq_compose_msi_msg(&self, _irq: &Arc<IrqData>, _msg: &mut MsiMsg) {}
+
+    /// optional to write message content for MSI
+    fn irq_write_msi_msg(&self, _irq: &Arc<IrqData>, _msg: &MsiMsg) {}
+
+    /// return the internal state of an interrupt
+    fn irqchip_state(
+        &self,
+        _irq: &Arc<IrqData>,
+        _which: IrqChipState,
+    ) -> Result<bool, SystemError> {
+        Err(SystemError::ENOSYS)
+    }
+
+    /// set the internal state of an interrupt
+    fn set_irqchip_state(
+        &self,
+        _irq: &Arc<IrqData>,
+        _which: IrqChipState,
+        _state: bool,
+    ) -> Result<(), SystemError> {
+        Err(SystemError::ENOSYS)
+    }
+
+    // todo: set vcpu affinity
+
+    /// send a single IPI to destination cpus
+    fn send_single_ipi(&self, irq: &Arc<IrqData>, cpu: u32);
+
+    // todo: send ipi with cpu mask
+
+    /// function called from core code before enabling an NMI
+    fn irq_nmi_setup(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
+        Err(SystemError::ENOSYS)
+    }
+
+    /// function called from core code after disabling an NMI
+    fn irq_nmi_teardown(&self, irq: &Arc<IrqData>);
+}
+
+#[allow(dead_code)]
+#[derive(Debug, Clone, Copy)]
+pub enum IrqChipState {
+    /// Is the interrupt pending?
+    Pending,
+    /// Is the interrupt in progress?
+    Active,
+    /// Is the interrupt masked?
+    Masked,
+    /// Is Irq line high?
+    LineLevel,
+}
+
+pub trait IrqChipData: Sync + Send + Any + Debug {}
+
+bitflags! {
+    /// 定义 IrqGcFlags 位标志
+    pub struct IrqGcFlags: u32 {
+        /// 通过读取mask reg来初始化mask_cache
+        const IRQ_GC_INIT_MASK_CACHE = 1 << 0;
+        /// 对于需要在父irq上调用irq_set_wake()的irq芯片, 将irqs的锁类设置为嵌套。Usually GPIO implementations
+        const IRQ_GC_INIT_NESTED_LOCK = 1 << 1;
+        /// Mask cache是芯片类型私有的
+        const IRQ_GC_MASK_CACHE_PER_TYPE = 1 << 2;
+        /// 不计算irqData->mask
+        const IRQ_GC_NO_MASK = 1 << 3;
+        /// 使用大端字节序的寄存器访问(默认:小端LE)
+        const IRQ_GC_BE_IO = 1 << 4;
+    }
+}
+
+#[allow(dead_code)]
+#[derive(Debug)]
+pub struct IrqChipGeneric {
+    inner: SpinLock<InnerIrqChipGeneric>,
+}
+
+#[allow(dead_code)]
+#[derive(Debug)]
+struct InnerIrqChipGeneric {
+    /// Register base address
+    reg_base: VirtAddr,
+    ops: &'static dyn IrqChipGenericOps,
+    /// Interrupt base num for this chip
+    irq_base: u32,
+    /// Number of interrupts handled by this chip
+    irq_cnt: u32,
+    /// Cached mask register shared between all chip types
+    mask_cache: u32,
+    /// Cached type register
+    type_cache: u32,
+    /// Cached polarity register
+    polarity_cache: u32,
+    /// Interrupt can wakeup from suspend
+    wake_enabled: bool,
+    /// Interrupt is marked as an wakeup from suspend source
+    wake_active: bool,
+    /// Number of available irq_chip_type instances (usually 1)
+    num_chip_type: u32,
+    private_data: Option<Arc<dyn IrqChipGenericPrivateData>>,
+    installed: u64,
+    unused: u64,
+    domain: Weak<IrqDomain>,
+    chip_types: Vec<IrqChipType>,
+}
+
+pub trait IrqChipGenericOps: Debug {
+    /// Alternate I/O accessor (defaults to readl if NULL)
+    unsafe fn reg_readl(&self, addr: VirtAddr) -> u32;
+
+    /// Alternate I/O accessor (defaults to writel if NULL)
+    unsafe fn reg_writel(&self, addr: VirtAddr, val: u32);
+
+    /// Function called from core code on suspend once per
+    /// chip; can be useful instead of irq_chip::suspend to
+    /// handle chip details even when no interrupts are in use
+    fn suspend(&self, gc: &Arc<IrqChipGeneric>);
+    /// Function called from core code on resume once per chip;
+    /// can be useful instead of irq_chip::resume to handle chip
+    /// details even when no interrupts are in use
+    fn resume(&self, gc: &Arc<IrqChipGeneric>);
+}
+
+pub trait IrqChipGenericPrivateData: Sync + Send + Any + Debug {}
+
+#[derive(Debug)]
+pub struct IrqChipType {
+    // todo https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#1024
+}

+ 332 - 0
kernel/src/exception/irqdata.rs

@@ -0,0 +1,332 @@
+use core::{any::Any, fmt::Debug};
+
+use alloc::sync::{Arc, Weak};
+
+use crate::libs::spinlock::SpinLock;
+
+use super::{
+    irqchip::{IrqChip, IrqChipData},
+    irqdomain::IrqDomain,
+    msi::MsiDesc,
+    HardwareIrqNumber, IrqNumber,
+};
+
+/// per irq chip data passed down to chip functions
+///
+/// 该结构体用于表示每个Irq的私有数据,且与具体的中断芯片绑定
+///
+/// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#179
+#[allow(dead_code)]
+#[derive(Debug)]
+pub struct IrqData {
+    /// 中断号, 用于表示软件逻辑视角的中断号,全局唯一
+    irq: IrqNumber,
+    /// 硬件中断号, 用于表示在某个IrqDomain中的中断号
+    hwirq: HardwareIrqNumber,
+    /// 涉及的所有irqchip之间共享的数据
+    common_data: Arc<IrqCommonData>,
+    /// 绑定到的中断芯片
+    chip: Arc<dyn IrqChip>,
+    /// 中断芯片的私有数据(与当前irq相关)
+    chip_data: Arc<dyn IrqChipData>,
+    /// 中断域
+    domain: Arc<IrqDomain>,
+    /// 中断的父中断(如果具有中断域继承的话)
+    parent_data: Option<Weak<IrqData>>,
+}
+
+/// per irq data shared by all irqchips
+///
+/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#147
+#[allow(dead_code)]
+#[derive(Debug)]
+pub struct IrqCommonData {
+    inner: SpinLock<InnerIrqCommonData>,
+}
+
+#[allow(dead_code)]
+#[derive(Debug)]
+struct InnerIrqCommonData {
+    /// status information for irq chip functions.
+    state: IrqStatus,
+    /// per-IRQ data for the irq_chip methods
+    handler_data: Option<Arc<dyn IrqHandlerData>>,
+    msi_desc: Option<Arc<MsiDesc>>,
+    // todo: affinity
+}
+
+pub trait IrqHandlerData: Send + Sync + Any + Debug {}
+
+bitflags! {
+    /// 中断线状态
+    /// https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h?fi=IRQ_TYPE_PROBE#77
+    pub struct IrqLineStatus: u32 {
+        /// 默认,未指明类型
+        const IRQ_TYPE_NONE     = 0x00000000;
+        /// 上升沿触发
+        const IRQ_TYPE_EDGE_RISING  = 0x00000001;
+        /// 下降沿触发
+        const IRQ_TYPE_EDGE_FALLING = 0x00000002;
+        /// 上升沿和下降沿触发
+        const IRQ_TYPE_EDGE_BOTH    = Self::IRQ_TYPE_EDGE_RISING.bits | Self::IRQ_TYPE_EDGE_FALLING.bits;
+        /// 高电平触发
+        const IRQ_TYPE_LEVEL_HIGH   = 0x00000004;
+        /// 低电平触发
+        const IRQ_TYPE_LEVEL_LOW    = 0x00000008;
+        /// 过滤掉电平位的掩码
+        const IRQ_TYPE_LEVEL_MASK   = Self::IRQ_TYPE_LEVEL_LOW.bits | Self::IRQ_TYPE_LEVEL_HIGH.bits;
+        /// 上述位掩码的掩码
+        const IRQ_TYPE_SENSE_MASK   = 0x0000000f;
+        /// 某些PICs使用此类型要求 `IrqChip::irq_set_type()` 设置硬件到一个合理的默认值
+        /// (由irqdomain的map()回调使用,以便为新分配的描述符同步硬件状态和软件标志位)。
+        const IRQ_TYPE_DEFAULT      = Self::IRQ_TYPE_SENSE_MASK.bits;
+
+        /// 特定于探测的过程中的特殊标志
+        const IRQ_TYPE_PROBE        = 0x00000010;
+
+        /// 中断是电平类型。当上述触发位通过`IrqChip::irq_set_type()` 修改时,也会在代码中更新
+        const IRQ_LEVEL     = 1 << 8;
+        /// 标记一个PER_CPU的中断。将保护其免受亲和性设置的影响
+        const IRQ_PER_CPU       = 1 << 9;
+        /// 中断不能被自动探测
+        const IRQ_NOPROBE       = 1 << 10;
+        /// 中断不能通过request_irq()请求
+        const IRQ_NOREQUEST     = 1 << 11;
+        /// 中断在request/setup_irq()中不会自动启用
+        const IRQ_NOAUTOEN      = 1 << 12;
+        /// 中断不能被平衡(亲和性设置)
+        const IRQ_NO_BALANCING      = 1 << 13;
+        /// 中断可以从进程上下文中迁移
+        const IRQ_MOVE_PCNTXT       = 1 << 14;
+        /// 中断嵌套在另一个线程中
+        const IRQ_NESTED_THREAD = 1 << 15;
+        /// 中断不能被线程化
+        const IRQ_NOTHREAD      = 1 << 16;
+        /// Dev_id是一个per-CPU变量
+        const IRQ_PER_CPU_DEVID = 1 << 17;
+        /// 总是由另一个中断轮询。将其从错误的中断检测机制和核心侧轮询中排除
+        const IRQ_IS_POLLED     = 1 << 18;
+        /// 禁用延迟的中断禁用 (Disable lazy irq disable)
+        const IRQ_DISABLE_UNLAZY    = 1 << 19;
+        /// 在/proc/interrupts中不显示
+        const IRQ_HIDDEN        = 1 << 20;
+        /// 从note_interrupt()调试中排除
+        const IRQ_NO_DEBUG      = 1 << 21;
+    }
+
+
+
+}
+bitflags! {
+    /// 中断状态(存储在IrqCommonData)
+    ///
+    /// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#227
+    pub struct IrqStatus: u32 {
+        /// 触发类型位的掩码
+        const IRQD_TRIGGER_MASK = 0xf;
+        /// 亲和性设置待处理
+        const IRQD_SETAFFINITY_PENDING = 1 << 8;
+        /// 中断已激活
+        const IRQD_ACTIVATED = 1 << 9;
+        /// 对此IRQ禁用平衡
+        const IRQD_NO_BALANCING = 1 << 10;
+        /// 中断是每个CPU特定的
+        const IRQD_PER_CPU = 1 << 11;
+        /// 中断亲和性已设置
+        const IRQD_AFFINITY_SET = 1 << 12;
+        /// 中断是电平触发
+        const IRQD_LEVEL = 1 << 13;
+        /// 中断配置为从挂起状态唤醒
+        const IRQD_WAKEUP_STATE = 1 << 14;
+        /// 中断可以在进程上下文中移动
+        const IRQD_MOVE_PCNTXT = 1 << 15;
+        /// 中断被禁用
+        const IRQD_IRQ_DISABLED = 1 << 16;
+        /// 中断被屏蔽
+        const IRQD_IRQ_MASKED = 1 << 17;
+        /// 中断正在处理中
+        const IRQD_IRQ_INPROGRESS = 1 << 18;
+        /// 唤醒模式已准备就绪
+        const IRQD_WAKEUP_ARMED = 1 << 19;
+        /// 中断被转发到一个虚拟CPU
+        const IRQD_FORWARDED_TO_VCPU = 1 << 20;
+        /// 亲和性由内核自动管理
+        const IRQD_AFFINITY_MANAGED = 1 << 21;
+        /// 中断已启动
+        const IRQD_IRQ_STARTED = 1 << 22;
+        /// 由于空亲和性掩码而关闭的中断。仅适用于亲和性管理的中断。
+        const IRQD_MANAGED_SHUTDOWN = 1 << 23;
+        /// IRQ只允许单个亲和性目标
+        const IRQD_SINGLE_TARGET = 1 << 24;
+        /// 预期的触发器已设置
+        const IRQD_DEFAULT_TRIGGER_SET = 1 << 25;
+        /// 可以使用保留模式
+        const IRQD_CAN_RESERVE = 1 << 26;
+        /// Non-maskable MSI quirk for affinity change required
+        const IRQD_MSI_NOMASK_QUIRK = 1 << 27;
+        /// 强制要求`handle_irq_()`只能在真实的中断上下文中调用
+        const IRQD_HANDLE_ENFORCE_IRQCTX = 1 << 28;
+        /// 激活时设置亲和性。在禁用时不要调用irq_chip::irq_set_affinity()。
+        const IRQD_AFFINITY_ON_ACTIVATE = 1 << 29;
+        /// 如果irqpm具有标志 IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND,则在挂起时中断被启用。
+        const IRQD_IRQ_ENABLED_ON_SUSPEND = 1 << 30;
+    }
+}
+
+#[allow(dead_code)]
+impl IrqStatus {
+    pub const fn is_set_affinity_pending(&self) -> bool {
+        self.contains(Self::IRQD_SETAFFINITY_PENDING)
+    }
+
+    pub const fn is_per_cpu(&self) -> bool {
+        self.contains(Self::IRQD_PER_CPU)
+    }
+
+    pub const fn can_balance(&self) -> bool {
+        !((self.bits & (Self::IRQD_PER_CPU.bits | Self::IRQD_NO_BALANCING.bits)) != 0)
+    }
+
+    pub const fn affinity_was_set(&self) -> bool {
+        self.contains(Self::IRQD_AFFINITY_SET)
+    }
+
+    pub fn mark_affinity_set(&mut self) {
+        self.insert(Self::IRQD_AFFINITY_SET);
+    }
+
+    pub const fn trigger_type_was_set(&self) -> bool {
+        self.contains(Self::IRQD_DEFAULT_TRIGGER_SET)
+    }
+
+    pub fn mark_trigger_type_set(&mut self) {
+        self.insert(Self::IRQD_DEFAULT_TRIGGER_SET);
+    }
+
+    pub const fn trigger_type(&self) -> IrqLineStatus {
+        IrqLineStatus::from_bits_truncate(self.bits & Self::IRQD_TRIGGER_MASK.bits)
+    }
+
+    /// Must only be called inside irq_chip.irq_set_type() functions or
+    /// from the DT/ACPI setup code.
+    pub const fn set_trigger_type(&mut self, trigger: IrqLineStatus) {
+        self.bits &= !Self::IRQD_TRIGGER_MASK.bits;
+        self.bits |= trigger.bits & Self::IRQD_TRIGGER_MASK.bits;
+
+        self.bits |= Self::IRQD_DEFAULT_TRIGGER_SET.bits;
+    }
+
+    pub const fn is_level_type(&self) -> bool {
+        self.contains(Self::IRQD_LEVEL)
+    }
+
+    /// Must only be called of irqchip.irq_set_affinity() or low level
+    /// hierarchy domain allocation functions.
+    pub fn set_single_target(&mut self) {
+        self.insert(Self::IRQD_SINGLE_TARGET);
+    }
+
+    pub const fn is_single_target(&self) -> bool {
+        self.contains(Self::IRQD_SINGLE_TARGET)
+    }
+
+    pub fn set_handle_enforce_irqctx(&mut self) {
+        self.insert(Self::IRQD_HANDLE_ENFORCE_IRQCTX);
+    }
+
+    pub const fn is_handle_enforce_irqctx(&self) -> bool {
+        self.contains(Self::IRQD_HANDLE_ENFORCE_IRQCTX)
+    }
+
+    pub const fn is_enabled_on_suspend(&self) -> bool {
+        self.contains(Self::IRQD_IRQ_ENABLED_ON_SUSPEND)
+    }
+
+    pub const fn is_wakeup_set(&self) -> bool {
+        self.contains(Self::IRQD_WAKEUP_STATE)
+    }
+
+    pub const fn can_move_in_process_context(&self) -> bool {
+        self.contains(Self::IRQD_MOVE_PCNTXT)
+    }
+
+    pub const fn is_irq_disabled(&self) -> bool {
+        self.contains(Self::IRQD_IRQ_DISABLED)
+    }
+
+    pub const fn is_irq_masked(&self) -> bool {
+        self.contains(Self::IRQD_IRQ_MASKED)
+    }
+
+    pub const fn is_irq_in_progress(&self) -> bool {
+        self.contains(Self::IRQD_IRQ_INPROGRESS)
+    }
+
+    pub const fn is_wakeup_armed(&self) -> bool {
+        self.contains(Self::IRQD_WAKEUP_ARMED)
+    }
+
+    pub const fn is_forwarded_to_vcpu(&self) -> bool {
+        self.contains(Self::IRQD_FORWARDED_TO_VCPU)
+    }
+
+    pub fn set_forwarded_to_vcpu(&mut self) {
+        self.insert(Self::IRQD_FORWARDED_TO_VCPU);
+    }
+
+    pub const fn is_affinity_managed(&self) -> bool {
+        self.contains(Self::IRQD_AFFINITY_MANAGED)
+    }
+
+    pub const fn is_activated(&self) -> bool {
+        self.contains(Self::IRQD_ACTIVATED)
+    }
+
+    pub fn set_activated(&mut self) {
+        self.insert(Self::IRQD_ACTIVATED);
+    }
+
+    pub fn clear_activated(&mut self) {
+        self.remove(Self::IRQD_ACTIVATED);
+    }
+
+    pub const fn is_started(&self) -> bool {
+        self.contains(Self::IRQD_IRQ_STARTED)
+    }
+
+    pub const fn is_managed_and_shutdown(&self) -> bool {
+        self.contains(Self::IRQD_MANAGED_SHUTDOWN)
+    }
+
+    pub fn set_can_reserve(&mut self) {
+        self.insert(Self::IRQD_CAN_RESERVE);
+    }
+
+    pub const fn can_reserve(&self) -> bool {
+        self.contains(Self::IRQD_CAN_RESERVE)
+    }
+
+    pub fn clear_can_reserve(&mut self) {
+        self.remove(Self::IRQD_CAN_RESERVE);
+    }
+
+    pub fn set_msi_nomask_quirk(&mut self) {
+        self.insert(Self::IRQD_MSI_NOMASK_QUIRK);
+    }
+
+    pub fn clear_msi_nomask_quirk(&mut self) {
+        self.remove(Self::IRQD_MSI_NOMASK_QUIRK);
+    }
+
+    pub const fn is_msi_nomask_quirk(&self) -> bool {
+        self.contains(Self::IRQD_MSI_NOMASK_QUIRK)
+    }
+
+    pub fn set_affinity_on_activate(&mut self) {
+        self.insert(Self::IRQD_AFFINITY_ON_ACTIVATE);
+    }
+
+    pub const fn is_affinity_on_activate(&self) -> bool {
+        self.contains(Self::IRQD_AFFINITY_ON_ACTIVATE)
+    }
+}

+ 184 - 0
kernel/src/exception/irqdomain.rs

@@ -0,0 +1,184 @@
+use core::fmt::Debug;
+
+use alloc::{
+    string::String,
+    sync::{Arc, Weak},
+    vec::Vec,
+};
+use hashbrown::HashMap;
+use system_error::SystemError;
+
+use crate::{
+    driver::{base::device::Device, open_firmware::device_node::DeviceNode},
+    libs::{rwlock::RwLock, spinlock::SpinLock},
+};
+
+use super::{
+    irqchip::{IrqChipGeneric, IrqGcFlags},
+    HardwareIrqNumber, IrqNumber,
+};
+
+/// 中断域
+///
+/// 用于把硬件中断号翻译为软件中断号的映射的对象
+///
+/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#164
+#[allow(dead_code)]
+#[derive(Debug)]
+pub struct IrqDomain {
+    /// 中断域的名字 (二选一)
+    name: Option<&'static str>,
+    allocated_name: Option<String>,
+    /// 中断域的操作
+    ops: &'static dyn IrqDomainOps,
+    inner: SpinLock<InnerIrqDomain>,
+    /// 中断号反向映射
+    revmap: RwLock<IrqDomainRevMap>,
+}
+
+#[allow(dead_code)]
+#[derive(Debug)]
+struct InnerIrqDomain {
+    /// host per irq_domain flags
+    flags: IrqDomainFlags,
+    /// The number of mapped interrupts
+    mapcount: u32,
+    bus_token: IrqDomainBusToken,
+    /// 指向 generic chip 列表的指针。
+    /// 有一个辅助函数用于为中断控制器驱动程序设置一个或
+    /// 多个 generic chip,该函数使用此指针并依赖于 generic chip 库。
+    generic_chip: Option<Arc<IrqDomainChipGeneric>>,
+    /// Pointer to a device that the domain represent, and that will be
+    /// used for power management purposes.
+    device: Option<Arc<dyn Device>>,
+    /// Pointer to parent irq_domain to support hierarchy irq_domains
+    parent: Option<Weak<IrqDomain>>,
+}
+
+impl IrqDomain {
+    #[allow(dead_code)]
+    pub fn new(
+        name: Option<&'static str>,
+        allocated_name: Option<String>,
+        ops: &'static dyn IrqDomainOps,
+        flags: IrqDomainFlags,
+        bus_token: IrqDomainBusToken,
+    ) -> Option<Arc<Self>> {
+        if name.is_none() && allocated_name.is_none() {
+            return None;
+        }
+
+        let x = IrqDomain {
+            name,
+            allocated_name,
+            ops,
+            inner: SpinLock::new(InnerIrqDomain {
+                flags,
+                mapcount: 0,
+                bus_token,
+                generic_chip: None,
+                device: None,
+                parent: None,
+            }),
+            revmap: RwLock::new(IrqDomainRevMap {
+                map: HashMap::new(),
+                hwirq_max: HardwareIrqNumber::new(0),
+            }),
+        };
+
+        return Some(Arc::new(x));
+    }
+}
+
+/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#190
+#[allow(dead_code)]
+#[derive(Debug)]
+struct IrqDomainRevMap {
+    map: HashMap<HardwareIrqNumber, IrqNumber>,
+    hwirq_max: HardwareIrqNumber,
+}
+
+bitflags! {
+    pub struct IrqDomainFlags: u32 {
+        /// Irq domain is hierarchical
+        const HIERARCHY = (1 << 0);
+        /// Irq domain name was allocated dynamically
+        const NAME_ALLOCATED = (1 << 1);
+        /// Irq domain is an IPI domain with virq per cpu
+        const IPI_PER_CPU = (1 << 2);
+        /// Irq domain is an IPI domain with single virq
+        const IPI_SINGLE = (1 << 3);
+        /// Irq domain implements MSIs
+        const MSI = (1 << 4);
+        /// Irq domain implements MSI remapping
+        const MSI_REMAP = (1 << 5);
+        /// Quirk to handle MSI implementations which do not provide masking
+        const MSI_NOMASK_QUIRK = (1 << 6);
+        /// Irq domain doesn't translate anything
+        const NO_MAP = (1 << 7);
+        /// Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
+        /// for implementation specific purposes and ignored by the core code
+        const NONCORE = (1 << 16);
+    }
+}
+
+/// 如果多个域有相同的设备节点,但服务于不同的目的(例如,一个域用于PCI/MSI,另一个用于有线IRQs),
+/// 它们可以使用特定于总线的token进行区分。预计大多数域只会携带`DomainBusAny`。
+///
+/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#78
+#[allow(dead_code)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum IrqDomainBusToken {
+    Any = 0,
+    Wired,
+    GenericMsi,
+    PciMsi,
+    PlatformMsi,
+    Nexus,
+    Ipi,
+    FslMcMsi,
+    TiSciIntaMsi,
+    Wakeup,
+    VmdMsi,
+}
+
+/// IrqDomain的操作方法
+///
+/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#107
+pub trait IrqDomainOps: Debug {
+    /// 匹配一个中断控制器设备节点到一个主机。
+    fn match_node(
+        &self,
+        irq_domain: &Arc<IrqDomain>,
+        device_node: &Arc<DeviceNode>,
+        bus_token: IrqDomainBusToken,
+    ) -> bool;
+
+    /// 创建或更新一个虚拟中断号与一个硬件中断号之间的映射。
+    /// 对于给定的映射,这只会被调用一次。
+    fn map(
+        &self,
+        irq_domain: &Arc<IrqDomain>,
+        hwirq: HardwareIrqNumber,
+        virq: IrqNumber,
+    ) -> Result<(), SystemError>;
+
+    /// 删除一个虚拟中断号与一个硬件中断号之间的映射。
+    fn unmap(&self, irq_domain: &Arc<IrqDomain>, virq: IrqNumber);
+}
+
+#[allow(dead_code)]
+#[derive(Debug)]
+pub struct IrqDomainChipGeneric {
+    inner: SpinLock<InnerIrqDomainChipGeneric>,
+}
+
+#[allow(dead_code)]
+#[derive(Debug)]
+struct InnerIrqDomainChipGeneric {
+    irqs_per_chip: u32,
+    flags_to_clear: IrqGcFlags,
+    flags_to_set: IrqGcFlags,
+    gc_flags: IrqGcFlags,
+    gc: Vec<Arc<IrqChipGeneric>>,
+}

+ 12 - 0
kernel/src/exception/mod.rs

@@ -4,6 +4,10 @@ use crate::arch::CurrentIrqArch;
 
 pub mod init;
 pub mod ipi;
+pub mod irqchip;
+pub mod irqdata;
+pub mod irqdomain;
+pub mod msi;
 pub mod softirq;
 
 /// 中断的架构相关的trait
@@ -77,3 +81,11 @@ impl Drop for IrqFlagsGuard {
         }
     }
 }
+
+// 定义中断号结构体
+// 用于表示软件逻辑视角的中断号,全局唯一
+int_like!(IrqNumber, u32);
+
+// 硬件中断号
+// 用于表示在某个IrqDomain中的中断号
+int_like!(HardwareIrqNumber, u32);

+ 126 - 0
kernel/src/exception/msi.rs

@@ -0,0 +1,126 @@
+use core::{any::Any, fmt::Debug};
+
+use alloc::sync::Arc;
+
+use crate::{
+    driver::{base::device::Device, pci::pci_irq::PciIrqMsg},
+    filesystem::sysfs::Attribute,
+    libs::spinlock::SpinLock,
+};
+
+use super::IrqNumber;
+
+#[derive(Clone, Copy)]
+pub struct MsiMsg {
+    pub address_lo: u32,
+    pub address_hi: u32,
+    pub data: u32,
+}
+
+impl Debug for MsiMsg {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(
+            f,
+            "MsiMsg {{ address_lo: 0x{:x}, address_hi: 0x{:x}, data: 0x{:x} }}",
+            self.address_lo, self.address_hi, self.data
+        )
+    }
+}
+
+#[allow(dead_code)]
+impl MsiMsg {
+    /// Create a new MSI message
+    pub const fn new(address: u64, data: u32) -> Self {
+        MsiMsg {
+            address_lo: address as u32,
+            address_hi: (address >> 32) as u32,
+            data,
+        }
+    }
+
+    /// Create a new MSI message
+    pub const fn new_lo_hi(address_lo: u32, address_hi: u32, data: u32) -> Self {
+        MsiMsg {
+            address_lo,
+            address_hi,
+            data,
+        }
+    }
+
+    /// Get the address of the MSI message
+    pub const fn address(&self) -> u64 {
+        (self.address_hi as u64) << 32 | self.address_lo as u64
+    }
+}
+
+#[allow(dead_code)]
+#[derive(Debug)]
+pub struct MsiDesc {
+    inner: SpinLock<InnerMsiDesc>,
+}
+
+#[allow(dead_code)]
+#[derive(Debug)]
+struct InnerMsiDesc {
+    /// The base interrupt number
+    irq: IrqNumber,
+    /// The number of vectors used
+    nvec_used: u32,
+    /// Pointer to the device which uses this descriptor
+    dev: Option<Arc<dyn Device>>,
+    /// The last set MSI message cached for reuse
+    msg: MsiMsg,
+    /// Pointer to sysfs device attribute
+    sysfs_attribute: Option<&'static dyn Attribute>,
+    /// Pointer to MSI callback function
+    func: Option<&'static dyn MsiDescFunc>,
+    /// The index of the MSI descriptor
+    index: u32,
+    /// PCI specific msi descriptor data
+    pci_msg: PciIrqMsg,
+}
+
+#[allow(dead_code)]
+impl MsiDesc {
+    pub const fn new(
+        irq: IrqNumber,
+        nvec_used: u32,
+        dev: Option<Arc<dyn Device>>,
+        index: u32,
+        pci_msg: PciIrqMsg,
+    ) -> Self {
+        MsiDesc {
+            inner: SpinLock::new(InnerMsiDesc {
+                irq,
+                nvec_used,
+                dev,
+                msg: MsiMsg {
+                    address_lo: 0,
+                    address_hi: 0,
+                    data: 0,
+                },
+                sysfs_attribute: None,
+                func: None,
+                index,
+                pci_msg,
+            }),
+        }
+    }
+
+    pub fn set_msg(&self, msg: MsiMsg) {
+        self.inner.lock().msg = msg;
+    }
+
+    pub fn msg(&self) -> MsiMsg {
+        self.inner.lock().msg
+    }
+}
+
+pub trait MsiDescFunc: Debug {
+    /// Callback that may be called when the MSI message
+    /// address or data changes.
+    fn write_msi_msg(&self, data: Arc<dyn MsiDescFuncData>);
+}
+
+/// Data parameter for the `MsiDescFunc` callback.
+pub trait MsiDescFuncData: Send + Sync + Any {}