1use 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#[unsafe(no_mangle)]
14pub static mut DTP: usize = 0x114514; lazy_static::lazy_static! {
17 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 pub static ref DEVICE_TREE_REGISTRY: RwLock<BTreeMap<&'static str, fn(&FdtNode)>> =
31 RwLock::new(BTreeMap::new());
32
33 pub static ref DEVICE_TREE_INTC: RwLock<BTreeMap<u32, Arc<dyn IntcDriver>>> =
37 RwLock::new(BTreeMap::new());
38}
39
40pub fn init() {
42 pr_info!(
43 "[Device] devicetree of {} is initialized",
44 FDT.root().model()
45 );
46
47 let cpus = FDT.cpus().count();
48 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 walk_dt(&FDT, true);
78 walk_dt(&FDT, false);
79}
80
81fn 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
100pub 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}