fdt_parser/cache/node/
pci.rs1use core::{
2 fmt::Debug,
3 ops::{Deref, Range},
4};
5
6use crate::{cache::node::NodeBase, FdtError, Phandle};
7use alloc::{vec, vec::Vec};
8
9#[derive(Clone, Debug, PartialEq)]
10pub enum PciSpace {
11 IO,
12 Memory32,
13 Memory64,
14}
15
16#[derive(Clone, Debug, PartialEq)]
17pub struct PciRange {
18 pub space: PciSpace,
19 pub bus_address: u64,
20 pub cpu_address: u64,
21 pub size: u64,
22 pub prefetchable: bool,
23}
24
25#[derive(Clone, Debug)]
26pub struct PciInterruptMap {
27 pub child_address: Vec<u32>,
28 pub child_irq: Vec<u32>,
29 pub interrupt_parent: Phandle,
30 pub parent_irq: Vec<u32>,
31}
32
33#[derive(Clone, Debug, PartialEq)]
34pub struct PciInterruptInfo {
35 pub irqs: Vec<u32>,
36}
37
38#[derive(Clone)]
39pub struct Pci {
40 node: NodeBase,
41}
42
43impl Pci {
44 pub(crate) fn new(node: NodeBase) -> Self {
45 Pci { node }
46 }
47
48 pub fn interrupt_cells(&self) -> u32 {
49 self.find_property("#interrupt-cells")
50 .and_then(|prop| prop.u32().ok())
51 .unwrap_or(1) }
53
54 pub fn interrupt_map_mask(&self) -> Option<Vec<u32>> {
56 self.node
57 .find_property("interrupt-map-mask")
58 .and_then(|prop| {
59 let mut data = prop.data.buffer();
60 let mut mask = Vec::new();
61 while !data.remain().as_ref().is_empty() {
62 match data.take_u32() {
63 Ok(value) => mask.push(value),
64 Err(_) => return None,
65 }
66 }
67 Some(mask)
68 })
69 }
70
71 pub fn interrupt_map(&self) -> Result<Vec<PciInterruptMap>, FdtError> {
73 let prop = self
74 .node
75 .find_property("interrupt-map")
76 .ok_or(FdtError::PropertyNotFound("interrupt-map"))?;
77
78 let mut mask = self
79 .interrupt_map_mask()
80 .ok_or(FdtError::PropertyNotFound("interrupt-map-mask"))?;
81
82 let mut data = prop.data.buffer();
83 let mut mappings = Vec::new();
84
85 let child_addr_cells = self.address_cells() as usize;
88 let child_irq_cells = self.interrupt_cells() as usize;
89
90 let required_mask_len = child_addr_cells + child_irq_cells;
91 if mask.len() < required_mask_len {
92 mask.resize(required_mask_len, 0xffff_ffff);
93 }
94
95 while !data.remain().as_ref().is_empty() {
96 let mut child_address = Vec::with_capacity(child_addr_cells);
98 for _ in 0..child_addr_cells {
99 child_address.push(
100 data.take_u32()
101 .map_err(|_| FdtError::BufferTooSmall { pos: data.pos() })?,
102 );
103 }
104
105 let mut child_irq = Vec::with_capacity(child_irq_cells);
107 for _ in 0..child_irq_cells {
108 child_irq.push(
109 data.take_u32()
110 .map_err(|_| FdtError::BufferTooSmall { pos: data.pos() })?,
111 );
112 }
113
114 let interrupt_parent_raw = data
116 .take_u32()
117 .map_err(|_| FdtError::BufferTooSmall { pos: data.pos() })?;
118 let interrupt_parent = if interrupt_parent_raw == 0 {
119 self.interrupt_parent_phandle().unwrap_or(Phandle::from(0))
120 } else {
121 Phandle::from(interrupt_parent_raw)
122 };
123
124 let irq_parent = self
125 .node
126 .interrupt_parent()
127 .ok_or(FdtError::NodeNotFound("interrupt-parent"))?;
128
129 let address_cells = irq_parent.address_cells();
130
131 for _ in 0..address_cells {
132 data.take_u32()
133 .map_err(|_| FdtError::BufferTooSmall { pos: data.pos() })?;
134 }
135
136 let parent_irq_cells = irq_parent.interrupt_cells()? as usize;
137
138 let mut parent_irq = Vec::with_capacity(parent_irq_cells);
140 for _ in 0..parent_irq_cells {
141 let irq = data
142 .take_u32()
143 .map_err(|_| FdtError::BufferTooSmall { pos: data.pos() })?;
144 parent_irq.push(irq);
145 }
146
147 let masked_address: Vec<u32> = child_address
149 .iter()
150 .enumerate()
151 .map(|(idx, value)| {
152 let mask_value = mask.get(idx).copied().unwrap_or(0xffff_ffff);
153 value & mask_value
154 })
155 .collect();
156 let masked_irq: Vec<u32> = child_irq
157 .iter()
158 .enumerate()
159 .map(|(idx, value)| {
160 let mask_value = mask
161 .get(child_addr_cells + idx)
162 .copied()
163 .unwrap_or(0xffff_ffff);
164 value & mask_value
165 })
166 .collect();
167
168 mappings.push(PciInterruptMap {
169 child_address: masked_address,
170 child_irq: masked_irq,
171 interrupt_parent,
172 parent_irq,
173 });
174 }
175
176 Ok(mappings)
177 }
178
179 pub fn bus_range(&self) -> Option<Range<u32>> {
181 self.node.find_property("bus-range").and_then(|prop| {
182 let mut data = prop.data.buffer();
183 let start = data.take_u32().ok()?;
184 let end = data.take_u32().unwrap_or(start);
185 Some(start..end)
186 })
187 }
188
189 pub fn device_type(&self) -> Option<&str> {
191 self.node
192 .find_property("device_type")
193 .and_then(|prop| prop.str().ok())
194 }
195
196 pub fn is_pci_host_bridge(&self) -> bool {
198 self.device_type() == Some("pci")
199 || self.node.name().contains("pci")
200 || self.node.compatibles().iter().any(|c| c.contains("pci"))
201 }
202
203 pub fn ranges(&self) -> Option<Vec<PciRange>> {
205 let prop = self.node.find_property("ranges")?;
206 let mut data = prop.data.buffer();
207 let mut ranges = Vec::new();
208
209 while !data.remain().as_ref().is_empty() {
214 let mut child_addr = [0u32; 3];
216 for i in 0..3 {
217 child_addr[i] = data.take_u32().ok()?;
218 }
219
220 let parent_addr_high = data.take_u32().ok()?;
222 let parent_addr_low = data.take_u32().ok()?;
223 let parent_addr = ((parent_addr_high as u64) << 32) | (parent_addr_low as u64);
224
225 let size_high = data.take_u32().ok()?;
227 let size_low = data.take_u32().ok()?;
228 let size = ((size_high as u64) << 32) | (size_low as u64);
229
230 let pci_hi = child_addr[0];
232 let (space, prefetchable) = self.decode_pci_address_space(pci_hi);
233
234 let bus_address = ((child_addr[1] as u64) << 32) | (child_addr[2] as u64);
236
237 ranges.push(PciRange {
238 space,
239 bus_address,
240 cpu_address: parent_addr,
241 size,
242 prefetchable,
243 });
244 }
245
246 Some(ranges)
247 }
248
249 fn decode_pci_address_space(&self, pci_hi: u32) -> (PciSpace, bool) {
251 let space_code = (pci_hi >> 24) & 0x03;
255 let prefetchable = (pci_hi >> 30) & 0x01 == 1;
256
257 let space = match space_code {
258 1 => PciSpace::IO,
259 2 => PciSpace::Memory32,
260 3 => PciSpace::Memory64,
261 _ => PciSpace::Memory32, };
263
264 (space, prefetchable)
265 }
266
267 pub fn child_interrupts(
270 &self,
271 bus: u32,
272 device: u32,
273 function: u32,
274 pin: u32,
275 ) -> Result<PciInterruptInfo, FdtError> {
276 let interrupt_map = self.interrupt_map()?;
278
279 let mut mask = self
280 .interrupt_map_mask()
281 .ok_or(FdtError::PropertyNotFound("interrupt-map-mask"))?;
282
283 let child_addr_high =
286 ((bus & 0xff) << 16) | ((device & 0x1f) << 11) | ((function & 0x7) << 8);
287 let child_addr_mid = 0;
288 let child_addr_low = 0;
289
290 let child_addr_cells = self.address_cells() as usize;
291 let child_irq_cells = self.interrupt_cells() as usize;
292 let required_mask_len = child_addr_cells + child_irq_cells;
293 if mask.len() < required_mask_len {
294 mask.resize(required_mask_len, 0xffff_ffff);
295 }
296
297 let encoded_address = [child_addr_high, child_addr_mid, child_addr_low];
298 let mut masked_child_address = Vec::with_capacity(child_addr_cells);
299 for idx in 0..child_addr_cells {
300 let value = *encoded_address.get(idx).unwrap_or(&0);
301 masked_child_address.push(value & mask[idx]);
302 }
303
304 let encoded_irq = [pin];
305 let mut masked_child_irq = Vec::with_capacity(child_irq_cells);
306 for idx in 0..child_irq_cells {
307 let value = *encoded_irq.get(idx).unwrap_or(&0);
308 masked_child_irq.push(value & mask[child_addr_cells + idx]);
309 }
310
311 for mapping in &interrupt_map {
313 if mapping.child_address == masked_child_address
315 && mapping.child_irq == masked_child_irq
316 {
317 return Ok(PciInterruptInfo {
318 irqs: mapping.parent_irq.clone(),
319 });
320 }
321 }
322 let simple_irq = (device * 4 + pin) % 32;
323 Ok(PciInterruptInfo {
324 irqs: vec![simple_irq],
325 })
326 }
327}
328
329impl Debug for Pci {
330 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
331 f.debug_struct("Pci")
332 .field("name", &self.node.name())
333 .field("is_pci_host_bridge", &self.is_pci_host_bridge())
334 .field("bus_range", &self.bus_range())
335 .field("interrupt_map_mask", &self.interrupt_map_mask())
336 .finish()
337 }
338}
339
340impl Deref for Pci {
341 type Target = NodeBase;
342
343 fn deref(&self) -> &Self::Target {
344 &self.node
345 }
346}
347
348#[cfg(test)]
349mod tests {
350 use crate::{cache::node::Node, Fdt};
351
352 #[test]
353 fn test_pci_node_detection() {
354 let dtb_data = include_bytes!("../../../../dtb-file/src/dtb/qemu_pci.dtb");
355 let fdt = Fdt::from_bytes(dtb_data).unwrap();
356
357 let mut pci_nodes_found = 0;
359 for node in fdt.find_nodes("/") {
360 {
361 if let Node::Pci(pci) = node {
362 pci_nodes_found += 1;
363 assert!(pci.is_pci_host_bridge());
365 }
366 }
367 }
368
369 assert!(pci_nodes_found > 0, "Should find at least one PCI node");
371 }
372
373 #[test]
374 fn test_interrupt_map_parsing() {
375 let dtb_data = include_bytes!("../../../../dtb-file/src/dtb/qemu_pci.dtb");
376 let fdt = Fdt::from_bytes(dtb_data).unwrap();
377
378 for node in fdt.find_nodes("/") {
380 {
381 if let Node::Pci(pci) = node {
382 if let Ok(interrupt_map) = pci.interrupt_map() {
383 assert!(!interrupt_map.is_empty());
384 return; }
386 }
387 }
388 }
389
390 }
393
394 #[test]
395 fn test_interrupt_map_mask() {
396 let dtb_data = include_bytes!("../../../../dtb-file/src/dtb/qemu_pci.dtb");
397 let fdt = Fdt::from_bytes(dtb_data).unwrap();
398
399 for node in fdt.find_nodes("/") {
400 {
401 if let Node::Pci(pci) = node {
402 if let Some(mask) = pci.interrupt_map_mask() {
403 assert_eq!(mask.len(), 4, "PCI interrupt-map-mask should have 4 cells");
405 return; }
407 }
408 }
409 }
410
411 }
413
414 #[test]
415 fn test_bus_range() {
416 let dtb_data = include_bytes!("../../../../dtb-file/src/dtb/qemu_pci.dtb");
417 let fdt = Fdt::from_bytes(dtb_data).unwrap();
418
419 for node in fdt.find_nodes("/") {
420 {
421 if let Node::Pci(pci) = node {
422 if let Some(range) = pci.bus_range() {
423 assert!(range.start <= range.end, "Bus range start should be <= end");
425 return; }
427 }
428 }
429 }
430
431 }
433
434 #[test]
435 fn test_pci_properties() {
436 let dtb_data = include_bytes!("../../../../dtb-file/src/dtb/qemu_pci.dtb");
437 let fdt = Fdt::from_bytes(dtb_data).unwrap();
438
439 for node in fdt.find_nodes("/") {
440 {
441 if let Node::Pci(pci) = node {
442 assert_eq!(pci.address_cells(), 3, "PCI should use 3 address cells");
444
445 assert_eq!(pci.interrupt_cells(), 1, "PCI should use 1 interrupt cell");
447
448 if let Some(device_type) = pci.device_type() {
450 assert!(!device_type.is_empty());
451 }
452
453 let compatibles = pci.compatibles();
455 if !compatibles.is_empty() {
456 }
458
459 return; }
461 }
462 }
463
464 panic!("No PCI nodes found for property testing");
465 }
466}