Prechádzať zdrojové kódy

Add support for `ranges` properties

Graham MacDonald 2 rokov pred
rodič
commit
4214454c3f
4 zmenil súbory, kde vykonal 81 pridanie a 2 odobranie
  1. 1 1
      src/lib.rs
  2. 39 1
      src/node.rs
  3. 11 0
      src/standard_nodes.rs
  4. 30 0
      src/tests.rs

+ 1 - 1
src/lib.rs

@@ -60,7 +60,7 @@ pub mod standard_nodes;
 
 use node::MemoryReservation;
 use parsing::{BigEndianU32, CStr, FdtData};
-use standard_nodes::{Aliases, Chosen, Cpu, Memory, MemoryRegion, Root};
+use standard_nodes::{Aliases, Chosen, Cpu, Memory, MemoryRegion, MemoryRange, Root};
 
 /// Possible errors when attempting to create an `Fdt`
 #[derive(Debug, Clone, Copy, PartialEq)]

+ 39 - 1
src/node.rs

@@ -4,7 +4,7 @@
 
 use crate::{
     parsing::{BigEndianU32, BigEndianU64, CStr, FdtData},
-    standard_nodes::{Compatible, MemoryRegion},
+    standard_nodes::{Compatible, MemoryRegion, MemoryRange},
     Fdt,
 };
 
@@ -173,6 +173,44 @@ impl<'b, 'a: 'b> FdtNode<'b, 'a> {
         reg
     }
 
+    pub fn ranges(self) -> Option<impl Iterator<Item = crate::MemoryRange> + 'a> {
+        let sizes = self.parent_cell_sizes();
+        if sizes.address_cells > 2 || sizes.size_cells > 2 {
+            return None;
+        }
+
+        let mut ranges = None;
+        for prop in self.properties() {
+            if prop.name == "ranges" {
+                let mut stream = FdtData::new(prop.value);
+                ranges = Some(core::iter::from_fn(move || {
+                    let child_bus_address = match sizes.address_cells {
+                        1 => stream.u32()?.get() as usize,
+                        2 => stream.u64()?.get() as usize,
+                        _ => return None,
+                    };
+
+                    let parent_bus_address = match sizes.address_cells {
+                        1 => stream.u32()?.get() as usize,
+                        2 => stream.u64()?.get() as usize,
+                        _ => return None,
+                    };
+
+                    let size = match sizes.size_cells {
+                        1 => stream.u32()?.get() as usize,
+                        2 => stream.u64()?.get() as usize,
+                        _ => return None,
+                    };
+
+                    Some(MemoryRange { child_bus_address, parent_bus_address, size })
+                }));
+                break;
+            }
+        }
+
+        ranges
+    }
+
     /// Convenience method that provides an iterator over the raw bytes for the
     /// address and size values inside of the `reg` property
     pub fn raw_reg(self) -> Option<impl Iterator<Item = RawReg<'a>> + 'a> {

+ 11 - 0
src/standard_nodes.rs

@@ -298,3 +298,14 @@ pub struct MemoryRegion {
     /// Size of the memory region
     pub size: Option<usize>,
 }
+
+/// Range mapping child bus addresses to parent bus addresses
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub struct MemoryRange {
+    /// Starting address on child bus
+    pub child_bus_address: usize,
+    /// Starting address on parent bus
+    pub parent_bus_address: usize,
+    /// Size of range
+    pub size: usize,
+}

+ 30 - 0
src/tests.rs

@@ -53,6 +53,36 @@ fn correct_flash_regions() {
     );
 }
 
+#[test]
+fn parses_populated_ranges() {
+    let fdt = Fdt::new(TEST).unwrap();
+    let ranges = fdt.find_node("/soc/pci").unwrap().ranges().unwrap().collect::<std::vec::Vec<_>>();
+
+    assert_eq!(
+        ranges,
+        &[
+            MemoryRange {
+                child_bus_address: 0x100_0000_0000_0000,
+                parent_bus_address: 0x0,
+                size: 0x300_0000_0000_0000
+            },
+            MemoryRange {
+                child_bus_address: 0x1_0000_0200_0000,
+                parent_bus_address: 0x4000_0000,
+                size: 0x4000_0000
+            }
+        ]
+    );
+}
+
+#[test]
+fn parses_empty_ranges() {
+    let fdt = Fdt::new(TEST).unwrap();
+    let ranges = fdt.find_node("/soc").unwrap().ranges().unwrap().collect::<std::vec::Vec<_>>();
+
+    assert_eq!(ranges, &[]);
+}
+
 #[test]
 fn finds_with_addr() {
     let fdt = Fdt::new(TEST).unwrap();