Browse Source

添加irqdesc的抽象,并在系统初始化时创建irqdesc (#522)

* 添加irqdesc的抽象,并在系统初始化时创建irqdesc
LoGin 1 year ago
parent
commit
3bc96fa4a9

+ 10 - 1
kernel/src/arch/riscv64/interrupt/mod.rs

@@ -1,6 +1,6 @@
 use system_error::SystemError;
 
-use crate::exception::{InterruptArch, IrqFlags, IrqFlagsGuard};
+use crate::exception::{InterruptArch, IrqFlags, IrqFlagsGuard, IrqNumber};
 
 pub mod ipi;
 
@@ -35,6 +35,15 @@ impl InterruptArch for RiscV64InterruptArch {
             riscv::register::sstatus::clear_sie();
         }
     }
+
+    fn probe_total_irq_num() -> u32 {
+        // todo: 获取中断总数
+        256
+    }
+
+    fn ack_bad_irq(irq: IrqNumber) {
+        todo!("ack_bad_irq: {}", irq.data());
+    }
 }
 
 /// 中断栈帧结构体

+ 13 - 1
kernel/src/arch/x86_64/interrupt/mod.rs

@@ -12,7 +12,8 @@ use system_error::SystemError;
 
 use crate::{
     arch::CurrentIrqArch,
-    exception::{InterruptArch, IrqFlags, IrqFlagsGuard},
+    exception::{InterruptArch, IrqFlags, IrqFlagsGuard, IrqNumber},
+    kerror,
 };
 
 use self::entry::setup_interrupt_gate;
@@ -78,6 +79,17 @@ impl InterruptArch for X86_64InterruptArch {
         local_irq_restore(flags.flags());
         compiler_fence(Ordering::SeqCst);
     }
+
+    fn probe_total_irq_num() -> u32 {
+        // todo: 从APIC获取
+        // 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/arch/x86/kernel/apic/vector.c?r=&mo=19514&fi=704#704
+        256
+    }
+
+    fn ack_bad_irq(irq: IrqNumber) {
+        kerror!("Unexpected IRQ trap at vector {}", irq.data());
+        CurrentApic.send_eoi();
+    }
 }
 
 /// 中断栈帧结构体

+ 42 - 0
kernel/src/driver/base/device/mod.rs

@@ -873,3 +873,45 @@ impl DeviceMatcher<&str> for DeviceMatchName {
         return device.name() == data;
     }
 }
+
+/// Cookie to identify the device
+#[derive(Debug, Clone)]
+pub struct DeviceId {
+    data: Option<&'static str>,
+    allocated: Option<String>,
+}
+
+impl DeviceId {
+    #[allow(dead_code)]
+    pub fn new(data: Option<&'static str>, allocated: Option<String>) -> Option<Self> {
+        if data.is_none() && allocated.is_none() {
+            return None;
+        }
+
+        // 如果data和allocated都有值,那么返回None
+        if data.is_some() && allocated.is_some() {
+            return None;
+        }
+
+        return Some(Self { data, allocated });
+    }
+
+    pub fn id(&self) -> Option<&str> {
+        if self.data.is_some() {
+            return Some(self.data.unwrap());
+        } else {
+            return self.allocated.as_deref();
+        }
+    }
+
+    pub fn set_allocated(&mut self, allocated: String) {
+        self.allocated = Some(allocated);
+        self.data = None;
+    }
+}
+
+impl PartialEq for DeviceId {
+    fn eq(&self, other: &Self) -> bool {
+        return self.id() == other.id();
+    }
+}

+ 111 - 0
kernel/src/exception/dummychip.rs

