Skip to content

Commit

Permalink
Ensure uniqueness of phandle values within FDT
Browse files Browse the repository at this point in the history
Signed-off-by: Sergii Glushchenko <gsserge@amazon.com>
  • Loading branch information
Sergii Glushchenko authored and danielverkamp committed Oct 25, 2021
1 parent bb53be4 commit 88554cf
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
target
Cargo.lock
kcov_output*
kcov_build
2 changes: 1 addition & 1 deletion coverage_config_x86_64.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"coverage_score": 87.8,
"coverage_score": 87.4,
"exclude_path": "",
"crate_features": "long_running_test"
}
21 changes: 21 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,27 @@
//!
//! # let dtb = create_fdt().unwrap();
//! ```
//!
//! The [`phandle`](https://devicetree-specification.readthedocs.io/en/stable/devicetree-basics.html?#phandle)
//! property should be set using [`FdtWriter::property_phandle`],
//! so that the value is checked for uniqueness within the devicetree.
//!
//! ```rust
//! use vm_fdt::{Error, FdtWriter};
//!
//! fn create_fdt() -> Result<Vec<u8>, Error> {
//! let mut fdt = FdtWriter::new()?;
//!
//! let root_node = fdt.begin_node("root")?;
//! fdt.property_phandle(1)?;
//!
//! fdt.end_node(root_node)?;
//!
//! fdt.finish()
//! }
//!
//! # let dtb = create_fdt().unwrap();
//! ```

mod writer;

Expand Down
52 changes: 51 additions & 1 deletion src/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! <https://devicetree-specification.readthedocs.io/en/stable/flattened-format.html>

use std::cmp::{Ord, Ordering};
use std::collections::BTreeMap;
use std::collections::{BTreeMap, HashSet};
use std::convert::TryInto;
use std::ffi::CString;
use std::fmt;
Expand Down Expand Up @@ -43,6 +43,8 @@ pub enum Error {
InvalidPropertyName,
/// Node depth exceeds FDT_MAX_NODE_DEPTH
NodeDepthTooLarge,
/// Duplicate phandle property
DuplicatePhandle,
}

impl fmt::Display for Error {
Expand All @@ -68,6 +70,7 @@ impl fmt::Display for Error {
Error::InvalidNodeName => write!(f, "Invalid node name"),
Error::InvalidPropertyName => write!(f, "Invalid property name"),
Error::NodeDepthTooLarge => write!(f, "Node depth exceeds FDT_MAX_NODE_DEPTH"),
Error::DuplicatePhandle => write!(f, "Duplicate phandle value"),
}
}
}
Expand All @@ -94,6 +97,9 @@ pub struct FdtWriter {
node_depth: usize,
node_ended: bool,
boot_cpuid_phys: u32,
// The set is used to track the uniqueness of phandle values as required by the spec
// https://devicetree-specification.readthedocs.io/en/stable/devicetree-basics.html#phandle
phandles: HashSet<u32>,
}

/// Reserved physical memory region.
Expand Down Expand Up @@ -250,6 +256,7 @@ impl FdtWriter {
node_depth: 0,
node_ended: false,
boot_cpuid_phys: 0,
phandles: HashSet::new(),
};

fdt.align(8);
Expand Down Expand Up @@ -474,6 +481,16 @@ impl FdtWriter {
self.property(name, &arr)
}

/// Write a [`phandle`](https://devicetree-specification.readthedocs.io/en/stable/devicetree-basics.html?#phandle)
/// property. The value is checked for uniqueness within the FDT. In the case of a duplicate
/// [`Error::DuplicatePhandle`] is returned.
pub fn property_phandle(&mut self, val: u32) -> Result<()> {
if !self.phandles.insert(val) {
return Err(Error::DuplicatePhandle);
}
self.property("phandle", &val.to_be_bytes())
}

/// Finish writing the Devicetree Blob (DTB).
///
/// Returns the DTB as a vector of bytes, consuming the `FdtWriter`.
Expand Down Expand Up @@ -1118,4 +1135,37 @@ mod tests {
Error::NodeDepthTooLarge
);
}

#[test]
fn unique_phandles() {
let mut fdt = FdtWriter::new().unwrap();
let root_node = fdt.begin_node("root").unwrap();

let prim_node = fdt.begin_node("phandle-1").unwrap();
fdt.property_phandle(1).unwrap();
fdt.end_node(prim_node).unwrap();

let prim_node = fdt.begin_node("phandle-2").unwrap();
fdt.property_phandle(2).unwrap();
fdt.end_node(prim_node).unwrap();

fdt.end_node(root_node).unwrap();
fdt.finish().unwrap();
}

#[test]
fn duplicate_phandles() {
let mut fdt = FdtWriter::new().unwrap();
let _root_node = fdt.begin_node("root").unwrap();

let prim_node = fdt.begin_node("phandle-1").unwrap();
fdt.property_phandle(1).unwrap();
fdt.end_node(prim_node).unwrap();

let _sec_node = fdt.begin_node("phandle-2").unwrap();
assert_eq!(
fdt.property_phandle(1).unwrap_err(),
Error::DuplicatePhandle
);
}
}

0 comments on commit 88554cf

Please sign in to comment.