diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 4ea5e6bb..376709b3 100644 --- a/kernel/Cargo.toml +++ b/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" diff --git a/kernel/crates/bitmap/src/alloc_bitmap.rs b/kernel/crates/bitmap/src/alloc_bitmap.rs index 7f06350e..d78ceb81 100644 --- a/kernel/crates/bitmap/src/alloc_bitmap.rs +++ b/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 for AllocBitmap { @@ -111,8 +117,8 @@ impl BitMapOps 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 + } +} diff --git a/kernel/crates/bitmap/tests/alloc-bitmap.rs b/kernel/crates/bitmap/tests/alloc-bitmap.rs index 80d14913..9b840afa 100644 --- a/kernel/crates/bitmap/tests/alloc-bitmap.rs +++ b/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)); +} diff --git a/kernel/src/arch/riscv64/asm/bitops.rs b/kernel/src/arch/riscv64/asm/bitops.rs index 26594a73..647043c2 100644 --- a/kernel/src/arch/riscv64/asm/bitops.rs +++ b/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 } diff --git a/kernel/src/arch/riscv64/driver/of.rs b/kernel/src/arch/riscv64/driver/of.rs index 95749767..2aa6adbe 100644 --- a/kernel/src/arch/riscv64/driver/of.rs +++ b/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}, }; diff --git a/kernel/src/arch/riscv64/interrupt/entry.rs b/kernel/src/arch/riscv64/interrupt/entry.rs index 7693a92d..31dd785b 100644 --- a/kernel/src/arch/riscv64/interrupt/entry.rs +++ b/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, }; diff --git a/kernel/src/arch/riscv64/interrupt/handle.rs b/kernel/src/arch/riscv64/interrupt/handle.rs index 891c57de..97f94d29 100644 --- a/kernel/src/arch/riscv64/interrupt/handle.rs +++ b/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; diff --git a/kernel/src/arch/riscv64/interrupt/mod.rs b/kernel/src/arch/riscv64/interrupt/mod.rs index a57eebaf..dc6d7893 100644 --- a/kernel/src/arch/riscv64/interrupt/mod.rs +++ b/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(()) diff --git a/kernel/src/arch/riscv64/mm/mod.rs b/kernel/src/arch/riscv64/mm/mod.rs index abf05f3d..76bfbed0 100644 --- a/kernel/src/arch/riscv64/mm/mod.rs +++ b/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, diff --git a/kernel/src/arch/x86_64/driver/apic/lapic_vector.rs b/kernel/src/arch/x86_64/driver/apic/lapic_vector.rs index 78ef4d99..74a1ee79 100644 --- a/kernel/src/arch/x86_64/driver/apic/lapic_vector.rs +++ b/kernel/src/arch/x86_64/driver/apic/lapic_vector.rs @@ -227,16 +227,23 @@ pub fn x86_vector_domain() -> &'static Arc { #[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()); diff --git a/kernel/src/driver/block/virtio_blk.rs b/kernel/src/driver/block/virtio_blk.rs index 44937e9a..75fe897e 100644 --- a/kernel/src/driver/block/virtio_blk.rs +++ b/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) -> Option> { + let irq = transport.irq().map(|irq| IrqNumber::new(irq.data())); let device_inner = VirtIOBlk::::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 = device_inner.unwrap(); + let mut device_inner: VirtIOBlk = 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, device_common: DeviceCommonData, kobject_common: KObjectCommonData, + irq: Option, } impl Debug for InnerVirtIOBlkDevice { @@ -199,11 +202,16 @@ impl Debug for InnerVirtIOBlkDevice { } impl VirtIODevice for VirtIOBlkDevice { + fn irq(&self) -> Option { + self.inner().irq + } + fn handle_irq( &self, _irq: crate::exception::IrqNumber, - ) -> Result { - todo!("VirtIOBlkDevice::handle_irq") + ) -> Result { + // todo: handle virtio blk irq + Ok(crate::exception::irqdesc::IrqReturn::Handled) } fn dev_id(&self) -> &Arc { diff --git a/kernel/src/driver/clocksource/timer_riscv.rs b/kernel/src/driver/clocksource/timer_riscv.rs index 3975296c..e5481f4e 100644 --- a/kernel/src/driver/clocksource/timer_riscv.rs +++ b/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); diff --git a/kernel/src/driver/irqchip/mod.rs b/kernel/src/driver/irqchip/mod.rs index bb03a2c3..a13c2dde 100644 --- a/kernel/src/driver/irqchip/mod.rs +++ b/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; diff --git a/kernel/src/driver/irqchip/riscv_intc.rs b/kernel/src/driver/irqchip/riscv_intc.rs index edafea17..2e83dbb3 100644 --- a/kernel/src/driver/irqchip/riscv_intc.rs +++ b/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> = None; static mut RISCV_INTC_CHIP: Option> = None; @@ -30,6 +32,9 @@ fn riscv_intc_chip() -> Option<&'static Arc> { 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, @@ -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 { + 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 { + 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 { + 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); diff --git a/kernel/src/driver/irqchip/riscv_sifive_plic.rs b/kernel/src/driver/irqchip/riscv_sifive_plic.rs new file mode 100644 index 00000000..83e26916 --- /dev/null +++ b/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> = None; + +static mut PLIC_IRQ_CHIP: Option> = None; + +#[inline(always)] +fn plic_irq_chip() -> Arc { + unsafe { PLIC_IRQ_CHIP.as_ref().unwrap().clone() } +} + +#[inline(always)] +fn plic_handlers() -> &'static PerCpuVar { + unsafe { PLIC_HANDLERS.as_ref().unwrap() } +} + +#[allow(dead_code)] +struct PlicChipData { + irq_domain: Weak, + phandle: u32, + lmask: SpinLock, + mmio_guard: Option, + regs: VirtAddr, +} + +impl PlicChipData { + fn new( + irq_domain: Weak, + mmio_guard: MMIOSpaceGuard, + regs: VirtAddr, + phandle: u32, + ) -> Arc { + let r = Self { + irq_domain, + lmask: SpinLock::new(CpuMask::new()), + mmio_guard: Some(mmio_guard), + regs, + phandle, + }; + + Arc::new(r) + } + + fn lmask(&self) -> SpinLockGuard { + 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>, + present: AtomicBool, + inner: SpinLock, +} + +struct InnerPlicHandler { + hart_base: VirtAddr, + enable_base: VirtAddr, + enable_save: Option, +} + +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) { + self.priv_data = Some(priv_data); + } + + fn priv_data(&self) -> Option> { + 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 { + 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, 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) -> 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) -> 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::() + .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) -> 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::() + .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) { + 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) { + 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) { + 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, + mask_val: &CpuMask, + force: bool, + ) -> Result { + 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::() + .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)); + + 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, + 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, _virq: IrqNumber) { + todo!() + } + + fn map( + &self, + irq_domain: &Arc, + 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::() + .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, + _irq_data: &Arc, + _reserve: bool, + ) -> Result<(), SystemError> { + kwarn!("plic: activate"); + loop {} + } + + fn deactivate(&self, _domain: &Arc, _irq_data: &Arc) {} +} + +/// 处理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:?}"); + } + } +} diff --git a/kernel/src/driver/net/virtio_net.rs b/kernel/src/driver/net/virtio_net.rs index f0d2622c..1bc1f6a6 100644 --- a/kernel/src/driver/net/virtio_net.rs +++ b/kernel/src/driver/net/virtio_net.rs @@ -207,6 +207,10 @@ impl VirtIODevice for VirtioInterface { return Ok(IrqReturn::Handled); } + fn irq(&self) -> Option { + None + } + fn dev_id(&self) -> &Arc { return &self.dev_id; } diff --git a/kernel/src/driver/virtio/irq.rs b/kernel/src/driver/virtio/irq.rs index 629c09f8..70f823ab 100644 --- a/kernel/src/driver/virtio/irq.rs +++ b/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>, + ) -> Result { + let dev_id = dev_id.ok_or(SystemError::EINVAL)?; + let dev_id = dev_id + .arc_any() + .downcast::() + .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); + } + } +} diff --git a/kernel/src/driver/virtio/mod.rs b/kernel/src/driver/virtio/mod.rs index 642027a3..9498dcb2 100644 --- a/kernel/src/driver/virtio/mod.rs +++ b/kernel/src/driver/virtio/mod.rs @@ -36,6 +36,13 @@ pub trait VirtIODevice: Device { /// virtio 设备厂商 fn vendor(&self) -> u32; + + /// virtio设备的中断号 + fn irq(&self) -> Option; + + fn set_irq_number(&self, _irq: IrqNumber) -> Result<(), SystemError> { + Err(SystemError::ENOSYS) + } } pub trait VirtIODriver: Driver { diff --git a/kernel/src/driver/virtio/sysfs.rs b/kernel/src/driver/virtio/sysfs.rs index 25e434e4..526a88ad 100644 --- a/kernel/src/driver/virtio/sysfs.rs +++ b/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)?; - device_manager().add_groups(&(dev as Arc), &[&VirtIODeviceAttrGroup]) + let r = device_manager() + .add_groups(&(dev.clone() as Arc), &[&VirtIODeviceAttrGroup]); + + self.setup_irq(&dev).ok(); + + return r; + } + + /// # setup_irq - 设置中断 + /// + /// 为virtio设备设置中断。 + fn setup_irq(&self, dev: &Arc) -> 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)] diff --git a/kernel/src/driver/virtio/transport.rs b/kernel/src/driver/virtio/transport.rs index f1f58a8b..b1819403 100644 --- a/kernel/src/driver/virtio/transport.rs +++ b/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 { + 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 { diff --git a/kernel/src/driver/virtio/transport_pci.rs b/kernel/src/driver/virtio/transport_pci.rs index fc001052..071f7edd 100644 --- a/kernel/src/driver/virtio/transport_pci.rs +++ b/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( fn nonnull_slice_from_raw_parts(data: NonNull, 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>, - ) -> Result { - let dev_id = dev_id.ok_or(SystemError::EINVAL)?; - let dev_id = dev_id - .arc_any() - .downcast::() - .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); - } - } -} diff --git a/kernel/src/exception/handle.rs b/kernel/src/exception/handle.rs index 9fb513ca..fcfea1e4 100644 --- a/kernel/src/exception/handle.rs +++ b/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, _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, _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| { + 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) { } } +pub(super) fn mask_irq(irq_data: &Arc) { + 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) { + 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, + 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) -> 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, +) { + 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 diff --git a/kernel/src/exception/irqchip.rs b/kernel/src/exception/irqchip.rs index 2f02b0f2..93e2aa09 100644 --- a/kernel/src/exception/irqchip.rs +++ b/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) -> Result<(), SystemError> { + fn irq_startup(&self, _irq_data: &Arc) -> Result<(), SystemError> { Err(SystemError::ENOSYS) } /// shut down the interrupt (defaults to ->disable if ENOSYS) - fn irq_shutdown(&self, _irq: &Arc) -> Result<(), SystemError> { + fn irq_shutdown(&self, _irq_data: &Arc) -> Result<(), SystemError> { Err(SystemError::ENOSYS) } /// enable the interrupt /// /// (defaults to ->unmask if ENOSYS) - fn irq_enable(&self, _irq: &Arc) -> Result<(), SystemError> { + fn irq_enable(&self, _irq_data: &Arc) -> Result<(), SystemError> { Err(SystemError::ENOSYS) } /// disable the interrupt - fn irq_disable(&self, irq: &Arc); + fn irq_disable(&self, irq_data: &Arc); /// start of a new interrupt - fn irq_ack(&self, irq: &Arc); + fn irq_ack(&self, irq_data: &Arc); /// 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) -> Result<(), SystemError> { + fn irq_mask(&self, _irq_data: &Arc) -> 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) {} + fn irq_mask_ack(&self, _irq_data: &Arc) {} /// unmask an interrupt source /// /// 用于取消屏蔽中断 /// /// 如果返回ENOSYS,则表明irq_unmask()不支持. - fn irq_unmask(&self, _irq: &Arc) -> Result<(), SystemError> { + fn irq_unmask(&self, _irq_data: &Arc) -> Result<(), SystemError> { Err(SystemError::ENOSYS) } /// end of interrupt - fn irq_eoi(&self, _irq: &Arc) {} + fn irq_eoi(&self, _irq_data: &Arc) {} /// 指示当前芯片是否可以设置中断亲和性。 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, + _irq_data: &Arc, _cpu: &CpuMask, _force: bool, ) -> Result { @@ -104,7 +104,7 @@ pub trait IrqChip: Sync + Send + Any + Debug { } /// retrigger an IRQ to the CPU - fn retrigger(&self, _irq: &Arc) -> Result<(), SystemError> { + fn retrigger(&self, _irq_data: &Arc) -> Result<(), SystemError> { Err(SystemError::ENOSYS) } @@ -119,65 +119,65 @@ pub trait IrqChip: Sync + Send + Any + Debug { /// fn irq_set_type( &self, - _irq: &Arc, + _irq_data: &Arc, _flow_type: IrqLineStatus, ) -> Result { Err(SystemError::ENOSYS) } /// enable/disable power management wake-on of an interrupt - fn irq_set_wake(&self, _irq: &Arc, _on: bool) -> Result<(), SystemError> { + fn irq_set_wake(&self, _irq_data: &Arc, _on: bool) -> Result<(), SystemError> { Err(SystemError::ENOSYS) } /// function to lock access to slow bus (i2c) chips - fn irq_bus_lock(&self, _irq: &Arc) -> Result<(), SystemError> { + fn irq_bus_lock(&self, _irq_data: &Arc) -> Result<(), SystemError> { Ok(()) } /// function to sync and unlock slow bus (i2c) chips - fn irq_bus_sync_unlock(&self, _irq: &Arc) -> Result<(), SystemError> { + fn irq_bus_sync_unlock(&self, _irq_data: &Arc) -> 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) {} + fn irq_suspend(&self, _irq_data: &Arc) {} /// function called from core code on resume once per chip, /// when one ore more interrupts are installed - fn irq_resume(&self, _irq: &Arc) {} + fn irq_resume(&self, _irq_data: &Arc) {} /// function called from core code on shutdown once per chip - fn irq_pm_shutdown(&self, _irq: &Arc) {} + fn irq_pm_shutdown(&self, _irq_data: &Arc) {} /// Optional function to set irq_data.mask for special cases - fn irq_calc_mask(&self, _irq: &Arc) {} + fn irq_calc_mask(&self, _irq_data: &Arc) {} // todo: print chip /// optional to request resources before calling /// any other callback related to this irq - fn irq_request_resources(&self, _irq: &Arc) -> Result<(), SystemError> { + fn irq_request_resources(&self, _irq_data: &Arc) -> Result<(), SystemError> { Ok(()) } /// optional to release resources acquired with /// irq_request_resources - fn irq_release_resources(&self, _irq: &Arc) {} + fn irq_release_resources(&self, _irq_data: &Arc) {} /// optional to compose message content for MSI /// /// 组装MSI消息并返回到msg中 - fn irq_compose_msi_msg(&self, _irq: &Arc, _msg: &mut MsiMsg) {} + fn irq_compose_msi_msg(&self, _irq_data: &Arc, _msg: &mut MsiMsg) {} /// optional to write message content for MSI - fn irq_write_msi_msg(&self, _irq: &Arc, _msg: &MsiMsg) {} + fn irq_write_msi_msg(&self, _irq_data: &Arc, _msg: &MsiMsg) {} /// return the internal state of an interrupt fn irqchip_state( &self, - _irq: &Arc, + _irq_data: &Arc, _which: IrqChipState, ) -> Result { 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, + _irq_data: &Arc, _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, _cpu: u32) {} + fn send_single_ipi(&self, _irq_data: &Arc, _cpu: u32) {} // todo: send ipi with cpu mask /// function called from core code before enabling an NMI - fn irq_nmi_setup(&self, _irq: &Arc) -> Result<(), SystemError> { + fn irq_nmi_setup(&self, _irq_data: &Arc) -> Result<(), SystemError> { Err(SystemError::ENOSYS) } /// function called from core code after disabling an NMI - fn irq_nmi_teardown(&self, _irq: &Arc) {} + fn irq_nmi_teardown(&self, _irq_data: &Arc) {} fn flags(&self) -> IrqChipFlags; } diff --git a/kernel/src/exception/irqdata.rs b/kernel/src/exception/irqdata.rs index 11e7287e..2388907c 100644 --- a/kernel/src/exception/irqdata.rs +++ b/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 { self.inner.lock_irqsave() } @@ -318,6 +324,7 @@ pub struct InnerIrqCommonData { handler_data: Option>, msi_desc: Option>, affinity: CpuMask, + effective_affinity: CpuMask, } impl InnerIrqCommonData { @@ -338,6 +345,10 @@ impl InnerIrqCommonData { pub fn handler_data(&self) -> Option> { self.handler_data.clone() } + + pub fn effective_affinity(&self) -> &CpuMask { + &self.effective_affinity + } } /// 中断处理函数传入的数据 diff --git a/kernel/src/exception/irqdesc.rs b/kernel/src/exception/irqdesc.rs index d7bd3d55..81565596 100644 --- a/kernel/src/exception/irqdesc.rs +++ b/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, // 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() diff --git a/kernel/src/exception/irqdomain.rs b/kernel/src/exception/irqdomain.rs index 666cd868..92267aa1 100644 --- a/kernel/src/exception/irqdomain.rs +++ b/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, 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); diff --git a/kernel/src/exception/manage.rs b/kernel/src/exception/manage.rs index 018ec6b9..80a63249 100644 --- a/kernel/src/exception/manage.rs +++ b/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, + 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, 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>) { kwarn!("Unimplemented free_irq"); } diff --git a/kernel/src/libs/cpumask.rs b/kernel/src/libs/cpumask.rs index 7cbac899..fc86b860 100644 --- a/kernel/src/libs/cpumask.rs +++ b/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 { 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() } } diff --git a/kernel/src/mm/mmio_buddy.rs b/kernel/src/mm/mmio_buddy.rs index e2008661..0c500572 100644 --- a/kernel/src/mm/mmio_buddy.rs +++ b/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 { + 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); diff --git a/kernel/src/smp/cpu/mod.rs b/kernel/src/smp/cpu/mod.rs index e85b600e..62c0b4d1 100644 --- a/kernel/src/smp/cpu/mod.rs +++ b/kernel/src/smp/cpu/mod.rs @@ -64,6 +64,7 @@ impl CpuHpCpuState { } } + #[allow(dead_code)] pub const fn thread(&self) -> &Option> { &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); }