@@ -0,0 +1,111 @@
+use alloc::sync::Arc;
+use system_error::SystemError;
+
+use crate::arch::CurrentIrqArch;
+
+use super::{
+    irqchip::{IrqChip, IrqChipFlags},
+    irqdata::IrqData,
+    InterruptArch,
+};
+
+static mut NO_IRQ_CHIP: Option<Arc<NoIrqChip>> = None;
+static mut DUMMY_IRQ_CHIP: Option<Arc<DummyIrqChip>> = None;
+
+#[inline(never)]
+pub fn no_irq_chip() -> Arc<dyn IrqChip> {
+    unsafe { NO_IRQ_CHIP.as_ref().unwrap().clone() }
+}
+
+#[allow(dead_code)]
+#[inline(never)]
+pub fn dummy_irq_chip() -> Arc<dyn IrqChip> {
+    unsafe { DUMMY_IRQ_CHIP.as_ref().unwrap().clone() }
+}
+
+fn ack_bad(irq_data: &Arc<IrqData>) {
+    // todo: print_irq_desc
+    CurrentIrqArch::ack_bad_irq(irq_data.irq());
+}
+
+#[derive(Debug)]
+struct NoIrqChip;
+
+impl NoIrqChip {
+    pub const fn new() -> Self {
+        NoIrqChip
+    }
+}
+
+impl IrqChip for NoIrqChip {
+    fn name(&self) -> &'static str {
+        "none"
+    }
+    fn irq_enable(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
+        Ok(())
+    }
+
+    fn irq_disable(&self, _irq: &Arc<IrqData>) {}
+
+    fn irq_ack(&self, irq: &Arc<IrqData>) {
+        ack_bad(irq);
+    }
+
+    fn irq_startup(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
+        Ok(())
+    }
+
+    fn irq_shutdown(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
+        Ok(())
+    }
+
+    fn flags(&self) -> IrqChipFlags {
+        IrqChipFlags::IRQCHIP_SKIP_SET_WAKE
+    }
+}
+
+#[derive(Debug)]
+struct DummyIrqChip;
+
+impl DummyIrqChip {
+    pub const fn new() -> Self {
+        DummyIrqChip
+    }
+}
+
+impl IrqChip for DummyIrqChip {
+    fn name(&self) -> &'static str {
+        "dummy"
+    }
+
+    fn irq_enable(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
+        Ok(())
+    }
+
+    fn irq_disable(&self, _irq: &Arc<IrqData>) {}
+
+    fn irq_ack(&self, _irq: &Arc<IrqData>) {}
+
+    fn irq_mask(&self, _irq: &Arc<IrqData>) {}
+    fn irq_unmask(&self, _irq: &Arc<IrqData>) {}
+
+    fn irq_startup(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
+        Ok(())
+    }
+
+    fn irq_shutdown(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
+        Ok(())
+    }
+
+    fn flags(&self) -> IrqChipFlags {
+        IrqChipFlags::IRQCHIP_SKIP_SET_WAKE
+    }
+}
+
+#[inline(never)]
+pub fn dummy_chip_init() {
+    unsafe {
+        NO_IRQ_CHIP = Some(Arc::new(NoIrqChip::new()));
+        DUMMY_IRQ_CHIP = Some(Arc::new(DummyIrqChip::new()));
+    }
+}

+ 27 - 0
kernel/src/exception/handle.rs

@@ -0,0 +1,27 @@
+use alloc::sync::Arc;
+
+use crate::arch::CurrentIrqArch;
+
+use super::{
+    irqdesc::{IrqDesc, IrqFlowHandler},
+    InterruptArch,
+};
+
+/// 获取用于处理错误的中断的处理程序
+#[inline(always)]
+pub fn bad_irq_handler() -> &'static dyn IrqFlowHandler {
+    &HandleBadIrq
+}
+
+/// handle spurious and unhandled irqs
+#[derive(Debug)]
+struct HandleBadIrq;
+
+impl IrqFlowHandler for HandleBadIrq {
+    /// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/handle.c?fi=handle_bad_irq#33
+    fn handle(&self, irq_desc: &Arc<IrqDesc>) {
+        // todo: print_irq_desc
+        // todo: 增加kstat计数
+        CurrentIrqArch::ack_bad_irq(irq_desc.irq());
+    }
+}

+ 4 - 1
kernel/src/exception/init.rs

@@ -2,13 +2,16 @@ use system_error::SystemError;
 
 use crate::arch::CurrentIrqArch;
 
