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;
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 .filter(|n| n.name().starts_with("cpu@"))
37 .map(|cpu| {
38 let reg = cpu.reg().unwrap().next().unwrap();
39 CPUInfo {
40 cpu_id: super::CPUHardId(reg.address as usize),
41 }
42 })
43 .collect()
44 }
45
46 pub fn get(&self) -> fdt_parser::Fdt<'static> {
47 fdt_parser::Fdt::from_ptr(self.get_addr()).unwrap()
48 }
49
50 pub fn get_addr(&self) -> NonNull<u8> {
51 NonNull::new((self.0 + LINER_OFFSET).raw() as _).unwrap()
52 }
53
54 pub fn memorys(&self) -> ArrayVec<Range<PhysAddr>, 12> {
55 let mut out = ArrayVec::new();
56
57 let fdt = self.get();
58
59 for node in fdt.memory() {
60 for region in node.regions() {
61 let addr = (region.address as usize).into();
62 out.push(addr..addr + region.size);
63 }
64 }
65 out
66 }
67
68 pub fn take_memory(&self) -> Range<PhysAddr> {
69 let region = self
70 .get()
71 .memory()
72 .next()
73 .unwrap()
74 .regions()
75 .next()
76 .unwrap();
77 let addr = (region.address as usize).into();
78 addr..addr + region.size
79 }
80
81 pub fn debugcon(&self) -> Option<SerialPort> {
82 let fdt = self.get();
83 let stdout = fdt.chosen()?.stdout()?;
84 let compatible = stdout.node.compatibles();
85 let reg = stdout.node.reg()?.next()?;
86 Some(SerialPort::new(
87 (reg.address as usize).into(),
88 reg.size,
89 compatible,
90 ))
91 }
92}
93
94pub trait GetIrqConfig {
95 fn irq_info(&self) -> Option<IrqInfo>;
96}
97
98impl GetIrqConfig for Node<'_> {
99 fn irq_info(&self) -> Option<IrqInfo> {
100 let irq_chip_node = self.interrupt_parent()?;
101 let phandle = irq_chip_node.node.phandle()?;
102
103 let interrupts = self.interrupts()?.map(|o| o.collect()).collect::<Vec<_>>();
104
105 parse_irq_config(phandle, &interrupts)
106 }
107}
108
109fn parse_irq_config(parent: Phandle, interrupts: &[Vec<u32>]) -> Option<IrqInfo> {
110 let irq_parent = rdrive::fdt_phandle_to_device_id(parent)?;
111 let parent = rdrive::get::<rdif_intc::Intc>(irq_parent).expect("Intc not found");
112 let parse_fun = { parent.lock().unwrap().parse_dtb_fn()? };
113
114 let mut cfgs = Vec::new();
115 for raw in interrupts {
116 if let Ok(v) = parse_fun(raw) {
117 cfgs.push(v);
118 } else {
119 warn!("Failed to parse IRQ config: {raw:?}");
120 continue;
121 }
122 }
123
124 Some(IrqInfo { irq_parent, cfgs })
125}
126
127pub trait GetPciIrqConfig {
128 fn child_irq_info(&self, bus: u8, device: u8, function: u8, irq_pin: u8) -> Option<IrqInfo>;
129}
130impl GetPciIrqConfig for Pci<'_> {
131 fn child_irq_info(&self, bus: u8, device: u8, func: u8, irq_pin: u8) -> Option<IrqInfo> {
132 let irq = self
133 .child_interrupts(bus, device, func, irq_pin as _)
134 .ok()?;
135
136 let raw = irq.irqs.collect::<Vec<_>>();
137
138 parse_irq_config(irq.parent, &[raw])
139 }
140}