sparreal_kernel/platform/
fdt.rs1use alloc::string::{String, ToString};
2use alloc::vec::Vec;
3use core::{
4 ops::Range,
5 ptr::{NonNull, slice_from_raw_parts, slice_from_raw_parts_mut},
6};
7use fdt_parser::{Node, Pci};
8use rdrive::{Phandle, probe::ProbeData};
9
10use crate::globals::{self, global_val};
11use crate::irq::IrqInfo;
12use crate::mem::{Align, VirtAddr};
13use crate::{io::print::*, mem::PhysAddr};
14
15use super::{CPUInfo, SerialPort};
16
17pub struct Fdt(PhysAddr);
18
19impl Fdt {
20 pub fn new(addr: NonNull<u8>) -> Self {
21 Self(VirtAddr::from(addr).into())
22 }
23
24 pub fn model_name(&self) -> Option<String> {
25 let fdt = self.get();
26 let node = fdt.all_nodes().next()?;
27
28 let model = node.find_property("model")?;
29
30 Some(model.str().to_string())
31 }
32
33 pub fn cpus(&self) -> Vec<CPUInfo> {
34 let fdt = self.get();
35
36 fdt.find_nodes("/cpus/cpu")
37 .map(|cpu| {
38 let reg = cpu.reg().unwrap().next().unwrap();
39 CPUInfo {
40 cpu_id: (reg.address as usize).into(),
41 }
42 })
43 .collect()
44 }
45
46 pub fn setup(&mut self) -> Result<(), &'static str> {
47 let main_memory = global_val().main_memory.clone();
48 let fdt_start = self.move_to(main_memory.end.as_usize());
49 unsafe { globals::edit(|g| g.kstack_top = fdt_start.into()) };
50 Ok(())
51 }
52
53 fn move_to(&mut self, dst_end: usize) -> usize {
54 let size = self.get().total_size();
55
56 let dst = (dst_end - size).align_down(0x1000);
57
58 early_dbg("Move FDT from ");
59 early_dbg_hex(self.0.as_usize() as _);
60 early_dbg(" to ");
61 early_dbg_hexln(dst as _);
62
63 unsafe {
64 let dest = &mut *slice_from_raw_parts_mut(dst as _, size);
65 let src = &*slice_from_raw_parts(VirtAddr::from(self.0).as_mut_ptr(), size);
66 dest.copy_from_slice(src);
67 self.0 = dst.into();
68 }
69 dst
70 }
71
72 pub fn get(&self) -> fdt_parser::Fdt<'static> {
73 let addr = VirtAddr::from(self.0).as_mut_ptr();
74 let ptr = NonNull::new(addr).unwrap();
75 fdt_parser::Fdt::from_ptr(ptr).unwrap()
76 }
77
78 pub fn get_addr(&self) -> NonNull<u8> {
79 unsafe { NonNull::new_unchecked(VirtAddr::from(self.0).as_mut_ptr()) }
80 }
81
82 pub fn memorys(&self) -> Vec<Range<PhysAddr>> {
83 let mut out = Vec::new();
84
85 let fdt = self.get();
86
87 for node in fdt.memory() {
88 for region in node.regions() {
89 let addr = (region.address as usize).into();
90 out.push(addr..addr + region.size);
91 }
92 }
93 out
94 }
95
96 pub fn take_memory(&self) -> Range<PhysAddr> {
97 let region = self
98 .get()
99 .memory()
100 .next()
101 .unwrap()
102 .regions()
103 .next()
104 .unwrap();
105 let addr = (region.address as usize).into();
106 addr..addr + region.size
107 }
108
109 pub fn debugcon(&self) -> Option<SerialPort> {
110 let fdt = self.get();
111 let stdout = fdt.chosen()?.stdout()?;
112 let compatible = stdout.node.compatibles();
113 let reg = stdout.node.reg()?.next()?;
114 Some(SerialPort::new(
115 (reg.address as usize).into(),
116 reg.size,
117 compatible,
118 ))
119 }
120}
121
122pub trait GetIrqConfig {
123 fn irq_info(&self) -> Option<IrqInfo>;
124}
125
126impl GetIrqConfig for Node<'_> {
127 fn irq_info(&self) -> Option<IrqInfo> {
128 let irq_chip_node = self.interrupt_parent()?;
129 let phandle = irq_chip_node.node.phandle()?;
130
131 let interrupts = self.interrupts()?.map(|o| o.collect()).collect::<Vec<_>>();
132
133 parse_irq_config(phandle, &interrupts)
134 }
135}
136
137fn parse_irq_config(parent: Phandle, interrupts: &[Vec<u32>]) -> Option<IrqInfo> {
138 let mut irq_parent = None;
139
140 let mut cfgs = Vec::new();
141 for raw in interrupts {
142 match rdrive::read(|m| match &m.probe_kind {
143 ProbeData::Fdt(probe_data) => {
144 irq_parent = probe_data.phandle_2_device_id(parent);
145 Some(probe_data.parse_irq(parent, raw))
146 }
147 ProbeData::Static => None,
148 }) {
149 Some(Ok(cfg)) => cfgs.push(cfg),
150 _ => continue,
151 }
152 }
153
154 Some(IrqInfo {
155 irq_parent: irq_parent?,
156 cfgs,
157 })
158}
159
160pub trait GetPciIrqConfig {
161 fn child_irq_info(&self, bus: u8, device: u8, function: u8, irq_pin: u8) -> Option<IrqInfo>;
162}
163impl GetPciIrqConfig for Pci<'_> {
164 fn child_irq_info(&self, bus: u8, device: u8, func: u8, irq_pin: u8) -> Option<IrqInfo> {
165 let irq = self
166 .child_interrupts(bus, device, func, irq_pin as _)
167 .ok()?;
168
169 let raw = irq.irqs.collect::<Vec<_>>();
170
171 parse_irq_config(irq.parent, &[raw])
172 }
173}