diff --git a/support/fdt/src/builder.rs b/support/fdt/src/builder.rs index e3f932e31f..5d2cb5b974 100644 --- a/support/fdt/src/builder.rs +++ b/support/fdt/src/builder.rs @@ -303,13 +303,25 @@ impl<'a, T> Builder<'a, Nest> { Ok(self) } - /// Adds an array of properties. The caller must ensure these are Big Endian - /// slices. + /// Adds an array of raw byte properties. Use this for unstructured byte data + /// such as entropy or empty arrays. For structured data that needs proper + /// byte ordering, prefer `add_be_array`, `add_u32_array`, or `add_u64_array`. pub fn add_prop_array(mut self, name: StringId, data_array: &[&[u8]]) -> Result { self.inner.prop_array_iter(name, data_array.iter())?; Ok(self) } + /// Adds an array of Big Endian typed properties. This method ensures that + /// the data is properly byte-ordered for FDT requirements. Use this for + /// structured data types that implement `IntoBytes` and `Immutable`. + pub fn add_be_array(mut self, name: StringId, data_array: &[U]) -> Result + where + U: IntoBytes + zerocopy::Immutable, + { + self.inner.prop_array_iter(name, data_array.iter().map(|item| item.as_bytes()))?; + Ok(self) + } + /// Adds a string property. pub fn add_str(mut self, name: StringId, data: &str) -> Result { self.inner @@ -425,6 +437,9 @@ impl<'a> Iterator for StringBytesWithZeroIter<'a> { #[cfg(test)] mod tests { + extern crate alloc; + use alloc::vec; + use alloc::vec::Vec; use super::*; fn create_entry(address: u64, size: u64) -> spec::ReserveEntry { @@ -492,4 +507,106 @@ mod tests { Ok(()) ); } + + #[test] + fn test_add_be_array() { + use zerocopy::byteorder::BigEndian; + use zerocopy::U32; + + let mut buf = vec![0; 1024]; + let mut builder = Builder::new(BuilderConfig { + blob_buffer: buf.as_mut_slice(), + string_table_cap: 128, + memory_reservations: &[], + }).unwrap(); + + let prop_name = builder.add_string("test-prop").unwrap(); + + // Test with BE u32 values + let be_values = [ + U32::::new(0x12345678), + U32::::new(0xDEADBEEF), + ]; + + let result = builder + .start_node("test") + .unwrap() + .add_be_array(prop_name, &be_values) + .unwrap() + .end_node() + .unwrap() + .build(0); + + assert!(result.is_ok()); + } + + #[test] + fn test_add_be_array_with_u64() { + use zerocopy::byteorder::BigEndian; + use zerocopy::U64; + + let mut buf = vec![0; 1024]; + let mut builder = Builder::new(BuilderConfig { + blob_buffer: buf.as_mut_slice(), + string_table_cap: 128, + memory_reservations: &[], + }).unwrap(); + + let prop_name = builder.add_string("test-prop-u64").unwrap(); + + // Test with BE u64 values - similar to what the parser test was doing + let native_values = [0x1122334455667788u64, 0xAABBCCDDEEFF0011u64]; + let be_values: Vec> = native_values + .iter() + .map(|v| U64::::new(*v)) + .collect(); + + let result = builder + .start_node("test") + .unwrap() + .add_be_array(prop_name, &be_values) + .unwrap() + .end_node() + .unwrap() + .build(0); + + assert!(result.is_ok()); + } + + // This test demonstrates that add_be_array enforces type safety. + // Uncommenting the code below would cause a compilation error, + // which is exactly the behavior we want. + #[test] + fn test_add_be_array_type_safety_documentation() { + // The following would NOT compile, demonstrating type safety: + // + // let native_u32s = [0x12345678u32, 0xDEADBEEF]; + // builder.add_be_array(prop_name, &native_u32s); // ERROR: u32 doesn't implement required traits + // + // Instead, you must use BE types: + // let be_u32s = [U32::::new(0x12345678), U32::::new(0xDEADBEEF)]; + // builder.add_be_array(prop_name, &be_u32s); // OK + + // This test just verifies that empty arrays work fine + let mut buf = vec![0; 1024]; + let mut builder = Builder::new(BuilderConfig { + blob_buffer: buf.as_mut_slice(), + string_table_cap: 128, + memory_reservations: &[], + }).unwrap(); + + let prop_name = builder.add_string("empty-prop").unwrap(); + let empty_array: &[u32] = &[]; + + let result = builder + .start_node("test") + .unwrap() + .add_be_array(prop_name, empty_array) + .unwrap() + .end_node() + .unwrap() + .build(0); + + assert!(result.is_ok()); + } } diff --git a/support/fdt/src/parser.rs b/support/fdt/src/parser.rs index 914fbe48da..b1a9021119 100644 --- a/support/fdt/src/parser.rs +++ b/support/fdt/src/parser.rs @@ -772,7 +772,6 @@ mod test { use alloc::string::String; use alloc::vec; use alloc::vec::Vec; - use zerocopy::IntoBytes; #[derive(Debug, Clone, PartialEq, Eq)] enum DtProp { @@ -825,14 +824,7 @@ mod test { .collect::>(); new_builder - .add_prop_array( - $ids.proplist, - big_endians - .iter() - .map(|v| v.as_bytes()) - .collect::>() - .as_slice(), - ) + .add_be_array($ids.proplist, &big_endians) .unwrap() } };