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