sparreal_kernel/platform/
fdt.rs

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