os/device/irq/
plic.rs

1//! Platform Level Interrupt Controller (PLIC) 驱动实现
2//!
3//! PLIC 提供对外设中断的集中管理,支持优先级和中断分发功能。
4
5use super::{super::DRIVERS, IrqManager};
6use crate::arch::constant::SUPERVISOR_EXTERNAL;
7use crate::device::device_tree::{DEVICE_TREE_INTC, DEVICE_TREE_REGISTRY};
8use crate::device::irq::IntcDriver;
9use crate::device::{DeviceType, Driver, IRQ_MANAGER};
10use crate::kernel::current_memory_space;
11use crate::mm::address::{Paddr, UsizeConvert};
12use crate::{pr_info, pr_warn};
13use crate::{sync::SpinLock as Mutex, util::read, util::write};
14use alloc::format;
15use alloc::string::String;
16use alloc::sync::Arc;
17use fdt::node::FdtNode;
18
19/// Platform Level Interrupt Controller (PLIC) 结构体
20pub struct Plic {
21    base: usize,
22    manager: Mutex<IrqManager>,
23}
24
25impl Driver for Plic {
26    /// 处理中断
27    /// # 参数:
28    /// * `irq` - 可选的中断号
29    /// # 返回值
30    /// 如果中断被处理则返回 true,否则返回 false
31    fn try_handle_interrupt(&self, _irq: Option<usize>) -> bool {
32        let pending: u32 = read(self.base + 0x1000);
33        if pending != 0 {
34            let claim: u32 = read(self.base + 0x201004);
35            let manager = self.manager.lock();
36            let res = manager.try_handle_interrupt(Some(claim as usize));
37            write(self.base + 0x201004, claim);
38            res
39        } else {
40            false
41        }
42    }
43
44    /// 返回设备类型
45    /// # 返回值
46    /// 设备类型枚举值
47    fn device_type(&self) -> DeviceType {
48        DeviceType::Intc
49    }
50
51    /// 获取设备唯一标识符
52    /// # 返回值
53    /// 设备标识符字符串
54    fn get_id(&self) -> String {
55        format!("plic_{}", self.base)
56    }
57}
58
59impl IntcDriver for Plic {
60    /// 注册本地中断处理程序
61    /// # 参数:
62    /// * `irq` - 中断号
63    /// * `driver` - 要注册的驱动程序
64    fn register_local_irq(&self, irq: usize, driver: Arc<dyn Driver>) {
65        write(
66            self.base + 0x2080,
67            read::<u32>(self.base + 0x2080) | (1 << irq),
68        );
69        write(self.base + irq * 4, 7);
70        let mut manager = self.manager.lock();
71        manager.register_irq(irq, driver);
72    }
73}
74
75/// 初始化设备树中的 PLIC 中断控制器
76/// # 参数:
77/// * `dt` - 设备树节点
78pub fn init_dt(dt: &FdtNode) {
79    if let Some(reg) = dt.reg().and_then(|mut reg| reg.next()) {
80        let paddr = reg.starting_address as usize;
81        let size = reg.size.unwrap_or(0);
82        if size == 0 {
83            pr_warn!("[Device] PLIC device tree node {} has no size", dt.name);
84            return;
85        }
86        let vaddr = current_memory_space()
87            .lock()
88            .map_mmio(Paddr::from_usize(paddr), size)
89            .ok()
90            .expect("Failed to map MMIO region");
91        let phandle = dt
92            .property("phandle")
93            .unwrap()
94            .as_usize()
95            .expect("Failed to convert 'phandle' property to usize");
96        let base = vaddr.as_usize();
97        let plic = Arc::new(Plic {
98            base,
99            manager: Mutex::new(IrqManager::new(false)),
100        });
101
102        // set prio threshold to 0 for context 1
103        write(base + 0x201000, 0);
104        DRIVERS.write().push(plic.clone());
105        // register under root irq manager
106        IRQ_MANAGER
107            .write()
108            .register_irq(SUPERVISOR_EXTERNAL, plic.clone());
109        // register interrupt controller
110        DEVICE_TREE_INTC
111            .write()
112            .insert(phandle.try_into().unwrap(), plic);
113    } else {
114        pr_warn!(
115            "[Device] PLIC device tree node {} has no 'reg' property",
116            dt.name
117        );
118    }
119    pr_info!(
120        "[Device] PLIC initialized from device tree node {}",
121        dt.name
122    );
123}
124
125/// 注册 PLIC 驱动初始化函数
126pub fn driver_init() {
127    DEVICE_TREE_REGISTRY.write().insert("riscv,plic0", init_dt);
128}