Explorar o código

feat:(riscv/intr) 实现riscv plic驱动,能处理外部中断 (#799)

* feat:(riscv/intr) 实现riscv plic驱动,能处理外部中断

- 实现riscv plic驱动,能处理外部中断
- 能收到virtio-blk的中断
- 实现fasteoi interrupt handler
LoGin hai 2 semanas
pai
achega
0102d69fdd

+ 2 - 2
kernel/Cargo.toml

@@ -47,8 +47,8 @@ num-traits = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/num
 smoltcp = { version = "=0.11.0", default-features = false, features = ["log", "alloc",  "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "socket-dhcpv4", "socket-dns", "proto-ipv4", "proto-ipv6"]}
 system_error = { path = "crates/system_error" }
 unified-init = { path = "crates/unified-init" }
-virtio-drivers = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/virtio-drivers", rev = "448a781" }
-fdt = "=0.1.5"
+virtio-drivers = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/virtio-drivers", rev = "f91c807965" }
+fdt = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/fdt", rev = "9862813020" }
 uefi = { version = "=0.26.0", features = ["alloc"] }
 uefi-raw = "=0.5.0"
 paste = "=1.0.14"

+ 16 - 2
kernel/crates/bitmap/src/alloc_bitmap.rs

@@ -20,6 +20,12 @@ impl AllocBitmap {
             core: BitMapCore::new(),
         }
     }
+
+    pub fn bitand_assign(&mut self, rhs: &Self) {
+        for i in 0..rhs.data.len() {
+            self.data[i] &= rhs.data[i];
+        }
+    }
 }
 
 impl BitMapOps<usize> for AllocBitmap {
@@ -111,8 +117,8 @@ impl BitMapOps<usize> for AllocBitmap {
     }
 }
 
-impl BitAnd for AllocBitmap {
-    type Output = Self;
+impl BitAnd for &AllocBitmap {
+    type Output = AllocBitmap;
 
     fn bitand(self, rhs: Self) -> Self::Output {
         let mut result = AllocBitmap::new(self.elements);
@@ -122,3 +128,11 @@ impl BitAnd for AllocBitmap {
         result
     }
 }
+
+impl BitAnd for AllocBitmap {
+    type Output = AllocBitmap;
+
+    fn bitand(self, rhs: Self) -> Self::Output {
+        &self & &rhs
+    }
+}

+ 20 - 0
kernel/crates/bitmap/tests/alloc-bitmap.rs

@@ -663,3 +663,23 @@ fn test_alloc_bitmap_bitand_128() {
     assert_eq!(bitmap3.first_false_index(), Some(2));
     assert_eq!(bitmap3.last_index(), Some(67));
 }
+
+#[test]
+fn test_alloc_bitmap_bitand_assign_128() {
+    let mut bitmap = AllocBitmap::new(128);
+    bitmap.set_all(true);
+
+    let mut bitmap2 = AllocBitmap::new(128);
+
+    bitmap2.set(0, true);
+    bitmap2.set(1, true);
+    bitmap2.set(67, true);
+
+    bitmap.bitand_assign(&bitmap2);
+
+    assert_eq!(bitmap.len(), 128);
+    assert_eq!(bitmap.size(), 16);
+    assert_eq!(bitmap.first_index(), Some(0));
+    assert_eq!(bitmap.first_false_index(), Some(2));
+    assert_eq!(bitmap.last_index(), Some(67));
+}

+ 1 - 0
kernel/src/arch/riscv64/asm/bitops.rs

@@ -4,6 +4,7 @@
 /// @param x 目标u64
 /// @return i32 bit-number(0..63) of the first (least significant) zero bit.
 #[inline]
+#[allow(dead_code)]
 pub fn ffz(x: u64) -> i32 {
     (!x).trailing_zeros() as i32
 }

+ 0 - 1
kernel/src/arch/riscv64/driver/of.rs

@@ -3,7 +3,6 @@ use system_error::SystemError;
 use crate::{
     driver::open_firmware::fdt::OpenFirmwareFdtDriver,
     init::boot_params,
-    kdebug,
     libs::align::page_align_up,
     mm::{mmio_buddy::mmio_pool, MemoryManagementArch, PhysAddr},
 };

+ 1 - 3
kernel/src/arch/riscv64/interrupt/entry.rs

@@ -1,7 +1,5 @@
 use crate::arch::{
-    asm::csr::{
-        CSR_SCAUSE, CSR_SEPC, CSR_SSCRATCH, CSR_SSTATUS, CSR_STVAL, SR_FS_VS, SR_SPP, SR_SUM,
-    },
+    asm::csr::{CSR_SCAUSE, CSR_SEPC, CSR_SSCRATCH, CSR_SSTATUS, CSR_STVAL, SR_SPP},
     cpu::LocalContext,
     interrupt::TrapFrame,
 };

+ 1 - 3
kernel/src/arch/riscv64/interrupt/handle.rs

@@ -5,9 +5,7 @@ use core::hint::spin_loop;
 
 use system_error::SystemError;
 
-use crate::{
-    arch::syscall::syscall_handler, driver::irqchip::riscv_intc::riscv_intc_irq, kdebug, kerror,
-};
+use crate::{arch::syscall::syscall_handler, driver::irqchip::riscv_intc::riscv_intc_irq, kerror};
 
 use super::TrapFrame;
 

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

@@ -2,7 +2,7 @@ use riscv::register::{scause::Scause, sstatus::Sstatus};
 use system_error::SystemError;
 
 use crate::{
-    driver::irqchip::riscv_intc::riscv_intc_init,
+    driver::irqchip::{riscv_intc::riscv_intc_init, riscv_sifive_plic::riscv_sifive_plic_init},
     exception::{InterruptArch, IrqFlags, IrqFlagsGuard, IrqNumber},
     libs::align::align_up,
 };
@@ -17,6 +17,9 @@ pub struct RiscV64InterruptArch;
 
 impl InterruptArch for RiscV64InterruptArch {
     unsafe fn arch_irq_init() -> Result<(), SystemError> {
+        Self::interrupt_disable();
+        riscv_sifive_plic_init()?;
+        // 注意,intc的初始化必须在plic之后,不然会导致plic无法关联上中断
         riscv_intc_init()?;
 
         Ok(())

+ 2 - 0
kernel/src/arch/riscv64/mm/mod.rs

@@ -43,6 +43,7 @@ pub struct RiscV64MMArch;
 
 impl RiscV64MMArch {
     /// 使远程cpu的TLB中,指定地址范围的页失效
+    #[allow(dead_code)]
     pub fn remote_invalidate_page(
         cpu: ProcessorId,
         address: VirtAddr,
@@ -57,6 +58,7 @@ impl RiscV64MMArch {
     }
 
     /// 使指定远程cpu的TLB中,所有范围的页失效
+    #[allow(dead_code)]
     pub fn remote_invalidate_all(cpu: ProcessorId) -> Result<(), SbiRet> {
         let r = Self::remote_invalidate_page(
             cpu,

+ 8 - 1
kernel/src/arch/x86_64/driver/apic/lapic_vector.rs

@@ -227,16 +227,23 @@ pub fn x86_vector_domain() -> &'static Arc<IrqDomain> {
 
 #[inline(never)]
 pub fn arch_early_irq_init() -> Result<(), SystemError> {
+    const IRQ_SIZE: u32 = 223;
     let vec_domain = irq_domain_manager()
         .create_and_add(
             "VECTOR".to_string(),
             &X86VectorDomainOps,
             IrqNumber::new(32),
             HardwareIrqNumber::new(32),
-            223,
+            IRQ_SIZE,
         )
         .ok_or(SystemError::ENOMEM)?;
     irq_domain_manager().set_default_domain(vec_domain.clone());
+    irq_domain_manager().domain_associate_many(
+        &vec_domain,
+        IrqNumber::new(0),
+        HardwareIrqNumber::new(0),
+        IRQ_SIZE,
+    );
     unsafe { X86_VECTOR_DOMAIN = Some(vec_domain) };
 
     let apic_chip = Arc::new(LocalApicChip::new());

+ 13 - 5
kernel/src/driver/block/virtio_blk.rs

@@ -32,6 +32,7 @@ use crate::{
             VirtIODevice, VirtIODeviceIndex, VirtIODriver, VIRTIO_VENDOR_ID,
         },
     },
+    exception::{irqdesc::IrqReturn, IrqNumber},
     filesystem::{kernfs::KernFSInode, mbr::MbrDiskPartionTable},
     init::initcall::INITCALL_POSTCORE,
     libs::{
@@ -85,15 +86,15 @@ unsafe impl Sync for VirtIOBlkDevice {}
 
 impl VirtIOBlkDevice {
     pub fn new(transport: VirtIOTransport, dev_id: Arc<DeviceId>) -> Option<Arc<Self>> {
+        let irq = transport.irq().map(|irq| IrqNumber::new(irq.data()));
         let device_inner = VirtIOBlk::<HalImpl, VirtIOTransport>::new(transport);
         if let Err(e) = device_inner {
             kerror!("VirtIOBlkDevice '{dev_id:?}' create failed: {:?}", e);
             return None;
         }
-        // !!!! 在这里临时测试virtio-blk的读写功能,后续需要删除 !!!!
-        // 目前read会报错 `NotReady`
-        let device_inner: VirtIOBlk<HalImpl, VirtIOTransport> = device_inner.unwrap();
 
+        let mut device_inner: VirtIOBlk<HalImpl, VirtIOTransport> = device_inner.unwrap();
+        device_inner.enable_interrupts();
         let dev = Arc::new_cyclic(|self_ref| Self {
             self_ref: self_ref.clone(),
             dev_id,
@@ -104,6 +105,7 @@ impl VirtIOBlkDevice {
                 virtio_index: None,
                 device_common: DeviceCommonData::default(),
                 kobject_common: KObjectCommonData::default(),
+                irq,
             }),
         });
 
@@ -190,6 +192,7 @@ struct InnerVirtIOBlkDevice {
     virtio_index: Option<VirtIODeviceIndex>,
     device_common: DeviceCommonData,
     kobject_common: KObjectCommonData,
+    irq: Option<IrqNumber>,
 }
 
 impl Debug for InnerVirtIOBlkDevice {
@@ -199,11 +202,16 @@ impl Debug for InnerVirtIOBlkDevice {
 }
 
 impl VirtIODevice for VirtIOBlkDevice {
+    fn irq(&self) -> Option<IrqNumber> {
+        self.inner().irq
+    }
+
     fn handle_irq(
         &self,
         _irq: crate::exception::IrqNumber,
-    ) -> Result<crate::exception::irqdesc::IrqReturn, system_error::SystemError> {
-        todo!("VirtIOBlkDevice::handle_irq")
+    ) -> Result<IrqReturn, system_error::SystemError> {
+        // todo: handle virtio blk irq
+        Ok(crate::exception::irqdesc::IrqReturn::Handled)
     }
 
     fn dev_id(&self) -> &Arc<DeviceId> {

+ 9 - 5
kernel/src/driver/clocksource/timer_riscv.rs

@@ -6,14 +6,17 @@ use system_error::SystemError;
 
 use crate::{
     arch::{interrupt::TrapFrame, time::riscv_time_base_freq, CurrentIrqArch, CurrentTimeArch},
-    driver::base::device::DeviceId,
+    driver::{
+        base::device::DeviceId,
+        irqchip::riscv_intc::{riscv_intc_assicate_irq, riscv_intc_hwirq_to_virq},
+    },
     exception::{
         irqdata::{IrqHandlerData, IrqLineStatus},
         irqdesc::{
             irq_desc_manager, IrqDesc, IrqFlowHandler, IrqHandleFlags, IrqHandler, IrqReturn,
         },
         manage::irq_manager,
-        InterruptArch, IrqNumber,
+        HardwareIrqNumber, InterruptArch, IrqNumber,
     },
     libs::spinlock::SpinLock,
     mm::percpu::PerCpu,
@@ -42,7 +45,7 @@ static mut HART0_NSEC_PASSED: usize = 0;
 static mut HART0_LAST_UPDATED: u64 = 0;
 
 impl RiscVSbiTimer {
-    pub const TIMER_IRQ: IrqNumber = IrqNumber::from(5);
+    pub const TIMER_IRQ: HardwareIrqNumber = HardwareIrqNumber::new(5);
 
     fn handle_irq(trap_frame: &mut TrapFrame) -> Result<(), SystemError> {
         // 更新下一次中断时间
@@ -117,7 +120,7 @@ pub fn riscv_sbi_timer_init_local() {
 
     irq_manager()
         .request_irq(
-            RiscVSbiTimer::TIMER_IRQ,
+            riscv_intc_hwirq_to_virq(RiscVSbiTimer::TIMER_IRQ).unwrap(),
             "riscv_clocksource".to_string(),
             &RiscvSbiTimerHandler,
             IrqHandleFlags::IRQF_SHARED | IrqHandleFlags::IRQF_PERCPU,
@@ -136,7 +139,8 @@ pub fn riscv_sbi_timer_init_local() {
 
 #[inline(never)]
 pub fn riscv_sbi_timer_irq_desc_init() {
-    let desc = irq_desc_manager().lookup(RiscVSbiTimer::TIMER_IRQ).unwrap();
+    let virq = riscv_intc_assicate_irq(RiscVSbiTimer::TIMER_IRQ).unwrap();
+    let desc = irq_desc_manager().lookup(virq).unwrap();
 
     desc.modify_status(IrqLineStatus::IRQ_LEVEL, IrqLineStatus::empty());
     desc.set_handler(&RiscvSbiTimerIrqFlowHandler);

+ 2 - 0
kernel/src/driver/irqchip/mod.rs

@@ -1,2 +1,4 @@
 #[cfg(target_arch = "riscv64")]
 pub mod riscv_intc;
+#[cfg(target_arch = "riscv64")]
+pub mod riscv_sifive_plic;

+ 60 - 4
kernel/src/driver/irqchip/riscv_intc.rs

@@ -17,6 +17,8 @@ use crate::{
     sched::{SchedMode, __schedule},
 };
 
+use super::riscv_sifive_plic::do_plic_irq;
+
 static mut RISCV_INTC_DOMAIN: Option<Arc<IrqDomain>> = None;
 static mut RISCV_INTC_CHIP: Option<Arc<RiscvIntcChip>> = None;
 
@@ -30,6 +32,9 @@ fn riscv_intc_chip() -> Option<&'static Arc<RiscvIntcChip>> {
     unsafe { RISCV_INTC_CHIP.as_ref() }
 }
 
+/// RISC-V INTC虚拟中断号的起始值(192映射物理的0)
+pub const RISCV_INTC_VIRQ_START: u32 = 192;
+
 #[derive(Debug)]
 struct RiscvIntcChip {
     inner: SpinLock<InnerIrqChip>,
@@ -87,6 +92,7 @@ impl IrqChip for RiscvIntcChip {
 }
 
 impl RiscvIntcChip {
+    const IRQ_SIZE: u32 = 64;
     fn new() -> Self {
         Self {
             inner: SpinLock::new(InnerIrqChip {
@@ -143,7 +149,11 @@ pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
     }
 
     let intc_domain = irq_domain_manager()
-        .create_and_add_linear("riscv-intc".to_string(), &RiscvIntcDomainOps, 64)
+        .create_and_add_linear(
+            "riscv-intc".to_string(),
+            &RiscvIntcDomainOps,
+            RiscvIntcChip::IRQ_SIZE,
+        )
         .ok_or_else(|| {
             kerror!("Failed to create riscv-intc domain");
             SystemError::ENXIO
@@ -152,7 +162,7 @@ pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
     irq_domain_manager().set_default_domain(intc_domain.clone());
 
     unsafe {
-        RISCV_INTC_DOMAIN = Some(intc_domain);
+        RISCV_INTC_DOMAIN = Some(intc_domain.clone());
     }
 
     riscv_sbi_timer_irq_desc_init();
@@ -160,12 +170,58 @@ pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
     return Ok(());
 }
 
+/// 把硬件中断号转换为riscv intc芯片的中断域的虚拟中断号
+pub const fn riscv_intc_hwirq_to_virq(hwirq: HardwareIrqNumber) -> Option<IrqNumber> {
+    if hwirq.data() < RiscvIntcChip::IRQ_SIZE {
+        Some(IrqNumber::new(hwirq.data() + RISCV_INTC_VIRQ_START))
+    } else {
+        None
+    }
+}
+
+/// 把riscv intc芯片的的中断域的虚拟中断号转换为硬件中断号
+#[allow(dead_code)]
+pub const fn riscv_intc_virq_to_hwirq(virq: IrqNumber) -> Option<HardwareIrqNumber> {
+    if virq.data() >= RISCV_INTC_VIRQ_START
+        && virq.data() < RISCV_INTC_VIRQ_START + RiscvIntcChip::IRQ_SIZE
+    {
+        Some(HardwareIrqNumber::new(virq.data() - RISCV_INTC_VIRQ_START))
+    } else {
+        None
+    }
+}
+
+/// 将硬件中断号与riscv intc芯片的虚拟中断号关联
+pub fn riscv_intc_assicate_irq(hwirq: HardwareIrqNumber) -> Option<IrqNumber> {
+    let virq = riscv_intc_hwirq_to_virq(hwirq)?;
+    irq_domain_manager()
+        .domain_associate(
+            riscv_intc_domain().as_ref().or_else(|| {
+                kerror!("riscv_intc_domain is None");
+                None
+            })?,
+            virq,
+            hwirq,
+        )
+        .ok();
+
+    Some(virq)
+}
+
 /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-riscv-intc.c#23
 pub fn riscv_intc_irq(trap_frame: &mut TrapFrame) {
     let hwirq = HardwareIrqNumber::new(trap_frame.cause.code() as u32);
-    // kdebug!("riscv64_do_irq: interrupt {hwirq:?}");
-    GenericIrqHandler::handle_domain_irq(riscv_intc_domain().clone().unwrap(), hwirq, trap_frame)
+    if hwirq.data() == 9 {
+        // external interrupt
+        do_plic_irq(trap_frame);
+    } else {
+        GenericIrqHandler::handle_domain_irq(
+            riscv_intc_domain().clone().unwrap(),
+            hwirq,
+            trap_frame,
+        )
         .ok();
+    }
     do_softirq();
     if hwirq.data() == RiscVSbiTimer::TIMER_IRQ.data() {
         __schedule(SchedMode::SM_PREEMPT);

+ 658 - 0
kernel/src/driver/irqchip/riscv_sifive_plic.rs

@@ -0,0 +1,658 @@
+//! 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-sifive-plic.c
+//!
+//!
+//!
+//!  This driver implements a version of the RISC-V PLIC with the actual layout
+//!  specified in chapter 8 of the SiFive U5 Coreplex Series Manual:
+//!
+//!      https://static.dev.sifive.com/U54-MC-RVCoreIP.pdf
+//!
+//!  The largest number supported by devices marked as 'sifive,plic-1.0.0', is
+//!  1024, of which device 0 is defined as non-existent by the RISC-V Privileged
+//!  Spec.
+//!
+
+use core::{
+    fmt::Debug,
+    ops::Deref,
+    ptr::{read_volatile, write_volatile},
+    sync::atomic::AtomicBool,
+};
+
+use alloc::{
+    string::ToString,
+    sync::{Arc, Weak},
+};
+use bitmap::AllocBitmap;
+use fdt::node::FdtNode;
+use system_error::SystemError;
+
+use crate::{
+    arch::interrupt::TrapFrame,
+    driver::open_firmware::fdt::open_firmware_fdt_driver,
+    exception::{
+        handle::fast_eoi_irq_handler,
+        irqchip::{IrqChip, IrqChipData, IrqChipFlags, IrqChipSetMaskResult},
+        irqdata::IrqData,
+        irqdesc::{irq_desc_manager, GenericIrqHandler},
+        irqdomain::{irq_domain_manager, IrqDomain, IrqDomainOps},
+        manage::irq_manager,
+        HardwareIrqNumber, IrqNumber,
+    },
+    libs::{
+        cpumask::CpuMask,
+        once::Once,
+        spinlock::{SpinLock, SpinLockGuard},
+    },
+    mm::{
+        mmio_buddy::{mmio_pool, MMIOSpaceGuard},
+        percpu::{PerCpu, PerCpuVar},
+        PhysAddr, VirtAddr,
+    },
+    smp::cpu::{smp_cpu_manager, ProcessorId},
+};
+
+static mut PLIC_HANDLERS: Option<PerCpuVar<PlicHandler>> = None;
+
+static mut PLIC_IRQ_CHIP: Option<Arc<PlicIrqChip>> = None;
+
+#[inline(always)]
+fn plic_irq_chip() -> Arc<PlicIrqChip> {
+    unsafe { PLIC_IRQ_CHIP.as_ref().unwrap().clone() }
+}
+
+#[inline(always)]
+fn plic_handlers() -> &'static PerCpuVar<PlicHandler> {
+    unsafe { PLIC_HANDLERS.as_ref().unwrap() }
+}
+
+#[allow(dead_code)]
+struct PlicChipData {
+    irq_domain: Weak<IrqDomain>,
+    phandle: u32,
+    lmask: SpinLock<CpuMask>,
+    mmio_guard: Option<MMIOSpaceGuard>,
+    regs: VirtAddr,
+}
+
+impl PlicChipData {
+    fn new(
+        irq_domain: Weak<IrqDomain>,
+        mmio_guard: MMIOSpaceGuard,
+        regs: VirtAddr,
+        phandle: u32,
+    ) -> Arc<Self> {
+        let r = Self {
+            irq_domain,
+            lmask: SpinLock::new(CpuMask::new()),
+            mmio_guard: Some(mmio_guard),
+            regs,
+            phandle,
+        };
+
+        Arc::new(r)
+    }
+
+    fn lmask(&self) -> SpinLockGuard<CpuMask> {
+        self.lmask.lock()
+    }
+}
+
+impl Debug for PlicChipData {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        f.debug_struct("PlicChipData").finish()
+    }
+}
+
+impl IrqChipData for PlicChipData {
+    fn as_any_ref(&self) -> &dyn core::any::Any {
+        self
+    }
+}
+
+struct PlicHandler {
+    priv_data: Option<Arc<PlicChipData>>,
+    present: AtomicBool,
+    inner: SpinLock<InnerPlicHandler>,
+}
+
+struct InnerPlicHandler {
+    hart_base: VirtAddr,
+    enable_base: VirtAddr,
+    enable_save: Option<AllocBitmap>,
+}
+
+impl PlicHandler {
+    fn new() -> Self {
+        let inner = InnerPlicHandler {
+            hart_base: VirtAddr::new(0),
+            enable_base: VirtAddr::new(0),
+            enable_save: None,
+        };
+        Self {
+            priv_data: None,
+            present: AtomicBool::new(false),
+            inner: SpinLock::new(inner),
+        }
+    }
+
+    fn set_threshold(&self, threshold: u32) {
+        let inner = self.inner();
+        unsafe {
+            /* priority must be > threshold to trigger an interrupt */
+            core::ptr::write_volatile(
+                (inner.hart_base + PlicIrqChip::CONTEXT_THRESHOLD).data() as *mut u32,
+                threshold,
+            );
+        }
+    }
+
+    unsafe fn force_set_priv_data(&mut self, priv_data: Arc<PlicChipData>) {
+        self.priv_data = Some(priv_data);
+    }
+
+    fn priv_data(&self) -> Option<Arc<PlicChipData>> {
+        self.priv_data.clone()
+    }
+
+    fn present(&self) -> bool {
+        self.present.load(core::sync::atomic::Ordering::SeqCst)
+    }
+
+    fn set_present(&self, present: bool) {
+        self.present
+            .store(present, core::sync::atomic::Ordering::SeqCst);
+    }
+
+    fn inner(&self) -> SpinLockGuard<InnerPlicHandler> {
+        self.inner.lock()
+    }
+
+    fn toggle(&self, hwirq: HardwareIrqNumber, enable: bool) {
+        let inner = self.inner();
+        let reg = (inner.enable_base + ((hwirq.data() / 32) * 4) as usize).data() as *mut u32;
+        let hwirq_mask = 1 << (hwirq.data() % 32);
+
+        if enable {
+            unsafe {
+                core::ptr::write_volatile(reg, core::ptr::read_volatile(reg) | hwirq_mask);
+            }
+        } else {
+            unsafe {
+                core::ptr::write_volatile(reg, core::ptr::read_volatile(reg) & !hwirq_mask);
+            }
+        }
+    }
+}
+
+fn plic_irq_toggle(cpumask: &CpuMask, irq_data: &Arc<IrqData>, enable: bool) {
+    cpumask.iter_cpu().for_each(|cpu| {
+        kdebug!("plic: irq_toggle: cpu: {cpu:?}");
+        let handler = unsafe { plic_handlers().force_get(cpu) };
+        handler.toggle(irq_data.hardware_irq(), enable);
+    });
+}
+
+/// SiFive PLIC中断控制器
+///
+/// https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-sifive-plic.c#204
+#[derive(Debug)]
+struct PlicIrqChip;
+#[allow(dead_code)]
+impl PlicIrqChip {
+    const COMPATIBLE: &'static str = "sifive,plic-1.0.0";
+
+    const MAX_DEVICES: u32 = 1024;
+    const MAX_CONTEXTS: u32 = 15872;
+
+    /*
+     * Each interrupt source has a priority register associated with it.
+     * We always hardwire it to one in Linux.
+     */
+    const PRIORITY_BASE: usize = 0;
+    const PRIORITY_PER_ID: usize = 4;
+
+    /*
+     * Each hart context has a vector of interrupt enable bits associated with it.
+     * There's one bit for each interrupt source.
+     */
+    const CONTEXT_ENABLE_BASE: usize = 0x2080;
+    const CONTEXT_ENABLE_SIZE: usize = 0x100;
+
+    /*
+     * Each hart context has a set of control registers associated with it.  Right
+     * now there's only two: a source priority threshold over which the hart will
+     * take an interrupt, and a register to claim interrupts.
+     */
+    const CONTEXT_BASE: usize = 0x201000;
+    const CONTEXT_SIZE: usize = 0x2000;
+    const CONTEXT_THRESHOLD: usize = 0x00;
+    const CONTEXT_CLAIM: usize = 0x04;
+
+    const PLIC_DISABLE_THRESHOLD: u32 = 0x7;
+    const PLIC_ENABLE_THRESHOLD: u32 = 0;
+
+    const PLIC_QUIRK_EDGE_INTERRUPT: u32 = 0;
+}
+
+impl IrqChip for PlicIrqChip {
+    fn name(&self) -> &'static str {
+        "SiFive PLIC"
+    }
+    fn irq_enable(&self, irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
+        // kwarn!("plic: irq_enable");
+        let common_data = irq_data.common_data();
+        let inner_guard = common_data.inner();
+        let mask = inner_guard.effective_affinity();
+
+        plic_irq_toggle(mask, irq_data, true);
+        self.irq_unmask(irq_data).expect("irq_unmask failed");
+
+        Ok(())
+    }
+
+    fn irq_unmask(&self, irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
+        // kwarn!("plic: irq_unmask");
+
+        let chip_data = irq_data
+            .chip_info_read_irqsave()
+            .chip_data()
+            .ok_or(SystemError::EINVAL)?;
+        let plic_chip_data = chip_data
+            .as_any_ref()
+            .downcast_ref::<PlicChipData>()
+            .ok_or(SystemError::EINVAL)?;
+
+        unsafe {
+            core::ptr::write_volatile(
+                (plic_chip_data.regs
+                    + PlicIrqChip::PRIORITY_BASE
+                    + irq_data.hardware_irq().data() as usize * PlicIrqChip::PRIORITY_PER_ID)
+                    .data() as *mut u32,
+                1,
+            );
+        }
+
+        Ok(())
+    }
+
+    fn irq_mask(&self, irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
+        let chip_data = irq_data
+            .chip_info_read_irqsave()
+            .chip_data()
+            .ok_or(SystemError::EINVAL)?;
+        let plic_chip_data = chip_data
+            .as_any_ref()
+            .downcast_ref::<PlicChipData>()
+            .ok_or(SystemError::EINVAL)?;
+
+        unsafe {
+            core::ptr::write_volatile(
+                (plic_chip_data.regs
+                    + PlicIrqChip::PRIORITY_BASE
+                    + irq_data.hardware_irq().data() as usize * PlicIrqChip::PRIORITY_PER_ID)
+                    .data() as *mut u32,
+                0,
+            );
+        }
+
+        Ok(())
+    }
+
+    fn irq_disable(&self, irq_data: &Arc<IrqData>) {
+        kdebug!("plic: irq_disable");
+        let common_data = irq_data.common_data();
+        let inner_guard = common_data.inner();
+        let mask = inner_guard.effective_affinity();
+        plic_irq_toggle(mask, irq_data, false);
+    }
+
+    fn irq_eoi(&self, irq_data: &Arc<IrqData>) {
+        let handler = plic_handlers().get();
+
+        if core::intrinsics::unlikely(irq_data.common_data().disabled()) {
+            handler.toggle(irq_data.hardware_irq(), true);
+            unsafe {
+                write_volatile(
+                    (handler.inner().hart_base + PlicIrqChip::CONTEXT_CLAIM).data() as *mut u32,
+                    irq_data.hardware_irq().data(),
+                );
+            }
+
+            handler.toggle(irq_data.hardware_irq(), false);
+        } else {
+            // kdebug!("plic: irq_eoi: hwirq: {:?}", irq_data.hardware_irq());
+            unsafe {
+                write_volatile(
+                    (handler.inner().hart_base + PlicIrqChip::CONTEXT_CLAIM).data() as *mut u32,
+                    irq_data.hardware_irq().data(),
+                );
+            }
+        }
+    }
+
+    fn irq_ack(&self, _irq: &Arc<IrqData>) {
+        todo!()
+    }
+
+    fn can_mask_ack(&self) -> bool {
+        false
+    }
+
+    fn can_set_affinity(&self) -> bool {
+        true
+    }
+
+    /// 设置中断的亲和性
+    ///
+    /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-sifive-plic.c#161
+    fn irq_set_affinity(
+        &self,
+        irq_data: &Arc<IrqData>,
+        mask_val: &CpuMask,
+        force: bool,
+    ) -> Result<IrqChipSetMaskResult, SystemError> {
+        let chip_data = irq_data
+            .chip_info_read_irqsave()
+            .chip_data()
+            .ok_or(SystemError::EINVAL)?;
+        let plic_chip_data = chip_data
+            .as_any_ref()
+            .downcast_ref::<PlicChipData>()
+            .ok_or(SystemError::EINVAL)?;
+
+        let mut amask = plic_chip_data.lmask().deref() & mask_val;
+        let cpu = if force {
+            mask_val.first()
+        } else {
+            amask.bitand_assign(smp_cpu_manager().possible_cpus());
+            // todo: 随机选择一个CPU
+            amask.first()
+        }
+        .ok_or(SystemError::EINVAL)?;
+
+        if cpu.data() > smp_cpu_manager().present_cpus_count() {
+            return Err(SystemError::EINVAL);
+        }
+
+        self.irq_disable(irq_data);
+        irq_data
+            .common_data()
+            .set_effective_affinity(CpuMask::from_cpu(cpu));
+        if !irq_data.common_data().disabled() {
+            self.irq_enable(irq_data).ok();
+        }
+
+        Ok(IrqChipSetMaskResult::Done)
+    }
+
+    fn can_set_flow_type(&self) -> bool {
+        false
+    }
+
+    fn flags(&self) -> IrqChipFlags {
+        IrqChipFlags::empty()
+    }
+}
+
+#[inline(never)]
+pub fn riscv_sifive_plic_init() -> Result<(), SystemError> {
+    static INIT_PLIC_IRQ_CHIP_ONCE: Once = Once::new();
+    INIT_PLIC_IRQ_CHIP_ONCE.call_once(|| unsafe {
+        PLIC_IRQ_CHIP = Some(Arc::new(PlicIrqChip));
+
+        PLIC_HANDLERS = Some(
+            PerCpuVar::new(
+                (0..PerCpu::MAX_CPU_NUM)
+                    .map(|_| PlicHandler::new())
+                    .collect(),
+            )
+            .unwrap(),
+        );
+    });
+
+    let fdt = open_firmware_fdt_driver().fdt_ref()?;
+    let all_plics = fdt.all_nodes().filter(|x| {
+        if let Some(compatible) = x.compatible() {
+            compatible
+                .all()
+                .any(|x| x == PlicIrqChip::COMPATIBLE || x == "riscv,plic0")
+        } else {
+            false
+        }
+    });
+    for node in all_plics {
+        if let Err(e) = do_riscv_sifive_plic_init(&node) {
+            kwarn!("Failed to init SiFive PLIC: node: {node:?} {e:?}");
+        }
+    }
+
+    unsafe { riscv::register::sie::set_sext() };
+    Ok(())
+}
+
+/// 初始化SiFive PLIC
+///
+/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-sifive-plic.c#415
+fn do_riscv_sifive_plic_init(fdt_node: &FdtNode) -> Result<(), SystemError> {
+    let reg = fdt_node
+        .reg()
+        .ok_or(SystemError::EINVAL)?
+        .next()
+        .ok_or(SystemError::EIO)?;
+    let paddr = PhysAddr::new(reg.starting_address as usize);
+    let size = reg.size.ok_or(SystemError::EINVAL)?;
+    let mmio_guard = mmio_pool().create_mmio(size)?;
+    let vaddr = unsafe { mmio_guard.map_any_phys(paddr, size) }?;
+
+    let phandle = fdt_node
+        .property("phandle")
+        .ok_or(SystemError::EINVAL)?
+        .as_usize()
+        .ok_or(SystemError::EINVAL)?;
+
+    // 中断数量
+    let irq_num = fdt_node
+        .property("riscv,ndev")
+        .ok_or(SystemError::EINVAL)?
+        .as_usize()
+        .ok_or(SystemError::EINVAL)?;
+    kdebug!(
+        "plic: node: {}, irq_num: {irq_num}, paddr: {paddr:?}, size: {size}",
+        fdt_node.name
+    );
+    let nr_contexts = fdt_node
+        .interrupts_extended()
+        .ok_or(SystemError::EINVAL)?
+        .count();
+    kdebug!("plic: nr_contexts: {nr_contexts}");
+
+    let irq_domain = irq_domain_manager()
+        .create_and_add_linear(
+            fdt_node.name.to_string(),
+            &PlicIrqDomainOps,
+            (irq_num + 1) as u32,
+        )
+        .ok_or(SystemError::EINVAL)?;
+    // kdebug!("plic: irq_domain: {irq_domain:?}");
+
+    let priv_data = PlicChipData::new(
+        Arc::downgrade(&irq_domain),
+        mmio_guard,
+        vaddr,
+        phandle as u32,
+    );
+    irq_domain.set_host_data(Some(priv_data.clone() as Arc<dyn IrqChipData>));
+
+    let loop_done_setup = |irq_handler: &PlicHandler| {
+        for x in 1..=irq_num {
+            irq_handler.toggle(HardwareIrqNumber::new(x as u32), false);
+
+            unsafe {
+                core::ptr::write_volatile(
+                    (priv_data.regs + PlicIrqChip::PRIORITY_BASE + x * PlicIrqChip::PRIORITY_PER_ID)
+                        .data() as *mut u32,
+                    1,
+                )
+            };
+        }
+    };
+
+    // todo: 学习linux那样处理,获取到hartid,这里暂时糊代码
+    // linux: https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-sifive-plic.c#458
+    for i in smp_cpu_manager().present_cpus().iter_cpu() {
+        let i = i.data() as usize;
+
+        let cpu = ProcessorId::new(i as u32);
+        let handler = unsafe { plic_handlers().force_get(cpu) };
+        if handler.present() {
+            kwarn!("plic: handler {i} already present.");
+            handler.set_threshold(PlicIrqChip::PLIC_ENABLE_THRESHOLD);
+            loop_done_setup(handler);
+            continue;
+        }
+
+        kdebug!("plic: setup lmask {cpu:?}.");
+        priv_data.lmask().set(cpu, true);
+        let mut handler_inner = handler.inner();
+        handler_inner.hart_base =
+            priv_data.regs + PlicIrqChip::CONTEXT_BASE + i * PlicIrqChip::CONTEXT_SIZE;
+        handler_inner.enable_base = priv_data.regs
+            + PlicIrqChip::CONTEXT_ENABLE_BASE
+            + i * PlicIrqChip::CONTEXT_ENABLE_SIZE;
+        handler.set_present(true);
+        unsafe {
+            plic_handlers()
+                .force_get_mut(cpu)
+                .force_set_priv_data(priv_data.clone())
+        };
+
+        handler_inner.enable_save = Some(AllocBitmap::new(irq_num as usize));
+
+        drop(handler_inner);
+        handler.set_threshold(PlicIrqChip::PLIC_ENABLE_THRESHOLD);
+
+        loop_done_setup(handler);
+    }
+
+    // 把外部设备的中断与PLIC关联起来
+    associate_irq_with_plic_domain(&irq_domain, phandle as u32).ok();
+
+    Ok(())
+}
+
+/// 把设备的中断与PLIC的关联起来
+fn associate_irq_with_plic_domain(
+    irq_domain: &Arc<IrqDomain>,
+    plic_phandle: u32,
+) -> Result<(), SystemError> {
+    let fdt_ref = open_firmware_fdt_driver().fdt_ref()?;
+    let nodes = fdt_ref.all_nodes().filter(|x| {
+        if let Some(pa) = x.property("interrupt-parent").and_then(|x| x.as_usize()) {
+            pa as u32 == plic_phandle
+        } else {
+            false
+        }
+    });
+
+    for node in nodes {
+        if let Some(irq) = node.interrupts().and_then(|mut x| x.next()) {
+            let irq = irq as u32;
+            let virq = IrqNumber::new(irq);
+            let hwirq = HardwareIrqNumber::new(irq);
+            kdebug!("plic: associate irq: {irq}, virq: {virq:?}, hwirq: {hwirq:?}");
+            irq_domain_manager()
+                .domain_associate(irq_domain, virq, hwirq)
+                .ok();
+        }
+    }
+
+    Ok(())
+}
+#[derive(Debug)]
+struct PlicIrqDomainOps;
+
+impl IrqDomainOps for PlicIrqDomainOps {
+    fn unmap(&self, _irq_domain: &Arc<IrqDomain>, _virq: IrqNumber) {
+        todo!()
+    }
+
+    fn map(
+        &self,
+        irq_domain: &Arc<IrqDomain>,
+        hwirq: HardwareIrqNumber,
+        virq: IrqNumber,
+    ) -> Result<(), SystemError> {
+        // kdebug!("plic: map: virq: {virq:?}, hwirq: {hwirq:?}");
+
+        let chip_data = irq_domain.host_data().ok_or(SystemError::EINVAL)?;
+        let plic_chip_data = chip_data
+            .as_any_ref()
+            .downcast_ref::<PlicChipData>()
+            .ok_or(SystemError::EINVAL)?;
+        irq_domain_manager().domain_set_info(
+            irq_domain,
+            virq,
+            hwirq,
+            plic_irq_chip(),
+            irq_domain.host_data(),
+            fast_eoi_irq_handler(),
+            None,
+            None,
+        );
+        let irq_desc = irq_desc_manager().lookup(virq).unwrap();
+        irq_desc.set_noprobe();
+        let mask = plic_chip_data.lmask().clone();
+        irq_manager().irq_set_affinity(&irq_desc.irq_data(), &irq_desc.inner(), &mask)?;
+        Ok(())
+    }
+
+    fn activate(
+        &self,
+        _domain: &Arc<IrqDomain>,
+        _irq_data: &Arc<IrqData>,
+        _reserve: bool,
+    ) -> Result<(), SystemError> {
+        kwarn!("plic: activate");
+        loop {}
+    }
+
+    fn deactivate(&self, _domain: &Arc<IrqDomain>, _irq_data: &Arc<IrqData>) {}
+}
+
+/// 处理PLIC中断
+pub(super) fn do_plic_irq(trap_frame: &mut TrapFrame) {
+    // kdebug!("plic: do_plic_irq");
+
+    let handler = plic_handlers().get();
+    let priv_data = handler.priv_data();
+    if priv_data.is_none() {
+        return;
+    }
+
+    let domain = priv_data.unwrap().irq_domain.upgrade();
+    if domain.is_none() {
+        return;
+    }
+
+    let domain = domain.unwrap();
+
+    // 循环处理中断
+    loop {
+        let claim = unsafe {
+            read_volatile(
+                (handler.inner().hart_base + PlicIrqChip::CONTEXT_CLAIM).data() as *const u32,
+            )
+        };
+
+        if claim == 0 {
+            break;
+        }
+        kdebug!("plic: claim: {claim:?}");
+
+        let hwirq = HardwareIrqNumber::new(claim);
+        if let Err(e) = GenericIrqHandler::handle_domain_irq(domain.clone(), hwirq, trap_frame) {
+            kwarn!("plic: can't find mapping for hwirq {hwirq:?}, {e:?}");
+        }
+    }
+}

+ 4 - 0
kernel/src/driver/net/virtio_net.rs

@@ -207,6 +207,10 @@ impl VirtIODevice for VirtioInterface {
         return Ok(IrqReturn::Handled);
     }
 
+    fn irq(&self) -> Option<IrqNumber> {
+        None
+    }
+
     fn dev_id(&self) -> &Arc<DeviceId> {
         return &self.dev_id;
     }

+ 43 - 1
kernel/src/driver/virtio/irq.rs

@@ -3,7 +3,16 @@ use hashbrown::HashMap;
 use system_error::SystemError;
 use unified_init::macros::unified_init;
 
-use crate::{driver::base::device::DeviceId, init::initcall::INITCALL_CORE, libs::rwlock::RwLock};
+use crate::{
+    driver::base::device::DeviceId,
+    exception::{
+        irqdata::IrqHandlerData,
+        irqdesc::{IrqHandler, IrqReturn},
+        IrqNumber,
+    },
+    init::initcall::INITCALL_CORE,
+    libs::rwlock::RwLock,
+};
 
 use super::VirtIODevice;
 
@@ -83,3 +92,36 @@ fn init_virtio_irq_manager() -> Result<(), SystemError> {
     }
     return Ok(());
 }
+
+/// `DefaultVirtioIrqHandler` 是一个默认的virtio设备中断处理程序。
+///
+/// 当虚拟设备产生中断时,该处理程序会被调用。
+///
+/// 它首先检查设备ID是否存在,然后尝试查找与设备ID关联的设备。
+/// 如果找到设备,它会调用设备的 `handle_irq` 方法来处理中断。
+/// 如果没有找到设备,它会记录一条警告并返回 `IrqReturn::NotHandled`,表示中断未被处理。
+#[derive(Debug)]
+pub(super) struct DefaultVirtioIrqHandler;
+
+impl IrqHandler for DefaultVirtioIrqHandler {
+    fn handle(
+        &self,
+        irq: IrqNumber,
+        _static_data: Option<&dyn IrqHandlerData>,
+        dev_id: Option<Arc<dyn IrqHandlerData>>,
+    ) -> Result<IrqReturn, SystemError> {
+        let dev_id = dev_id.ok_or(SystemError::EINVAL)?;
+        let dev_id = dev_id
+            .arc_any()
+            .downcast::<DeviceId>()
+            .map_err(|_| SystemError::EINVAL)?;
+
+        if let Some(dev) = virtio_irq_manager().lookup_device(&dev_id) {
+            return dev.handle_irq(irq);
+        } else {
+            // 未绑定具体设备,因此无法处理中断
+            kwarn!("No device found for IRQ: {:?}", irq);
+            return Ok(IrqReturn::NotHandled);
+        }
+    }
+}

+ 7 - 0
kernel/src/driver/virtio/mod.rs

@@ -36,6 +36,13 @@ pub trait VirtIODevice: Device {
 
     /// virtio 设备厂商
     fn vendor(&self) -> u32;
+
+    /// virtio设备的中断号
+    fn irq(&self) -> Option<IrqNumber>;
+
+    fn set_irq_number(&self, _irq: IrqNumber) -> Result<(), SystemError> {
+        Err(SystemError::ENOSYS)
+    }
 }
 
 pub trait VirtIODriver: Driver {

+ 53 - 9
kernel/src/driver/virtio/sysfs.rs

@@ -8,16 +8,20 @@ use system_error::SystemError;
 use unified_init::macros::unified_init;
 
 use crate::{
-    driver::base::{
-        device::{
-            bus::{bus_manager, Bus},
-            device_manager,
-            driver::{driver_manager, Driver},
-            Device,
+    driver::{
+        base::{
+            device::{
+                bus::{bus_manager, Bus},
+                device_manager,
+                driver::{driver_manager, Driver},
+                Device,
+            },
+            kobject::KObject,
+            subsys::SubSysPrivate,
         },
-        kobject::KObject,
-        subsys::SubSysPrivate,
+        virtio::irq::{virtio_irq_manager, DefaultVirtioIrqHandler},
     },
+    exception::{irqdesc::IrqHandleFlags, manage::irq_manager},
     filesystem::{
         sysfs::{
             file::sysfs_emit_str, Attribute, AttributeGroup, SysFSOpsSupport, SYSFS_ATTR_MODE_RO,
@@ -175,7 +179,47 @@ impl VirtIODeviceManager {
         virtio_drv.probe(&dev)?;
 
         device_manager().add_device(dev.clone() as Arc<dyn Device>)?;
-        device_manager().add_groups(&(dev as Arc<dyn Device>), &[&VirtIODeviceAttrGroup])
+        let r = device_manager()
+            .add_groups(&(dev.clone() as Arc<dyn Device>), &[&VirtIODeviceAttrGroup]);
+
+        self.setup_irq(&dev).ok();
+
+        return r;
+    }
+
+    /// # setup_irq - 设置中断
+    ///
+    /// 为virtio设备设置中断。
+    fn setup_irq(&self, dev: &Arc<dyn VirtIODevice>) -> Result<(), SystemError> {
+        let irq = dev.irq().ok_or(SystemError::EINVAL)?;
+        if let Err(e) = irq_manager().request_irq(
+            irq,
+            dev.device_name(),
+            &DefaultVirtioIrqHandler,
+            IrqHandleFlags::IRQF_SHARED,
+            Some(dev.dev_id().clone()),
+        ) {
+            kerror!(
+                "Failed to request irq for virtio device '{}': irq: {:?}, error {:?}",
+                dev.device_name(),
+                irq,
+                e
+            );
+            return Err(e);
+        }
+
+        virtio_irq_manager()
+            .register_device(dev.clone())
+            .map_err(|e| {
+                kerror!(
+                    "Failed to register virtio device's irq, dev: '{}', irq: {:?}, error {:?}",
+                    dev.device_name(),
+                    irq,
+                    e
+                );
+                e
+            })?;
+        return Ok(());
     }
 
     #[allow(dead_code)]

+ 11 - 0
kernel/src/driver/virtio/transport.rs

@@ -1,5 +1,7 @@
 use virtio_drivers::transport::Transport;
 
+use crate::exception::HardwareIrqNumber;
+
 use super::{transport_mmio::VirtIOMmioTransport, transport_pci::PciTransport};
 
 pub enum VirtIOTransport {
@@ -7,6 +9,15 @@ pub enum VirtIOTransport {
     Mmio(VirtIOMmioTransport),
 }
 
+impl VirtIOTransport {
+    pub fn irq(&self) -> Option<HardwareIrqNumber> {
+        match self {
+            VirtIOTransport::Mmio(transport) => Some(transport.irq()),
+            _ => None,
+        }
+    }
+}
+
 impl core::fmt::Debug for VirtIOTransport {
     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         match self {

+ 1 - 37
kernel/src/driver/virtio/transport_pci.rs

@@ -8,9 +8,6 @@ use crate::driver::pci::pci::{
 
 use crate::driver::pci::pci_irq::{IrqCommonMsg, IrqSpecificMsg, PciInterrupt, PciIrqMsg, IRQ};
 use crate::driver::pci::root::pci_root_0;
-use crate::driver::virtio::irq::virtio_irq_manager;
-use crate::exception::irqdata::IrqHandlerData;
-use crate::exception::irqdesc::{IrqHandler, IrqReturn};
 
 use crate::exception::IrqNumber;
 
@@ -26,12 +23,12 @@ use core::{
     mem::{align_of, size_of},
     ptr::{self, addr_of_mut, NonNull},
 };
-use system_error::SystemError;
 use virtio_drivers::{
     transport::{DeviceStatus, DeviceType, Transport},
     Error, Hal, PhysAddr,
 };
 
+use super::irq::DefaultVirtioIrqHandler;
 use super::VIRTIO_VENDOR_ID;
 
 /// The offset to add to a VirtIO device ID to get the corresponding PCI device ID.
@@ -569,36 +566,3 @@ fn get_bar_region_slice<T>(
 fn nonnull_slice_from_raw_parts<T>(data: NonNull<T>, len: usize) -> NonNull<[T]> {
     NonNull::new(ptr::slice_from_raw_parts_mut(data.as_ptr(), len)).unwrap()
 }
-
-/// `DefaultVirtioIrqHandler` 是一个默认的virtio设备中断处理程序。
-///
-/// 当虚拟设备产生中断时,该处理程序会被调用。
-///
-/// 它首先检查设备ID是否存在,然后尝试查找与设备ID关联的设备。
-/// 如果找到设备,它会调用设备的 `handle_irq` 方法来处理中断。
-/// 如果没有找到设备,它会记录一条警告并返回 `IrqReturn::NotHandled`,表示中断未被处理。
-#[derive(Debug)]
-struct DefaultVirtioIrqHandler;
-
-impl IrqHandler for DefaultVirtioIrqHandler {
-    fn handle(
-        &self,
-        irq: IrqNumber,
-        _static_data: Option<&dyn IrqHandlerData>,
-        dev_id: Option<Arc<dyn IrqHandlerData>>,
-    ) -> Result<IrqReturn, SystemError> {
-        let dev_id = dev_id.ok_or(SystemError::EINVAL)?;
-        let dev_id = dev_id
-            .arc_any()
-            .downcast::<DeviceId>()
-            .map_err(|_| SystemError::EINVAL)?;
-
-        if let Some(dev) = virtio_irq_manager().lookup_device(&dev_id) {
-            return dev.handle_irq(irq);
-        } else {
-            // 未绑定具体设备,因此无法处理中断
-
-            return Ok(IrqReturn::NotHandled);
-        }
-    }
-}

+ 118 - 15
kernel/src/exception/handle.rs

@@ -5,13 +5,14 @@ use system_error::SystemError;
 
 use crate::{
     arch::{interrupt::TrapFrame, CurrentIrqArch},
-    exception::irqdesc::InnerIrqDesc,
+    exception::{irqchip::IrqChipFlags, irqdesc::InnerIrqDesc},
     libs::{once::Once, spinlock::SpinLockGuard},
     process::{ProcessFlags, ProcessManager},
     smp::core::smp_get_processor_id,
 };
 
 use super::{
+    irqchip::IrqChip,
     irqdata::{IrqData, IrqHandlerData, IrqStatus},
     irqdesc::{
         InnerIrqAction, IrqDesc, IrqDescState, IrqFlowHandler, IrqReturn, ThreadedHandlerFlags,
@@ -34,6 +35,7 @@ pub fn fast_eoi_irq_handler() -> &'static dyn IrqFlowHandler {
 
 /// 获取用于处理边沿触发中断的处理程序
 #[inline(always)]
+#[allow(dead_code)]
 pub fn edge_irq_handler() -> &'static dyn IrqFlowHandler {
     &EdgeIrqHandler
 }
@@ -55,9 +57,38 @@ impl IrqFlowHandler for HandleBadIrq {
 struct FastEOIIrqHandler;
 
 impl IrqFlowHandler for FastEOIIrqHandler {
-    fn handle(&self, _irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
-        // https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/chip.c?r=&mo=17578&fi=689#689
-        todo!("FastEOIIrqHandler");
+    /// https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/chip.c?r=&mo=17578&fi=689#689
+    fn handle(&self, irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
+        let chip = irq_desc.irq_data().chip_info_read_irqsave().chip();
+
+        let mut desc_inner = irq_desc.inner();
+        let out = |din: SpinLockGuard<InnerIrqDesc>| {
+            if !chip.flags().contains(IrqChipFlags::IRQCHIP_EOI_IF_HANDLED) {
+                chip.irq_eoi(din.irq_data());
+            }
+        };
+        if !irq_may_run(&desc_inner) {
+            out(desc_inner);
+            return;
+        }
+
+        desc_inner
+            .internal_state_mut()
+            .remove(IrqDescState::IRQS_REPLAY | IrqDescState::IRQS_WAITING);
+
+        if desc_inner.actions().is_empty() || desc_inner.common_data().disabled() {
+            desc_inner
+                .internal_state_mut()
+                .insert(IrqDescState::IRQS_PENDING);
+            mask_irq(desc_inner.irq_data());
+            out(desc_inner);
+            return;
+        }
+
+        desc_inner = handle_irq_event(irq_desc, desc_inner);
+        cond_unmask_eoi_irq(&desc_inner, &chip);
+
+        return;
     }
 }
 
@@ -112,17 +143,7 @@ impl IrqFlowHandler for EdgeIrqHandler {
 
             // kdebug!("handle_irq_event");
 
-            desc_inner_guard
-                .internal_state_mut()
-                .remove(IrqDescState::IRQS_PENDING);
-            desc_inner_guard.common_data().set_inprogress();
-
-            drop(desc_inner_guard);
-
-            let _r = do_handle_irq_event(irq_desc);
-
-            desc_inner_guard = irq_desc.inner();
-            desc_inner_guard.common_data().clear_inprogress();
+            desc_inner_guard = handle_irq_event(irq_desc, desc_inner_guard);
 
             if !desc_inner_guard
                 .internal_state()
@@ -160,6 +181,29 @@ pub(super) fn mask_ack_irq(irq_data: &Arc<IrqData>) {
     }
 }
 
+pub(super) fn mask_irq(irq_data: &Arc<IrqData>) {
+    if irq_data.common_data().masked() {
+        return;
+    }
+
+    let chip = irq_data.chip_info_read_irqsave().chip();
+    if chip.irq_mask(irq_data).is_ok() {
+        irq_data.irqd_set(IrqStatus::IRQD_IRQ_MASKED);
+    }
+}
+
+pub(super) fn unmask_irq(irq_data: &Arc<IrqData>) {
+    if !irq_data.common_data().masked() {
+        return;
+    }
+
+    let chip = irq_data.chip_info_read_irqsave().chip();
+
+    if chip.irq_unmask(irq_data).is_ok() {
+        irq_data.irqd_clear(IrqStatus::IRQD_IRQ_MASKED);
+    }
+}
+
 impl IrqManager {
     pub(super) fn do_irq_wake_thread(
         &self,
@@ -191,6 +235,24 @@ impl IrqManager {
     }
 }
 
+fn handle_irq_event<'a>(
+    irq_desc: &'a Arc<IrqDesc>,
+    mut desc_inner_guard: SpinLockGuard<'_, InnerIrqDesc>,
+) -> SpinLockGuard<'a, InnerIrqDesc> {
+    desc_inner_guard
+        .internal_state_mut()
+        .remove(IrqDescState::IRQS_PENDING);
+    desc_inner_guard.common_data().set_inprogress();
+
+    drop(desc_inner_guard);
+
+    let _r = do_handle_irq_event(irq_desc);
+
+    let desc_inner_guard = irq_desc.inner();
+    desc_inner_guard.common_data().clear_inprogress();
+
+    return desc_inner_guard;
+}
 /// 处理中断事件
 ///
 /// https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/handle.c?fi=handle_irq_event#139
@@ -228,6 +290,47 @@ fn do_handle_irq_event(desc: &Arc<IrqDesc>) -> Result<(), SystemError> {
     return r.map(|_| ());
 }
 
+/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/chip.c?r=&mo=17578&fi=659
+fn cond_unmask_eoi_irq(
+    desc_inner_guard: &SpinLockGuard<'_, InnerIrqDesc>,
+    chip: &Arc<dyn IrqChip>,
+) {
+    if !desc_inner_guard
+        .internal_state()
+        .contains(IrqDescState::IRQS_ONESHOT)
+    {
+        chip.irq_eoi(desc_inner_guard.irq_data());
+        return;
+    }
+
+    /*
+     * We need to unmask in the following cases:
+     * - Oneshot irq which did not wake the thread (caused by a
+     *   spurious interrupt or a primary handler handling it
+     *   completely).
+     */
+
+    if !desc_inner_guard.common_data().disabled()
+        && desc_inner_guard.common_data().masked()
+        && desc_inner_guard.threads_oneshot() == 0
+    {
+        kdebug!(
+            "eoi unmask irq {}",
+            desc_inner_guard.irq_data().irq().data()
+        );
+        chip.irq_eoi(desc_inner_guard.irq_data());
+        unmask_irq(desc_inner_guard.irq_data());
+    } else if !chip.flags().contains(IrqChipFlags::IRQCHIP_EOI_THREADED) {
+        kdebug!("eoi irq {}", desc_inner_guard.irq_data().irq().data());
+        chip.irq_eoi(desc_inner_guard.irq_data());
+    } else {
+        kwarn!(
+            "irq {} eoi failed",
+            desc_inner_guard.irq_data().irq().data()
+        );
+    }
+}
+
 fn warn_no_thread(irq: IrqNumber, action_inner: &mut SpinLockGuard<'_, InnerIrqAction>) {
     // warn on once
     if action_inner

+ 28 - 28
kernel/src/exception/irqchip.rs

@@ -37,27 +37,27 @@ use super::{
 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> {
+    fn irq_startup(&self, _irq_data: &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> {
+    fn irq_shutdown(&self, _irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
         Err(SystemError::ENOSYS)
     }
 
     /// enable the interrupt
     ///
     /// (defaults to ->unmask if ENOSYS)
-    fn irq_enable(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
+    fn irq_enable(&self, _irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
         Err(SystemError::ENOSYS)
     }
 
     /// disable the interrupt
-    fn irq_disable(&self, irq: &Arc<IrqData>);
+    fn irq_disable(&self, irq_data: &Arc<IrqData>);
 
     /// start of a new interrupt
-    fn irq_ack(&self, irq: &Arc<IrqData>);
+    fn irq_ack(&self, irq_data: &Arc<IrqData>);
 
     /// mask an interrupt source
     ///
@@ -66,7 +66,7 @@ pub trait IrqChip: Sync + Send + Any + Debug {
     /// 如果返回ENOSYS,则表明irq_mask()不支持. 那么中断机制代码将调用irq_disable()。
     ///
     /// 如果返回错误,那么中断的屏蔽状态将不会改变。
-    fn irq_mask(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
+    fn irq_mask(&self, _irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
         Err(SystemError::ENOSYS)
     }
 
@@ -74,18 +74,18 @@ pub trait IrqChip: Sync + Send + Any + Debug {
     fn can_mask_ack(&self) -> bool;
 
     /// ack and mask an interrupt source
-    fn irq_mask_ack(&self, _irq: &Arc<IrqData>) {}
+    fn irq_mask_ack(&self, _irq_data: &Arc<IrqData>) {}
 
     /// unmask an interrupt source
     ///
     /// 用于取消屏蔽中断
     ///
     /// 如果返回ENOSYS,则表明irq_unmask()不支持.
-    fn irq_unmask(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
+    fn irq_unmask(&self, _irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
         Err(SystemError::ENOSYS)
     }
     /// end of interrupt
-    fn irq_eoi(&self, _irq: &Arc<IrqData>) {}
+    fn irq_eoi(&self, _irq_data: &Arc<IrqData>) {}
 
     /// 指示当前芯片是否可以设置中断亲和性。
     fn can_set_affinity(&self) -> bool;
@@ -96,7 +96,7 @@ pub trait IrqChip: Sync + Send + Any + Debug {
     /// 不需要对提供的亲和性掩码进行完整性检查。这用于CPU热插拔,其中目标CPU尚未在cpu_online_mask中设置。
     fn irq_set_affinity(
         &self,
-        _irq: &Arc<IrqData>,
+        _irq_data: &Arc<IrqData>,
         _cpu: &CpuMask,
         _force: bool,
     ) -> Result<IrqChipSetMaskResult, SystemError> {
@@ -104,7 +104,7 @@ pub trait IrqChip: Sync + Send + Any + Debug {
     }
 
     /// retrigger an IRQ to the CPU
-    fn retrigger(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
+    fn retrigger(&self, _irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
         Err(SystemError::ENOSYS)
     }
 
@@ -119,65 +119,65 @@ pub trait IrqChip: Sync + Send + Any + Debug {
     ///
     fn irq_set_type(
         &self,
-        _irq: &Arc<IrqData>,
+        _irq_data: &Arc<IrqData>,
         _flow_type: IrqLineStatus,
     ) -> Result<IrqChipSetMaskResult, 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> {
+    fn irq_set_wake(&self, _irq_data: &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> {
+    fn irq_bus_lock(&self, _irq_data: &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> {
+    fn irq_bus_sync_unlock(&self, _irq_data: &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>) {}
+    fn irq_suspend(&self, _irq_data: &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_data: &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_data: &Arc<IrqData>) {}
 
     /// Optional function to set irq_data.mask for special cases
-    fn irq_calc_mask(&self, _irq: &Arc<IrqData>) {}
+    fn irq_calc_mask(&self, _irq_data: &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> {
+    fn irq_request_resources(&self, _irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
         Ok(())
     }
 
     /// optional to release resources acquired with
     /// irq_request_resources
-    fn irq_release_resources(&self, _irq: &Arc<IrqData>) {}
+    fn irq_release_resources(&self, _irq_data: &Arc<IrqData>) {}
 
     /// optional to compose message content for MSI
     ///
     /// 组装MSI消息并返回到msg中
-    fn irq_compose_msi_msg(&self, _irq: &Arc<IrqData>, _msg: &mut MsiMsg) {}
+    fn irq_compose_msi_msg(&self, _irq_data: &Arc<IrqData>, _msg: &mut MsiMsg) {}
 
     /// optional to write message content for MSI
-    fn irq_write_msi_msg(&self, _irq: &Arc<IrqData>, _msg: &MsiMsg) {}
+    fn irq_write_msi_msg(&self, _irq_data: &Arc<IrqData>, _msg: &MsiMsg) {}
 
     /// return the internal state of an interrupt
     fn irqchip_state(
         &self,
-        _irq: &Arc<IrqData>,
+        _irq_data: &Arc<IrqData>,
         _which: IrqChipState,
     ) -> Result<bool, SystemError> {
         Err(SystemError::ENOSYS)
@@ -186,7 +186,7 @@ pub trait IrqChip: Sync + Send + Any + Debug {
     /// set the internal state of an interrupt
     fn set_irqchip_state(
         &self,
-        _irq: &Arc<IrqData>,
+        _irq_data: &Arc<IrqData>,
         _which: IrqChipState,
         _state: bool,
     ) -> Result<(), SystemError> {
@@ -196,17 +196,17 @@ 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_data: &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> {
+    fn irq_nmi_setup(&self, _irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
         Err(SystemError::ENOSYS)
     }
 
     /// function called from core code after disabling an NMI
-    fn irq_nmi_teardown(&self, _irq: &Arc<IrqData>) {}
+    fn irq_nmi_teardown(&self, _irq_data: &Arc<IrqData>) {}
 
     fn flags(&self) -> IrqChipFlags;
 }

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

@@ -80,6 +80,7 @@ impl IrqData {
         self.inner.lock_irqsave().desc = desc;
     }
 
+    #[allow(dead_code)]
     pub fn clear_irq_desc(&self) {
         self.inner.lock_irqsave().desc = Weak::new();
     }
@@ -210,6 +211,7 @@ impl IrqCommonData {
             handler_data: None,
             msi_desc: None,
             affinity: CpuMask::new(),
+            effective_affinity: CpuMask::new(),
         };
         return IrqCommonData {
             inner: SpinLock::new(inner),
@@ -304,6 +306,10 @@ impl IrqCommonData {
         self.inner.lock_irqsave().affinity = affinity;
     }
 
+    pub fn set_effective_affinity(&self, affinity: CpuMask) {
+        self.inner.lock_irqsave().effective_affinity = affinity;
+    }
+
     pub fn inner(&self) -> SpinLockGuard<InnerIrqCommonData> {
         self.inner.lock_irqsave()
     }
@@ -318,6 +324,7 @@ pub struct InnerIrqCommonData {
     handler_data: Option<Arc<dyn IrqHandlerData>>,
     msi_desc: Option<Arc<MsiDesc>>,
     affinity: CpuMask,
+    effective_affinity: CpuMask,
 }
 
 impl InnerIrqCommonData {
@@ -338,6 +345,10 @@ impl InnerIrqCommonData {
     pub fn handler_data(&self) -> Option<Arc<dyn IrqHandlerData>> {
         self.handler_data.clone()
     }
+
+    pub fn effective_affinity(&self) -> &CpuMask {
+        &self.effective_affinity
+    }
 }
 
 /// 中断处理函数传入的数据

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

@@ -114,6 +114,7 @@ impl IrqDesc {
                 kern_inode: None,
                 kset: None,
                 parent_kobj: None,
+                threads_oneshot: 0,
             }),
             request_mutex: Mutex::new(()),
             handler: RwLock::new(None),
@@ -285,6 +286,14 @@ impl IrqDesc {
         );
     }
 
+    pub fn set_probe(&self) {
+        self.modify_status(IrqLineStatus::IRQ_NOPROBE, IrqLineStatus::empty());
+    }
+
+    pub fn set_noprobe(&self) {
+        self.modify_status(IrqLineStatus::empty(), IrqLineStatus::IRQ_NOPROBE);
+    }
+
     pub fn modify_status(&self, clear: IrqLineStatus, set: IrqLineStatus) {
         let mut desc_guard = self.inner();
         desc_guard.line_status.remove(clear);
@@ -365,6 +374,8 @@ pub struct InnerIrqDesc {
     /// per-cpu affinity
     percpu_affinity: Option<CpuMask>,
     // wait_for_threads: EventWaitQueue
+    /// bitfield to handle shared oneshot threads
+    threads_oneshot: u64,
 }
 
 impl InnerIrqDesc {
@@ -444,6 +455,10 @@ impl InnerIrqDesc {
         !self.line_status.contains(IrqLineStatus::IRQ_NOTHREAD)
     }
 
+    pub fn threads_oneshot(&self) -> u64 {
+        self.threads_oneshot
+    }
+
     /// 中断是否可以设置CPU亲和性
     pub fn can_set_affinity(&self) -> bool {
         if !self.common_data.status().can_balance()

+ 6 - 2
kernel/src/exception/irqdomain.rs

@@ -110,8 +110,6 @@ impl IrqDomainManager {
 
         self.add_domain(domain.clone());
 
-        self.domain_associate_many(&domain, first_irq, first_hwirq, irq_size);
-
         return Some(domain);
     }
 
@@ -248,6 +246,10 @@ impl IrqDomainManager {
     /// 这是调用 domain_ops->activate 以编程中断控制器的第二步,以便中断实际上可以被传递。
     pub fn activate_irq(&self, irq_data: &Arc<IrqData>, reserve: bool) -> Result<(), SystemError> {
         let mut r = Ok(());
+        // kdebug!(
+        //     "activate_irq: irq_data.common_data().status().is_activated()={}",
+        //     irq_data.common_data().status().is_activated()
+        // );
         if !irq_data.common_data().status().is_activated() {
             r = self.do_activate_irq(Some(irq_data.clone()), reserve);
         }
@@ -268,7 +270,9 @@ impl IrqDomainManager {
         let mut r = Ok(());
 
         if let Some(irq_data) = irq_data {
+            // kdebug!("do_activate_irq: irq_data={:?}", irq_data);
             if let Some(domain) = irq_data.domain() {
+                // kdebug!("do_activate_irq: domain={:?}", domain.name());
                 let parent_data = irq_data.parent_data().and_then(|x| x.upgrade());
                 if let Some(parent_data) = parent_data.clone() {
                     r = self.do_activate_irq(Some(parent_data), reserve);

+ 52 - 3
kernel/src/exception/manage.rs

@@ -155,7 +155,7 @@ impl IrqManager {
         *action_guard.flags_mut() = flags;
         *action_guard.dev_id_mut() = dev_id;
         drop(action_guard);
-
+        kdebug!("to inner_setup_irq");
         return self.inner_setup_irq(irq, irqaction, desc);
     }
 
@@ -370,6 +370,15 @@ impl IrqManager {
                 || ((old_guard.flags().bitxor(*action_guard.flags()))
                     .contains(IrqHandleFlags::IRQF_ONESHOT))
             {
+                kdebug!(
+                    "Flags mismatch for irq {} (name: {}, flags: {:?}). old action name: {}, old flags: {:?}",
+                    irq.data(),
+                    action_guard.name(),
+                    action_guard.flags(),
+                    old_guard.name(),
+                    old_guard.flags()
+                );
+
                 return Err(err_out_mismatch(
                     old_guard,
                     desc_inner_guard,
@@ -383,6 +392,12 @@ impl IrqManager {
             if *old_guard.flags() & IrqHandleFlags::IRQF_PERCPU
                 != *action_guard.flags() & IrqHandleFlags::IRQF_PERCPU
             {
+                kdebug!(
+                    "Per-cpu mismatch for irq {} (name: {}, flags: {:?})",
+                    irq.data(),
+                    action_guard.name(),
+                    action_guard.flags()
+                );
                 return Err(err_out_mismatch(
                     old_guard,
                     desc_inner_guard,
@@ -436,6 +451,13 @@ impl IrqManager {
                 if let Err(e) =
                     self.do_set_irq_trigger(desc.clone(), &mut desc_inner_guard, trigger_type)
                 {
+                    kdebug!(
+                        "Failed to set trigger type for irq {} (name: {}, flags: {:?}), error {:?}",
+                        irq.data(),
+                        action_guard.name(),
+                        action_guard.flags(),
+                        e
+                    );
                     return Err(err_out_unlock(
                         e,
                         desc_inner_guard,
@@ -445,9 +467,16 @@ impl IrqManager {
                     ));
                 }
             }
-
+            kdebug!("to irq_activate");
             // 激活中断。这种激活必须独立于IRQ_NOAUTOEN进行*desc_inner_guard.internal_state_mut() |= IrqDescState::IRQS_NOREQUEST;uest.
             if let Err(e) = self.irq_activate(&desc, &mut desc_inner_guard) {
+                kdebug!(
+                    "Failed to activate irq {} (name: {}, flags: {:?}), error {:?}",
+                    irq.data(),
+                    action_guard.name(),
+                    action_guard.flags(),
+                    e
+                );
                 return Err(err_out_unlock(
                     e,
                     desc_inner_guard,
@@ -599,6 +628,11 @@ impl IrqManager {
         desc_inner_guard: &mut SpinLockGuard<'_, InnerIrqDesc>,
         resend: bool,
     ) -> Result<(), SystemError> {
+        kdebug!(
+            "irq_activate_and_startup: irq: {}, name: {:?}",
+            desc.irq().data(),
+            desc_inner_guard.name()
+        );
         self.irq_activate(desc, desc_inner_guard)?;
         self.irq_startup(desc, desc_inner_guard, resend, Self::IRQ_START_FORCE)
     }
@@ -625,6 +659,11 @@ impl IrqManager {
         resend: bool,
         force: bool,
     ) -> Result<(), SystemError> {
+        kdebug!(
+            "irq_startup: irq: {}, name: {:?}",
+            desc_inner_guard.irq_data().irq().data(),
+            desc_inner_guard.name()
+        );
         let mut ret = Ok(());
         let irq_data = desc_inner_guard.irq_data().clone();
         let affinity = desc_inner_guard.common_data().affinity();
@@ -745,7 +784,15 @@ impl IrqManager {
         );
     }
 
-    pub fn irq_do_set_affinity(
+    pub fn irq_set_affinity(
+        &self,
+        irq_data: &Arc<IrqData>,
+        desc_inner_guard: &SpinLockGuard<'_, InnerIrqDesc>,
+        cpumask: &CpuMask,
+    ) -> Result<(), SystemError> {
+        return self.irq_do_set_affinity(irq_data, desc_inner_guard, cpumask, false);
+    }
+    fn irq_do_set_affinity(
         &self,
         irq_data: &Arc<IrqData>,
         desc_inner_guard: &SpinLockGuard<'_, InnerIrqDesc>,
@@ -1050,6 +1097,8 @@ impl IrqManager {
     /// ## 注意
     ///
     /// 此函数不可以在中断上下文中调用。
+    ///
+    /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/irq/manage.c#2026
     pub fn free_irq(&self, _irq: IrqNumber, _dev_id: Option<Arc<DeviceId>>) {
         kwarn!("Unimplemented free_irq");
     }

+ 30 - 5
kernel/src/libs/cpumask.rs

@@ -16,6 +16,21 @@ impl CpuMask {
         Self { bmp }
     }
 
+    /// # from_cpu - 从指定的CPU创建CPU掩码
+    ///
+    /// 该函数用于根据给定的CPU标识创建一个CPU掩码,只有指定的CPU被设置为激活状态。
+    ///
+    /// ## 参数
+    /// - `cpu`: `ProcessorId`,指定要设置为激活状态的CPU。
+    ///
+    /// ## 返回值
+    /// - `Self`: 返回一个新的`CpuMask`实例,其中只有指定的CPU被设置为激活状态。
+    pub fn from_cpu(cpu: ProcessorId) -> Self {
+        let mut mask = Self::new();
+        mask.set(cpu, true);
+        mask
+    }
+
     /// 获取CpuMask中的第一个cpu
     pub fn first(&self) -> Option<ProcessorId> {
         self.bmp
@@ -86,14 +101,24 @@ impl CpuMask {
     pub fn inner(&self) -> &AllocBitmap {
         &self.bmp
     }
+
+    pub fn bitand_assign(&mut self, rhs: &CpuMask) {
+        self.bmp.bitand_assign(&rhs.bmp);
+    }
 }
 
-impl BitAnd for CpuMask {
-    type Output = Self;
+impl BitAnd for &CpuMask {
+    type Output = CpuMask;
 
-    fn bitand(self, rhs: Self) -> Self::Output {
-        let bmp = self.bmp & rhs.bmp;
-        Self { bmp }
+    fn bitand(self, rhs: &CpuMask) -> Self::Output {
+        let bmp = &self.bmp & &rhs.bmp;
+        CpuMask { bmp }
+    }
+}
+
+impl Default for CpuMask {
+    fn default() -> Self {
+        Self::new()
     }
 }
 

+ 36 - 0
kernel/src/mm/mmio_buddy.rs

@@ -1,3 +1,4 @@
+use crate::libs::align::{page_align_down, page_align_up};
 use crate::libs::spinlock::{SpinLock, SpinLockGuard};
 use crate::mm::kernel_mapper::KernelMapper;
 use crate::mm::page::{PAGE_1G_SHIFT, PAGE_4K_SHIFT};
@@ -682,6 +683,41 @@ impl MMIOSpaceGuard {
         return r;
     }
 
+    /// # map_any_phys - 将任意物理地址映射到虚拟地址
+    ///
+    /// 将指定的物理地址和长度映射到虚拟地址空间。
+    ///
+    /// ## 参数
+    ///
+    /// - `paddr`: 物理地址,需要被映射的起始地址。
+    /// - `length`: 要映射的物理地址长度。
+    ///
+    /// ## 返回值
+    /// - `Ok(VirtAddr)`: 映射成功,返回虚拟地址的起始地址。
+    /// - `Err(SystemError)`: 映射失败,返回系统错误。
+    ///
+    /// ## 副作用
+    ///
+    /// 该函数会修改虚拟地址空间,将物理地址映射到虚拟地址。
+    ///
+    /// ## Safety
+    ///
+    /// 由于该函数涉及到内存操作,因此它是非安全的。确保在调用该函数时,你传入的物理地址是正确的。
+    #[allow(dead_code)]
+    pub unsafe fn map_any_phys(
+        &self,
+        paddr: PhysAddr,
+        length: usize,
+    ) -> Result<VirtAddr, SystemError> {
+        let paddr_base = PhysAddr::new(page_align_down(paddr.data()));
+        let offset = paddr - paddr_base;
+        let vaddr_base = self.vaddr;
+        let vaddr = vaddr_base + offset;
+
+        self.map_phys(paddr_base, page_align_up(length + offset))?;
+        return Ok(vaddr);
+    }
+
     /// 泄露一个MMIO space guard,不会释放映射的空间
     pub unsafe fn leak(self) {
         core::mem::forget(self);

+ 2 - 0
kernel/src/smp/cpu/mod.rs

@@ -64,6 +64,7 @@ impl CpuHpCpuState {
         }
     }
 
+    #[allow(dead_code)]
     pub const fn thread(&self) -> &Option<Arc<ProcessControlBlock>> {
         &self.thread
     }
@@ -305,6 +306,7 @@ pub fn smp_cpu_manager_init(boot_cpu: ProcessorId) {
     }
 
     unsafe { smp_cpu_manager().set_possible_cpu(boot_cpu, true) };
+    unsafe { smp_cpu_manager().set_present_cpu(boot_cpu, true) };
 
     SmpCpuManager::arch_init(boot_cpu);
 }