-use super::InterruptArch;
+use super::{dummychip::dummy_chip_init, irqdesc::early_irq_init, InterruptArch};
 
 /// 初始化中断
 #[inline(never)]
 pub fn irq_init() -> Result<(), SystemError> {
     // todo: 通用初始化
 
+    dummy_chip_init();
+    early_irq_init().expect("early_irq_init failed");
+
     // 初始化架构相关的中断
     unsafe { CurrentIrqArch::arch_irq_init() }?;
     return Ok(());

+ 43 - 11
kernel/src/exception/irqchip.rs

@@ -41,18 +41,18 @@ pub trait IrqChip: Sync + Send + Any + Debug {
     fn irq_ack(&self, irq: &Arc<IrqData>);
 
     /// mask an interrupt source
-    fn irq_mask(&self, irq: &Arc<IrqData>);
+    fn irq_mask(&self, _irq: &Arc<IrqData>) {}
     /// ack and mask an interrupt source
-    fn irq_mask_ack(&self, irq: &Arc<IrqData>);
+    fn irq_mask_ack(&self, _irq: &Arc<IrqData>) {}
     /// unmask an interrupt source
-    fn irq_unmask(&self, irq: &Arc<IrqData>);
+    fn irq_unmask(&self, _irq: &Arc<IrqData>) {}
     /// end of interrupt
-    fn irq_eoi(&self, irq: &Arc<IrqData>);
+    fn irq_eoi(&self, _irq: &Arc<IrqData>) {}
 
     // todo: set affinity
 
     /// retrigger an IRQ to the CPU
-    fn retrigger(&self, irq: &Arc<IrqData>);
+    fn retrigger(&self, _irq: &Arc<IrqData>) {}
 
     /// set the flow type of an interrupt
     ///
@@ -83,14 +83,14 @@ pub trait IrqChip: Sync + Send + Any + Debug {
 
     /// function called from core code on suspend once per
     /// chip, when one or more interrupts are installed
-    fn irq_suspend(&self, irq: &Arc<IrqData>);
+    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>);
+    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>);
+    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>) {}
@@ -135,7 +135,7 @@ pub trait IrqChip: Sync + Send + Any + Debug {
     // todo: set vcpu affinity
 
     /// send a single IPI to destination cpus
-    fn send_single_ipi(&self, irq: &Arc<IrqData>, cpu: u32);
+    fn send_single_ipi(&self, _irq: &Arc<IrqData>, _cpu: u32) {}
 
     // todo: send ipi with cpu mask
 
@@ -145,7 +145,9 @@ pub trait IrqChip: Sync + Send + Any + Debug {
     }
 
     /// function called from core code after disabling an NMI
-    fn irq_nmi_teardown(&self, irq: &Arc<IrqData>);
+    fn irq_nmi_teardown(&self, _irq: &Arc<IrqData>) {}
+
+    fn flags(&self) -> IrqChipFlags;
 }
 
 #[allow(dead_code)]
@@ -214,7 +216,7 @@ struct InnerIrqChipGeneric {
     chip_types: Vec<IrqChipType>,
 }
 
