sparreal_kernel/platform/
fdt.rs

1use 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}