diff --git a/kernel/src/arch/riscv64/interrupt/mod.rs b/kernel/src/arch/riscv64/interrupt/mod.rs index 379f5ded..8fa31e2e 100644 --- a/kernel/src/arch/riscv64/interrupt/mod.rs +++ b/kernel/src/arch/riscv64/interrupt/mod.rs @@ -1,6 +1,6 @@ use system_error::SystemError; -use crate::exception::{InterruptArch, IrqFlags, IrqFlagsGuard}; +use crate::exception::{InterruptArch, IrqFlags, IrqFlagsGuard, IrqNumber}; pub mod ipi; @@ -35,6 +35,15 @@ impl InterruptArch for RiscV64InterruptArch { riscv::register::sstatus::clear_sie(); } } + + fn probe_total_irq_num() -> u32 { + // todo: 获取中断总数 + 256 + } + + fn ack_bad_irq(irq: IrqNumber) { + todo!("ack_bad_irq: {}", irq.data()); + } } /// 中断栈帧结构体 diff --git a/kernel/src/arch/x86_64/interrupt/mod.rs b/kernel/src/arch/x86_64/interrupt/mod.rs index 44dae4d1..db36c1d9 100644 --- a/kernel/src/arch/x86_64/interrupt/mod.rs +++ b/kernel/src/arch/x86_64/interrupt/mod.rs @@ -12,7 +12,8 @@ use system_error::SystemError; use crate::{ arch::CurrentIrqArch, - exception::{InterruptArch, IrqFlags, IrqFlagsGuard}, + exception::{InterruptArch, IrqFlags, IrqFlagsGuard, IrqNumber}, + kerror, }; use self::entry::setup_interrupt_gate; @@ -78,6 +79,17 @@ impl InterruptArch for X86_64InterruptArch { local_irq_restore(flags.flags()); compiler_fence(Ordering::SeqCst); } + + fn probe_total_irq_num() -> u32 { + // todo: 从APIC获取 + // 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/arch/x86/kernel/apic/vector.c?r=&mo=19514&fi=704#704 + 256 + } + + fn ack_bad_irq(irq: IrqNumber) { + kerror!("Unexpected IRQ trap at vector {}", irq.data()); + CurrentApic.send_eoi(); + } } /// 中断栈帧结构体 diff --git a/kernel/src/driver/base/device/mod.rs b/kernel/src/driver/base/device/mod.rs index 4f78a4e7..f020d292 100644 --- a/kernel/src/driver/base/device/mod.rs +++ b/kernel/src/driver/base/device/mod.rs @@ -873,3 +873,45 @@ impl DeviceMatcher<&str> for DeviceMatchName { return device.name() == data; } } + +/// Cookie to identify the device +#[derive(Debug, Clone)] +pub struct DeviceId { + data: Option<&'static str>, + allocated: Option, +} + +impl DeviceId { + #[allow(dead_code)] + pub fn new(data: Option<&'static str>, allocated: Option) -> Option { + if data.is_none() && allocated.is_none() { + return None; + } + + // 如果data和allocated都有值,那么返回None + if data.is_some() && allocated.is_some() { + return None; + } + + return Some(Self { data, allocated }); + } + + pub fn id(&self) -> Option<&str> { + if self.data.is_some() { + return Some(self.data.unwrap()); + } else { + return self.allocated.as_deref(); + } + } + + pub fn set_allocated(&mut self, allocated: String) { + self.allocated = Some(allocated); + self.data = None; + } +} + +impl PartialEq for DeviceId { + fn eq(&self, other: &Self) -> bool { + return self.id() == other.id(); + } +} diff --git a/kernel/src/exception/dummychip.rs b/kernel/src/exception/dummychip.rs new file mode 100644 index 00000000..181149d9 --- /dev/null +++ b/kernel/src/exception/dummychip.rs @@ -0,0 +1,111 @@ +use alloc::sync::Arc; +use system_error::SystemError; + +use crate::arch::CurrentIrqArch; + +use super::{ + irqchip::{IrqChip, IrqChipFlags}, + irqdata::IrqData, + InterruptArch, +}; + +static mut NO_IRQ_CHIP: Option> = None; +static mut DUMMY_IRQ_CHIP: Option> = None; + +#[inline(never)] +pub fn no_irq_chip() -> Arc { + unsafe { NO_IRQ_CHIP.as_ref().unwrap().clone() } +} + +#[allow(dead_code)] +#[inline(never)] +pub fn dummy_irq_chip() -> Arc { + unsafe { DUMMY_IRQ_CHIP.as_ref().unwrap().clone() } +} + +fn ack_bad(irq_data: &Arc) { + // todo: print_irq_desc + CurrentIrqArch::ack_bad_irq(irq_data.irq()); +} + +#[derive(Debug)] +struct NoIrqChip; + +impl NoIrqChip { + pub const fn new() -> Self { + NoIrqChip + } +} + +impl IrqChip for NoIrqChip { + fn name(&self) -> &'static str { + "none" + } + fn irq_enable(&self, _irq: &Arc) -> Result<(), SystemError> { + Ok(()) + } + + fn irq_disable(&self, _irq: &Arc) {} + + fn irq_ack(&self, irq: &Arc) { + ack_bad(irq); + } + + fn irq_startup(&self, _irq: &Arc) -> Result<(), SystemError> { + Ok(()) + } + + fn irq_shutdown(&self, _irq: &Arc) -> Result<(), SystemError> { + Ok(()) + } + + fn flags(&self) -> IrqChipFlags { + IrqChipFlags::IRQCHIP_SKIP_SET_WAKE + } +} + +#[derive(Debug)] +struct DummyIrqChip; + +impl DummyIrqChip { + pub const fn new() -> Self { + DummyIrqChip + } +} + +impl IrqChip for DummyIrqChip { + fn name(&self) -> &'static str { + "dummy" + } + + fn irq_enable(&self, _irq: &Arc) -> Result<(), SystemError> { + Ok(()) + } + + fn irq_disable(&self, _irq: &Arc) {} + + fn irq_ack(&self, _irq: &Arc) {} + + fn irq_mask(&self, _irq: &Arc) {} + fn irq_unmask(&self, _irq: &Arc) {} + + fn irq_startup(&self, _irq: &Arc) -> Result<(), SystemError> { + Ok(()) + } + + fn irq_shutdown(&self, _irq: &Arc) -> Result<(), SystemError> { + Ok(()) + } + + fn flags(&self) -> IrqChipFlags { + IrqChipFlags::IRQCHIP_SKIP_SET_WAKE + } +} + +#[inline(never)] +pub fn dummy_chip_init() { + unsafe { + NO_IRQ_CHIP = Some(Arc::new(NoIrqChip::new())); + DUMMY_IRQ_CHIP = Some(Arc::new(DummyIrqChip::new())); + } +} diff --git a/kernel/src/exception/handle.rs b/kernel/src/exception/handle.rs new file mode 100644 index 00000000..59141072 --- /dev/null +++ b/kernel/src/exception/handle.rs @@ -0,0 +1,27 @@ +use alloc::sync::Arc; + +use crate::arch::CurrentIrqArch; + +use super::{ + irqdesc::{IrqDesc, IrqFlowHandler}, + InterruptArch, +}; + +/// 获取用于处理错误的中断的处理程序 +#[inline(always)] +pub fn bad_irq_handler() -> &'static dyn IrqFlowHandler { + &HandleBadIrq +} + +/// handle spurious and unhandled irqs +#[derive(Debug)] +struct HandleBadIrq; + +impl IrqFlowHandler for HandleBadIrq { + /// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/handle.c?fi=handle_bad_irq#33 + fn handle(&self, irq_desc: &Arc) { + // todo: print_irq_desc + // todo: 增加kstat计数 + CurrentIrqArch::ack_bad_irq(irq_desc.irq()); + } +} diff --git a/kernel/src/exception/init.rs b/kernel/src/exception/init.rs index b96fcf0d..742865f7 100644 --- a/kernel/src/exception/init.rs +++ b/kernel/src/exception/init.rs @@ -2,13 +2,16 @@ use system_error::SystemError; use crate::arch::CurrentIrqArch; -use super::InterruptArch; +use super::{dummychip::dummy_chip_init, irqdesc::early_irq_init, InterruptArch}; /// 初始化中断 #[inline(never)] pub fn irq_init() -> Result<(), SystemError> { // todo: 通用初始化 + dummy_chip_init(); + early_irq_init().expect("early_irq_init failed"); + // 初始化架构相关的中断 unsafe { CurrentIrqArch::arch_irq_init() }?; return Ok(()); diff --git a/kernel/src/exception/irqchip.rs b/kernel/src/exception/irqchip.rs index 9f98e931..4cca4903 100644 --- a/kernel/src/exception/irqchip.rs +++ b/kernel/src/exception/irqchip.rs @@ -41,18 +41,18 @@ pub trait IrqChip: Sync + Send + Any + Debug { fn irq_ack(&self, irq: &Arc); /// mask an interrupt source - fn irq_mask(&self, irq: &Arc); + fn irq_mask(&self, _irq: &Arc) {} /// ack and mask an interrupt source - fn irq_mask_ack(&self, irq: &Arc); + fn irq_mask_ack(&self, _irq: &Arc) {} /// unmask an interrupt source - fn irq_unmask(&self, irq: &Arc); + fn irq_unmask(&self, _irq: &Arc) {} /// end of interrupt - fn irq_eoi(&self, irq: &Arc); + fn irq_eoi(&self, _irq: &Arc) {} // todo: set affinity /// retrigger an IRQ to the CPU - fn retrigger(&self, irq: &Arc); + fn retrigger(&self, _irq: &Arc) {} /// set the flow type of an interrupt /// @@ -83,14 +83,14 @@ pub trait IrqChip: Sync + Send + Any + Debug { /// function called from core code on suspend once per /// chip, when one or more interrupts are installed - fn irq_suspend(&self, irq: &Arc); + fn irq_suspend(&self, _irq: &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: &Arc) {} /// function called from core code on shutdown once per chip - fn irq_pm_shutdown(&self, irq: &Arc); + fn irq_pm_shutdown(&self, _irq: &Arc) {} /// Optional function to set irq_data.mask for special cases fn irq_calc_mask(&self, _irq: &Arc) {} @@ -135,7 +135,7 @@ pub trait IrqChip: Sync + Send + Any + Debug { // todo: set vcpu affinity /// send a single IPI to destination cpus - fn send_single_ipi(&self, irq: &Arc, cpu: u32); + fn send_single_ipi(&self, _irq: &Arc, _cpu: u32) {} // todo: send ipi with cpu mask @@ -145,7 +145,9 @@ pub trait IrqChip: Sync + Send + Any + Debug { } /// function called from core code after disabling an NMI - fn irq_nmi_teardown(&self, irq: &Arc); + fn irq_nmi_teardown(&self, _irq: &Arc) {} + + fn flags(&self) -> IrqChipFlags; } #[allow(dead_code)] @@ -214,7 +216,7 @@ struct InnerIrqChipGeneric { chip_types: Vec, } -pub trait IrqChipGenericOps: Debug { +pub trait IrqChipGenericOps: Debug + Send + Sync { /// Alternate I/O accessor (defaults to readl if NULL) unsafe fn reg_readl(&self, addr: VirtAddr) -> u32; @@ -237,3 +239,33 @@ pub trait IrqChipGenericPrivateData: Sync + Send + Any + Debug {} pub struct IrqChipType { // todo https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#1024 } + +bitflags! { + /// IrqChip specific flags + pub struct IrqChipFlags: u32 { + /// 在调用chip.irq_set_type()之前屏蔽 + const IRQCHIP_SET_TYPE_MASKED = 1 << 0; + /// 只有在irq被处理时才发出irq_eoi() + const IRQCHIP_EOI_IF_HANDLED = 1 << 1; + /// 在挂起路径中屏蔽非唤醒irq + const IRQCHIP_MASK_ON_SUSPEND = 1 << 2; + /// 只有在irq启用时才调用irq_on/off_line回调 + const IRQCHIP_ONOFFLINE_ENABLED = 1 << 3; + /// 跳过chip.irq_set_wake(),对于这个irq芯片 + const IRQCHIP_SKIP_SET_WAKE = 1 << 4; + /// 单次触发不需要屏蔽/取消屏蔽 + const IRQCHIP_ONESHOT_SAFE = 1 << 5; + /// 芯片在线程模式下需要在取消屏蔽时eoi() + const IRQCHIP_EOI_THREADED = 1 << 6; + /// 芯片可以为Level MSIs提供两个门铃 + const IRQCHIP_SUPPORTS_LEVEL_MSI = 1 << 7; + /// 芯片可以传递NMIs,仅适用于根irqchips + const IRQCHIP_SUPPORTS_NMI = 1 << 8; + /// 在挂起路径中,如果它们处于禁用状态,则调用__enable_irq()/__disable_irq()以唤醒irq + const IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND = 1 << 9; + /// 在启动前更新默认亲和性 + const IRQCHIP_AFFINITY_PRE_STARTUP = 1 << 10; + /// 不要在这个芯片中改变任何东西 + const IRQCHIP_IMMUTABLE = 1 << 11; + } +} diff --git a/kernel/src/exception/irqdata.rs b/kernel/src/exception/irqdata.rs index 8d18dcb6..7fe9bb68 100644 --- a/kernel/src/exception/irqdata.rs +++ b/kernel/src/exception/irqdata.rs @@ -21,6 +21,50 @@ use super::{ pub struct IrqData { /// 中断号, 用于表示软件逻辑视角的中断号,全局唯一 irq: IrqNumber, + inner: SpinLock, +} + +impl IrqData { + pub fn new( + irq: IrqNumber, + hwirq: HardwareIrqNumber, + common_data: Arc, + chip: Arc, + ) -> Self { + return IrqData { + irq, + inner: SpinLock::new(InnerIrqData { + hwirq, + common_data, + chip, + chip_data: None, + domain: None, + parent_data: None, + }), + }; + } + + pub fn irqd_set(&self, status: IrqStatus) { + // clone是为了释放inner锁 + let common_data = self.inner.lock().common_data.clone(); + common_data.irqd_set(status); + } + + #[allow(dead_code)] + pub fn irqd_clear(&self, status: IrqStatus) { + // clone是为了释放inner锁 + let common_data = self.inner.lock().common_data.clone(); + common_data.irqd_clear(status); + } + + pub fn irq(&self) -> IrqNumber { + self.irq + } +} + +#[allow(dead_code)] +#[derive(Debug)] +struct InnerIrqData { /// 硬件中断号, 用于表示在某个IrqDomain中的中断号 hwirq: HardwareIrqNumber, /// 涉及的所有irqchip之间共享的数据 @@ -28,9 +72,9 @@ pub struct IrqData { /// 绑定到的中断芯片 chip: Arc, /// 中断芯片的私有数据(与当前irq相关) - chip_data: Arc, + chip_data: Option>, /// 中断域 - domain: Arc, + domain: Option>, /// 中断的父中断(如果具有中断域继承的话) parent_data: Option>, } @@ -38,12 +82,32 @@ pub struct IrqData { /// per irq data shared by all irqchips /// /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#147 -#[allow(dead_code)] #[derive(Debug)] pub struct IrqCommonData { inner: SpinLock, } +impl IrqCommonData { + pub fn new() -> Self { + let inner = InnerIrqCommonData { + state: IrqStatus::empty(), + handler_data: None, + msi_desc: None, + }; + return IrqCommonData { + inner: SpinLock::new(inner), + }; + } + + pub fn irqd_set(&self, status: IrqStatus) { + self.inner.lock_irqsave().irqd_set(status); + } + + pub fn irqd_clear(&self, status: IrqStatus) { + self.inner.lock_irqsave().irqd_clear(status); + } +} + #[allow(dead_code)] #[derive(Debug)] struct InnerIrqCommonData { @@ -55,6 +119,16 @@ struct InnerIrqCommonData { // todo: affinity } +impl InnerIrqCommonData { + pub fn irqd_set(&mut self, status: IrqStatus) { + self.state.insert(status); + } + + pub fn irqd_clear(&mut self, status: IrqStatus) { + self.state.remove(status); + } +} + pub trait IrqHandlerData: Send + Sync + Any + Debug {} bitflags! { diff --git a/kernel/src/exception/irqdesc.rs b/kernel/src/exception/irqdesc.rs new file mode 100644 index 00000000..c7e558db --- /dev/null +++ b/kernel/src/exception/irqdesc.rs @@ -0,0 +1,294 @@ +use core::{any::Any, fmt::Debug}; + +use alloc::{ + collections::BTreeMap, + string::String, + sync::{Arc, Weak}, + vec::Vec, +}; +use system_error::SystemError; + +use crate::{ + arch::CurrentIrqArch, + driver::base::{ + device::DeviceId, + kobject::{KObjType, KObject, KObjectState, LockedKObjectState}, + kset::KSet, + }, + filesystem::kernfs::KernFSInode, + libs::{ + rwlock::{RwLockReadGuard, RwLockWriteGuard}, + spinlock::{SpinLock, SpinLockGuard}, + }, + process::ProcessControlBlock, +}; + +use super::{ + dummychip::no_irq_chip, + handle::bad_irq_handler, + irqdata::{IrqCommonData, IrqData, IrqStatus}, + sysfs::IrqKObjType, + HardwareIrqNumber, InterruptArch, IrqNumber, +}; + +/// 中断流处理程序 +pub trait IrqFlowHandler: Debug + Send + Sync { + fn handle(&self, irq_desc: &Arc); +} + +/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdesc.h#55 +#[derive(Debug)] +pub struct IrqDesc { + inner: SpinLock, + + handler: SpinLock>, + + kobj_state: LockedKObjectState, +} + +impl IrqDesc { + #[inline(never)] + pub fn new(irq: IrqNumber, name: Option, irqd_flags: IrqStatus) -> Arc { + // 初始化的过程参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdesc.c#392 + let common_data = Arc::new(IrqCommonData::new()); + let irq_data = Arc::new(IrqData::new( + irq, + HardwareIrqNumber::new(irq.data()), + common_data.clone(), + no_irq_chip(), + )); + + irq_data.irqd_set(IrqStatus::IRQD_IRQ_DISABLED); + common_data.irqd_set(IrqStatus::IRQD_IRQ_MASKED); + + let irq_desc = IrqDesc { + inner: SpinLock::new(InnerIrqDesc { + common_data, + irq_data, + actions: Vec::new(), + name, + parent_irq: None, + depth: 1, + wake_depth: 0, + kern_inode: None, + kset: None, + parent_kobj: None, + }), + handler: SpinLock::new(None), + kobj_state: LockedKObjectState::new(Some(KObjectState::INITIALIZED)), + }; + + irq_desc.set_handler(bad_irq_handler()); + irq_desc.inner().irq_data.irqd_set(irqd_flags); + + return Arc::new(irq_desc); + } + + pub fn set_handler(&self, handler: &'static dyn IrqFlowHandler) { + let mut guard = self.handler.lock_irqsave(); + *guard = Some(handler); + } + + fn inner(&self) -> SpinLockGuard { + self.inner.lock_irqsave() + } + + pub fn irq(&self) -> IrqNumber { + self.inner().irq_data.irq() + } +} + +#[allow(dead_code)] +#[derive(Debug)] +struct InnerIrqDesc { + /// per irq and chip data passed down to chip functions + common_data: Arc, + irq_data: Arc, + actions: Vec>, + name: Option, + parent_irq: Option, + /// nested irq disables + depth: u32, + /// nested wake enables + wake_depth: u32, + + kern_inode: Option>, + kset: Option>, + parent_kobj: Option>, +} + +impl KObject for IrqDesc { + fn as_any_ref(&self) -> &dyn Any { + self + } + + fn set_inode(&self, inode: Option>) { + self.inner().kern_inode = inode; + } + + fn inode(&self) -> Option> { + self.inner().kern_inode.clone() + } + + fn parent(&self) -> Option> { + self.inner().parent_kobj.clone() + } + + fn set_parent(&self, parent: Option>) { + self.inner().parent_kobj = parent; + } + + fn kset(&self) -> Option> { + self.inner().kset.clone() + } + + fn set_kset(&self, kset: Option>) { + self.inner().kset = kset; + } + + fn kobj_type(&self) -> Option<&'static dyn KObjType> { + Some(&IrqKObjType) + } + + fn set_kobj_type(&self, _ktype: Option<&'static dyn KObjType>) {} + + fn name(&self) -> String { + self.inner().name.clone().unwrap_or_else(|| format!("")) + } + + fn set_name(&self, _name: String) {} + + fn kobj_state(&self) -> RwLockReadGuard { + self.kobj_state.read() + } + + fn kobj_state_mut(&self) -> RwLockWriteGuard { + self.kobj_state.write() + } + + fn set_kobj_state(&self, state: KObjectState) { + *self.kobj_state_mut() = state; + } +} + +/// 每个中断的响应动作的描述符 +/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/interrupt.h#118 +#[allow(dead_code)] +#[derive(Debug)] +pub struct IrqAction { + inner: SpinLock, +} + +impl IrqAction { + #[allow(dead_code)] + pub fn new( + irq: IrqNumber, + name: String, + handler: Option<&'static dyn IrqFlowHandler>, + ) -> Arc { + let action = IrqAction { + inner: SpinLock::new(InnerIrqAction { + dev_id: None, + handler, + thread_fn: None, + thread: None, + secondary: None, + irq, + flags: IrqHandleFlags::empty(), + name, + }), + }; + + return Arc::new(action); + } +} + +#[allow(dead_code)] +#[derive(Debug)] +struct InnerIrqAction { + /// cookie to identify the device + dev_id: Option, + /// 中断处理程序 + handler: Option<&'static dyn IrqFlowHandler>, + /// interrupt handler function for threaded interrupts + thread_fn: Option<&'static dyn IrqFlowHandler>, + /// thread pointer for threaded interrupts + thread: Option>, + /// pointer to secondary irqaction (force threading) + secondary: Option>, + /// 中断号 + irq: IrqNumber, + flags: IrqHandleFlags, + /// name of the device + name: String, +} + +// 定义IrqFlags位标志 +bitflags! { + /// 这些标志仅由内核在中断处理例程中使用。 + pub struct IrqHandleFlags: u32 { + /// IRQF_SHARED - 允许多个设备共享中断 + const IRQF_SHARED = 0x00000080; + /// IRQF_PROBE_SHARED - 当预期出现共享不匹配时,由调用者设置 + const IRQF_PROBE_SHARED = 0x00000100; + /// IRQF_TIMER - 标记此中断为定时器中断 + const __IRQF_TIMER = 0x00000200; + /// IRQF_PERCPU - 中断是每个CPU的 + const IRQF_PERCPU = 0x00000400; + /// IRQF_NOBALANCING - 将此中断从中断平衡中排除 + const IRQF_NOBALANCING = 0x00000800; + /// IRQF_IRQPOLL - 中断用于轮询(出于性能原因,只有在共享中断中首次注册的中断会被考虑) + const IRQF_IRQPOLL = 0x00001000; + /// IRQF_ONESHOT - 在硬中断处理程序完成后,不会重新启用中断。由需要在运行线程处理程序之前保持中断线路禁用的线程中断使用。 + const IRQF_ONESHOT = 0x00002000; + /// IRQF_NO_SUSPEND - 在挂起期间不禁用此IRQ。不能保证此中断会从挂起状态唤醒系统。 + const IRQF_NO_SUSPEND = 0x00004000; + /// IRQF_FORCE_RESUME - 即使设置了IRQF_NO_SUSPEND,也强制在恢复时启用它 + const IRQF_FORCE_RESUME = 0x00008000; + /// IRQF_NO_THREAD - 中断不能被线程化 + const IRQF_NO_THREAD = 0x00010000; + /// IRQF_EARLY_RESUME - 在syscore而不是在设备恢复时间早期恢复IRQ。 + const IRQF_EARLY_RESUME = 0x00020000; + /// IRQF_COND_SUSPEND - 如果IRQ与NO_SUSPEND用户共享,则在挂起中断后执行此中断处理程序。对于系统唤醒设备用户,需要在他们的中断处理程序中实现唤醒检测。 + const IRQF_COND_SUSPEND = 0x00040000; + /// IRQF_NO_AUTOEN - 当用户请求时,不会自动启用IRQ或NMI。用户稍后会通过enable_irq()或enable_nmi()显式启用它。 + const IRQF_NO_AUTOEN = 0x00080000; + /// IRQF_NO_DEBUG - 从IPI和类似处理程序的逃逸检测中排除,取决于IRQF_PERCPU。 + const IRQF_NO_DEBUG = 0x00100000; + const IRQF_TIMER = Self::__IRQF_TIMER.bits | Self::IRQF_NO_SUSPEND.bits | Self::IRQF_NO_THREAD.bits; + } +} + +#[inline(never)] +pub(super) fn early_irq_init() -> Result<(), SystemError> { + let irqcnt = CurrentIrqArch::probe_total_irq_num(); + let mut manager = IrqDescManager::new(); + for i in 0..irqcnt { + let irq_desc = IrqDesc::new(IrqNumber::new(i), None, IrqStatus::empty()); + manager.insert(IrqNumber::new(i), irq_desc); + } + + return CurrentIrqArch::arch_early_irq_init(); +} + +pub(super) struct IrqDescManager { + irq_descs: BTreeMap>, +} + +impl IrqDescManager { + fn new() -> Self { + IrqDescManager { + irq_descs: BTreeMap::new(), + } + } + + /// 查找中断描述符 + #[allow(dead_code)] + pub fn lookup(&self, irq: IrqNumber) -> Option> { + self.irq_descs.get(&irq).map(|desc| desc.clone()) + } + + fn insert(&mut self, irq: IrqNumber, desc: Arc) { + self.irq_descs.insert(irq, desc); + } +} diff --git a/kernel/src/exception/irqdomain.rs b/kernel/src/exception/irqdomain.rs index f6327ee7..885aade9 100644 --- a/kernel/src/exception/irqdomain.rs +++ b/kernel/src/exception/irqdomain.rs @@ -145,7 +145,7 @@ pub enum IrqDomainBusToken { /// IrqDomain的操作方法 /// /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#107 -pub trait IrqDomainOps: Debug { +pub trait IrqDomainOps: Debug + Send + Sync { /// 匹配一个中断控制器设备节点到一个主机。 fn match_node( &self, diff --git a/kernel/src/exception/mod.rs b/kernel/src/exception/mod.rs index d199c117..90aa0d9b 100644 --- a/kernel/src/exception/mod.rs +++ b/kernel/src/exception/mod.rs @@ -2,13 +2,17 @@ use system_error::SystemError; use crate::arch::CurrentIrqArch; +pub mod dummychip; +pub mod handle; pub mod init; pub mod ipi; pub mod irqchip; pub mod irqdata; +pub mod irqdesc; pub mod irqdomain; pub mod msi; pub mod softirq; +pub mod sysfs; /// 中断的架构相关的trait pub trait InterruptArch: Send + Sync { @@ -24,6 +28,16 @@ pub trait InterruptArch: Send + Sync { /// 保存当前中断状态,并且禁止中断 unsafe fn save_and_disable_irq() -> IrqFlagsGuard; unsafe fn restore_irq(flags: IrqFlags); + + /// 检测系统支持的中断总数 + fn probe_total_irq_num() -> u32; + + fn arch_early_irq_init() -> Result<(), SystemError> { + Ok(()) + } + + /// 响应未注册的中断 + fn ack_bad_irq(irq: IrqNumber); } #[derive(Debug, Clone, Copy)] diff --git a/kernel/src/exception/msi.rs b/kernel/src/exception/msi.rs index 31fcb1e7..10f2ef5f 100644 --- a/kernel/src/exception/msi.rs +++ b/kernel/src/exception/msi.rs @@ -116,7 +116,7 @@ impl MsiDesc { } } -pub trait MsiDescFunc: Debug { +pub trait MsiDescFunc: Debug + Send + Sync { /// Callback that may be called when the MSI message /// address or data changes. fn write_msi_msg(&self, data: Arc); diff --git a/kernel/src/exception/sysfs.rs b/kernel/src/exception/sysfs.rs new file mode 100644 index 00000000..7efd5991 --- /dev/null +++ b/kernel/src/exception/sysfs.rs @@ -0,0 +1,65 @@ +use alloc::sync::Arc; +use system_error::SystemError; +use unified_init::macros::unified_init; + +use crate::{ + driver::base::kobject::{KObjType, KObject, KObjectSysFSOps}, + filesystem::{ + sysfs::{Attribute, AttributeGroup, SysFSOps}, + vfs::syscall::ModeType, + }, + init::initcall::INITCALL_POSTCORE, +}; + +/// 中断描述符的kobjtype +/// +/// https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdesc.c#280 +#[derive(Debug)] +pub(super) struct IrqKObjType; + +impl KObjType for IrqKObjType { + fn sysfs_ops(&self) -> Option<&dyn SysFSOps> { + Some(&KObjectSysFSOps) + } + + fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> { + Some(&[&IrqAttrGroup]) + } + + fn release(&self, _kobj: Arc) { + + // https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdesc.c#428 + } +} + +#[derive(Debug)] +struct IrqAttrGroup; + +impl AttributeGroup for IrqAttrGroup { + fn name(&self) -> Option<&str> { + None + } + + fn attrs(&self) -> &[&'static dyn Attribute] { + todo!("irq_attr_group.attrs") + // todo: https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdesc.c#268 + } + + fn is_visible( + &self, + _kobj: Arc, + attr: &'static dyn Attribute, + ) -> Option { + Some(attr.mode()) + } +} + +/// 初始化irq模块在sysfs中的目录 +/// +/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdesc.c#313 +#[unified_init(INITCALL_POSTCORE)] +fn irq_sysfs_init() -> Result<(), SystemError> { + // todo!("irq_sysfs_init"); + kwarn!("Unimplemented: irq_sysfs_init"); + Ok(()) +}