Skip to main content

fdt_edit/node/view/
pci.rs

1//! PCI node view specialization.
2
3use core::ops::{Deref, Range};
4
5use alloc::vec::Vec;
6use fdt_raw::{FdtError, Phandle};
7
8use super::NodeView;
9use crate::{NodeGeneric, NodeGenericMut, Property, ViewMutOp, ViewOp};
10
11// ---------------------------------------------------------------------------
12// PCI types
13// ---------------------------------------------------------------------------
14
15/// PCI address space types.
16#[derive(Clone, Debug, PartialEq)]
17pub enum PciSpace {
18    /// I/O space
19    IO,
20    /// 32-bit memory space
21    Memory32,
22    /// 64-bit memory space
23    Memory64,
24}
25
26/// PCI address range entry.
27///
28/// Represents a range of addresses in PCI address space with mapping to CPU address space.
29#[derive(Clone, Debug, PartialEq)]
30pub struct PciRange {
31    /// The PCI address space type
32    pub space: PciSpace,
33    /// Address on the PCI bus
34    pub bus_address: u64,
35    /// Address in CPU physical address space
36    pub cpu_address: u64,
37    /// Size of the range in bytes
38    pub size: u64,
39    /// Whether the memory region is prefetchable
40    pub prefetchable: bool,
41}
42
43/// PCI interrupt mapping entry.
44///
45/// Represents a mapping from PCI device interrupts to parent interrupt controller inputs.
46#[derive(Clone, Debug)]
47pub struct PciInterruptMap {
48    /// Child device address (masked)
49    pub child_address: Vec<u32>,
50    /// Child device IRQ (masked)
51    pub child_irq: Vec<u32>,
52    /// Phandle of the interrupt parent controller
53    pub interrupt_parent: Phandle,
54    /// Parent controller IRQ inputs
55    pub parent_irq: Vec<u32>,
56}
57
58/// PCI interrupt information.
59///
60/// Contains the resolved interrupt information for a PCI device.
61#[derive(Clone, Debug, PartialEq)]
62pub struct PciInterruptInfo {
63    /// List of IRQ numbers
64    pub irqs: Vec<u32>,
65}
66
67// ---------------------------------------------------------------------------
68// PciNodeView
69// ---------------------------------------------------------------------------
70
71/// Specialized view for PCI bridge nodes.
72#[derive(Clone, Copy)]
73pub struct PciNodeView<'a> {
74    pub(super) inner: NodeGeneric<'a>,
75}
76
77impl<'a> Deref for PciNodeView<'a> {
78    type Target = NodeGeneric<'a>;
79
80    fn deref(&self) -> &Self::Target {
81        &self.inner
82    }
83}
84
85impl<'a> ViewOp<'a> for PciNodeView<'a> {
86    fn as_view(&self) -> NodeView<'a> {
87        self.inner.as_view()
88    }
89}
90
91impl<'a> PciNodeView<'a> {
92    pub(crate) fn try_from_view(view: NodeView<'a>) -> Option<Self> {
93        if view.as_node().is_pci() {
94            Some(Self {
95                inner: NodeGeneric { inner: view },
96            })
97        } else {
98            None
99        }
100    }
101
102    /// Returns the `#interrupt-cells` property value.
103    ///
104    /// Defaults to 1 for PCI devices if not specified.
105    pub fn interrupt_cells(&self) -> u32 {
106        self.as_view()
107            .as_node()
108            .get_property("#interrupt-cells")
109            .and_then(|prop| prop.get_u32())
110            .unwrap_or(1)
111    }
112
113    /// Get the interrupt-map-mask property if present.
114    pub fn interrupt_map_mask(&self) -> Option<Vec<u32>> {
115        self.as_view()
116            .as_node()
117            .get_property("interrupt-map-mask")
118            .map(|prop| prop.get_u32_iter().collect())
119    }
120
121    /// Get the bus range property if present.
122    pub fn bus_range(&self) -> Option<Range<u32>> {
123        self.as_view()
124            .as_node()
125            .get_property("bus-range")
126            .and_then(|prop| {
127                let mut iter = prop.get_u32_iter();
128                let start = iter.next()?;
129                let end = iter.next()?;
130                Some(start..end)
131            })
132    }
133
134    /// Decode PCI address space from the high cell of PCI address.
135    ///
136    /// PCI address high cell format:
137    /// - Bits 31-28: 1 for IO space, 2 for Memory32, 3 for Memory64
138    /// - Bit 30: Prefetchable for memory spaces
139    fn decode_pci_address_space(&self, pci_hi: u32) -> (PciSpace, bool) {
140        let space_code = (pci_hi >> 24) & 0x03;
141        let prefetchable = (pci_hi >> 30) & 0x01 == 1;
142
143        let space = match space_code {
144            1 => PciSpace::IO,
145            2 => PciSpace::Memory32,
146            3 => PciSpace::Memory64,
147            _ => PciSpace::Memory32,
148        };
149
150        (space, prefetchable)
151    }
152
153    /// Get the ranges property for address translation.
154    pub fn ranges(&self) -> Option<Vec<PciRange>> {
155        let prop = self.as_view().as_node().get_property("ranges")?;
156        let mut data = prop.as_reader();
157        let mut ranges = Vec::new();
158
159        // PCI ranges format: <child-bus-address parent-bus-address size>
160        // child-bus-address: 3 cells (pci.hi pci.mid pci.lo) - PCI 地址固定 3 cells
161        // parent-bus-address: 使用父节点的 #address-cells
162        // size: 使用当前节点的 #size-cells
163
164        // Get parent's address-cells
165        let parent_addr_cells = if let Some(parent) = self.as_view().parent() {
166            parent.as_view().address_cells().unwrap_or(2) as usize
167        } else {
168            2_usize
169        };
170
171        let size_cells = self.as_view().size_cells().unwrap_or(2) as usize;
172
173        while let Some(pci_hi) = data.read_u32() {
174            // Parse child bus address (3 cells for PCI: phys.hi, phys.mid, phys.lo)
175            // pci_hi 用于解析地址空间类型,bus_address 由 pci_mid 和 pci_lo 组成
176            let pci_mid = data.read_u32()?;
177            let pci_lo = data.read_u32()?;
178            let bus_address = ((pci_mid as u64) << 32) | (pci_lo as u64);
179
180            // Parse parent bus address (使用父节点的 #address-cells)
181            let mut parent_addr = 0u64;
182            for _ in 0..parent_addr_cells {
183                let cell = data.read_u32()? as u64;
184                parent_addr = (parent_addr << 32) | cell;
185            }
186
187            // Parse size (使用当前节点的 #size-cells)
188            let mut size = 0u64;
189            for _ in 0..size_cells {
190                let cell = data.read_u32()? as u64;
191                size = (size << 32) | cell;
192            }
193
194            // Extract PCI address space and prefetchable from child_addr[0]
195            let (space, prefetchable) = self.decode_pci_address_space(pci_hi);
196
197            ranges.push(PciRange {
198                space,
199                bus_address,
200                cpu_address: parent_addr,
201                size,
202                prefetchable,
203            });
204        }
205
206        Some(ranges)
207    }
208
209    /// 解析 interrupt-map 属性
210    pub fn interrupt_map(&self) -> Result<Vec<PciInterruptMap>, FdtError> {
211        let prop = self
212            .as_view()
213            .as_node()
214            .get_property("interrupt-map")
215            .ok_or(FdtError::NotFound)?;
216
217        // 将 mask 转换为 Vec 以便索引访问
218        let mask: Vec<u32> = self
219            .interrupt_map_mask()
220            .ok_or(FdtError::NotFound)?
221            .into_iter()
222            .collect();
223
224        let mut data = prop.as_reader();
225        let mut mappings = Vec::new();
226
227        // 计算每个条目的大小
228        // 格式: <child-address child-irq interrupt-parent parent-address parent-irq...>
229        let child_addr_cells = self.as_view().address_cells().unwrap_or(3) as usize;
230        let child_irq_cells = self.interrupt_cells() as usize;
231
232        loop {
233            // 解析子地址
234            let mut child_address = Vec::with_capacity(child_addr_cells);
235            for _ in 0..child_addr_cells {
236                match data.read_u32() {
237                    Some(v) => child_address.push(v),
238                    None => return Ok(mappings), // 数据结束
239                }
240            }
241
242            // 解析子 IRQ
243            let mut child_irq = Vec::with_capacity(child_irq_cells);
244            for _ in 0..child_irq_cells {
245                match data.read_u32() {
246                    Some(v) => child_irq.push(v),
247                    None => return Ok(mappings),
248                }
249            }
250
251            // 解析中断父 phandle
252            let interrupt_parent_raw = match data.read_u32() {
253                Some(v) => v,
254                None => return Ok(mappings),
255            };
256            let interrupt_parent = Phandle::from(interrupt_parent_raw);
257
258            // 通过 phandle 查找中断父节点以获取其 #address-cells 和 #interrupt-cells
259            // 根据 devicetree 规范,interrupt-map 中的 parent unit address 使用中断父节点的 #address-cells
260            let (parent_addr_cells, parent_irq_cells) =
261                if let Some(irq_parent) = self.as_view().fdt().get_by_phandle(interrupt_parent) {
262                    // 直接使用中断父节点的 #address-cells
263                    let addr_cells = irq_parent.as_view().address_cells().unwrap_or(0) as usize;
264
265                    let irq_cells = irq_parent
266                        .as_view()
267                        .as_node()
268                        .get_property("#interrupt-cells")
269                        .and_then(|p| p.get_u32())
270                        .unwrap_or(3) as usize;
271                    (addr_cells, irq_cells)
272                } else {
273                    // 默认值:address_cells=0, interrupt_cells=3 (GIC 格式)
274                    (0, 3)
275                };
276
277            // 跳过父地址 cells
278            for _ in 0..parent_addr_cells {
279                if data.read_u32().is_none() {
280                    return Ok(mappings);
281                }
282            }
283
284            // 解析父 IRQ
285            let mut parent_irq = Vec::with_capacity(parent_irq_cells);
286            for _ in 0..parent_irq_cells {
287                match data.read_u32() {
288                    Some(v) => parent_irq.push(v),
289                    None => return Ok(mappings),
290                }
291            }
292
293            // 应用 mask 到子地址和 IRQ
294            let masked_address: Vec<u32> = child_address
295                .iter()
296                .enumerate()
297                .map(|(i, value)| {
298                    let mask_value = mask.get(i).copied().unwrap_or(0xffff_ffff);
299                    value & mask_value
300                })
301                .collect();
302            let masked_irq: Vec<u32> = child_irq
303                .iter()
304                .enumerate()
305                .map(|(i, value)| {
306                    let mask_value = mask
307                        .get(child_addr_cells + i)
308                        .copied()
309                        .unwrap_or(0xffff_ffff);
310                    value & mask_value
311                })
312                .collect();
313
314            mappings.push(PciInterruptMap {
315                child_address: masked_address,
316                child_irq: masked_irq,
317                interrupt_parent,
318                parent_irq,
319            });
320        }
321    }
322
323    /// 获取 PCI 设备的中断信息
324    /// 参数: bus, device, function, pin (1=INTA, 2=INTB, 3=INTC, 4=INTD)
325    pub fn child_interrupts(
326        &self,
327        bus: u8,
328        device: u8,
329        function: u8,
330        interrupt_pin: u8,
331    ) -> Result<PciInterruptInfo, FdtError> {
332        // 获取 interrupt-map 和 mask
333        let interrupt_map = self.interrupt_map()?;
334
335        // 将 mask 转换为 Vec 以便索引访问
336        let mask: Vec<u32> = self
337            .interrupt_map_mask()
338            .ok_or(FdtError::NotFound)?
339            .into_iter()
340            .collect();
341
342        // 构造 PCI 设备的子地址
343        // 格式: [bus_num, device_num, func_num] 在适当的位
344        let child_addr_high = ((bus as u32 & 0xff) << 16)
345            | ((device as u32 & 0x1f) << 11)
346            | ((function as u32 & 0x07) << 8);
347        let child_addr_mid = 0u32;
348        let child_addr_low = 0u32;
349
350        let child_addr_cells = self.as_view().address_cells().unwrap_or(3) as usize;
351        let child_irq_cells = self.interrupt_cells() as usize;
352
353        let encoded_address = [child_addr_high, child_addr_mid, child_addr_low];
354        let mut masked_child_address = Vec::with_capacity(child_addr_cells);
355
356        // 应用 mask 到子地址
357        for (idx, value) in encoded_address.iter().take(child_addr_cells).enumerate() {
358            let mask_value = mask.get(idx).copied().unwrap_or(0xffff_ffff);
359            masked_child_address.push(value & mask_value);
360        }
361
362        // 如果 encoded_address 比 child_addr_cells 短,填充 0
363        let remaining = child_addr_cells.saturating_sub(encoded_address.len());
364        masked_child_address.extend(core::iter::repeat_n(0, remaining));
365
366        let encoded_irq = [interrupt_pin as u32];
367        let mut masked_child_irq = Vec::with_capacity(child_irq_cells);
368
369        // 应用 mask 到子 IRQ
370        for (idx, value) in encoded_irq.iter().take(child_irq_cells).enumerate() {
371            let mask_value = mask
372                .get(child_addr_cells + idx)
373                .copied()
374                .unwrap_or(0xffff_ffff);
375            masked_child_irq.push(value & mask_value);
376        }
377
378        // 如果 encoded_irq 比 child_irq_cells 短,填充 0
379        let remaining_irq = child_irq_cells.saturating_sub(encoded_irq.len());
380        masked_child_irq.extend(core::iter::repeat_n(0, remaining_irq));
381
382        // 在 interrupt-map 中查找匹配的条目
383        for mapping in &interrupt_map {
384            if mapping.child_address == masked_child_address
385                && mapping.child_irq == masked_child_irq
386            {
387                return Ok(PciInterruptInfo {
388                    irqs: mapping.parent_irq.clone(),
389                });
390            }
391        }
392
393        // 回退到简单的 IRQ 计算
394        let simple_irq = (device as u32 * 4 + interrupt_pin as u32) % 32;
395        Ok(PciInterruptInfo {
396            irqs: vec![simple_irq],
397        })
398    }
399}
400
401// ---------------------------------------------------------------------------
402// PciNodeViewMut
403// ---------------------------------------------------------------------------
404
405/// Mutable view for PCI bridge nodes.
406pub struct PciNodeViewMut<'a> {
407    pub(super) inner: NodeGenericMut<'a>,
408}
409
410impl<'a> Deref for PciNodeViewMut<'a> {
411    type Target = NodeGenericMut<'a>;
412
413    fn deref(&self) -> &Self::Target {
414        &self.inner
415    }
416}
417
418impl<'a> ViewOp<'a> for PciNodeViewMut<'a> {
419    fn as_view(&self) -> NodeView<'a> {
420        self.inner.as_view()
421    }
422}
423
424impl<'a> ViewMutOp<'a> for PciNodeViewMut<'a> {
425    fn new(node: NodeGenericMut<'a>) -> Self {
426        let mut s = Self { inner: node };
427        let n = s.inner.inner.as_node_mut();
428        // Set PCI-specific properties
429        n.set_property(Property::new("device_type", b"pci\0".to_vec()));
430        // PCI uses #address-cells = 3, #size-cells = 2
431        n.set_property(Property::new(
432            "#address-cells",
433            (3u32).to_be_bytes().to_vec(),
434        ));
435        n.set_property(Property::new("#size-cells", (2u32).to_be_bytes().to_vec()));
436        n.set_property(Property::new(
437            "#interrupt-cells",
438            (1u32).to_be_bytes().to_vec(),
439        ));
440        s
441    }
442}
443
444impl<'a> PciNodeViewMut<'a> {
445    pub(crate) fn try_from_view(view: NodeView<'a>) -> Option<Self> {
446        if view.as_node().is_pci() {
447            Some(Self {
448                inner: NodeGenericMut { inner: view },
449            })
450        } else {
451            None
452        }
453    }
454}