os/device/
device_tree.rs

1//! 设备树模块
2
3use crate::{
4    device::{CMDLINE, irq::IntcDriver},
5    kernel::{CLOCK_FREQ, NUM_CPU},
6    mm::address::{ConvertablePaddr, Paddr, UsizeConvert},
7    pr_info,
8};
9use alloc::{collections::btree_map::BTreeMap, string::String, sync::Arc};
10use fdt::{Fdt, node::FdtNode};
11use spin::RwLock;
12/// 指向设备树的指针,在启动时由引导程序设置
13#[unsafe(no_mangle)]
14pub static mut DTP: usize = 0x114514; // 占位地址,实际由引导程序设置
15
16lazy_static::lazy_static! {
17    /// 设备树
18    /// 通过 DTP 指针解析得到
19    /// XXX: 是否需要这个?
20    pub static ref FDT: Fdt<'static> = {
21        unsafe {
22            let addr = Paddr::to_vaddr(&Paddr::from_usize(DTP));
23            fdt::Fdt::from_ptr(addr.as_usize() as *mut u8).expect("Failed to parse device tree")
24        }
25    };
26
27    /// Compatible 字符串到探测函数的映射表
28    /// 键为设备的 compatible 字符串,值为对应的探测函数
29    /// 用于在设备树中查找和初始化设备
30    pub static ref DEVICE_TREE_REGISTRY: RwLock<BTreeMap<&'static str, fn(&FdtNode)>> =
31        RwLock::new(BTreeMap::new());
32
33    /// 设备树中断控制器映射表
34    /// 键为中断控制器的 phandle,值为对应的中断控制器驱动程序
35    /// 用于在设备树中查找和管理中断控制器
36    pub static ref DEVICE_TREE_INTC: RwLock<BTreeMap<u32, Arc<dyn IntcDriver>>> =
37        RwLock::new(BTreeMap::new());
38}
39
40/// 初始化设备树
41pub fn init() {
42    pr_info!(
43        "[Device] devicetree of {} is initialized",
44        FDT.root().model()
45    );
46
47    let cpus = FDT.cpus().count();
48    // SAFETY: 这里是在单核初始化阶段设置 CPU 数量
49    unsafe { NUM_CPU = cpus };
50    pr_info!("[Device] now has {} CPU(s)", cpus);
51
52    unsafe {
53        CLOCK_FREQ = FDT
54            .cpus()
55            .next()
56            .expect("No CPU found in device tree")
57            .timebase_frequency()
58    };
59    pr_info!("[Device] CLOCK_FREQ set to {} Hz", unsafe { CLOCK_FREQ });
60
61    FDT.memory().regions().for_each(|region| {
62        pr_info!(
63            "[Device] Memory Region: Start = {:#X}, Size = {:#X}",
64            region.starting_address as usize,
65            region.size.unwrap() as usize
66        );
67    });
68
69    if let Some(bootargs) = FDT.chosen().bootargs() {
70        if !bootargs.is_empty() {
71            pr_info!("Kernel cmdline: {}", bootargs);
72            *CMDLINE.write() = String::from(bootargs);
73        }
74    }
75
76    // 首先初始化中断控制器
77    walk_dt(&FDT, true);
78    walk_dt(&FDT, false);
79}
80
81/// 遍历设备树,查找并初始化 virtio 设备
82/// # 参数
83/// * `fdt` - 设备树对象
84fn walk_dt(fdt: &Fdt, intc_only: bool) {
85    for node in fdt.all_nodes() {
86        if let Some(compatible) = node.compatible() {
87            if node.property("interrupt-controller").is_some() == intc_only {
88                pr_info!("[Device] Found device: {}", node.name);
89                let registry = DEVICE_TREE_REGISTRY.read();
90                for c in compatible.all() {
91                    if let Some(f) = registry.get(c) {
92                        f(&node);
93                    }
94                }
95            }
96        }
97    }
98}
99
100/// 返回 DRAM 的起始物理地址与总大小(合并所有 memory.regions)
101/// # 返回值
102/// * `Option<(usize, usize)>` - 返回起始地址和大小的元组,如果没有有效的内存区域则返回 None
103pub fn dram_info() -> Option<(usize, usize)> {
104    let mut start = usize::MAX;
105    let mut end = 0usize;
106
107    for region in FDT.memory().regions() {
108        let s = region.starting_address as usize;
109        let size = region.size.unwrap_or(0) as usize;
110        let e = s.saturating_add(size);
111        if size == 0 {
112            continue;
113        }
114        if s < start {
115            start = s;
116        }
117        if e > end {
118            end = e;
119        }
120    }
121
122    if start < end {
123        Some((start, end - start))
124    } else {
125        None
126    }
127}