sparreal_kernel/platform/
fdt.rs1use alloc::{
2 string::{String, ToString},
3 vec::Vec,
4};
5use arrayvec::ArrayVec;
6use core::{ops::Range, ptr::NonNull};
7use fdt_parser::{Node, Pci};
8use log::warn;
9use rdrive::{Phandle, driver::Intc};
10
11use super::{CPUInfo, SerialPort};
12use crate::mem::PhysAddr;
13use crate::{irq::IrqInfo, mem::mmu::LINER_OFFSET};
14
15#[derive(Clone)]
16pub struct Fdt(PhysAddr);
17
18impl Fdt {
19 pub fn new(addr: PhysAddr) -> Self {
20 Self(addr)
21 }
22
23 pub fn model_name(&self) -> Option<String> {
24 let fdt = self.get();
25 let node = fdt.all_nodes().next()?;
26
27 let model = node.find_property("model")?;
28
29 Some(model.str().to_string())
30 }
31
32 pub fn cpus(&self) -> Vec<CPUInfo> {
33 let fdt = self.get();
34
35 fdt.find_nodes("/cpus/cpu")
36 .map(|cpu| {
37 let reg = cpu.reg().unwrap().next().unwrap();
38 CPUInfo {
39 cpu_id: super::CPUHardId(reg.address as usize),
40 }
41 })
42 .collect()
43 }
44
45 pub fn get(&self) -> fdt_parser::Fdt<'static> {
46 fdt_parser::Fdt::from_ptr(self.get_addr()).unwrap()
47 }
48
49 pub fn get_addr(&self) -> NonNull<u8> {
50 NonNull::new((self.0 + LINER_OFFSET).raw() as _).unwrap()
51 }
52
53 pub fn memorys(&self) -> ArrayVec<Range<PhysAddr>, 12> {
54 let mut out = ArrayVec::new();
55
56 let fdt = self.get();
57
58 for node in fdt.memory() {
59 for region in node.regions() {
60 let addr = (region.address as usize).into();
61 out.push(addr..addr + region.size);
62 }
63 }
64 out
65 }
66
67 pub fn take_memory(&self) -> Range<PhysAddr> {
68 let region = self
69 .get()
70 .memory()
71 .next()
72 .unwrap()
73 .regions()
74 .next()
75 .unwrap();
76 let addr = (region.address as usize).into();
77 addr..addr + region.size
78 }
79
80 pub fn debugcon(&self) -> Option<SerialPort> {
81 let fdt = self.get();
82 let stdout = fdt.chosen()?.stdout()?;
83 let compatible = stdout.node.compatibles();
84 let reg = stdout.node.reg()?.next()?;
85 Some(SerialPort::new(
86 (reg.address as usize).into(),
87 reg.size,
88 compatible,
89 ))
90 }
91}
92
93pub trait GetIrqConfig {
94 fn irq_info(&self) -> Option<IrqInfo>;
95}
96
97impl GetIrqConfig for Node<'_> {
98 fn irq_info(&self) -> Option<IrqInfo> {
99 let irq_chip_node = self.interrupt_parent()?;
100 let phandle = irq_chip_node.node.phandle()?;
101
102 let interrupts = self.interrupts()?.map(|o| o.collect()).collect::<Vec<_>>();
103
104 parse_irq_config(phandle, &interrupts)
105 }
106}
107
108fn parse_irq_config(parent: Phandle, interrupts: &[Vec<u32>]) -> Option<IrqInfo> {
109 let irq_parent = rdrive::fdt_phandle_to_device_id(parent)?;
110 let parent = rdrive::get::<Intc>(irq_parent).expect("Intc not found");
111 let parse_fun = { parent.lock().unwrap().parse_dtb_fn()? };
112
113 let mut cfgs = Vec::new();
114 for raw in interrupts {
115 if let Ok(v) = parse_fun(raw) {
116 cfgs.push(v);
117 } else {
118 warn!("Failed to parse IRQ config: {raw:?}");
119 continue;
120 }
121 }
122
123 Some(IrqInfo { irq_parent, cfgs })
124}
125
126pub trait GetPciIrqConfig {
127 fn child_irq_info(&self, bus: u8, device: u8, function: u8, irq_pin: u8) -> Option<IrqInfo>;
128}
129impl GetPciIrqConfig for Pci<'_> {
130 fn child_irq_info(&self, bus: u8, device: u8, func: u8, irq_pin: u8) -> Option<IrqInfo> {
131 let irq = self
132 .child_interrupts(bus, device, func, irq_pin as _)
133 .ok()?;
134
135 let raw = irq.irqs.collect::<Vec<_>>();
136
137 parse_irq_config(irq.parent, &[raw])
138 }
139}