-pub trait IrqChipGenericOps: Debug {
+pub trait IrqChipGenericOps: Debug + Send + Sync {
     /// Alternate I/O accessor (defaults to readl if NULL)
     unsafe fn reg_readl(&self, addr: VirtAddr) -> u32;
 
@@ -237,3 +239,33 @@ pub trait IrqChipGenericPrivateData: Sync + Send + Any + Debug {}
 pub struct IrqChipType {
     // todo https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#1024
 }
+
+bitflags! {
+    /// IrqChip specific flags
+    pub struct IrqChipFlags: u32 {
+        /// 在调用chip.irq_set_type()之前屏蔽
+        const IRQCHIP_SET_TYPE_MASKED = 1 << 0;
+        /// 只有在irq被处理时才发出irq_eoi()
+        const IRQCHIP_EOI_IF_HANDLED = 1 << 1;
+        /// 在挂起路径中屏蔽非唤醒irq
+        const IRQCHIP_MASK_ON_SUSPEND = 1 << 2;
+        /// 只有在irq启用时才调用irq_on/off_line回调
+        const IRQCHIP_ONOFFLINE_ENABLED = 1 << 3;
+        /// 跳过chip.irq_set_wake(),对于这个irq芯片
+        const IRQCHIP_SKIP_SET_WAKE = 1 << 4;
+        /// 单次触发不需要屏蔽/取消屏蔽
+        const IRQCHIP_ONESHOT_SAFE = 1 << 5;
+        /// 芯片在线程模式下需要在取消屏蔽时eoi()
+        const IRQCHIP_EOI_THREADED = 1 << 6;
+        /// 芯片可以为Level MSIs提供两个门铃
+        const IRQCHIP_SUPPORTS_LEVEL_MSI = 1 << 7;
+        /// 芯片可以传递NMIs,仅适用于根irqchips
+        const IRQCHIP_SUPPORTS_NMI = 1 << 8;
+        /// 在挂起路径中,如果它们处于禁用状态,则调用__enable_irq()/__disable_irq()以唤醒irq
+        const IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND = 1 << 9;
+        /// 在启动前更新默认亲和性
+        const IRQCHIP_AFFINITY_PRE_STARTUP = 1 << 10;
+        /// 不要在这个芯片中改变任何东西
+        const IRQCHIP_IMMUTABLE = 1 << 11;
+    }
+}

+ 77 - 3
kernel/src/exception/irqdata.rs

@@ -21,6 +21,50 @@ use super::{
 pub struct IrqData {
     /// 中断号, 用于表示软件逻辑视角的中断号,全局唯一
     irq: IrqNumber,
+    inner: SpinLock<InnerIrqData>,
+}
+
+impl IrqData {
+    pub fn new(
+        irq: IrqNumber,
+        hwirq: HardwareIrqNumber,
+        common_data: Arc<IrqCommonData>,
+        chip: Arc<dyn IrqChip>,
+    ) -> Self {
+        return IrqData {
+            irq,
+            inner: SpinLock::new(InnerIrqData {
+                hwirq,
+                common_data,
+                chip,
+                chip_data: None,
+                domain: None,
+                parent_data: None,
+            }),
+        };
+    }
+
+    pub fn irqd_set(&self, status: IrqStatus) {
+        // clone是为了释放inner锁
+        let common_data = self.inner.lock().common_data.clone();
+        common_data.irqd_set(status);
+    }
+
+    #[allow(dead_code)]
+    pub fn irqd_clear(&self, status: IrqStatus) {
+        // clone是为了释放inner锁
+        let common_data = self.inner.lock().common_data.clone();
+        common_data.irqd_clear(status);
+    }
+
+    pub fn irq(&self) -> IrqNumber {
+        self.irq
+    }
+}
+
+#[allow(dead_code)]
+#[derive(Debug)]
+struct InnerIrqData {
     /// 硬件中断号, 用于表示在某个IrqDomain中的中断号
     hwirq: HardwareIrqNumber,
     /// 涉及的所有irqchip之间共享的数据
@@ -28,9 +72,9 @@ pub struct IrqData {
     /// 绑定到的中断芯片
     chip: Arc<dyn IrqChip>,
     /// 中断芯片的私有数据(与当前irq相关)
-    chip_data: Arc<dyn IrqChipData>,
+    chip_data: Option<Arc<dyn IrqChipData>>,
     /// 中断域
-    domain: Arc<IrqDomain>,
+    domain: Option<Arc<IrqDomain>>,
     /// 中断的父中断(如果具有中断域继承的话)
     parent_data: Option<Weak<IrqData>>,
 }
@@ -38,12 +82,32 @@ pub struct 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>,
 }
 
+impl IrqCommonData {
+    pub fn new() -> Self {
+        let inner = InnerIrqCommonData {
+            state: IrqStatus::empty(),
+            handler_data: None,
+            msi_desc: None,
+        };
+        return IrqCommonData {
+            inner: SpinLock::new(inner),
+        };
+    }
+
+    pub fn irqd_set(&self, status: IrqStatus) {
+        self.inner.lock_irqsave().irqd_set(status);
+    }
+
+    pub fn irqd_clear(&self, status: IrqStatus) {
+        self.inner.lock_irqsave().irqd_clear(status);
+    }
+}
+
 #[allow(dead_code)]
 #[derive(Debug)]
 struct InnerIrqCommonData {
@@ -55,6 +119,16 @@ struct InnerIrqCommonData {
     // todo: affinity
 }
 
+impl InnerIrqCommonData {
+    pub fn irqd_set(&mut self, status: IrqStatus) {
+        self.state.insert(status);
+    }
+
+    pub fn irqd_clear(&mut self, status: IrqStatus) {
+        self.state.remove(status);
+    }
+}
+
 pub trait IrqHandlerData: Send + Sync + Any + Debug {}
 
 bitflags! {

+ 294 - 0
kernel/src/exception/irqdesc.rs

@@ -0,0 +1,294 @@
+use core::{any::Any, fmt::Debug};
+
+use alloc::{
+    collections::BTreeMap,
+    string::String,
+    sync::{Arc, Weak},
+    vec::Vec,
+};
+use system_error::SystemError;
+
+use crate::{
+    arch::CurrentIrqArch,
+    driver::base::{
+        device::DeviceId,
+        kobject::{KObjType, KObject, KObjectState, LockedKObjectState},
+        kset::KSet,
+    },
+    filesystem::kernfs::KernFSInode,
+    libs::{
+        rwlock::{RwLockReadGuard, RwLockWriteGuard},
+        spinlock::{SpinLock, SpinLockGuard},
+    },
+    process::ProcessControlBlock,
+};
+
+use super::{
+    dummychip::no_irq_chip,
+    handle::bad_irq_handler,
+    irqdata::{IrqCommonData, IrqData, IrqStatus},
+    sysfs::IrqKObjType,
+    HardwareIrqNumber, InterruptArch, IrqNumber,
+};
+
+/// 中断流处理程序
+pub trait IrqFlowHandler: Debug + Send + Sync {
+    fn handle(&self, irq_desc: &Arc<IrqDesc>);
+}
+
+/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdesc.h#55
+#[derive(Debug)]
+pub struct IrqDesc {
+    inner: SpinLock<InnerIrqDesc>,
+
+    handler: SpinLock<Option<&'static dyn IrqFlowHandler>>,
+
+    kobj_state: LockedKObjectState,
+}
+
+impl IrqDesc {
+    #[inline(never)]
+    pub fn new(irq: IrqNumber, name: Option<String>, irqd_flags: IrqStatus) -> Arc<Self> {
+        // 初始化的过程参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdesc.c#392
+        let common_data = Arc::new(IrqCommonData::new());
+        let irq_data = Arc::new(IrqData::new(
+            irq,
+            HardwareIrqNumber::new(irq.data()),
+            common_data.clone(),
+            no_irq_chip(),
+        ));
+
+        irq_data.irqd_set(IrqStatus::IRQD_IRQ_DISABLED);
+        common_data.irqd_set(IrqStatus::IRQD_IRQ_MASKED);
+
+        let irq_desc = IrqDesc {
+            inner: SpinLock::new(InnerIrqDesc {
+                common_data,
+                irq_data,
+                actions: Vec::new(),
+                name,
+                parent_irq: None,
+                depth: 1,
+                wake_depth: 0,
+                kern_inode: None,
+                kset: None,
+                parent_kobj: None,
+            }),
+            handler: SpinLock::new(None),
+            kobj_state: LockedKObjectState::new(Some(KObjectState::INITIALIZED)),
+        };
+
+        irq_desc.set_handler(bad_irq_handler());
+        irq_desc.inner().irq_data.irqd_set(irqd_flags);
+
+        return Arc::new(irq_desc);
+    }
+
+    pub fn set_handler(&self, handler: &'static dyn IrqFlowHandler) {
+        let mut guard = self.handler.lock_irqsave();
+        *guard = Some(handler);
+    }
+
+    fn inner(&self) -> SpinLockGuard<InnerIrqDesc> {
+        self.inner.lock_irqsave()
+    }
+
+    pub fn irq(&self) -> IrqNumber {
+        self.inner().irq_data.irq()
+    }
+}
+
+#[allow(dead_code)]
+#[derive(Debug)]
+struct InnerIrqDesc {
+    /// per irq and chip data passed down to chip functions
+    common_data: Arc<IrqCommonData>,
+    irq_data: Arc<IrqData>,
+    actions: Vec<Arc<IrqAction>>,
+    name: Option<String>,
+    parent_irq: Option<IrqNumber>,
+    /// nested irq disables
+    depth: u32,
+    /// nested wake enables
+    wake_depth: u32,
+
+    kern_inode: Option<Arc<KernFSInode>>,
+    kset: Option<Arc<KSet>>,
+    parent_kobj: Option<Weak<dyn KObject>>,
+}
+
+impl KObject for IrqDesc {
+    fn as_any_ref(&self) -> &dyn Any {
+        self
+    }
+
+    fn set_inode(&self, inode: Option<Arc<KernFSInode>>) {
+        self.inner().kern_inode = inode;
+    }
+
+    fn inode(&self) -> Option<Arc<KernFSInode>> {
+        self.inner().kern_inode.clone()
+    }
+
+    fn parent(&self) -> Option<Weak<dyn KObject>> {
+        self.inner().parent_kobj.clone()
+    }
+
+    fn set_parent(&self, parent: Option<Weak<dyn KObject>>) {
+        self.inner().parent_kobj = parent;
+    }
+
+    fn kset(&self) -> Option<Arc<KSet>> {
+        self.inner().kset.clone()
+    }
+
+    fn set_kset(&self, kset: Option<Arc<KSet>>) {
+        self.inner().kset = kset;
+    }
+
+    fn kobj_type(&self) -> Option<&'static dyn KObjType> {
+        Some(&IrqKObjType)
+    }
+
+    fn set_kobj_type(&self, _ktype: Option<&'static dyn KObjType>) {}
+
+    fn name(&self) -> String {
+        self.inner().name.clone().unwrap_or_else(|| format!(""))
+    }
+
+    fn set_name(&self, _name: String) {}
+
+    fn kobj_state(&self) -> RwLockReadGuard<KObjectState> {
+        self.kobj_state.read()
+    }
+
+    fn kobj_state_mut(&self) -> RwLockWriteGuard<KObjectState> {
+        self.kobj_state.write()
+    }
+
+    fn set_kobj_state(&self, state: KObjectState) {
+        *self.kobj_state_mut() = state;
+    }
+}
+
+/// 每个中断的响应动作的描述符
+/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/interrupt.h#118
+#[allow(dead_code)]
+#[derive(Debug)]
+pub struct IrqAction {
+    inner: SpinLock<InnerIrqAction>,
+}
+
+impl IrqAction {
+    #[allow(dead_code)]
+    pub fn new(
+        irq: IrqNumber,
+        name: String,
+        handler: Option<&'static dyn IrqFlowHandler>,
+    ) -> Arc<Self> {
+        let action = IrqAction {
+            inner: SpinLock::new(InnerIrqAction {
+                dev_id: None,
+                handler,
+                thread_fn: None,
+                thread: None,
+                secondary: None,
+                irq,
+                flags: IrqHandleFlags::empty(),
+                name,
+            }),
+        };
+
+        return Arc::new(action);
+    }
+}
+
+#[allow(dead_code)]
+#[derive(Debug)]
+struct InnerIrqAction {
+    /// cookie to identify the device
+    dev_id: Option<DeviceId>,
+    /// 中断处理程序
+    handler: Option<&'static dyn IrqFlowHandler>,
+    /// interrupt handler function for threaded interrupts
+    thread_fn: Option<&'static dyn IrqFlowHandler>,
+    /// thread pointer for threaded interrupts
+    thread: Option<Arc<ProcessControlBlock>>,
+    /// pointer to secondary irqaction (force threading)
+    secondary: Option<Arc<IrqAction>>,
+    /// 中断号
+    irq: IrqNumber,
+    flags: IrqHandleFlags,
+    /// name of the device
+    name: String,
+}
+
+// 定义IrqFlags位标志
+bitflags! {
+    /// 这些标志仅由内核在中断处理例程中使用。
+    pub struct IrqHandleFlags: u32 {
+        /// IRQF_SHARED - 允许多个设备共享中断
+        const IRQF_SHARED = 0x00000080;
+        /// IRQF_PROBE_SHARED - 当预期出现共享不匹配时,由调用者设置
+        const IRQF_PROBE_SHARED = 0x00000100;
+        /// IRQF_TIMER - 标记此中断为定时器中断
+        const __IRQF_TIMER = 0x00000200;
+        /// IRQF_PERCPU - 中断是每个CPU的
+        const IRQF_PERCPU = 0x00000400;
+        /// IRQF_NOBALANCING - 将此中断从中断平衡中排除
+        const IRQF_NOBALANCING = 0x00000800;
+        /// IRQF_IRQPOLL - 中断用于轮询(出于性能原因,只有在共享中断中首次注册的中断会被考虑)
+        const IRQF_IRQPOLL = 0x00001000;
+        /// IRQF_ONESHOT - 在硬中断处理程序完成后,不会重新启用中断。由需要在运行线程处理程序之前保持中断线路禁用的线程中断使用。
+        const IRQF_ONESHOT = 0x00002000;
+        /// IRQF_NO_SUSPEND - 在挂起期间不禁用此IRQ。不能保证此中断会从挂起状态唤醒系统。
+        const IRQF_NO_SUSPEND = 0x00004000;
+        /// IRQF_FORCE_RESUME - 即使设置了IRQF_NO_SUSPEND,也强制在恢复时启用它
+        const IRQF_FORCE_RESUME = 0x00008000;
+        /// IRQF_NO_THREAD - 中断不能被线程化
+        const IRQF_NO_THREAD = 0x00010000;
+        /// IRQF_EARLY_RESUME - 在syscore而不是在设备恢复时间早期恢复IRQ。
+        const IRQF_EARLY_RESUME = 0x00020000;
+        /// IRQF_COND_SUSPEND - 如果IRQ与NO_SUSPEND用户共享,则在挂起中断后执行此中断处理程序。对于系统唤醒设备用户,需要在他们的中断处理程序中实现唤醒检测。
+        const IRQF_COND_SUSPEND = 0x00040000;
+        /// IRQF_NO_AUTOEN - 当用户请求时,不会自动启用IRQ或NMI。用户稍后会通过enable_irq()或enable_nmi()显式启用它。
+        const IRQF_NO_AUTOEN = 0x00080000;
+        /// IRQF_NO_DEBUG - 从IPI和类似处理程序的逃逸检测中排除,取决于IRQF_PERCPU。
+        const IRQF_NO_DEBUG = 0x00100000;
+        const IRQF_TIMER = Self::__IRQF_TIMER.bits | Self::IRQF_NO_SUSPEND.bits | Self::IRQF_NO_THREAD.bits;
+    }
+}
+
+#[inline(never)]
+pub(super) fn early_irq_init() -> Result<(), SystemError> {
+    let irqcnt = CurrentIrqArch::probe_total_irq_num();
+    let mut manager = IrqDescManager::new();
+    for i in 0..irqcnt {
+        let irq_desc = IrqDesc::new(IrqNumber::new(i), None, IrqStatus::empty());
+        manager.insert(IrqNumber::new(i), irq_desc);
+    }
+
+    return CurrentIrqArch::arch_early_irq_init();
+}
+
+pub(super) struct IrqDescManager {
+    irq_descs: BTreeMap<IrqNumber, Arc<IrqDesc>>,
+}
+
+impl IrqDescManager {
+    fn new() -> Self {
+        IrqDescManager {
+            irq_descs: BTreeMap::new(),
+        }
+    }
+
+    /// 查找中断描述符
+    #[allow(dead_code)]
+    pub fn lookup(&self, irq: IrqNumber) -> Option<Arc<IrqDesc>> {
+        self.irq_descs.get(&irq).map(|desc| desc.clone())
+    }
+
+    fn insert(&mut self, irq: IrqNumber, desc: Arc<IrqDesc>) {
+        self.irq_descs.insert(irq, desc);
+    }
+}

+ 1 - 1
kernel/src/exception/irqdomain.rs

@@ -145,7 +145,7 @@ pub enum IrqDomainBusToken {
 /// IrqDomain的操作方法
 ///
 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#107
-pub trait IrqDomainOps: Debug {
+pub trait IrqDomainOps: Debug + Send + Sync {
     /// 匹配一个中断控制器设备节点到一个主机。
     fn match_node(
         &self,

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

@@ -2,13 +2,17 @@ use system_error::SystemError;
 
 use crate::arch::CurrentIrqArch;
 
+pub mod dummychip;
+pub mod handle;
 pub mod init;
 pub mod ipi;
 pub mod irqchip;
 pub mod irqdata;
+pub mod irqdesc;
 pub mod irqdomain;
 pub mod msi;
 pub mod softirq;
+pub mod sysfs;
 
 /// 中断的架构相关的trait
 pub trait InterruptArch: Send + Sync {
@@ -24,6 +28,16 @@ pub trait InterruptArch: Send + Sync {
     /// 保存当前中断状态,并且禁止中断
     unsafe fn save_and_disable_irq() -> IrqFlagsGuard;
     unsafe fn restore_irq(flags: IrqFlags);
+
+    /// 检测系统支持的中断总数
+    fn probe_total_irq_num() -> u32;
+
+    fn arch_early_irq_init() -> Result<(), SystemError> {
+        Ok(())
+    }
+
+    /// 响应未注册的中断
+    fn ack_bad_irq(irq: IrqNumber);
 }
 
 #[derive(Debug, Clone, Copy)]

+ 1 - 1
kernel/src/exception/msi.rs

@@ -116,7 +116,7 @@ impl MsiDesc {
     }
 }
 
-pub trait MsiDescFunc: Debug {
+pub trait MsiDescFunc: Debug + Send + Sync {
     /// Callback that may be called when the MSI message
     /// address or data changes.
     fn write_msi_msg(&self, data: Arc<dyn MsiDescFuncData>);

+ 65 - 0
kernel/src/exception/sysfs.rs

@@ -0,0 +1,65 @@
+use alloc::sync::Arc;
+use system_error::SystemError;
+use unified_init::macros::unified_init;
+
+use crate::{
+    driver::base::kobject::{KObjType, KObject, KObjectSysFSOps},
+    filesystem::{
+        sysfs::{Attribute, AttributeGroup, SysFSOps},
+        vfs::syscall::ModeType,
+    },
+    init::initcall::INITCALL_POSTCORE,
+};
+
+/// 中断描述符的kobjtype
+///
+/// https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdesc.c#280
+#[derive(Debug)]
+pub(super) struct IrqKObjType;
+
+impl KObjType for IrqKObjType {
+    fn sysfs_ops(&self) -> Option<&dyn SysFSOps> {
+        Some(&KObjectSysFSOps)
+    }
+
+    fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
+        Some(&[&IrqAttrGroup])
+    }
+
+    fn release(&self, _kobj: Arc<dyn KObject>) {
+
+        // https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdesc.c#428
+    }
+}
+
+#[derive(Debug)]
+struct IrqAttrGroup;
+
+impl AttributeGroup for IrqAttrGroup {
+    fn name(&self) -> Option<&str> {
+        None
+    }
+
+    fn attrs(&self) -> &[&'static dyn Attribute] {
+        todo!("irq_attr_group.attrs")
+        // todo: https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdesc.c#268
+    }
+
+    fn is_visible(
+        &self,
+        _kobj: Arc<dyn KObject>,
+        attr: &'static dyn Attribute,
+    ) -> Option<ModeType> {
+        Some(attr.mode())
+    }
+}
+
+/// 初始化irq模块在sysfs中的目录
+///
+/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdesc.c#313
+#[unified_init(INITCALL_POSTCORE)]
+fn irq_sysfs_init() -> Result<(), SystemError> {
+    // todo!("irq_sysfs_init");
+    kwarn!("Unimplemented: irq_sysfs_init");
+    Ok(())
+}