xref: /aosp_15_r20/external/crosvm/cros_fdt/src/fdt.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2018 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker //! This module writes Flattened Devicetree blobs as defined here:
6*bb4ee6a4SAndroid Build Coastguard Worker //! <https://devicetree-specification.readthedocs.io/en/stable/flattened-format.html>
7*bb4ee6a4SAndroid Build Coastguard Worker 
8*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BTreeMap;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::convert::TryInto;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::io;
11*bb4ee6a4SAndroid Build Coastguard Worker 
12*bb4ee6a4SAndroid Build Coastguard Worker use indexmap::map::Entry;
13*bb4ee6a4SAndroid Build Coastguard Worker use indexmap::IndexMap;
14*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted;
15*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error as ThisError;
16*bb4ee6a4SAndroid Build Coastguard Worker 
17*bb4ee6a4SAndroid Build Coastguard Worker use crate::path::Path;
18*bb4ee6a4SAndroid Build Coastguard Worker use crate::propval::FromFdtPropval;
19*bb4ee6a4SAndroid Build Coastguard Worker use crate::propval::ToFdtPropval;
20*bb4ee6a4SAndroid Build Coastguard Worker 
21*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) const SIZE_U32: usize = std::mem::size_of::<u32>();
22*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) const SIZE_U64: usize = std::mem::size_of::<u64>();
23*bb4ee6a4SAndroid Build Coastguard Worker 
24*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
25*bb4ee6a4SAndroid Build Coastguard Worker #[derive(ThisError, Debug)]
26*bb4ee6a4SAndroid Build Coastguard Worker pub enum Error {
27*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Error applying device tree overlay: {}", .0)]
28*bb4ee6a4SAndroid Build Coastguard Worker     ApplyOverlayError(String),
29*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Binary size must fit in 32 bits")]
30*bb4ee6a4SAndroid Build Coastguard Worker     BinarySizeTooLarge,
31*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Duplicate node {}", .0)]
32*bb4ee6a4SAndroid Build Coastguard Worker     DuplicateNode(String),
33*bb4ee6a4SAndroid Build Coastguard Worker     #[error("I/O error dumping FDT to file code={} path={}", .0, .1.display())]
34*bb4ee6a4SAndroid Build Coastguard Worker     FdtDumpIoError(io::Error, std::path::PathBuf),
35*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Error writing FDT to guest memory")]
36*bb4ee6a4SAndroid Build Coastguard Worker     FdtGuestMemoryWriteError,
37*bb4ee6a4SAndroid Build Coastguard Worker     #[error("I/O error code={0}")]
38*bb4ee6a4SAndroid Build Coastguard Worker     FdtIoError(io::Error),
39*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Parse error reading FDT parameters: {}", .0)]
40*bb4ee6a4SAndroid Build Coastguard Worker     FdtParseError(String),
41*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Error applying FDT tree filter: {}", .0)]
42*bb4ee6a4SAndroid Build Coastguard Worker     FilterError(String),
43*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Invalid name string: {}", .0)]
44*bb4ee6a4SAndroid Build Coastguard Worker     InvalidName(String),
45*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Invalid path: {}", .0)]
46*bb4ee6a4SAndroid Build Coastguard Worker     InvalidPath(String),
47*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Invalid string value {}", .0)]
48*bb4ee6a4SAndroid Build Coastguard Worker     InvalidString(String),
49*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Expected phandle value for IOMMU of type: {}, id: {:?}", .0, .1)]
50*bb4ee6a4SAndroid Build Coastguard Worker     MissingIommuPhandle(String, Option<u32>),
51*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Property value is not valid")]
52*bb4ee6a4SAndroid Build Coastguard Worker     PropertyValueInvalid,
53*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Property value size must fit in 32 bits")]
54*bb4ee6a4SAndroid Build Coastguard Worker     PropertyValueTooLarge,
55*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Total size must fit in 32 bits")]
56*bb4ee6a4SAndroid Build Coastguard Worker     TotalSizeTooLarge,
57*bb4ee6a4SAndroid Build Coastguard Worker }
58*bb4ee6a4SAndroid Build Coastguard Worker 
59*bb4ee6a4SAndroid Build Coastguard Worker impl From<io::Error> for Error {
from(value: io::Error) -> Self60*bb4ee6a4SAndroid Build Coastguard Worker     fn from(value: io::Error) -> Self {
61*bb4ee6a4SAndroid Build Coastguard Worker         Self::FdtIoError(value)
62*bb4ee6a4SAndroid Build Coastguard Worker     }
63*bb4ee6a4SAndroid Build Coastguard Worker }
64*bb4ee6a4SAndroid Build Coastguard Worker 
65*bb4ee6a4SAndroid Build Coastguard Worker pub type Result<T> = std::result::Result<T, Error>;
66*bb4ee6a4SAndroid Build Coastguard Worker type Blob<'a> = &'a [u8];
67*bb4ee6a4SAndroid Build Coastguard Worker 
68*bb4ee6a4SAndroid Build Coastguard Worker const FDT_BEGIN_NODE: u32 = 0x00000001;
69*bb4ee6a4SAndroid Build Coastguard Worker const FDT_END_NODE: u32 = 0x00000002;
70*bb4ee6a4SAndroid Build Coastguard Worker const FDT_PROP: u32 = 0x00000003;
71*bb4ee6a4SAndroid Build Coastguard Worker const FDT_NOP: u32 = 0x00000004;
72*bb4ee6a4SAndroid Build Coastguard Worker const FDT_END: u32 = 0x00000009;
73*bb4ee6a4SAndroid Build Coastguard Worker 
74*bb4ee6a4SAndroid Build Coastguard Worker // Consume and return `n` bytes from the beginning of a slice.
consume<'a>(bytes: &mut &'a [u8], n: usize) -> Result<&'a [u8]>75*bb4ee6a4SAndroid Build Coastguard Worker fn consume<'a>(bytes: &mut &'a [u8], n: usize) -> Result<&'a [u8]> {
76*bb4ee6a4SAndroid Build Coastguard Worker     let mid = n;
77*bb4ee6a4SAndroid Build Coastguard Worker     if mid > bytes.len() {
78*bb4ee6a4SAndroid Build Coastguard Worker         Err(Error::PropertyValueInvalid)
79*bb4ee6a4SAndroid Build Coastguard Worker     } else {
80*bb4ee6a4SAndroid Build Coastguard Worker         let (data_bytes, rest) = bytes.split_at(n);
81*bb4ee6a4SAndroid Build Coastguard Worker         *(bytes) = rest;
82*bb4ee6a4SAndroid Build Coastguard Worker         Ok(data_bytes)
83*bb4ee6a4SAndroid Build Coastguard Worker     }
84*bb4ee6a4SAndroid Build Coastguard Worker }
85*bb4ee6a4SAndroid Build Coastguard Worker 
86*bb4ee6a4SAndroid Build Coastguard Worker // Consume a u32 from a byte slice.
87*bb4ee6a4SAndroid Build Coastguard Worker #[inline]
rdu32(data: &mut Blob) -> Result<u32>88*bb4ee6a4SAndroid Build Coastguard Worker fn rdu32(data: &mut Blob) -> Result<u32> {
89*bb4ee6a4SAndroid Build Coastguard Worker     Ok(u32::from_be_bytes(
90*bb4ee6a4SAndroid Build Coastguard Worker         // Unwrap won't panic because the slice length is checked in consume().
91*bb4ee6a4SAndroid Build Coastguard Worker         consume(data, SIZE_U32)?.try_into().unwrap(),
92*bb4ee6a4SAndroid Build Coastguard Worker     ))
93*bb4ee6a4SAndroid Build Coastguard Worker }
94*bb4ee6a4SAndroid Build Coastguard Worker 
95*bb4ee6a4SAndroid Build Coastguard Worker // Consume a u64 from a byte slice.
96*bb4ee6a4SAndroid Build Coastguard Worker #[inline]
rdu64(data: &mut Blob) -> Result<u64>97*bb4ee6a4SAndroid Build Coastguard Worker fn rdu64(data: &mut Blob) -> Result<u64> {
98*bb4ee6a4SAndroid Build Coastguard Worker     Ok(u64::from_be_bytes(
99*bb4ee6a4SAndroid Build Coastguard Worker         // Unwrap won't panic because the slice length is checked in consume().
100*bb4ee6a4SAndroid Build Coastguard Worker         consume(data, SIZE_U64)?.try_into().unwrap(),
101*bb4ee6a4SAndroid Build Coastguard Worker     ))
102*bb4ee6a4SAndroid Build Coastguard Worker }
103*bb4ee6a4SAndroid Build Coastguard Worker 
104*bb4ee6a4SAndroid Build Coastguard Worker // Return the number of padding bytes required to align `size` to `alignment`.
105*bb4ee6a4SAndroid Build Coastguard Worker #[inline]
align_pad_len(size: usize, alignment: usize) -> usize106*bb4ee6a4SAndroid Build Coastguard Worker fn align_pad_len(size: usize, alignment: usize) -> usize {
107*bb4ee6a4SAndroid Build Coastguard Worker     (alignment - size % alignment) % alignment
108*bb4ee6a4SAndroid Build Coastguard Worker }
109*bb4ee6a4SAndroid Build Coastguard Worker 
110*bb4ee6a4SAndroid Build Coastguard Worker // Pad a byte vector to given alignment.
111*bb4ee6a4SAndroid Build Coastguard Worker #[inline]
align_data(data: &mut Vec<u8>, alignment: usize)112*bb4ee6a4SAndroid Build Coastguard Worker fn align_data(data: &mut Vec<u8>, alignment: usize) {
113*bb4ee6a4SAndroid Build Coastguard Worker     data.resize(align_pad_len(data.len(), alignment) + data.len(), 0u8);
114*bb4ee6a4SAndroid Build Coastguard Worker }
115*bb4ee6a4SAndroid Build Coastguard Worker 
116*bb4ee6a4SAndroid Build Coastguard Worker // Construct a string from the start of a byte slice until the first null byte.
c_str_to_string(input: Blob) -> Option<String>117*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) fn c_str_to_string(input: Blob) -> Option<String> {
118*bb4ee6a4SAndroid Build Coastguard Worker     let size = input.iter().position(|&v| v == 0u8)?;
119*bb4ee6a4SAndroid Build Coastguard Worker     String::from_utf8(input[..size].to_vec()).ok()
120*bb4ee6a4SAndroid Build Coastguard Worker }
121*bb4ee6a4SAndroid Build Coastguard Worker 
122*bb4ee6a4SAndroid Build Coastguard Worker // Verify FDT property name.
is_valid_prop_name(name: &str) -> bool123*bb4ee6a4SAndroid Build Coastguard Worker fn is_valid_prop_name(name: &str) -> bool {
124*bb4ee6a4SAndroid Build Coastguard Worker     const ALLOWED_SPECIAL_CHARS: [u8; 7] = [b'.', b',', b'_', b'+', b'?', b'#', b'-'];
125*bb4ee6a4SAndroid Build Coastguard Worker     name.bytes()
126*bb4ee6a4SAndroid Build Coastguard Worker         .all(|c| c.is_ascii_alphanumeric() || ALLOWED_SPECIAL_CHARS.contains(&c))
127*bb4ee6a4SAndroid Build Coastguard Worker }
128*bb4ee6a4SAndroid Build Coastguard Worker 
129*bb4ee6a4SAndroid Build Coastguard Worker // Verify FDT node name.
is_valid_node_name(name: &str) -> bool130*bb4ee6a4SAndroid Build Coastguard Worker fn is_valid_node_name(name: &str) -> bool {
131*bb4ee6a4SAndroid Build Coastguard Worker     const ALLOWED_SPECIAL_CHARS: [u8; 6] = [b'.', b',', b'_', b'+', b'-', b'@'];
132*bb4ee6a4SAndroid Build Coastguard Worker     const ADDR_SEP: u8 = b'@';
133*bb4ee6a4SAndroid Build Coastguard Worker     // At most one `@` separating node-name and unit-address
134*bb4ee6a4SAndroid Build Coastguard Worker     if name.bytes().filter(|&c| c == ADDR_SEP).count() > 1 {
135*bb4ee6a4SAndroid Build Coastguard Worker         return false;
136*bb4ee6a4SAndroid Build Coastguard Worker     }
137*bb4ee6a4SAndroid Build Coastguard Worker     name.bytes()
138*bb4ee6a4SAndroid Build Coastguard Worker         .all(|c| c.is_ascii_alphanumeric() || ALLOWED_SPECIAL_CHARS.contains(&c))
139*bb4ee6a4SAndroid Build Coastguard Worker }
140*bb4ee6a4SAndroid Build Coastguard Worker 
141*bb4ee6a4SAndroid Build Coastguard Worker // An implementation of FDT header.
142*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Default, Debug)]
143*bb4ee6a4SAndroid Build Coastguard Worker struct FdtHeader {
144*bb4ee6a4SAndroid Build Coastguard Worker     magic: u32,             // magic word
145*bb4ee6a4SAndroid Build Coastguard Worker     total_size: u32,        // total size of DT block
146*bb4ee6a4SAndroid Build Coastguard Worker     off_dt_struct: u32,     // offset to structure
147*bb4ee6a4SAndroid Build Coastguard Worker     off_dt_strings: u32,    // offset to strings
148*bb4ee6a4SAndroid Build Coastguard Worker     off_mem_rsvmap: u32,    // offset to memory reserve map
149*bb4ee6a4SAndroid Build Coastguard Worker     version: u32,           // format version
150*bb4ee6a4SAndroid Build Coastguard Worker     last_comp_version: u32, // last compatible version
151*bb4ee6a4SAndroid Build Coastguard Worker     boot_cpuid_phys: u32,   // Which physical CPU id we're booting on
152*bb4ee6a4SAndroid Build Coastguard Worker     size_dt_strings: u32,   // size of the strings block
153*bb4ee6a4SAndroid Build Coastguard Worker     size_dt_struct: u32,    // size of the structure block
154*bb4ee6a4SAndroid Build Coastguard Worker }
155*bb4ee6a4SAndroid Build Coastguard Worker 
156*bb4ee6a4SAndroid Build Coastguard Worker impl FdtHeader {
157*bb4ee6a4SAndroid Build Coastguard Worker     const MAGIC: u32 = 0xd00dfeed;
158*bb4ee6a4SAndroid Build Coastguard Worker     const VERSION: u32 = 17;
159*bb4ee6a4SAndroid Build Coastguard Worker     const LAST_COMP_VERSION: u32 = 16;
160*bb4ee6a4SAndroid Build Coastguard Worker     const SIZE: usize = 10 * SIZE_U32;
161*bb4ee6a4SAndroid Build Coastguard Worker 
162*bb4ee6a4SAndroid Build Coastguard Worker     // Create a new FdtHeader instance.
new( total_size: u32, off_dt_struct: u32, off_dt_strings: u32, off_mem_rsvmap: u32, boot_cpuid_phys: u32, size_dt_strings: u32, size_dt_struct: u32, ) -> Self163*bb4ee6a4SAndroid Build Coastguard Worker     fn new(
164*bb4ee6a4SAndroid Build Coastguard Worker         total_size: u32,
165*bb4ee6a4SAndroid Build Coastguard Worker         off_dt_struct: u32,
166*bb4ee6a4SAndroid Build Coastguard Worker         off_dt_strings: u32,
167*bb4ee6a4SAndroid Build Coastguard Worker         off_mem_rsvmap: u32,
168*bb4ee6a4SAndroid Build Coastguard Worker         boot_cpuid_phys: u32,
169*bb4ee6a4SAndroid Build Coastguard Worker         size_dt_strings: u32,
170*bb4ee6a4SAndroid Build Coastguard Worker         size_dt_struct: u32,
171*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Self {
172*bb4ee6a4SAndroid Build Coastguard Worker         Self {
173*bb4ee6a4SAndroid Build Coastguard Worker             magic: Self::MAGIC,
174*bb4ee6a4SAndroid Build Coastguard Worker             total_size,
175*bb4ee6a4SAndroid Build Coastguard Worker             off_dt_struct,
176*bb4ee6a4SAndroid Build Coastguard Worker             off_dt_strings,
177*bb4ee6a4SAndroid Build Coastguard Worker             off_mem_rsvmap,
178*bb4ee6a4SAndroid Build Coastguard Worker             version: Self::VERSION,
179*bb4ee6a4SAndroid Build Coastguard Worker             last_comp_version: Self::LAST_COMP_VERSION,
180*bb4ee6a4SAndroid Build Coastguard Worker             boot_cpuid_phys,
181*bb4ee6a4SAndroid Build Coastguard Worker             size_dt_strings,
182*bb4ee6a4SAndroid Build Coastguard Worker             size_dt_struct,
183*bb4ee6a4SAndroid Build Coastguard Worker         }
184*bb4ee6a4SAndroid Build Coastguard Worker     }
185*bb4ee6a4SAndroid Build Coastguard Worker 
186*bb4ee6a4SAndroid Build Coastguard Worker     // Dump FDT header to a byte vector.
write_blob(&self, buffer: &mut [u8]) -> Result<()>187*bb4ee6a4SAndroid Build Coastguard Worker     fn write_blob(&self, buffer: &mut [u8]) -> Result<()> {
188*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(buffer.len(), Self::SIZE);
189*bb4ee6a4SAndroid Build Coastguard Worker         for (chunk, val_u32) in buffer.chunks_exact_mut(SIZE_U32).zip(&[
190*bb4ee6a4SAndroid Build Coastguard Worker             self.magic,
191*bb4ee6a4SAndroid Build Coastguard Worker             self.total_size,
192*bb4ee6a4SAndroid Build Coastguard Worker             self.off_dt_struct,
193*bb4ee6a4SAndroid Build Coastguard Worker             self.off_dt_strings,
194*bb4ee6a4SAndroid Build Coastguard Worker             self.off_mem_rsvmap,
195*bb4ee6a4SAndroid Build Coastguard Worker             self.version,
196*bb4ee6a4SAndroid Build Coastguard Worker             self.last_comp_version,
197*bb4ee6a4SAndroid Build Coastguard Worker             self.boot_cpuid_phys,
198*bb4ee6a4SAndroid Build Coastguard Worker             self.size_dt_strings,
199*bb4ee6a4SAndroid Build Coastguard Worker             self.size_dt_struct,
200*bb4ee6a4SAndroid Build Coastguard Worker         ]) {
201*bb4ee6a4SAndroid Build Coastguard Worker             chunk.copy_from_slice(&val_u32.to_be_bytes());
202*bb4ee6a4SAndroid Build Coastguard Worker         }
203*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
204*bb4ee6a4SAndroid Build Coastguard Worker     }
205*bb4ee6a4SAndroid Build Coastguard Worker 
206*bb4ee6a4SAndroid Build Coastguard Worker     // Load FDT header from a byte slice.
from_blob(mut input: Blob) -> Result<Self>207*bb4ee6a4SAndroid Build Coastguard Worker     fn from_blob(mut input: Blob) -> Result<Self> {
208*bb4ee6a4SAndroid Build Coastguard Worker         if input.len() < Self::SIZE {
209*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::FdtParseError("invalid binary size".into()));
210*bb4ee6a4SAndroid Build Coastguard Worker         }
211*bb4ee6a4SAndroid Build Coastguard Worker         let input = &mut input;
212*bb4ee6a4SAndroid Build Coastguard Worker         let header = Self {
213*bb4ee6a4SAndroid Build Coastguard Worker             magic: rdu32(input)?,
214*bb4ee6a4SAndroid Build Coastguard Worker             total_size: rdu32(input)?,
215*bb4ee6a4SAndroid Build Coastguard Worker             off_dt_struct: rdu32(input)?,
216*bb4ee6a4SAndroid Build Coastguard Worker             off_dt_strings: rdu32(input)?,
217*bb4ee6a4SAndroid Build Coastguard Worker             off_mem_rsvmap: rdu32(input)?,
218*bb4ee6a4SAndroid Build Coastguard Worker             version: rdu32(input)?,
219*bb4ee6a4SAndroid Build Coastguard Worker             last_comp_version: rdu32(input)?,
220*bb4ee6a4SAndroid Build Coastguard Worker             boot_cpuid_phys: rdu32(input)?,
221*bb4ee6a4SAndroid Build Coastguard Worker             size_dt_strings: rdu32(input)?,
222*bb4ee6a4SAndroid Build Coastguard Worker             size_dt_struct: rdu32(input)?,
223*bb4ee6a4SAndroid Build Coastguard Worker         };
224*bb4ee6a4SAndroid Build Coastguard Worker         if header.magic != Self::MAGIC {
225*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::FdtParseError("invalid header magic".into()));
226*bb4ee6a4SAndroid Build Coastguard Worker         }
227*bb4ee6a4SAndroid Build Coastguard Worker         if header.version < Self::VERSION {
228*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::FdtParseError("unsupported FDT version".into()));
229*bb4ee6a4SAndroid Build Coastguard Worker         }
230*bb4ee6a4SAndroid Build Coastguard Worker         if header.off_mem_rsvmap >= header.off_dt_strings
231*bb4ee6a4SAndroid Build Coastguard Worker             || header.off_mem_rsvmap < FdtHeader::SIZE as u32
232*bb4ee6a4SAndroid Build Coastguard Worker         {
233*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::FdtParseError(
234*bb4ee6a4SAndroid Build Coastguard Worker                 "invalid reserved memory offset".into(),
235*bb4ee6a4SAndroid Build Coastguard Worker             ));
236*bb4ee6a4SAndroid Build Coastguard Worker         }
237*bb4ee6a4SAndroid Build Coastguard Worker 
238*bb4ee6a4SAndroid Build Coastguard Worker         let off_dt_struct_end = header
239*bb4ee6a4SAndroid Build Coastguard Worker             .off_dt_struct
240*bb4ee6a4SAndroid Build Coastguard Worker             .checked_add(header.size_dt_struct)
241*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or_else(|| Error::FdtParseError("struct end offset must fit in 32 bits".into()))?;
242*bb4ee6a4SAndroid Build Coastguard Worker         if off_dt_struct_end > header.off_dt_strings {
243*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::FdtParseError("struct and strings overlap".into()));
244*bb4ee6a4SAndroid Build Coastguard Worker         }
245*bb4ee6a4SAndroid Build Coastguard Worker 
246*bb4ee6a4SAndroid Build Coastguard Worker         let off_dt_strings_end = header
247*bb4ee6a4SAndroid Build Coastguard Worker             .off_dt_strings
248*bb4ee6a4SAndroid Build Coastguard Worker             .checked_add(header.size_dt_strings)
249*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or_else(|| Error::FdtParseError("strings end offset must fit in 32 bits".into()))?;
250*bb4ee6a4SAndroid Build Coastguard Worker         if off_dt_strings_end > header.total_size {
251*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::FdtParseError("strings data past total size".into()));
252*bb4ee6a4SAndroid Build Coastguard Worker         }
253*bb4ee6a4SAndroid Build Coastguard Worker 
254*bb4ee6a4SAndroid Build Coastguard Worker         Ok(header)
255*bb4ee6a4SAndroid Build Coastguard Worker     }
256*bb4ee6a4SAndroid Build Coastguard Worker }
257*bb4ee6a4SAndroid Build Coastguard Worker 
258*bb4ee6a4SAndroid Build Coastguard Worker // An implementation of FDT strings block (property names)
259*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Default)]
260*bb4ee6a4SAndroid Build Coastguard Worker struct FdtStrings {
261*bb4ee6a4SAndroid Build Coastguard Worker     strings: Vec<u8>,
262*bb4ee6a4SAndroid Build Coastguard Worker     string_offsets: BTreeMap<String, u32>,
263*bb4ee6a4SAndroid Build Coastguard Worker }
264*bb4ee6a4SAndroid Build Coastguard Worker 
265*bb4ee6a4SAndroid Build Coastguard Worker impl FdtStrings {
266*bb4ee6a4SAndroid Build Coastguard Worker     // Load the strings block from a byte slice.
from_blob(input: Blob) -> Result<Self>267*bb4ee6a4SAndroid Build Coastguard Worker     fn from_blob(input: Blob) -> Result<Self> {
268*bb4ee6a4SAndroid Build Coastguard Worker         if input.last().map_or(false, |i| *i != 0) {
269*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::FdtParseError(
270*bb4ee6a4SAndroid Build Coastguard Worker                 "strings block missing null terminator".into(),
271*bb4ee6a4SAndroid Build Coastguard Worker             ));
272*bb4ee6a4SAndroid Build Coastguard Worker         }
273*bb4ee6a4SAndroid Build Coastguard Worker         let mut string_offsets = BTreeMap::new();
274*bb4ee6a4SAndroid Build Coastguard Worker         let mut offset = 0u32;
275*bb4ee6a4SAndroid Build Coastguard Worker         for bytes in input.split(|&x| x == 0u8) {
276*bb4ee6a4SAndroid Build Coastguard Worker             if bytes.is_empty() {
277*bb4ee6a4SAndroid Build Coastguard Worker                 break;
278*bb4ee6a4SAndroid Build Coastguard Worker             }
279*bb4ee6a4SAndroid Build Coastguard Worker             let string = String::from_utf8(bytes.to_vec())
280*bb4ee6a4SAndroid Build Coastguard Worker                 .map_err(|_| Error::FdtParseError("invalid value in strings block".into()))?;
281*bb4ee6a4SAndroid Build Coastguard Worker             string_offsets.insert(string, offset);
282*bb4ee6a4SAndroid Build Coastguard Worker             offset += u32::try_from(bytes.len() + 1).map_err(|_| Error::BinarySizeTooLarge)?;
283*bb4ee6a4SAndroid Build Coastguard Worker         }
284*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Self {
285*bb4ee6a4SAndroid Build Coastguard Worker             strings: input.to_vec(),
286*bb4ee6a4SAndroid Build Coastguard Worker             string_offsets,
287*bb4ee6a4SAndroid Build Coastguard Worker         })
288*bb4ee6a4SAndroid Build Coastguard Worker     }
289*bb4ee6a4SAndroid Build Coastguard Worker 
290*bb4ee6a4SAndroid Build Coastguard Worker     // Find an existing instance of a string `s`, or add it to the strings block.
291*bb4ee6a4SAndroid Build Coastguard Worker     // Returns the offset into the strings block.
intern_string(&mut self, s: &str) -> u32292*bb4ee6a4SAndroid Build Coastguard Worker     fn intern_string(&mut self, s: &str) -> u32 {
293*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(off) = self.string_offsets.get(s) {
294*bb4ee6a4SAndroid Build Coastguard Worker             *off
295*bb4ee6a4SAndroid Build Coastguard Worker         } else {
296*bb4ee6a4SAndroid Build Coastguard Worker             let off = self.strings.len() as u32;
297*bb4ee6a4SAndroid Build Coastguard Worker             self.strings.extend_from_slice(s.as_bytes());
298*bb4ee6a4SAndroid Build Coastguard Worker             self.strings.push(0u8);
299*bb4ee6a4SAndroid Build Coastguard Worker             self.string_offsets.insert(s.to_owned(), off);
300*bb4ee6a4SAndroid Build Coastguard Worker             off
301*bb4ee6a4SAndroid Build Coastguard Worker         }
302*bb4ee6a4SAndroid Build Coastguard Worker     }
303*bb4ee6a4SAndroid Build Coastguard Worker 
304*bb4ee6a4SAndroid Build Coastguard Worker     // Write the strings blob to a `Write` object.
write_blob(&self, mut writer: impl io::Write) -> Result<()>305*bb4ee6a4SAndroid Build Coastguard Worker     fn write_blob(&self, mut writer: impl io::Write) -> Result<()> {
306*bb4ee6a4SAndroid Build Coastguard Worker         Ok(writer.write_all(&self.strings)?)
307*bb4ee6a4SAndroid Build Coastguard Worker     }
308*bb4ee6a4SAndroid Build Coastguard Worker 
309*bb4ee6a4SAndroid Build Coastguard Worker     // Return the string at given offset or `None` if such a string doesn't exist.
at_offset(&self, off: u32) -> Option<String>310*bb4ee6a4SAndroid Build Coastguard Worker     fn at_offset(&self, off: u32) -> Option<String> {
311*bb4ee6a4SAndroid Build Coastguard Worker         self.strings
312*bb4ee6a4SAndroid Build Coastguard Worker             .get(off as usize..)
313*bb4ee6a4SAndroid Build Coastguard Worker             .and_then(c_str_to_string)
314*bb4ee6a4SAndroid Build Coastguard Worker             .filter(|s| !s.is_empty())
315*bb4ee6a4SAndroid Build Coastguard Worker     }
316*bb4ee6a4SAndroid Build Coastguard Worker }
317*bb4ee6a4SAndroid Build Coastguard Worker 
318*bb4ee6a4SAndroid Build Coastguard Worker /// Flattened device tree node.
319*bb4ee6a4SAndroid Build Coastguard Worker ///
320*bb4ee6a4SAndroid Build Coastguard Worker /// This represents a single node from the FDT structure block. Every node may contain properties
321*bb4ee6a4SAndroid Build Coastguard Worker /// and other (child) nodes.
322*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone)]
323*bb4ee6a4SAndroid Build Coastguard Worker pub struct FdtNode {
324*bb4ee6a4SAndroid Build Coastguard Worker     /// Node name
325*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) name: String,
326*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) props: IndexMap<String, Vec<u8>>,
327*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) subnodes: IndexMap<String, FdtNode>,
328*bb4ee6a4SAndroid Build Coastguard Worker }
329*bb4ee6a4SAndroid Build Coastguard Worker 
330*bb4ee6a4SAndroid Build Coastguard Worker impl FdtNode {
331*bb4ee6a4SAndroid Build Coastguard Worker     // Create a new node with the given name, properties, and child nodes. Return an error if
332*bb4ee6a4SAndroid Build Coastguard Worker     // node or property names do not satisfy devicetree naming criteria.
new( name: String, props: IndexMap<String, Vec<u8>>, subnodes: IndexMap<String, FdtNode>, ) -> Result<Self>333*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) fn new(
334*bb4ee6a4SAndroid Build Coastguard Worker         name: String,
335*bb4ee6a4SAndroid Build Coastguard Worker         props: IndexMap<String, Vec<u8>>,
336*bb4ee6a4SAndroid Build Coastguard Worker         subnodes: IndexMap<String, FdtNode>,
337*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<Self> {
338*bb4ee6a4SAndroid Build Coastguard Worker         if !is_valid_node_name(&name) {
339*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::InvalidName(name));
340*bb4ee6a4SAndroid Build Coastguard Worker         }
341*bb4ee6a4SAndroid Build Coastguard Worker         for pname in props.keys() {
342*bb4ee6a4SAndroid Build Coastguard Worker             if !is_valid_prop_name(pname) {
343*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(Error::InvalidName(pname.into()));
344*bb4ee6a4SAndroid Build Coastguard Worker             }
345*bb4ee6a4SAndroid Build Coastguard Worker         }
346*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Self {
347*bb4ee6a4SAndroid Build Coastguard Worker             name,
348*bb4ee6a4SAndroid Build Coastguard Worker             props,
349*bb4ee6a4SAndroid Build Coastguard Worker             subnodes,
350*bb4ee6a4SAndroid Build Coastguard Worker         })
351*bb4ee6a4SAndroid Build Coastguard Worker     }
352*bb4ee6a4SAndroid Build Coastguard Worker 
353*bb4ee6a4SAndroid Build Coastguard Worker     // Create an empty node with the given name.
empty(name: impl Into<String>) -> Result<Self>354*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) fn empty(name: impl Into<String>) -> Result<Self> {
355*bb4ee6a4SAndroid Build Coastguard Worker         FdtNode::new(name.into(), [].into(), [].into())
356*bb4ee6a4SAndroid Build Coastguard Worker     }
357*bb4ee6a4SAndroid Build Coastguard Worker 
read_token(input: &mut Blob) -> Result<u32>358*bb4ee6a4SAndroid Build Coastguard Worker     fn read_token(input: &mut Blob) -> Result<u32> {
359*bb4ee6a4SAndroid Build Coastguard Worker         loop {
360*bb4ee6a4SAndroid Build Coastguard Worker             let value = rdu32(input)?;
361*bb4ee6a4SAndroid Build Coastguard Worker             if value != FDT_NOP {
362*bb4ee6a4SAndroid Build Coastguard Worker                 return Ok(value);
363*bb4ee6a4SAndroid Build Coastguard Worker             }
364*bb4ee6a4SAndroid Build Coastguard Worker         }
365*bb4ee6a4SAndroid Build Coastguard Worker     }
366*bb4ee6a4SAndroid Build Coastguard Worker 
367*bb4ee6a4SAndroid Build Coastguard Worker     // Parse binary content of an FDT node.
parse_node(input: &mut Blob, strings: &FdtStrings) -> Result<Self>368*bb4ee6a4SAndroid Build Coastguard Worker     fn parse_node(input: &mut Blob, strings: &FdtStrings) -> Result<Self> {
369*bb4ee6a4SAndroid Build Coastguard Worker         // Node name
370*bb4ee6a4SAndroid Build Coastguard Worker         let name = c_str_to_string(input)
371*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or_else(|| Error::FdtParseError("could not parse node name".into()))?;
372*bb4ee6a4SAndroid Build Coastguard Worker         let name_nbytes = name.len() + 1;
373*bb4ee6a4SAndroid Build Coastguard Worker         consume(input, name_nbytes + align_pad_len(name_nbytes, SIZE_U32))?;
374*bb4ee6a4SAndroid Build Coastguard Worker 
375*bb4ee6a4SAndroid Build Coastguard Worker         // Node properties and subnodes
376*bb4ee6a4SAndroid Build Coastguard Worker         let mut props = IndexMap::new();
377*bb4ee6a4SAndroid Build Coastguard Worker         let mut subnodes = IndexMap::new();
378*bb4ee6a4SAndroid Build Coastguard Worker         let mut encountered_subnode = false; // Properties must appear before subnodes
379*bb4ee6a4SAndroid Build Coastguard Worker 
380*bb4ee6a4SAndroid Build Coastguard Worker         loop {
381*bb4ee6a4SAndroid Build Coastguard Worker             match Self::read_token(input)? {
382*bb4ee6a4SAndroid Build Coastguard Worker                 FDT_BEGIN_NODE => {
383*bb4ee6a4SAndroid Build Coastguard Worker                     encountered_subnode = true;
384*bb4ee6a4SAndroid Build Coastguard Worker                     let subnode = Self::parse_node(input, strings)?;
385*bb4ee6a4SAndroid Build Coastguard Worker                     match subnodes.entry(subnode.name.clone()) {
386*bb4ee6a4SAndroid Build Coastguard Worker                         Entry::Vacant(e) => e.insert(subnode),
387*bb4ee6a4SAndroid Build Coastguard Worker                         Entry::Occupied(_) => return Err(Error::DuplicateNode(subnode.name)),
388*bb4ee6a4SAndroid Build Coastguard Worker                     };
389*bb4ee6a4SAndroid Build Coastguard Worker                 }
390*bb4ee6a4SAndroid Build Coastguard Worker                 FDT_END_NODE => break,
391*bb4ee6a4SAndroid Build Coastguard Worker                 FDT_PROP => {
392*bb4ee6a4SAndroid Build Coastguard Worker                     if encountered_subnode {
393*bb4ee6a4SAndroid Build Coastguard Worker                         return Err(Error::FdtParseError(
394*bb4ee6a4SAndroid Build Coastguard Worker                             "unexpected prop token after subnode".into(),
395*bb4ee6a4SAndroid Build Coastguard Worker                         ));
396*bb4ee6a4SAndroid Build Coastguard Worker                     }
397*bb4ee6a4SAndroid Build Coastguard Worker                     let prop_len = rdu32(input)? as usize;
398*bb4ee6a4SAndroid Build Coastguard Worker                     let prop_name_offset = rdu32(input)?;
399*bb4ee6a4SAndroid Build Coastguard Worker                     let prop_blob = consume(input, prop_len + align_pad_len(prop_len, SIZE_U32))?;
400*bb4ee6a4SAndroid Build Coastguard Worker                     let prop_name = strings.at_offset(prop_name_offset).ok_or_else(|| {
401*bb4ee6a4SAndroid Build Coastguard Worker                         Error::FdtParseError(format!(
402*bb4ee6a4SAndroid Build Coastguard Worker                             "invalid property name at {prop_name_offset:#x}",
403*bb4ee6a4SAndroid Build Coastguard Worker                         ))
404*bb4ee6a4SAndroid Build Coastguard Worker                     })?;
405*bb4ee6a4SAndroid Build Coastguard Worker                     // Keep the original (non-aligned) size as property value
406*bb4ee6a4SAndroid Build Coastguard Worker                     props.insert(prop_name, prop_blob[..prop_len].to_vec());
407*bb4ee6a4SAndroid Build Coastguard Worker                 }
408*bb4ee6a4SAndroid Build Coastguard Worker                 FDT_NOP => continue,
409*bb4ee6a4SAndroid Build Coastguard Worker                 FDT_END => return Err(Error::FdtParseError("unexpected END token".into())),
410*bb4ee6a4SAndroid Build Coastguard Worker                 t => return Err(Error::FdtParseError(format!("invalid FDT token {t}"))),
411*bb4ee6a4SAndroid Build Coastguard Worker             }
412*bb4ee6a4SAndroid Build Coastguard Worker         }
413*bb4ee6a4SAndroid Build Coastguard Worker         FdtNode::new(name, props, subnodes)
414*bb4ee6a4SAndroid Build Coastguard Worker     }
415*bb4ee6a4SAndroid Build Coastguard Worker 
416*bb4ee6a4SAndroid Build Coastguard Worker     // Load an `FdtNode` instance from a slice of bytes.
from_blob(mut input: Blob, strings: &FdtStrings) -> Result<Self>417*bb4ee6a4SAndroid Build Coastguard Worker     fn from_blob(mut input: Blob, strings: &FdtStrings) -> Result<Self> {
418*bb4ee6a4SAndroid Build Coastguard Worker         let input = &mut input;
419*bb4ee6a4SAndroid Build Coastguard Worker         if Self::read_token(input)? != FDT_BEGIN_NODE {
420*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::FdtParseError("expected begin node token".into()));
421*bb4ee6a4SAndroid Build Coastguard Worker         }
422*bb4ee6a4SAndroid Build Coastguard Worker         let root = Self::parse_node(input, strings)?;
423*bb4ee6a4SAndroid Build Coastguard Worker         if Self::read_token(input)? != FDT_END {
424*bb4ee6a4SAndroid Build Coastguard Worker             Err(Error::FdtParseError("expected end node token".into()))
425*bb4ee6a4SAndroid Build Coastguard Worker         } else {
426*bb4ee6a4SAndroid Build Coastguard Worker             Ok(root)
427*bb4ee6a4SAndroid Build Coastguard Worker         }
428*bb4ee6a4SAndroid Build Coastguard Worker     }
429*bb4ee6a4SAndroid Build Coastguard Worker 
430*bb4ee6a4SAndroid Build Coastguard Worker     // Write binary contents of a node to a vector of bytes.
write_blob(&self, writer: &mut impl io::Write, strings: &mut FdtStrings) -> Result<()>431*bb4ee6a4SAndroid Build Coastguard Worker     fn write_blob(&self, writer: &mut impl io::Write, strings: &mut FdtStrings) -> Result<()> {
432*bb4ee6a4SAndroid Build Coastguard Worker         // Token
433*bb4ee6a4SAndroid Build Coastguard Worker         writer.write_all(&FDT_BEGIN_NODE.to_be_bytes())?;
434*bb4ee6a4SAndroid Build Coastguard Worker         // Name
435*bb4ee6a4SAndroid Build Coastguard Worker         writer.write_all(self.name.as_bytes())?;
436*bb4ee6a4SAndroid Build Coastguard Worker         writer.write_all(&[0])?; // Node name terminator
437*bb4ee6a4SAndroid Build Coastguard Worker         let pad_len = align_pad_len(self.name.len() + 1, SIZE_U32);
438*bb4ee6a4SAndroid Build Coastguard Worker         writer.write_all(&vec![0; pad_len])?;
439*bb4ee6a4SAndroid Build Coastguard Worker         // Properties
440*bb4ee6a4SAndroid Build Coastguard Worker         for (propname, propblob) in self.props.iter() {
441*bb4ee6a4SAndroid Build Coastguard Worker             // Prop token
442*bb4ee6a4SAndroid Build Coastguard Worker             writer.write_all(&FDT_PROP.to_be_bytes())?;
443*bb4ee6a4SAndroid Build Coastguard Worker             // Prop size
444*bb4ee6a4SAndroid Build Coastguard Worker             writer.write_all(&(propblob.len() as u32).to_be_bytes())?;
445*bb4ee6a4SAndroid Build Coastguard Worker             // Prop name offset
446*bb4ee6a4SAndroid Build Coastguard Worker             writer.write_all(&strings.intern_string(propname).to_be_bytes())?;
447*bb4ee6a4SAndroid Build Coastguard Worker             // Prop value
448*bb4ee6a4SAndroid Build Coastguard Worker             writer.write_all(propblob)?;
449*bb4ee6a4SAndroid Build Coastguard Worker             let pad_len = align_pad_len(propblob.len(), SIZE_U32);
450*bb4ee6a4SAndroid Build Coastguard Worker             writer.write_all(&vec![0; pad_len])?;
451*bb4ee6a4SAndroid Build Coastguard Worker         }
452*bb4ee6a4SAndroid Build Coastguard Worker         // Subnodes
453*bb4ee6a4SAndroid Build Coastguard Worker         for subnode in self.subnodes.values() {
454*bb4ee6a4SAndroid Build Coastguard Worker             subnode.write_blob(writer, strings)?;
455*bb4ee6a4SAndroid Build Coastguard Worker         }
456*bb4ee6a4SAndroid Build Coastguard Worker         // Token
457*bb4ee6a4SAndroid Build Coastguard Worker         writer.write_all(&FDT_END_NODE.to_be_bytes())?;
458*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
459*bb4ee6a4SAndroid Build Coastguard Worker     }
460*bb4ee6a4SAndroid Build Coastguard Worker 
461*bb4ee6a4SAndroid Build Coastguard Worker     // Iterate over property names defined for this node.
prop_names(&self) -> impl std::iter::Iterator<Item = &str>462*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) fn prop_names(&self) -> impl std::iter::Iterator<Item = &str> {
463*bb4ee6a4SAndroid Build Coastguard Worker         self.props.keys().map(|s| s.as_str())
464*bb4ee6a4SAndroid Build Coastguard Worker     }
465*bb4ee6a4SAndroid Build Coastguard Worker 
466*bb4ee6a4SAndroid Build Coastguard Worker     // Return true if a property with the given name exists.
has_prop(&self, name: &str) -> bool467*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) fn has_prop(&self, name: &str) -> bool {
468*bb4ee6a4SAndroid Build Coastguard Worker         self.props.contains_key(name)
469*bb4ee6a4SAndroid Build Coastguard Worker     }
470*bb4ee6a4SAndroid Build Coastguard Worker 
471*bb4ee6a4SAndroid Build Coastguard Worker     /// Read property value if it exists.
472*bb4ee6a4SAndroid Build Coastguard Worker     ///
473*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
474*bb4ee6a4SAndroid Build Coastguard Worker     ///
475*bb4ee6a4SAndroid Build Coastguard Worker     /// `name` - name of the property.
get_prop<T>(&self, name: &str) -> Option<T> where T: FromFdtPropval,476*bb4ee6a4SAndroid Build Coastguard Worker     pub fn get_prop<T>(&self, name: &str) -> Option<T>
477*bb4ee6a4SAndroid Build Coastguard Worker     where
478*bb4ee6a4SAndroid Build Coastguard Worker         T: FromFdtPropval,
479*bb4ee6a4SAndroid Build Coastguard Worker     {
480*bb4ee6a4SAndroid Build Coastguard Worker         T::from_propval(self.props.get(name)?.as_slice())
481*bb4ee6a4SAndroid Build Coastguard Worker     }
482*bb4ee6a4SAndroid Build Coastguard Worker 
483*bb4ee6a4SAndroid Build Coastguard Worker     // Read a phandle value (a `u32`) at some offset within a property value.
484*bb4ee6a4SAndroid Build Coastguard Worker     // Returns `None` if a phandle value cannot be constructed.
phandle_at_offset(&self, name: &str, offset: usize) -> Option<u32>485*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) fn phandle_at_offset(&self, name: &str, offset: usize) -> Option<u32> {
486*bb4ee6a4SAndroid Build Coastguard Worker         let data = self.props.get(name)?;
487*bb4ee6a4SAndroid Build Coastguard Worker         data.get(offset..offset + SIZE_U32)
488*bb4ee6a4SAndroid Build Coastguard Worker             .and_then(u32::from_propval)
489*bb4ee6a4SAndroid Build Coastguard Worker     }
490*bb4ee6a4SAndroid Build Coastguard Worker 
491*bb4ee6a4SAndroid Build Coastguard Worker     // Overwrite a phandle value (a `u32`) at some offset within a property value.
492*bb4ee6a4SAndroid Build Coastguard Worker     // Returns `Err` if the property doesn't exist, or if the property value is too short to
493*bb4ee6a4SAndroid Build Coastguard Worker     // construct a `u32` at given offset. Does not change property value size.
update_phandle_at_offset( &mut self, name: &str, offset: usize, phandle: u32, ) -> Result<()>494*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) fn update_phandle_at_offset(
495*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
496*bb4ee6a4SAndroid Build Coastguard Worker         name: &str,
497*bb4ee6a4SAndroid Build Coastguard Worker         offset: usize,
498*bb4ee6a4SAndroid Build Coastguard Worker         phandle: u32,
499*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
500*bb4ee6a4SAndroid Build Coastguard Worker         let propval = self
501*bb4ee6a4SAndroid Build Coastguard Worker             .props
502*bb4ee6a4SAndroid Build Coastguard Worker             .get_mut(name)
503*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or_else(|| Error::InvalidName(format!("property {name} does not exist")))?;
504*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(bytes) = propval.get_mut(offset..offset + SIZE_U32) {
505*bb4ee6a4SAndroid Build Coastguard Worker             bytes.copy_from_slice(phandle.to_propval()?.as_slice());
506*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
507*bb4ee6a4SAndroid Build Coastguard Worker         } else {
508*bb4ee6a4SAndroid Build Coastguard Worker             Err(Error::PropertyValueInvalid)
509*bb4ee6a4SAndroid Build Coastguard Worker         }
510*bb4ee6a4SAndroid Build Coastguard Worker     }
511*bb4ee6a4SAndroid Build Coastguard Worker 
512*bb4ee6a4SAndroid Build Coastguard Worker     /// Write a property.
513*bb4ee6a4SAndroid Build Coastguard Worker     ///
514*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
515*bb4ee6a4SAndroid Build Coastguard Worker     ///
516*bb4ee6a4SAndroid Build Coastguard Worker     /// `name` - name of the property; must be a valid property name according to DT spec.
517*bb4ee6a4SAndroid Build Coastguard Worker     /// `val` - value of the property (raw byte array).
set_prop<T>(&mut self, name: &str, value: T) -> Result<()> where T: ToFdtPropval,518*bb4ee6a4SAndroid Build Coastguard Worker     pub fn set_prop<T>(&mut self, name: &str, value: T) -> Result<()>
519*bb4ee6a4SAndroid Build Coastguard Worker     where
520*bb4ee6a4SAndroid Build Coastguard Worker         T: ToFdtPropval,
521*bb4ee6a4SAndroid Build Coastguard Worker     {
522*bb4ee6a4SAndroid Build Coastguard Worker         if !is_valid_prop_name(name) {
523*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::InvalidName(name.into()));
524*bb4ee6a4SAndroid Build Coastguard Worker         }
525*bb4ee6a4SAndroid Build Coastguard Worker         let bytes = value.to_propval()?;
526*bb4ee6a4SAndroid Build Coastguard Worker         // FDT property byte size must fit into a u32.
527*bb4ee6a4SAndroid Build Coastguard Worker         u32::try_from(bytes.len()).map_err(|_| Error::PropertyValueTooLarge)?;
528*bb4ee6a4SAndroid Build Coastguard Worker         self.props.insert(name.into(), bytes);
529*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
530*bb4ee6a4SAndroid Build Coastguard Worker     }
531*bb4ee6a4SAndroid Build Coastguard Worker 
532*bb4ee6a4SAndroid Build Coastguard Worker     /// Return a reference to an existing subnode with given name, or `None` if it doesn't exist.
533*bb4ee6a4SAndroid Build Coastguard Worker     ///
534*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
535*bb4ee6a4SAndroid Build Coastguard Worker     ///
536*bb4ee6a4SAndroid Build Coastguard Worker     /// `name` - name of the node.
subnode(&self, name: &str) -> Option<&FdtNode>537*bb4ee6a4SAndroid Build Coastguard Worker     pub fn subnode(&self, name: &str) -> Option<&FdtNode> {
538*bb4ee6a4SAndroid Build Coastguard Worker         self.subnodes.get(name)
539*bb4ee6a4SAndroid Build Coastguard Worker     }
540*bb4ee6a4SAndroid Build Coastguard Worker 
541*bb4ee6a4SAndroid Build Coastguard Worker     /// Create a node if it doesn't already exist, and return a mutable reference to it. Return
542*bb4ee6a4SAndroid Build Coastguard Worker     /// an error if the node name is not valid.
543*bb4ee6a4SAndroid Build Coastguard Worker     ///
544*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
545*bb4ee6a4SAndroid Build Coastguard Worker     ///
546*bb4ee6a4SAndroid Build Coastguard Worker     /// `name` - name of the node; must be a valid node name according to DT specification.
subnode_mut(&mut self, name: &str) -> Result<&mut FdtNode>547*bb4ee6a4SAndroid Build Coastguard Worker     pub fn subnode_mut(&mut self, name: &str) -> Result<&mut FdtNode> {
548*bb4ee6a4SAndroid Build Coastguard Worker         if !self.subnodes.contains_key(name) {
549*bb4ee6a4SAndroid Build Coastguard Worker             self.subnodes.insert(name.into(), FdtNode::empty(name)?);
550*bb4ee6a4SAndroid Build Coastguard Worker         }
551*bb4ee6a4SAndroid Build Coastguard Worker         Ok(self.subnodes.get_mut(name).unwrap())
552*bb4ee6a4SAndroid Build Coastguard Worker     }
553*bb4ee6a4SAndroid Build Coastguard Worker 
554*bb4ee6a4SAndroid Build Coastguard Worker     // Iterate subnode references.
iter_subnodes(&self) -> impl std::iter::Iterator<Item = &FdtNode>555*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) fn iter_subnodes(&self) -> impl std::iter::Iterator<Item = &FdtNode> {
556*bb4ee6a4SAndroid Build Coastguard Worker         self.subnodes.values()
557*bb4ee6a4SAndroid Build Coastguard Worker     }
558*bb4ee6a4SAndroid Build Coastguard Worker 
559*bb4ee6a4SAndroid Build Coastguard Worker     // Iterate mutable subnode references.
iter_subnodes_mut(&mut self) -> impl std::iter::Iterator<Item = &mut FdtNode>560*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) fn iter_subnodes_mut(&mut self) -> impl std::iter::Iterator<Item = &mut FdtNode> {
561*bb4ee6a4SAndroid Build Coastguard Worker         self.subnodes.values_mut()
562*bb4ee6a4SAndroid Build Coastguard Worker     }
563*bb4ee6a4SAndroid Build Coastguard Worker }
564*bb4ee6a4SAndroid Build Coastguard Worker 
565*bb4ee6a4SAndroid Build Coastguard Worker /// Interface for creating and manipulating a Flattened Devicetree (FDT) and emitting
566*bb4ee6a4SAndroid Build Coastguard Worker /// a Devicetree Blob (DTB).
567*bb4ee6a4SAndroid Build Coastguard Worker ///
568*bb4ee6a4SAndroid Build Coastguard Worker /// # Example
569*bb4ee6a4SAndroid Build Coastguard Worker ///
570*bb4ee6a4SAndroid Build Coastguard Worker /// ```rust
571*bb4ee6a4SAndroid Build Coastguard Worker /// use cros_fdt::Fdt;
572*bb4ee6a4SAndroid Build Coastguard Worker ///
573*bb4ee6a4SAndroid Build Coastguard Worker /// # fn main() -> cros_fdt::Result<()> {
574*bb4ee6a4SAndroid Build Coastguard Worker /// let mut fdt = Fdt::new(&[]);
575*bb4ee6a4SAndroid Build Coastguard Worker /// let root_node = fdt.root_mut();
576*bb4ee6a4SAndroid Build Coastguard Worker /// root_node.set_prop("compatible", "linux,dummy-virt")?;
577*bb4ee6a4SAndroid Build Coastguard Worker /// root_node.set_prop("#address-cells", 0x2u32)?;
578*bb4ee6a4SAndroid Build Coastguard Worker /// root_node.set_prop("#size-cells", 0x2u32)?;
579*bb4ee6a4SAndroid Build Coastguard Worker /// let chosen_node = root_node.subnode_mut("chosen")?;
580*bb4ee6a4SAndroid Build Coastguard Worker /// chosen_node.set_prop("linux,pci-probe-only", 1u32)?;
581*bb4ee6a4SAndroid Build Coastguard Worker /// chosen_node.set_prop("bootargs", "panic=-1 console=hvc0 root=/dev/vda")?;
582*bb4ee6a4SAndroid Build Coastguard Worker /// let dtb = fdt.finish().unwrap();
583*bb4ee6a4SAndroid Build Coastguard Worker /// # Ok(())
584*bb4ee6a4SAndroid Build Coastguard Worker /// # }
585*bb4ee6a4SAndroid Build Coastguard Worker /// ```
586*bb4ee6a4SAndroid Build Coastguard Worker pub struct Fdt {
587*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) reserved_memory: Vec<FdtReserveEntry>,
588*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) root: FdtNode,
589*bb4ee6a4SAndroid Build Coastguard Worker     strings: FdtStrings,
590*bb4ee6a4SAndroid Build Coastguard Worker     boot_cpuid_phys: u32,
591*bb4ee6a4SAndroid Build Coastguard Worker }
592*bb4ee6a4SAndroid Build Coastguard Worker 
593*bb4ee6a4SAndroid Build Coastguard Worker /// Reserved physical memory region.
594*bb4ee6a4SAndroid Build Coastguard Worker ///
595*bb4ee6a4SAndroid Build Coastguard Worker /// This represents an area of physical memory reserved by the firmware and unusable by the OS.
596*bb4ee6a4SAndroid Build Coastguard Worker /// For example, this could be used to preserve bootloader code or data used at runtime.
597*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, PartialEq, Debug)]
598*bb4ee6a4SAndroid Build Coastguard Worker pub struct FdtReserveEntry {
599*bb4ee6a4SAndroid Build Coastguard Worker     /// Physical address of the beginning of the reserved region.
600*bb4ee6a4SAndroid Build Coastguard Worker     pub address: u64,
601*bb4ee6a4SAndroid Build Coastguard Worker     /// Size of the reserved region in bytes.
602*bb4ee6a4SAndroid Build Coastguard Worker     pub size: u64,
603*bb4ee6a4SAndroid Build Coastguard Worker }
604*bb4ee6a4SAndroid Build Coastguard Worker 
605*bb4ee6a4SAndroid Build Coastguard Worker // Last entry in the reserved memory section
606*bb4ee6a4SAndroid Build Coastguard Worker const RESVMEM_TERMINATOR: FdtReserveEntry = FdtReserveEntry::new(0, 0);
607*bb4ee6a4SAndroid Build Coastguard Worker 
608*bb4ee6a4SAndroid Build Coastguard Worker impl FdtReserveEntry {
609*bb4ee6a4SAndroid Build Coastguard Worker     /// Create a new FdtReserveEntry
610*bb4ee6a4SAndroid Build Coastguard Worker     ///
611*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
612*bb4ee6a4SAndroid Build Coastguard Worker     ///
613*bb4ee6a4SAndroid Build Coastguard Worker     /// `address` - start of reserved memory region.
614*bb4ee6a4SAndroid Build Coastguard Worker     /// `size` - size of reserved memory region.
new(address: u64, size: u64) -> Self615*bb4ee6a4SAndroid Build Coastguard Worker     pub const fn new(address: u64, size: u64) -> Self {
616*bb4ee6a4SAndroid Build Coastguard Worker         Self { address, size }
617*bb4ee6a4SAndroid Build Coastguard Worker     }
618*bb4ee6a4SAndroid Build Coastguard Worker 
619*bb4ee6a4SAndroid Build Coastguard Worker     // Load a reserved memory entry from a byte slice.
from_blob(input: &mut Blob) -> Result<Self>620*bb4ee6a4SAndroid Build Coastguard Worker     fn from_blob(input: &mut Blob) -> Result<Self> {
621*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Self {
622*bb4ee6a4SAndroid Build Coastguard Worker             address: rdu64(input)?,
623*bb4ee6a4SAndroid Build Coastguard Worker             size: rdu64(input)?,
624*bb4ee6a4SAndroid Build Coastguard Worker         })
625*bb4ee6a4SAndroid Build Coastguard Worker     }
626*bb4ee6a4SAndroid Build Coastguard Worker 
627*bb4ee6a4SAndroid Build Coastguard Worker     // Dump the entry as a vector of bytes.
write_blob(&self, mut writer: impl io::Write) -> Result<()>628*bb4ee6a4SAndroid Build Coastguard Worker     fn write_blob(&self, mut writer: impl io::Write) -> Result<()> {
629*bb4ee6a4SAndroid Build Coastguard Worker         writer.write_all(&self.address.to_be_bytes())?;
630*bb4ee6a4SAndroid Build Coastguard Worker         writer.write_all(&self.size.to_be_bytes())?;
631*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
632*bb4ee6a4SAndroid Build Coastguard Worker     }
633*bb4ee6a4SAndroid Build Coastguard Worker }
634*bb4ee6a4SAndroid Build Coastguard Worker 
635*bb4ee6a4SAndroid Build Coastguard Worker impl Fdt {
636*bb4ee6a4SAndroid Build Coastguard Worker     /// Create a new flattened device tree instance with an initialized root node.
637*bb4ee6a4SAndroid Build Coastguard Worker     ///
638*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
639*bb4ee6a4SAndroid Build Coastguard Worker     ///
640*bb4ee6a4SAndroid Build Coastguard Worker     /// `mem_reservations` - reserved physical memory regions to list in the FDT header.
new(mem_reservations: &[FdtReserveEntry]) -> Self641*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(mem_reservations: &[FdtReserveEntry]) -> Self {
642*bb4ee6a4SAndroid Build Coastguard Worker         Self {
643*bb4ee6a4SAndroid Build Coastguard Worker             reserved_memory: mem_reservations.to_vec(),
644*bb4ee6a4SAndroid Build Coastguard Worker             root: FdtNode::empty("").unwrap(),
645*bb4ee6a4SAndroid Build Coastguard Worker             strings: FdtStrings::default(),
646*bb4ee6a4SAndroid Build Coastguard Worker             boot_cpuid_phys: 0u32,
647*bb4ee6a4SAndroid Build Coastguard Worker         }
648*bb4ee6a4SAndroid Build Coastguard Worker     }
649*bb4ee6a4SAndroid Build Coastguard Worker 
650*bb4ee6a4SAndroid Build Coastguard Worker     /// Set the `boot_cpuid_phys` field of the devicetree header.
651*bb4ee6a4SAndroid Build Coastguard Worker     ///
652*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
653*bb4ee6a4SAndroid Build Coastguard Worker     ///
654*bb4ee6a4SAndroid Build Coastguard Worker     /// `boot_cpuid_phys` - CPU ID
set_boot_cpuid_phys(&mut self, boot_cpuid_phys: u32)655*bb4ee6a4SAndroid Build Coastguard Worker     pub fn set_boot_cpuid_phys(&mut self, boot_cpuid_phys: u32) {
656*bb4ee6a4SAndroid Build Coastguard Worker         self.boot_cpuid_phys = boot_cpuid_phys;
657*bb4ee6a4SAndroid Build Coastguard Worker     }
658*bb4ee6a4SAndroid Build Coastguard Worker 
659*bb4ee6a4SAndroid Build Coastguard Worker     // Parse the reserved memory block from a binary blob.
parse_reserved_memory(mut input: Blob) -> Result<Vec<FdtReserveEntry>>660*bb4ee6a4SAndroid Build Coastguard Worker     fn parse_reserved_memory(mut input: Blob) -> Result<Vec<FdtReserveEntry>> {
661*bb4ee6a4SAndroid Build Coastguard Worker         let mut entries = vec![];
662*bb4ee6a4SAndroid Build Coastguard Worker         let input = &mut input;
663*bb4ee6a4SAndroid Build Coastguard Worker         loop {
664*bb4ee6a4SAndroid Build Coastguard Worker             let entry = FdtReserveEntry::from_blob(input)?;
665*bb4ee6a4SAndroid Build Coastguard Worker             if entry == RESVMEM_TERMINATOR {
666*bb4ee6a4SAndroid Build Coastguard Worker                 break;
667*bb4ee6a4SAndroid Build Coastguard Worker             }
668*bb4ee6a4SAndroid Build Coastguard Worker             entries.push(entry);
669*bb4ee6a4SAndroid Build Coastguard Worker         }
670*bb4ee6a4SAndroid Build Coastguard Worker         Ok(entries)
671*bb4ee6a4SAndroid Build Coastguard Worker     }
672*bb4ee6a4SAndroid Build Coastguard Worker 
673*bb4ee6a4SAndroid Build Coastguard Worker     // Write the reserved memory block to a buffer.
write_reserved_memory(&self, mut writer: impl io::Write) -> Result<()>674*bb4ee6a4SAndroid Build Coastguard Worker     fn write_reserved_memory(&self, mut writer: impl io::Write) -> Result<()> {
675*bb4ee6a4SAndroid Build Coastguard Worker         for entry in &self.reserved_memory {
676*bb4ee6a4SAndroid Build Coastguard Worker             entry.write_blob(&mut writer)?;
677*bb4ee6a4SAndroid Build Coastguard Worker         }
678*bb4ee6a4SAndroid Build Coastguard Worker         RESVMEM_TERMINATOR.write_blob(writer)
679*bb4ee6a4SAndroid Build Coastguard Worker     }
680*bb4ee6a4SAndroid Build Coastguard Worker 
681*bb4ee6a4SAndroid Build Coastguard Worker     /// Load a flattened device tree from a byte slice.
682*bb4ee6a4SAndroid Build Coastguard Worker     ///
683*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
684*bb4ee6a4SAndroid Build Coastguard Worker     ///
685*bb4ee6a4SAndroid Build Coastguard Worker     /// `input` - byte slice from which to load the FDT.
from_blob(input: Blob) -> Result<Self>686*bb4ee6a4SAndroid Build Coastguard Worker     pub fn from_blob(input: Blob) -> Result<Self> {
687*bb4ee6a4SAndroid Build Coastguard Worker         let header = input
688*bb4ee6a4SAndroid Build Coastguard Worker             .get(..FdtHeader::SIZE)
689*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or_else(|| Error::FdtParseError("cannot extract header, input too small".into()))?;
690*bb4ee6a4SAndroid Build Coastguard Worker         let header = FdtHeader::from_blob(header)?;
691*bb4ee6a4SAndroid Build Coastguard Worker         if header.total_size as usize != input.len() {
692*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::FdtParseError("input size doesn't match".into()));
693*bb4ee6a4SAndroid Build Coastguard Worker         }
694*bb4ee6a4SAndroid Build Coastguard Worker 
695*bb4ee6a4SAndroid Build Coastguard Worker         let reserved_mem_blob = &input[header.off_mem_rsvmap as usize..];
696*bb4ee6a4SAndroid Build Coastguard Worker         let nodes_blob = &input[header.off_dt_struct as usize
697*bb4ee6a4SAndroid Build Coastguard Worker             ..(header.off_dt_struct + header.size_dt_struct) as usize];
698*bb4ee6a4SAndroid Build Coastguard Worker         let strings_blob = &input[header.off_dt_strings as usize
699*bb4ee6a4SAndroid Build Coastguard Worker             ..(header.off_dt_strings + header.size_dt_strings) as usize];
700*bb4ee6a4SAndroid Build Coastguard Worker 
701*bb4ee6a4SAndroid Build Coastguard Worker         let reserved_memory = Self::parse_reserved_memory(reserved_mem_blob)?;
702*bb4ee6a4SAndroid Build Coastguard Worker         let strings = FdtStrings::from_blob(strings_blob)?;
703*bb4ee6a4SAndroid Build Coastguard Worker         let root = FdtNode::from_blob(nodes_blob, &strings)?;
704*bb4ee6a4SAndroid Build Coastguard Worker 
705*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Self {
706*bb4ee6a4SAndroid Build Coastguard Worker             reserved_memory,
707*bb4ee6a4SAndroid Build Coastguard Worker             root,
708*bb4ee6a4SAndroid Build Coastguard Worker             strings,
709*bb4ee6a4SAndroid Build Coastguard Worker             boot_cpuid_phys: header.boot_cpuid_phys,
710*bb4ee6a4SAndroid Build Coastguard Worker         })
711*bb4ee6a4SAndroid Build Coastguard Worker     }
712*bb4ee6a4SAndroid Build Coastguard Worker 
713*bb4ee6a4SAndroid Build Coastguard Worker     // Write the structure block of the FDT
write_struct(&mut self, mut writer: impl io::Write) -> Result<()>714*bb4ee6a4SAndroid Build Coastguard Worker     fn write_struct(&mut self, mut writer: impl io::Write) -> Result<()> {
715*bb4ee6a4SAndroid Build Coastguard Worker         self.root.write_blob(&mut writer, &mut self.strings)?;
716*bb4ee6a4SAndroid Build Coastguard Worker         writer.write_all(&FDT_END.to_be_bytes())?;
717*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
718*bb4ee6a4SAndroid Build Coastguard Worker     }
719*bb4ee6a4SAndroid Build Coastguard Worker 
720*bb4ee6a4SAndroid Build Coastguard Worker     /// Finish writing the Devicetree Blob (DTB).
721*bb4ee6a4SAndroid Build Coastguard Worker     ///
722*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns the DTB as a vector of bytes.
finish(&mut self) -> Result<Vec<u8>>723*bb4ee6a4SAndroid Build Coastguard Worker     pub fn finish(&mut self) -> Result<Vec<u8>> {
724*bb4ee6a4SAndroid Build Coastguard Worker         let mut result = vec![0u8; FdtHeader::SIZE];
725*bb4ee6a4SAndroid Build Coastguard Worker         align_data(&mut result, SIZE_U64);
726*bb4ee6a4SAndroid Build Coastguard Worker 
727*bb4ee6a4SAndroid Build Coastguard Worker         let off_mem_rsvmap = result.len();
728*bb4ee6a4SAndroid Build Coastguard Worker         self.write_reserved_memory(&mut result)?;
729*bb4ee6a4SAndroid Build Coastguard Worker         align_data(&mut result, SIZE_U64);
730*bb4ee6a4SAndroid Build Coastguard Worker 
731*bb4ee6a4SAndroid Build Coastguard Worker         let off_dt_struct = result.len();
732*bb4ee6a4SAndroid Build Coastguard Worker         self.write_struct(&mut result)?;
733*bb4ee6a4SAndroid Build Coastguard Worker         align_data(&mut result, SIZE_U32);
734*bb4ee6a4SAndroid Build Coastguard Worker 
735*bb4ee6a4SAndroid Build Coastguard Worker         let off_dt_strings = result.len();
736*bb4ee6a4SAndroid Build Coastguard Worker         self.strings.write_blob(&mut result)?;
737*bb4ee6a4SAndroid Build Coastguard Worker         let total_size = u32::try_from(result.len()).map_err(|_| Error::TotalSizeTooLarge)?;
738*bb4ee6a4SAndroid Build Coastguard Worker 
739*bb4ee6a4SAndroid Build Coastguard Worker         let header = FdtHeader::new(
740*bb4ee6a4SAndroid Build Coastguard Worker             total_size,
741*bb4ee6a4SAndroid Build Coastguard Worker             off_dt_struct as u32,
742*bb4ee6a4SAndroid Build Coastguard Worker             off_dt_strings as u32,
743*bb4ee6a4SAndroid Build Coastguard Worker             off_mem_rsvmap as u32,
744*bb4ee6a4SAndroid Build Coastguard Worker             self.boot_cpuid_phys,
745*bb4ee6a4SAndroid Build Coastguard Worker             total_size - off_dt_strings as u32, // strings size
746*bb4ee6a4SAndroid Build Coastguard Worker             off_dt_strings as u32 - off_dt_struct as u32, // struct size
747*bb4ee6a4SAndroid Build Coastguard Worker         );
748*bb4ee6a4SAndroid Build Coastguard Worker         header.write_blob(&mut result[..FdtHeader::SIZE])?;
749*bb4ee6a4SAndroid Build Coastguard Worker         Ok(result)
750*bb4ee6a4SAndroid Build Coastguard Worker     }
751*bb4ee6a4SAndroid Build Coastguard Worker 
752*bb4ee6a4SAndroid Build Coastguard Worker     /// Return a mutable reference to the root node of the FDT.
root_mut(&mut self) -> &mut FdtNode753*bb4ee6a4SAndroid Build Coastguard Worker     pub fn root_mut(&mut self) -> &mut FdtNode {
754*bb4ee6a4SAndroid Build Coastguard Worker         &mut self.root
755*bb4ee6a4SAndroid Build Coastguard Worker     }
756*bb4ee6a4SAndroid Build Coastguard Worker 
757*bb4ee6a4SAndroid Build Coastguard Worker     /// Return a reference to the node the path points to, or `None` if it doesn't exist.
758*bb4ee6a4SAndroid Build Coastguard Worker     ///
759*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
760*bb4ee6a4SAndroid Build Coastguard Worker     ///
761*bb4ee6a4SAndroid Build Coastguard Worker     /// `path` - device tree path of the target node.
get_node<T: TryInto<Path>>(&self, path: T) -> Option<&FdtNode>762*bb4ee6a4SAndroid Build Coastguard Worker     pub fn get_node<T: TryInto<Path>>(&self, path: T) -> Option<&FdtNode> {
763*bb4ee6a4SAndroid Build Coastguard Worker         let mut result_node = &self.root;
764*bb4ee6a4SAndroid Build Coastguard Worker         let path: Path = path.try_into().ok()?;
765*bb4ee6a4SAndroid Build Coastguard Worker         for node_name in path.iter() {
766*bb4ee6a4SAndroid Build Coastguard Worker             result_node = result_node.subnodes.get(node_name)?;
767*bb4ee6a4SAndroid Build Coastguard Worker         }
768*bb4ee6a4SAndroid Build Coastguard Worker         Some(result_node)
769*bb4ee6a4SAndroid Build Coastguard Worker     }
770*bb4ee6a4SAndroid Build Coastguard Worker 
771*bb4ee6a4SAndroid Build Coastguard Worker     /// Return a mutable reference to the node the path points to, or `None` if it
772*bb4ee6a4SAndroid Build Coastguard Worker     /// doesn't exist.
773*bb4ee6a4SAndroid Build Coastguard Worker     ///
774*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
775*bb4ee6a4SAndroid Build Coastguard Worker     ///
776*bb4ee6a4SAndroid Build Coastguard Worker     /// `path` - device tree path of the target node.
get_node_mut<T: TryInto<Path>>(&mut self, path: T) -> Option<&mut FdtNode>777*bb4ee6a4SAndroid Build Coastguard Worker     pub fn get_node_mut<T: TryInto<Path>>(&mut self, path: T) -> Option<&mut FdtNode> {
778*bb4ee6a4SAndroid Build Coastguard Worker         let mut result_node = &mut self.root;
779*bb4ee6a4SAndroid Build Coastguard Worker         let path: Path = path.try_into().ok()?;
780*bb4ee6a4SAndroid Build Coastguard Worker         for node_name in path.iter() {
781*bb4ee6a4SAndroid Build Coastguard Worker             result_node = result_node.subnodes.get_mut(node_name)?;
782*bb4ee6a4SAndroid Build Coastguard Worker         }
783*bb4ee6a4SAndroid Build Coastguard Worker         Some(result_node)
784*bb4ee6a4SAndroid Build Coastguard Worker     }
785*bb4ee6a4SAndroid Build Coastguard Worker 
786*bb4ee6a4SAndroid Build Coastguard Worker     /// Find a device tree path to the symbol exported by the FDT. The symbol must be a node label.
787*bb4ee6a4SAndroid Build Coastguard Worker     ///
788*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
789*bb4ee6a4SAndroid Build Coastguard Worker     ///
790*bb4ee6a4SAndroid Build Coastguard Worker     /// `symbol` - symbol to search for.
symbol_to_path(&self, symbol: &str) -> Result<Path>791*bb4ee6a4SAndroid Build Coastguard Worker     pub fn symbol_to_path(&self, symbol: &str) -> Result<Path> {
792*bb4ee6a4SAndroid Build Coastguard Worker         const SYMBOLS_NODE: &str = "__symbols__";
793*bb4ee6a4SAndroid Build Coastguard Worker         let Some(symbols_node) = self.root.subnode(SYMBOLS_NODE) else {
794*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::InvalidPath("no symbols in fdt".into()));
795*bb4ee6a4SAndroid Build Coastguard Worker         };
796*bb4ee6a4SAndroid Build Coastguard Worker         symbols_node
797*bb4ee6a4SAndroid Build Coastguard Worker             .get_prop::<String>(symbol)
798*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or_else(|| Error::InvalidName(format!("filter symbol {symbol} does not exist")))?
799*bb4ee6a4SAndroid Build Coastguard Worker             .parse()
800*bb4ee6a4SAndroid Build Coastguard Worker     }
801*bb4ee6a4SAndroid Build Coastguard Worker }
802*bb4ee6a4SAndroid Build Coastguard Worker 
803*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
804*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
805*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
806*bb4ee6a4SAndroid Build Coastguard Worker 
807*bb4ee6a4SAndroid Build Coastguard Worker     const FDT_BLOB_HEADER_ONLY: [u8; 0x48] = [
808*bb4ee6a4SAndroid Build Coastguard Worker         0xd0, 0x0d, 0xfe, 0xed, // 0000: magic (0xd00dfeed)
809*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x48, // 0004: totalsize (0x48)
810*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x38, // 0008: off_dt_struct (0x38)
811*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x48, // 000C: off_dt_strings (0x48)
812*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x28, // 0010: off_mem_rsvmap (0x28)
813*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x11, // 0014: version (0x11 = 17)
814*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x10, // 0018: last_comp_version (0x10 = 16)
815*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // 001C: boot_cpuid_phys (0)
816*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // 0020: size_dt_strings (0)
817*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x10, // 0024: size_dt_struct (0x10)
818*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // 0028: rsvmap terminator (address = 0 high)
819*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // 002C: rsvmap terminator (address = 0 low)
820*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // 0030: rsvmap terminator (size = 0 high)
821*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // 0034: rsvmap terminator (size = 0 low)
822*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x01, // 0038: FDT_BEGIN_NODE
823*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // 003C: node name ("") + padding
824*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x02, // 0040: FDT_END_NODE
825*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x09, // 0044: FDT_END
826*bb4ee6a4SAndroid Build Coastguard Worker     ];
827*bb4ee6a4SAndroid Build Coastguard Worker 
828*bb4ee6a4SAndroid Build Coastguard Worker     const FDT_BLOB_RSVMAP: [u8; 0x68] = [
829*bb4ee6a4SAndroid Build Coastguard Worker         0xd0, 0x0d, 0xfe, 0xed, // 0000: magic (0xd00dfeed)
830*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x68, // 0004: totalsize (0x68)
831*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x58, // 0008: off_dt_struct (0x58)
832*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x68, // 000C: off_dt_strings (0x68)
833*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x28, // 0010: off_mem_rsvmap (0x28)
834*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x11, // 0014: version (0x11 = 17)
835*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x10, // 0018: last_comp_version (0x10 = 16)
836*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // 001C: boot_cpuid_phys (0)
837*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // 0020: size_dt_strings (0)
838*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x10, // 0024: size_dt_struct (0x10)
839*bb4ee6a4SAndroid Build Coastguard Worker         0x12, 0x34, 0x56, 0x78, // 0028: rsvmap entry 0 address high
840*bb4ee6a4SAndroid Build Coastguard Worker         0xAA, 0xBB, 0xCC, 0xDD, // 002C: rsvmap entry 0 address low
841*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // 0030: rsvmap entry 0 size high
842*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x12, 0x34, // 0034: rsvmap entry 0 size low
843*bb4ee6a4SAndroid Build Coastguard Worker         0x10, 0x20, 0x30, 0x40, // 0038: rsvmap entry 1 address high
844*bb4ee6a4SAndroid Build Coastguard Worker         0x50, 0x60, 0x70, 0x80, // 003C: rsvmap entry 1 address low
845*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // 0040: rsvmap entry 1 size high
846*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x56, 0x78, // 0044: rsvmap entry 1 size low
847*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // 0048: rsvmap terminator (address = 0 high)
848*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // 004C: rsvmap terminator (address = 0 low)
849*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // 0050: rsvmap terminator (size = 0 high)
850*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // 0054: rsvmap terminator (size = 0 low)
851*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x01, // 0058: FDT_BEGIN_NODE
852*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // 005C: node name ("") + padding
853*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x02, // 0060: FDT_END_NODE
854*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x09, // 0064: FDT_END
855*bb4ee6a4SAndroid Build Coastguard Worker     ];
856*bb4ee6a4SAndroid Build Coastguard Worker 
857*bb4ee6a4SAndroid Build Coastguard Worker     const FDT_BLOB_STRINGS: [u8; 0x26] = [
858*bb4ee6a4SAndroid Build Coastguard Worker         b'n', b'u', b'l', b'l', 0x00, b'u', b'3', b'2', 0x00, b'u', b'6', b'4', 0x00, b's', b't',
859*bb4ee6a4SAndroid Build Coastguard Worker         b'r', 0x00, b's', b't', b'r', b'l', b's', b't', 0x00, b'a', b'r', b'r', b'u', b'3', b'2',
860*bb4ee6a4SAndroid Build Coastguard Worker         0x00, b'a', b'r', b'r', b'u', b'6', b'4', 0x00,
861*bb4ee6a4SAndroid Build Coastguard Worker     ];
862*bb4ee6a4SAndroid Build Coastguard Worker 
863*bb4ee6a4SAndroid Build Coastguard Worker     const EXPECTED_STRINGS: [&str; 7] = ["null", "u32", "u64", "str", "strlst", "arru32", "arru64"];
864*bb4ee6a4SAndroid Build Coastguard Worker 
865*bb4ee6a4SAndroid Build Coastguard Worker     const FDT_BLOB_NODES_ROOT_ONLY: [u8; 0x90] = [
866*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x01, // FDT_BEGIN_NODE
867*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // node name ("") + padding
868*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x03, // FDT_PROP (null)
869*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // prop len (0)
870*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // prop nameoff (0)
871*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x03, // FDT_PROP (u32)
872*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x04, // prop len (4)
873*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x05, // prop nameoff (0x05)
874*bb4ee6a4SAndroid Build Coastguard Worker         0x12, 0x34, 0x56, 0x78, // prop u32 value (0x12345678)
875*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x03, // FDT_PROP (u64)
876*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x08, // prop len (8)
877*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x09, // prop nameoff (0x09)
878*bb4ee6a4SAndroid Build Coastguard Worker         0x12, 0x34, 0x56, 0x78, // prop u64 value high (0x12345678)
879*bb4ee6a4SAndroid Build Coastguard Worker         0x87, 0x65, 0x43, 0x21, // prop u64 value low (0x87654321)
880*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x03, // FDT_PROP (string)
881*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x06, // prop len (6)
882*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x0D, // prop nameoff (0x0D)
883*bb4ee6a4SAndroid Build Coastguard Worker         b'h', b'e', b'l', b'l', // prop str value ("hello") + padding
884*bb4ee6a4SAndroid Build Coastguard Worker         b'o', 0x00, 0x00, 0x00, // "o\0" + padding
885*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x03, // FDT_PROP (string list)
886*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x07, // prop len (7)
887*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x11, // prop nameoff (0x11)
888*bb4ee6a4SAndroid Build Coastguard Worker         b'h', b'i', 0x00, b'b', // prop value ("hi", "bye")
889*bb4ee6a4SAndroid Build Coastguard Worker         b'y', b'e', 0x00, 0x00, // "ye\0" + padding
890*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x03, // FDT_PROP (u32 array)
891*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x08, // prop len (8)
892*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x18, // prop nameoff (0x18)
893*bb4ee6a4SAndroid Build Coastguard Worker         0x12, 0x34, 0x56, 0x78, // prop value 0
894*bb4ee6a4SAndroid Build Coastguard Worker         0xAA, 0xBB, 0xCC, 0xDD, // prop value 1
895*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x03, // FDT_PROP (u64 array)
896*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x08, // prop len (8)
897*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x1f, // prop nameoff (0x1F)
898*bb4ee6a4SAndroid Build Coastguard Worker         0x12, 0x34, 0x56, 0x78, // prop u64 value 0 high
899*bb4ee6a4SAndroid Build Coastguard Worker         0x87, 0x65, 0x43, 0x21, // prop u64 value 0 low
900*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x02, // FDT_END_NODE
901*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x09, // FDT_END
902*bb4ee6a4SAndroid Build Coastguard Worker     ];
903*bb4ee6a4SAndroid Build Coastguard Worker 
904*bb4ee6a4SAndroid Build Coastguard Worker     /*
905*bb4ee6a4SAndroid Build Coastguard Worker     Node structure:
906*bb4ee6a4SAndroid Build Coastguard Worker     /
907*bb4ee6a4SAndroid Build Coastguard Worker     |- nested
908*bb4ee6a4SAndroid Build Coastguard Worker     |- nested2
909*bb4ee6a4SAndroid Build Coastguard Worker        |- nested3
910*bb4ee6a4SAndroid Build Coastguard Worker      */
911*bb4ee6a4SAndroid Build Coastguard Worker     const FDT_BLOB_NESTED_NODES: [u8; 0x80] = [
912*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x01, // FDT_BEGIN_NODE
913*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // node name ("") + padding
914*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x03, // FDT_PROP
915*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x04, // prop len (4)
916*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x00, // prop nameoff (0x00)
917*bb4ee6a4SAndroid Build Coastguard Worker         0x13, 0x57, 0x90, 0x24, // prop u32 value (0x13579024)
918*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x01, // FDT_BEGIN_NODE
919*bb4ee6a4SAndroid Build Coastguard Worker         b'n', b'e', b's', b't', // Node name ("nested")
920*bb4ee6a4SAndroid Build Coastguard Worker         b'e', b'd', 0x00, 0x00, // "ed\0" + pad
921*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x03, // FDT_PROP
922*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x04, // prop len (4)
923*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x05, // prop nameoff (0x05)
924*bb4ee6a4SAndroid Build Coastguard Worker         0x12, 0x12, 0x12, 0x12, // prop u32 value (0x12121212)
925*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x03, // FDT_PROP
926*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x04, // prop len (4)
927*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x18, // prop nameoff (0x18)
928*bb4ee6a4SAndroid Build Coastguard Worker         0x13, 0x57, 0x90, 0x24, // prop u32 value (0x13579024)
929*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x02, // FDT_END_NODE ("nested")
930*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x01, // FDT_BEGIN_NODE
931*bb4ee6a4SAndroid Build Coastguard Worker         b'n', b'e', b's', b't', // Node name ("nested2")
932*bb4ee6a4SAndroid Build Coastguard Worker         b'e', b'd', b'2', 0x00, // "ed2\0"
933*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x03, // FDT_PROP
934*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x04, // prop len (0)
935*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x05, // prop nameoff (0x05)
936*bb4ee6a4SAndroid Build Coastguard Worker         0x12, 0x12, 0x12, 0x12, // prop u32 value (0x12121212)
937*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x01, // FDT_BEGIN_NODE
938*bb4ee6a4SAndroid Build Coastguard Worker         b'n', b'e', b's', b't', // Node name ("nested3")
939*bb4ee6a4SAndroid Build Coastguard Worker         b'e', b'd', b'3', 0x00, // "ed3\0"
940*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x02, // FDT_END_NODE ("nested3")
941*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x02, // FDT_END_NODE ("nested2")
942*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x02, // FDT_END_NODE ("")
943*bb4ee6a4SAndroid Build Coastguard Worker         0x00, 0x00, 0x00, 0x09, // FDT_END
944*bb4ee6a4SAndroid Build Coastguard Worker     ];
945*bb4ee6a4SAndroid Build Coastguard Worker 
946*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_load_header()947*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_load_header() {
948*bb4ee6a4SAndroid Build Coastguard Worker         let blob: &[u8] = &FDT_BLOB_HEADER_ONLY;
949*bb4ee6a4SAndroid Build Coastguard Worker         let header = FdtHeader::from_blob(blob).unwrap();
950*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(header.magic, FdtHeader::MAGIC);
951*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(header.total_size, 0x48);
952*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(header.off_dt_struct, 0x38);
953*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(header.off_dt_strings, 0x48);
954*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(header.off_mem_rsvmap, 0x28);
955*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(header.version, 17);
956*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(header.last_comp_version, 16);
957*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(header.boot_cpuid_phys, 0);
958*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(header.size_dt_strings, 0);
959*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(header.size_dt_struct, 0x10);
960*bb4ee6a4SAndroid Build Coastguard Worker     }
961*bb4ee6a4SAndroid Build Coastguard Worker 
962*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_load_invalid_header()963*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_load_invalid_header() {
964*bb4ee6a4SAndroid Build Coastguard Worker         // HEADER is valid
965*bb4ee6a4SAndroid Build Coastguard Worker         const HEADER: [u8; 40] = [
966*bb4ee6a4SAndroid Build Coastguard Worker             0xd0, 0x0d, 0xfe, 0xed, // 0000: magic (0xd00dfeed)
967*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0xda, // 0004: totalsize (0xda)
968*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x58, // 0008: off_dt_struct (0x58)
969*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0xb2, // 000C: off_dt_strings (0xb2)
970*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x28, // 0010: off_mem_rsvmap (0x28)
971*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x11, // 0014: version (0x11 = 17)
972*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x10, // 0018: last_comp_version (0x10 = 16)
973*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x00, // 001C: boot_cpuid_phys (0)
974*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x28, // 0020: size_dt_strings (0x28)
975*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x5a, // 0024: size_dt_struct (0x5a)
976*bb4ee6a4SAndroid Build Coastguard Worker         ];
977*bb4ee6a4SAndroid Build Coastguard Worker 
978*bb4ee6a4SAndroid Build Coastguard Worker         FdtHeader::from_blob(&HEADER).unwrap();
979*bb4ee6a4SAndroid Build Coastguard Worker 
980*bb4ee6a4SAndroid Build Coastguard Worker         // Header too small
981*bb4ee6a4SAndroid Build Coastguard Worker         assert!(FdtHeader::from_blob(&HEADER[..FdtHeader::SIZE - 4]).is_err());
982*bb4ee6a4SAndroid Build Coastguard Worker         assert!(FdtHeader::from_blob(&[]).is_err());
983*bb4ee6a4SAndroid Build Coastguard Worker 
984*bb4ee6a4SAndroid Build Coastguard Worker         let mut invalid_header = HEADER;
985*bb4ee6a4SAndroid Build Coastguard Worker         invalid_header[0x00] = 0x00; // change magic to (0x000dfeed)
986*bb4ee6a4SAndroid Build Coastguard Worker         FdtHeader::from_blob(&invalid_header).expect_err("invalid magic");
987*bb4ee6a4SAndroid Build Coastguard Worker 
988*bb4ee6a4SAndroid Build Coastguard Worker         let mut invalid_header = HEADER;
989*bb4ee6a4SAndroid Build Coastguard Worker         invalid_header[0x07] = 0x10; // make totalsize too small
990*bb4ee6a4SAndroid Build Coastguard Worker         FdtHeader::from_blob(&invalid_header).expect_err("invalid totalsize");
991*bb4ee6a4SAndroid Build Coastguard Worker 
992*bb4ee6a4SAndroid Build Coastguard Worker         let mut invalid_header = HEADER;
993*bb4ee6a4SAndroid Build Coastguard Worker         invalid_header[0x0b] = 0x60; // increase off_dt_struct
994*bb4ee6a4SAndroid Build Coastguard Worker         FdtHeader::from_blob(&invalid_header).expect_err("dt struct overlaps with strings");
995*bb4ee6a4SAndroid Build Coastguard Worker 
996*bb4ee6a4SAndroid Build Coastguard Worker         let mut invalid_header = HEADER;
997*bb4ee6a4SAndroid Build Coastguard Worker         invalid_header[0x27] = 0x5c; // increase size_dt_struct
998*bb4ee6a4SAndroid Build Coastguard Worker         FdtHeader::from_blob(&invalid_header).expect_err("dt struct overlaps with strings");
999*bb4ee6a4SAndroid Build Coastguard Worker 
1000*bb4ee6a4SAndroid Build Coastguard Worker         let mut invalid_header = HEADER;
1001*bb4ee6a4SAndroid Build Coastguard Worker         invalid_header[0x13] = 0x20; // decrease off_mem_rsvmap
1002*bb4ee6a4SAndroid Build Coastguard Worker         FdtHeader::from_blob(&invalid_header).expect_err("reserved memory overlaps with header");
1003*bb4ee6a4SAndroid Build Coastguard Worker 
1004*bb4ee6a4SAndroid Build Coastguard Worker         let mut invalid_header = HEADER;
1005*bb4ee6a4SAndroid Build Coastguard Worker         invalid_header[0x0f] = 0x50; // decrease off_dt_strings
1006*bb4ee6a4SAndroid Build Coastguard Worker         FdtHeader::from_blob(&invalid_header).expect_err("strings start before struct");
1007*bb4ee6a4SAndroid Build Coastguard Worker 
1008*bb4ee6a4SAndroid Build Coastguard Worker         let mut invalid_header = HEADER;
1009*bb4ee6a4SAndroid Build Coastguard Worker         invalid_header[0x23] = 0x50; // increase size_dt_strings
1010*bb4ee6a4SAndroid Build Coastguard Worker         FdtHeader::from_blob(&invalid_header).expect_err("strings go past totalsize");
1011*bb4ee6a4SAndroid Build Coastguard Worker     }
1012*bb4ee6a4SAndroid Build Coastguard Worker 
1013*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_load_resv_map()1014*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_load_resv_map() {
1015*bb4ee6a4SAndroid Build Coastguard Worker         let blob: &[u8] = &FDT_BLOB_RSVMAP;
1016*bb4ee6a4SAndroid Build Coastguard Worker         let fdt = Fdt::from_blob(blob).unwrap();
1017*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(fdt.reserved_memory.len(), 2);
1018*bb4ee6a4SAndroid Build Coastguard Worker         assert!(
1019*bb4ee6a4SAndroid Build Coastguard Worker             fdt.reserved_memory[0].address == 0x12345678AABBCCDD
1020*bb4ee6a4SAndroid Build Coastguard Worker                 && fdt.reserved_memory[0].size == 0x1234
1021*bb4ee6a4SAndroid Build Coastguard Worker         );
1022*bb4ee6a4SAndroid Build Coastguard Worker         assert!(
1023*bb4ee6a4SAndroid Build Coastguard Worker             fdt.reserved_memory[1].address == 0x1020304050607080
1024*bb4ee6a4SAndroid Build Coastguard Worker                 && fdt.reserved_memory[1].size == 0x5678
1025*bb4ee6a4SAndroid Build Coastguard Worker         );
1026*bb4ee6a4SAndroid Build Coastguard Worker     }
1027*bb4ee6a4SAndroid Build Coastguard Worker 
1028*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_test_node_props()1029*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_test_node_props() {
1030*bb4ee6a4SAndroid Build Coastguard Worker         let mut node = FdtNode::empty("mynode").unwrap();
1031*bb4ee6a4SAndroid Build Coastguard Worker         node.set_prop("myprop", 1u32).unwrap();
1032*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(node.get_prop::<u32>("myprop").unwrap(), 1u32);
1033*bb4ee6a4SAndroid Build Coastguard Worker         node.set_prop("myprop", 0xabcdef9876543210u64).unwrap();
1034*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
1035*bb4ee6a4SAndroid Build Coastguard Worker             node.get_prop::<u64>("myprop").unwrap(),
1036*bb4ee6a4SAndroid Build Coastguard Worker             0xabcdef9876543210u64
1037*bb4ee6a4SAndroid Build Coastguard Worker         );
1038*bb4ee6a4SAndroid Build Coastguard Worker         node.set_prop("myprop", ()).unwrap();
1039*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(node.get_prop::<Vec<u8>>("myprop").unwrap(), []);
1040*bb4ee6a4SAndroid Build Coastguard Worker         node.set_prop("myprop", vec![1u8, 2u8, 3u8]).unwrap();
1041*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
1042*bb4ee6a4SAndroid Build Coastguard Worker             node.get_prop::<Vec<u8>>("myprop").unwrap(),
1043*bb4ee6a4SAndroid Build Coastguard Worker             vec![1u8, 2u8, 3u8]
1044*bb4ee6a4SAndroid Build Coastguard Worker         );
1045*bb4ee6a4SAndroid Build Coastguard Worker         node.set_prop("myprop", vec![1u32, 2u32, 3u32]).unwrap();
1046*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
1047*bb4ee6a4SAndroid Build Coastguard Worker             node.get_prop::<Vec<u32>>("myprop").unwrap(),
1048*bb4ee6a4SAndroid Build Coastguard Worker             vec![1u32, 2u32, 3u32]
1049*bb4ee6a4SAndroid Build Coastguard Worker         );
1050*bb4ee6a4SAndroid Build Coastguard Worker         node.set_prop("myprop", vec![1u64, 2u64, 3u64]).unwrap();
1051*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
1052*bb4ee6a4SAndroid Build Coastguard Worker             node.get_prop::<Vec<u64>>("myprop").unwrap(),
1053*bb4ee6a4SAndroid Build Coastguard Worker             vec![1u64, 2u64, 3u64]
1054*bb4ee6a4SAndroid Build Coastguard Worker         );
1055*bb4ee6a4SAndroid Build Coastguard Worker         node.set_prop("myprop", "myval".to_string()).unwrap();
1056*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
1057*bb4ee6a4SAndroid Build Coastguard Worker             node.get_prop::<String>("myprop").unwrap(),
1058*bb4ee6a4SAndroid Build Coastguard Worker             "myval".to_string()
1059*bb4ee6a4SAndroid Build Coastguard Worker         );
1060*bb4ee6a4SAndroid Build Coastguard Worker         node.set_prop(
1061*bb4ee6a4SAndroid Build Coastguard Worker             "myprop",
1062*bb4ee6a4SAndroid Build Coastguard Worker             vec![
1063*bb4ee6a4SAndroid Build Coastguard Worker                 "myval1".to_string(),
1064*bb4ee6a4SAndroid Build Coastguard Worker                 "myval2".to_string(),
1065*bb4ee6a4SAndroid Build Coastguard Worker                 "myval3".to_string(),
1066*bb4ee6a4SAndroid Build Coastguard Worker             ],
1067*bb4ee6a4SAndroid Build Coastguard Worker         )
1068*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
1069*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
1070*bb4ee6a4SAndroid Build Coastguard Worker             node.get_prop::<Vec<String>>("myprop").unwrap(),
1071*bb4ee6a4SAndroid Build Coastguard Worker             vec![
1072*bb4ee6a4SAndroid Build Coastguard Worker                 "myval1".to_string(),
1073*bb4ee6a4SAndroid Build Coastguard Worker                 "myval2".to_string(),
1074*bb4ee6a4SAndroid Build Coastguard Worker                 "myval3".to_string()
1075*bb4ee6a4SAndroid Build Coastguard Worker             ]
1076*bb4ee6a4SAndroid Build Coastguard Worker         );
1077*bb4ee6a4SAndroid Build Coastguard Worker     }
1078*bb4ee6a4SAndroid Build Coastguard Worker 
1079*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_simple_use()1080*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_simple_use() {
1081*bb4ee6a4SAndroid Build Coastguard Worker         let mut fdt = Fdt::new(&[]);
1082*bb4ee6a4SAndroid Build Coastguard Worker         let root_node = fdt.root_mut();
1083*bb4ee6a4SAndroid Build Coastguard Worker         root_node
1084*bb4ee6a4SAndroid Build Coastguard Worker             .set_prop("compatible", "linux,dummy-virt")
1085*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
1086*bb4ee6a4SAndroid Build Coastguard Worker         root_node.set_prop("#address-cells", 0x2u32).unwrap();
1087*bb4ee6a4SAndroid Build Coastguard Worker         root_node.set_prop("#size-cells", 0x2u32).unwrap();
1088*bb4ee6a4SAndroid Build Coastguard Worker         let chosen_node = root_node.subnode_mut("chosen").unwrap();
1089*bb4ee6a4SAndroid Build Coastguard Worker         chosen_node.set_prop("linux,pci-probe-only", 1u32).unwrap();
1090*bb4ee6a4SAndroid Build Coastguard Worker         chosen_node
1091*bb4ee6a4SAndroid Build Coastguard Worker             .set_prop("bootargs", "panic=-1 console=hvc0 root=/dev/vda")
1092*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
1093*bb4ee6a4SAndroid Build Coastguard Worker         fdt.finish().unwrap();
1094*bb4ee6a4SAndroid Build Coastguard Worker     }
1095*bb4ee6a4SAndroid Build Coastguard Worker 
1096*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_load_strings()1097*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_load_strings() {
1098*bb4ee6a4SAndroid Build Coastguard Worker         let blob = &FDT_BLOB_STRINGS[..];
1099*bb4ee6a4SAndroid Build Coastguard Worker         let strings = FdtStrings::from_blob(blob).unwrap();
1100*bb4ee6a4SAndroid Build Coastguard Worker         let mut offset = 0u32;
1101*bb4ee6a4SAndroid Build Coastguard Worker 
1102*bb4ee6a4SAndroid Build Coastguard Worker         for s in EXPECTED_STRINGS {
1103*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(strings.at_offset(offset).unwrap(), s);
1104*bb4ee6a4SAndroid Build Coastguard Worker             offset += strings.at_offset(offset).unwrap().len() as u32 + 1;
1105*bb4ee6a4SAndroid Build Coastguard Worker         }
1106*bb4ee6a4SAndroid Build Coastguard Worker     }
1107*bb4ee6a4SAndroid Build Coastguard Worker 
1108*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_load_strings_intern()1109*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_load_strings_intern() {
1110*bb4ee6a4SAndroid Build Coastguard Worker         let strings_blob = &FDT_BLOB_STRINGS[..];
1111*bb4ee6a4SAndroid Build Coastguard Worker         let mut strings = FdtStrings::from_blob(strings_blob).unwrap();
1112*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(strings.intern_string("null"), 0);
1113*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(strings.intern_string("strlst"), 17);
1114*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(strings.intern_string("arru64"), 31);
1115*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(strings.intern_string("abc"), 38);
1116*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(strings.intern_string("def"), 42);
1117*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(strings.intern_string("strlst"), 17);
1118*bb4ee6a4SAndroid Build Coastguard Worker     }
1119*bb4ee6a4SAndroid Build Coastguard Worker 
1120*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_load_props()1121*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_load_props() {
1122*bb4ee6a4SAndroid Build Coastguard Worker         const PROP_SIZES: [(&str, usize); 7] = [
1123*bb4ee6a4SAndroid Build Coastguard Worker             ("null", 0),
1124*bb4ee6a4SAndroid Build Coastguard Worker             ("u32", 4),
1125*bb4ee6a4SAndroid Build Coastguard Worker             ("u64", 8),
1126*bb4ee6a4SAndroid Build Coastguard Worker             ("str", 6),
1127*bb4ee6a4SAndroid Build Coastguard Worker             ("strlst", 7),
1128*bb4ee6a4SAndroid Build Coastguard Worker             ("arru32", 8),
1129*bb4ee6a4SAndroid Build Coastguard Worker             ("arru64", 8),
1130*bb4ee6a4SAndroid Build Coastguard Worker         ];
1131*bb4ee6a4SAndroid Build Coastguard Worker 
1132*bb4ee6a4SAndroid Build Coastguard Worker         let blob: &[u8] = &FDT_BLOB_STRINGS[..];
1133*bb4ee6a4SAndroid Build Coastguard Worker         let strings = FdtStrings::from_blob(blob).unwrap();
1134*bb4ee6a4SAndroid Build Coastguard Worker         let blob: &[u8] = &FDT_BLOB_NODES_ROOT_ONLY[..];
1135*bb4ee6a4SAndroid Build Coastguard Worker         let node = FdtNode::from_blob(blob, &strings).unwrap();
1136*bb4ee6a4SAndroid Build Coastguard Worker 
1137*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(node.name, "");
1138*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(node.subnodes.len(), 0);
1139*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(node.props.len(), PROP_SIZES.len());
1140*bb4ee6a4SAndroid Build Coastguard Worker 
1141*bb4ee6a4SAndroid Build Coastguard Worker         for (pname, s) in PROP_SIZES.into_iter() {
1142*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(node.get_prop::<Vec<u8>>(pname).unwrap().len(), s);
1143*bb4ee6a4SAndroid Build Coastguard Worker         }
1144*bb4ee6a4SAndroid Build Coastguard Worker     }
1145*bb4ee6a4SAndroid Build Coastguard Worker 
1146*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_load_nodes_nested()1147*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_load_nodes_nested() {
1148*bb4ee6a4SAndroid Build Coastguard Worker         let strings_blob = &FDT_BLOB_STRINGS[..];
1149*bb4ee6a4SAndroid Build Coastguard Worker         let strings = FdtStrings::from_blob(strings_blob).unwrap();
1150*bb4ee6a4SAndroid Build Coastguard Worker         let blob: &[u8] = &FDT_BLOB_NESTED_NODES[..];
1151*bb4ee6a4SAndroid Build Coastguard Worker         let root_node = FdtNode::from_blob(blob, &strings).unwrap();
1152*bb4ee6a4SAndroid Build Coastguard Worker 
1153*bb4ee6a4SAndroid Build Coastguard Worker         // Check root node
1154*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(root_node.name, "");
1155*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(root_node.subnodes.len(), 2);
1156*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(root_node.props.len(), 1);
1157*bb4ee6a4SAndroid Build Coastguard Worker 
1158*bb4ee6a4SAndroid Build Coastguard Worker         // Check first nested node
1159*bb4ee6a4SAndroid Build Coastguard Worker         let nested_node = root_node.subnodes.get("nested").unwrap();
1160*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(nested_node.name, "nested");
1161*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(nested_node.subnodes.len(), 0);
1162*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(nested_node.props.len(), 2);
1163*bb4ee6a4SAndroid Build Coastguard Worker 
1164*bb4ee6a4SAndroid Build Coastguard Worker         // Check second nested node
1165*bb4ee6a4SAndroid Build Coastguard Worker         let nested2_node = root_node.subnodes.get("nested2").unwrap();
1166*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(nested2_node.name, "nested2");
1167*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(nested2_node.subnodes.len(), 1);
1168*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(nested2_node.props.len(), 1);
1169*bb4ee6a4SAndroid Build Coastguard Worker 
1170*bb4ee6a4SAndroid Build Coastguard Worker         // Check third nested node
1171*bb4ee6a4SAndroid Build Coastguard Worker         let nested3_node = nested2_node.subnodes.get("nested3").unwrap();
1172*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(nested3_node.name, "nested3");
1173*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(nested3_node.subnodes.len(), 0);
1174*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(nested3_node.props.len(), 0);
1175*bb4ee6a4SAndroid Build Coastguard Worker     }
1176*bb4ee6a4SAndroid Build Coastguard Worker 
1177*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_get_node()1178*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_get_node() {
1179*bb4ee6a4SAndroid Build Coastguard Worker         let fdt = Fdt::new(&[]);
1180*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node("/").is_some());
1181*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node("/a").is_none());
1182*bb4ee6a4SAndroid Build Coastguard Worker     }
1183*bb4ee6a4SAndroid Build Coastguard Worker 
1184*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
fdt_find_nested_node()1185*bb4ee6a4SAndroid Build Coastguard Worker     fn fdt_find_nested_node() {
1186*bb4ee6a4SAndroid Build Coastguard Worker         let mut fdt = Fdt::new(&[]);
1187*bb4ee6a4SAndroid Build Coastguard Worker         let node1 = fdt.root.subnode_mut("N1").unwrap();
1188*bb4ee6a4SAndroid Build Coastguard Worker         node1.subnode_mut("N1-1").unwrap();
1189*bb4ee6a4SAndroid Build Coastguard Worker         node1.subnode_mut("N1-2").unwrap();
1190*bb4ee6a4SAndroid Build Coastguard Worker         let node2 = fdt.root.subnode_mut("N2").unwrap();
1191*bb4ee6a4SAndroid Build Coastguard Worker         let node2_1 = node2.subnode_mut("N2-1").unwrap();
1192*bb4ee6a4SAndroid Build Coastguard Worker         node2_1.subnode_mut("N2-1-1").unwrap();
1193*bb4ee6a4SAndroid Build Coastguard Worker 
1194*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node("/").is_some());
1195*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node("/N1").is_some());
1196*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node("/N2").is_some());
1197*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node("/N1/N1-1").is_some());
1198*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node("/N1/N1-2").is_some());
1199*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node("/N2/N2-1").is_some());
1200*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node("/N2/N2-1/N2-1-1").is_some());
1201*bb4ee6a4SAndroid Build Coastguard Worker         assert!(fdt.get_node("/N2/N2-1/A").is_none());
1202*bb4ee6a4SAndroid Build Coastguard Worker     }
1203*bb4ee6a4SAndroid Build Coastguard Worker 
1204*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
minimal()1205*bb4ee6a4SAndroid Build Coastguard Worker     fn minimal() {
1206*bb4ee6a4SAndroid Build Coastguard Worker         let mut fdt = Fdt::new(&[]);
1207*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
1208*bb4ee6a4SAndroid Build Coastguard Worker             fdt.finish().unwrap(),
1209*bb4ee6a4SAndroid Build Coastguard Worker             [
1210*bb4ee6a4SAndroid Build Coastguard Worker                 0xd0, 0x0d, 0xfe, 0xed, // 0000: magic (0xd00dfeed)
1211*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x48, // 0004: totalsize (0x48)
1212*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x38, // 0008: off_dt_struct (0x38)
1213*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x48, // 000C: off_dt_strings (0x48)
1214*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x28, // 0010: off_mem_rsvmap (0x28)
1215*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x11, // 0014: version (0x11 = 17)
1216*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x10, // 0018: last_comp_version (0x10 = 16)
1217*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 001C: boot_cpuid_phys (0)
1218*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0020: size_dt_strings (0)
1219*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x10, // 0024: size_dt_struct (0x10)
1220*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0028: rsvmap terminator (address = 0 high)
1221*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 002C: rsvmap terminator (address = 0 low)
1222*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0030: rsvmap terminator (size = 0 high)
1223*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0034: rsvmap terminator (size = 0 low)
1224*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x01, // 0038: FDT_BEGIN_NODE
1225*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 003C: node name ("") + padding
1226*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x02, // 0040: FDT_END_NODE
1227*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x09, // 0044: FDT_END
1228*bb4ee6a4SAndroid Build Coastguard Worker             ]
1229*bb4ee6a4SAndroid Build Coastguard Worker         );
1230*bb4ee6a4SAndroid Build Coastguard Worker     }
1231*bb4ee6a4SAndroid Build Coastguard Worker 
1232*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
reservemap()1233*bb4ee6a4SAndroid Build Coastguard Worker     fn reservemap() {
1234*bb4ee6a4SAndroid Build Coastguard Worker         let mut fdt = Fdt::new(&[
1235*bb4ee6a4SAndroid Build Coastguard Worker             FdtReserveEntry {
1236*bb4ee6a4SAndroid Build Coastguard Worker                 address: 0x12345678AABBCCDD,
1237*bb4ee6a4SAndroid Build Coastguard Worker                 size: 0x1234,
1238*bb4ee6a4SAndroid Build Coastguard Worker             },
1239*bb4ee6a4SAndroid Build Coastguard Worker             FdtReserveEntry {
1240*bb4ee6a4SAndroid Build Coastguard Worker                 address: 0x1020304050607080,
1241*bb4ee6a4SAndroid Build Coastguard Worker                 size: 0x5678,
1242*bb4ee6a4SAndroid Build Coastguard Worker             },
1243*bb4ee6a4SAndroid Build Coastguard Worker         ]);
1244*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
1245*bb4ee6a4SAndroid Build Coastguard Worker             fdt.finish().unwrap(),
1246*bb4ee6a4SAndroid Build Coastguard Worker             [
1247*bb4ee6a4SAndroid Build Coastguard Worker                 0xd0, 0x0d, 0xfe, 0xed, // 0000: magic (0xd00dfeed)
1248*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x68, // 0004: totalsize (0x68)
1249*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x58, // 0008: off_dt_struct (0x58)
1250*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x68, // 000C: off_dt_strings (0x68)
1251*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x28, // 0010: off_mem_rsvmap (0x28)
1252*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x11, // 0014: version (0x11 = 17)
1253*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x10, // 0018: last_comp_version (0x10 = 16)
1254*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 001C: boot_cpuid_phys (0)
1255*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0020: size_dt_strings (0)
1256*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x10, // 0024: size_dt_struct (0x10)
1257*bb4ee6a4SAndroid Build Coastguard Worker                 0x12, 0x34, 0x56, 0x78, // 0028: rsvmap entry 0 address high
1258*bb4ee6a4SAndroid Build Coastguard Worker                 0xAA, 0xBB, 0xCC, 0xDD, // 002C: rsvmap entry 0 address low
1259*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0030: rsvmap entry 0 size high
1260*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x12, 0x34, // 0034: rsvmap entry 0 size low
1261*bb4ee6a4SAndroid Build Coastguard Worker                 0x10, 0x20, 0x30, 0x40, // 0038: rsvmap entry 1 address high
1262*bb4ee6a4SAndroid Build Coastguard Worker                 0x50, 0x60, 0x70, 0x80, // 003C: rsvmap entry 1 address low
1263*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0040: rsvmap entry 1 size high
1264*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x56, 0x78, // 0044: rsvmap entry 1 size low
1265*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0048: rsvmap terminator (address = 0 high)
1266*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 004C: rsvmap terminator (address = 0 low)
1267*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0050: rsvmap terminator (size = 0 high)
1268*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0054: rsvmap terminator (size = 0 low)
1269*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x01, // 0058: FDT_BEGIN_NODE
1270*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 005C: node name ("") + padding
1271*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x02, // 0060: FDT_END_NODE
1272*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x09, // 0064: FDT_END
1273*bb4ee6a4SAndroid Build Coastguard Worker             ]
1274*bb4ee6a4SAndroid Build Coastguard Worker         );
1275*bb4ee6a4SAndroid Build Coastguard Worker     }
1276*bb4ee6a4SAndroid Build Coastguard Worker 
1277*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
prop_null()1278*bb4ee6a4SAndroid Build Coastguard Worker     fn prop_null() {
1279*bb4ee6a4SAndroid Build Coastguard Worker         let mut fdt = Fdt::new(&[]);
1280*bb4ee6a4SAndroid Build Coastguard Worker         let root_node = fdt.root_mut();
1281*bb4ee6a4SAndroid Build Coastguard Worker         root_node.set_prop("null", ()).unwrap();
1282*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
1283*bb4ee6a4SAndroid Build Coastguard Worker             fdt.finish().unwrap(),
1284*bb4ee6a4SAndroid Build Coastguard Worker             [
1285*bb4ee6a4SAndroid Build Coastguard Worker                 0xd0, 0x0d, 0xfe, 0xed, // 0000: magic (0xd00dfeed)
1286*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x59, // 0004: totalsize (0x59)
1287*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x38, // 0008: off_dt_struct (0x38)
1288*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x54, // 000C: off_dt_strings (0x54)
1289*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x28, // 0010: off_mem_rsvmap (0x28)
1290*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x11, // 0014: version (0x11 = 17)
1291*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x10, // 0018: last_comp_version (0x10 = 16)
1292*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 001C: boot_cpuid_phys (0)
1293*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x05, // 0020: size_dt_strings (0x05)
1294*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x1c, // 0024: size_dt_struct (0x1C)
1295*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0028: rsvmap terminator (address = 0 high)
1296*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 002C: rsvmap terminator (address = 0 low)
1297*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0030: rsvmap terminator (size = 0 high)
1298*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0034: rsvmap terminator (size = 0 low)
1299*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x01, // 0038: FDT_BEGIN_NODE
1300*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 003C: node name ("") + padding
1301*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x03, // 0040: FDT_PROP
1302*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0044: prop len (0)
1303*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0048: prop nameoff (0)
1304*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x02, // 004C: FDT_END_NODE
1305*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x09, // 0050: FDT_END
1306*bb4ee6a4SAndroid Build Coastguard Worker                 b'n', b'u', b'l', b'l', 0x00, // 0054: strings block
1307*bb4ee6a4SAndroid Build Coastguard Worker             ]
1308*bb4ee6a4SAndroid Build Coastguard Worker         );
1309*bb4ee6a4SAndroid Build Coastguard Worker     }
1310*bb4ee6a4SAndroid Build Coastguard Worker 
1311*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
prop_u32()1312*bb4ee6a4SAndroid Build Coastguard Worker     fn prop_u32() {
1313*bb4ee6a4SAndroid Build Coastguard Worker         let mut fdt = Fdt::new(&[]);
1314*bb4ee6a4SAndroid Build Coastguard Worker         let root_node = fdt.root_mut();
1315*bb4ee6a4SAndroid Build Coastguard Worker         root_node.set_prop("u32", 0x12345678u32).unwrap();
1316*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
1317*bb4ee6a4SAndroid Build Coastguard Worker             fdt.finish().unwrap(),
1318*bb4ee6a4SAndroid Build Coastguard Worker             [
1319*bb4ee6a4SAndroid Build Coastguard Worker                 0xd0, 0x0d, 0xfe, 0xed, // 0000: magic (0xd00dfeed)
1320*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x5c, // 0004: totalsize (0x5C)
1321*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x38, // 0008: off_dt_struct (0x38)
1322*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x58, // 000C: off_dt_strings (0x58)
1323*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x28, // 0010: off_mem_rsvmap (0x28)
1324*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x11, // 0014: version (0x11 = 17)
1325*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x10, // 0018: last_comp_version (0x10 = 16)
1326*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 001C: boot_cpuid_phys (0)
1327*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x04, // 0020: size_dt_strings (0x04)
1328*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x20, // 0024: size_dt_struct (0x20)
1329*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0028: rsvmap terminator (address = 0 high)
1330*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 002C: rsvmap terminator (address = 0 low)
1331*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0030: rsvmap terminator (size = 0 high)
1332*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0034: rsvmap terminator (size = 0 low)
1333*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x01, // 0038: FDT_BEGIN_NODE
1334*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 003C: node name ("") + padding
1335*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x03, // 0040: FDT_PROP
1336*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x04, // 0044: prop len (4)
1337*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0048: prop nameoff (0)
1338*bb4ee6a4SAndroid Build Coastguard Worker                 0x12, 0x34, 0x56, 0x78, // 004C: prop u32 value (0x12345678)
1339*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x02, // 0050: FDT_END_NODE
1340*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x09, // 0054: FDT_END
1341*bb4ee6a4SAndroid Build Coastguard Worker                 b'u', b'3', b'2', 0x00, // 0058: strings block
1342*bb4ee6a4SAndroid Build Coastguard Worker             ]
1343*bb4ee6a4SAndroid Build Coastguard Worker         );
1344*bb4ee6a4SAndroid Build Coastguard Worker     }
1345*bb4ee6a4SAndroid Build Coastguard Worker 
1346*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
all_props()1347*bb4ee6a4SAndroid Build Coastguard Worker     fn all_props() {
1348*bb4ee6a4SAndroid Build Coastguard Worker         let mut fdt = Fdt::new(&[]);
1349*bb4ee6a4SAndroid Build Coastguard Worker         let root_node = fdt.root_mut();
1350*bb4ee6a4SAndroid Build Coastguard Worker         root_node
1351*bb4ee6a4SAndroid Build Coastguard Worker             .set_prop("arru32", &[0x12345678u32, 0xAABBCCDDu32])
1352*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
1353*bb4ee6a4SAndroid Build Coastguard Worker         root_node
1354*bb4ee6a4SAndroid Build Coastguard Worker             .set_prop("arru64", &[0x1234567887654321u64])
1355*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
1356*bb4ee6a4SAndroid Build Coastguard Worker         root_node.set_prop("null", ()).unwrap();
1357*bb4ee6a4SAndroid Build Coastguard Worker         root_node.set_prop("str", "hello").unwrap();
1358*bb4ee6a4SAndroid Build Coastguard Worker         root_node.set_prop("strlst", &["hi", "bye"]).unwrap();
1359*bb4ee6a4SAndroid Build Coastguard Worker         root_node.set_prop("u32", 0x12345678u32).unwrap();
1360*bb4ee6a4SAndroid Build Coastguard Worker         root_node.set_prop("u64", 0x1234567887654321u64).unwrap();
1361*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
1362*bb4ee6a4SAndroid Build Coastguard Worker             fdt.finish().unwrap(),
1363*bb4ee6a4SAndroid Build Coastguard Worker             [
1364*bb4ee6a4SAndroid Build Coastguard Worker                 0xd0, 0x0d, 0xfe, 0xed, // 0000: magic (0xd00dfeed)
1365*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0xee, // 0004: totalsize (0xEE)
1366*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x38, // 0008: off_dt_struct (0x38)
1367*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0xc8, // 000C: off_dt_strings (0xC8)
1368*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x28, // 0010: off_mem_rsvmap (0x28)
1369*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x11, // 0014: version (0x11 = 17)
1370*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x10, // 0018: last_comp_version (0x10 = 16)
1371*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 001C: boot_cpuid_phys (0)
1372*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x26, // 0020: size_dt_strings (0x26)
1373*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x90, // 0024: size_dt_struct (0x90)
1374*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0028: rsvmap terminator (address = 0 high)
1375*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 002C: rsvmap terminator (address = 0 low)
1376*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0030: rsvmap terminator (size = 0 high)
1377*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0034: rsvmap terminator (size = 0 low)
1378*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x01, // 0038: FDT_BEGIN_NODE
1379*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 003C: node name ("") + padding
1380*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x03, // 0040: FDT_PROP (u32 array)
1381*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x08, // 0044: prop len (8)
1382*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0048: prop nameoff (0x00)
1383*bb4ee6a4SAndroid Build Coastguard Worker                 0x12, 0x34, 0x56, 0x78, // 004C: prop value 0
1384*bb4ee6a4SAndroid Build Coastguard Worker                 0xAA, 0xBB, 0xCC, 0xDD, // 0050: prop value 1
1385*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x03, // 0054: FDT_PROP (u64 array)
1386*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x08, // 0058: prop len (8)
1387*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x07, // 005C: prop nameoff (0x07)
1388*bb4ee6a4SAndroid Build Coastguard Worker                 0x12, 0x34, 0x56, 0x78, // 0060: prop u64 value 0 high
1389*bb4ee6a4SAndroid Build Coastguard Worker                 0x87, 0x65, 0x43, 0x21, // 0064: prop u64 value 0 low
1390*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x03, // 0068: FDT_PROP (null)
1391*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 006C: prop len (0)
1392*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x0E, // 0070: prop nameoff (0x0e)
1393*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x03, // 0074: FDT_PROP (string)
1394*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x06, // 0078: prop len (6)
1395*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x13, // 007C: prop nameoff (0x13)
1396*bb4ee6a4SAndroid Build Coastguard Worker                 b'h', b'e', b'l', b'l', // 0080: prop str value ("hello") + padding
1397*bb4ee6a4SAndroid Build Coastguard Worker                 b'o', 0x00, 0x00, 0x00, // 0084: "o\0" + padding
1398*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x03, // 0088: FDT_PROP (string list)
1399*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x07, // 008C: prop len (7)
1400*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x17, // 0090: prop nameoff (0x17)
1401*bb4ee6a4SAndroid Build Coastguard Worker                 b'h', b'i', 0x00, b'b', // 0094: prop value ("hi", "bye")
1402*bb4ee6a4SAndroid Build Coastguard Worker                 b'y', b'e', 0x00, 0x00, // 0098: "ye\0" + padding
1403*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x03, // 009C: FDT_PROP (u32)
1404*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x04, // 00A0: prop len (4)
1405*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x1E, // 00A4: prop nameoff (0x1E)
1406*bb4ee6a4SAndroid Build Coastguard Worker                 0x12, 0x34, 0x56, 0x78, // 00A8: prop u32 value (0x12345678)
1407*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x03, // 00AC: FDT_PROP (u64)
1408*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x08, // 00B0: prop len (8)
1409*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x22, // 00B4: prop nameoff (0x22)
1410*bb4ee6a4SAndroid Build Coastguard Worker                 0x12, 0x34, 0x56, 0x78, // 00B8: prop u64 value high (0x12345678)
1411*bb4ee6a4SAndroid Build Coastguard Worker                 0x87, 0x65, 0x43, 0x21, // 00BC: prop u64 value low (0x87654321)
1412*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x02, // 00C0: FDT_END_NODE
1413*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x09, // 00C4: FDT_END
1414*bb4ee6a4SAndroid Build Coastguard Worker                 b'a', b'r', b'r', b'u', b'3', b'2', 0x00, // 00C8: strings + 0x00: "arru32"
1415*bb4ee6a4SAndroid Build Coastguard Worker                 b'a', b'r', b'r', b'u', b'6', b'4', 0x00, // 00CF: strings + 0x07: "arru64"
1416*bb4ee6a4SAndroid Build Coastguard Worker                 b'n', b'u', b'l', b'l', 0x00, // 00D6: strings + 0x0E: "null"
1417*bb4ee6a4SAndroid Build Coastguard Worker                 b's', b't', b'r', 0x00, // 00DB: strings + 0x13: "str"
1418*bb4ee6a4SAndroid Build Coastguard Worker                 b's', b't', b'r', b'l', b's', b't', 0x00, // 00DF: strings + 0x17: "strlst"
1419*bb4ee6a4SAndroid Build Coastguard Worker                 b'u', b'3', b'2', 0x00, // 00E6: strings + 0x1E: "u32"
1420*bb4ee6a4SAndroid Build Coastguard Worker                 b'u', b'6', b'4', 0x00, // 00EA: strings + 0x22: "u64"
1421*bb4ee6a4SAndroid Build Coastguard Worker             ]
1422*bb4ee6a4SAndroid Build Coastguard Worker         );
1423*bb4ee6a4SAndroid Build Coastguard Worker     }
1424*bb4ee6a4SAndroid Build Coastguard Worker 
1425*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
node_order()1426*bb4ee6a4SAndroid Build Coastguard Worker     fn node_order() {
1427*bb4ee6a4SAndroid Build Coastguard Worker         let expected: &[u8] = &[
1428*bb4ee6a4SAndroid Build Coastguard Worker             0xd0, 0x0d, 0xfe, 0xed, // 0000: magic (0xd00dfeed)
1429*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x9C, // 0004: totalsize (0x9C)
1430*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x38, // 0008: off_dt_struct (0x38)
1431*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x9C, // 000C: off_dt_strings (0x9C)
1432*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x28, // 0010: off_mem_rsvmap (0x28)
1433*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x11, // 0014: version (0x11 = 17)
1434*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x10, // 0018: last_comp_version (0x10 = 16)
1435*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x00, // 001C: boot_cpuid_phys (0)
1436*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x00, // 0020: size_dt_strings (0x00)
1437*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x64, // 0024: size_dt_struct (0x64)
1438*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x00, // 0028: rsvmap terminator (address = 0 high)
1439*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x00, // 002C: rsvmap terminator (address = 0 low)
1440*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x00, // 0030: rsvmap terminator (size = 0 high)
1441*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x00, // 0034: rsvmap terminator (size = 0 low)
1442*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x01, // 0038: FDT_BEGIN_NODE
1443*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x00, // 003C: node name ("") + padding
1444*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x01, // 0040: FDT_BEGIN_NODE
1445*bb4ee6a4SAndroid Build Coastguard Worker             b'B', 0x00, 0x00, 0x00, // 0044: node name ("B") + padding
1446*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x02, // 0048: FDT_END_NODE
1447*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x01, // 004C: FDT_BEGIN_NODE
1448*bb4ee6a4SAndroid Build Coastguard Worker             b'A', 0x00, 0x00, 0x00, // 0050: node name ("A") + padding
1449*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x02, // 0054: FDT_END_NODE
1450*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x01, // 0058: FDT_BEGIN_NODE
1451*bb4ee6a4SAndroid Build Coastguard Worker             b'C', 0x00, 0x00, 0x00, // 005C: node name ("C") + padding
1452*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x01, // 0060: FDT_BEGIN_NODE
1453*bb4ee6a4SAndroid Build Coastguard Worker             b'D', 0x00, 0x00, 0x00, // 0064: node name ("D") + padding
1454*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x02, // 0068: FDT_END_NODE
1455*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x01, // 006C: FDT_BEGIN_NODE
1456*bb4ee6a4SAndroid Build Coastguard Worker             b'E', 0x00, 0x00, 0x00, // 0070: node name ("E") + padding
1457*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x02, // 0074: FDT_END_NODE
1458*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x01, // 0078: FDT_BEGIN_NODE
1459*bb4ee6a4SAndroid Build Coastguard Worker             b'B', 0x00, 0x00, 0x00, // 007C: node name ("B") + padding
1460*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x02, // 0080: FDT_END_NODE
1461*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x01, // 0084: FDT_BEGIN_NODE
1462*bb4ee6a4SAndroid Build Coastguard Worker             b'F', 0x00, 0x00, 0x00, // 0088: node name ("F") + padding
1463*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x02, // 008C: FDT_END_NODE
1464*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x02, // 0090: FDT_END_NODE
1465*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x02, // 0094: FDT_END_NODE
1466*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x09, // 0098: FDT_END
1467*bb4ee6a4SAndroid Build Coastguard Worker         ];
1468*bb4ee6a4SAndroid Build Coastguard Worker 
1469*bb4ee6a4SAndroid Build Coastguard Worker         let mut fdt = Fdt::new(&[]);
1470*bb4ee6a4SAndroid Build Coastguard Worker         let root = fdt.root_mut();
1471*bb4ee6a4SAndroid Build Coastguard Worker         let root_subnode_names = ["B", "A", "C"];
1472*bb4ee6a4SAndroid Build Coastguard Worker         let node_c_subnode_names = ["D", "E", "B", "F"];
1473*bb4ee6a4SAndroid Build Coastguard Worker         for n in root_subnode_names {
1474*bb4ee6a4SAndroid Build Coastguard Worker             root.subnode_mut(n).unwrap();
1475*bb4ee6a4SAndroid Build Coastguard Worker         }
1476*bb4ee6a4SAndroid Build Coastguard Worker         let node_c = root.subnode_mut("C").unwrap();
1477*bb4ee6a4SAndroid Build Coastguard Worker         for n in node_c_subnode_names {
1478*bb4ee6a4SAndroid Build Coastguard Worker             node_c.subnode_mut(n).unwrap();
1479*bb4ee6a4SAndroid Build Coastguard Worker         }
1480*bb4ee6a4SAndroid Build Coastguard Worker 
1481*bb4ee6a4SAndroid Build Coastguard Worker         assert!(root
1482*bb4ee6a4SAndroid Build Coastguard Worker             .iter_subnodes()
1483*bb4ee6a4SAndroid Build Coastguard Worker             .zip(root_subnode_names)
1484*bb4ee6a4SAndroid Build Coastguard Worker             .all(|(sn, n)| sn.name == n));
1485*bb4ee6a4SAndroid Build Coastguard Worker         assert!(root
1486*bb4ee6a4SAndroid Build Coastguard Worker             .subnode("C")
1487*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap()
1488*bb4ee6a4SAndroid Build Coastguard Worker             .iter_subnodes()
1489*bb4ee6a4SAndroid Build Coastguard Worker             .zip(node_c_subnode_names)
1490*bb4ee6a4SAndroid Build Coastguard Worker             .all(|(sn, n)| sn.name == n));
1491*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(fdt.finish().unwrap(), expected);
1492*bb4ee6a4SAndroid Build Coastguard Worker     }
1493*bb4ee6a4SAndroid Build Coastguard Worker 
1494*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
prop_order()1495*bb4ee6a4SAndroid Build Coastguard Worker     fn prop_order() {
1496*bb4ee6a4SAndroid Build Coastguard Worker         let expected: &[u8] = &[
1497*bb4ee6a4SAndroid Build Coastguard Worker             0xd0, 0x0d, 0xfe, 0xed, // 0000: magic (0xd00dfeed)
1498*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x98, // 0004: totalsize (0x98)
1499*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x38, // 0008: off_dt_struct (0x38)
1500*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x88, // 000C: off_dt_strings (0x88)
1501*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x28, // 0010: off_mem_rsvmap (0x28)
1502*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x11, // 0014: version (0x11 = 17)
1503*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x10, // 0018: last_comp_version (0x10 = 16)
1504*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x00, // 001C: boot_cpuid_phys (0)
1505*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x10, // 0020: size_dt_strings (0x10)
1506*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x50, // 0024: size_dt_struct (0x50)
1507*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x00, // 0028: rsvmap terminator (address = 0 high)
1508*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x00, // 002C: rsvmap terminator (address = 0 low)
1509*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x00, // 0030: rsvmap terminator (size = 0 high)
1510*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x00, // 0034: rsvmap terminator (size = 0 low)
1511*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x01, // 0038: FDT_BEGIN_NODE
1512*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x00, // 003C: node name ("") + padding
1513*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x03, // 0040: FDT_PROP (u32)
1514*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x04, // 0044: prop len (4)
1515*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x00, // 0048: prop nameoff (0x00)
1516*bb4ee6a4SAndroid Build Coastguard Worker             0x76, 0x61, 0x6c, 0x00, // 004C: prop string value ("val")
1517*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x03, // 0050: FDT_PROP (u32)
1518*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x04, // 0054: prop len (4)
1519*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x04, // 0058: prop nameoff (0x04)
1520*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x02, // 005C: prop u32 high (0x2)
1521*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x03, // 0060: FDT_PROP (u32)
1522*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x04, // 0064: prop len (4)
1523*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x08, // 0068: prop nameoff (0x08)
1524*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x01, // 006C: prop u32 value (0x1)
1525*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x03, // 0070: FDT_PROP (u32)
1526*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x04, // 0074: prop len (4)
1527*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x0C, // 0078: prop nameoff (0x0B)
1528*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x03, // 007C: prop u32 value (0x3)
1529*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x02, // 0080: FDT_END_NODE
1530*bb4ee6a4SAndroid Build Coastguard Worker             0x00, 0x00, 0x00, 0x09, // 0084: FDT_END
1531*bb4ee6a4SAndroid Build Coastguard Worker             b'g', b'h', b'i', 0x00, // 0088: strings + 0x00: "ghi"
1532*bb4ee6a4SAndroid Build Coastguard Worker             b'd', b'e', b'f', 0x00, // 008C: strings + 0x04: "def"
1533*bb4ee6a4SAndroid Build Coastguard Worker             b'a', b'b', b'c', 0x00, // 0090: strings + 0x08: "abc"
1534*bb4ee6a4SAndroid Build Coastguard Worker             b'b', b'c', b'd', 0x00, // 0094: strings + 0x0C: "bcd"
1535*bb4ee6a4SAndroid Build Coastguard Worker         ];
1536*bb4ee6a4SAndroid Build Coastguard Worker 
1537*bb4ee6a4SAndroid Build Coastguard Worker         let mut fdt = Fdt::new(&[]);
1538*bb4ee6a4SAndroid Build Coastguard Worker         let root_node = fdt.root_mut();
1539*bb4ee6a4SAndroid Build Coastguard Worker         root_node.set_prop("ghi", "val").unwrap();
1540*bb4ee6a4SAndroid Build Coastguard Worker         root_node.set_prop("def", 2u32).unwrap();
1541*bb4ee6a4SAndroid Build Coastguard Worker         root_node.set_prop("abc", 1u32).unwrap();
1542*bb4ee6a4SAndroid Build Coastguard Worker         root_node.set_prop("bcd", 3u32).unwrap();
1543*bb4ee6a4SAndroid Build Coastguard Worker 
1544*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
1545*bb4ee6a4SAndroid Build Coastguard Worker             root_node.prop_names().collect::<Vec<_>>(),
1546*bb4ee6a4SAndroid Build Coastguard Worker             ["ghi", "def", "abc", "bcd"]
1547*bb4ee6a4SAndroid Build Coastguard Worker         );
1548*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(fdt.finish().unwrap(), expected);
1549*bb4ee6a4SAndroid Build Coastguard Worker     }
1550*bb4ee6a4SAndroid Build Coastguard Worker 
1551*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
nested_nodes()1552*bb4ee6a4SAndroid Build Coastguard Worker     fn nested_nodes() {
1553*bb4ee6a4SAndroid Build Coastguard Worker         let mut fdt = Fdt::new(&[]);
1554*bb4ee6a4SAndroid Build Coastguard Worker         let root_node = fdt.root_mut();
1555*bb4ee6a4SAndroid Build Coastguard Worker         root_node.set_prop("abc", 0x13579024u32).unwrap();
1556*bb4ee6a4SAndroid Build Coastguard Worker         let nested_node = root_node.subnode_mut("nested").unwrap();
1557*bb4ee6a4SAndroid Build Coastguard Worker         nested_node.set_prop("def", 0x12121212u32).unwrap();
1558*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
1559*bb4ee6a4SAndroid Build Coastguard Worker             fdt.finish().unwrap(),
1560*bb4ee6a4SAndroid Build Coastguard Worker             [
1561*bb4ee6a4SAndroid Build Coastguard Worker                 0xd0, 0x0d, 0xfe, 0xed, // 0000: magic (0xd00dfeed)
1562*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x80, // 0004: totalsize (0x80)
1563*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x38, // 0008: off_dt_struct (0x38)
1564*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x78, // 000C: off_dt_strings (0x78)
1565*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x28, // 0010: off_mem_rsvmap (0x28)
1566*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x11, // 0014: version (0x11 = 17)
1567*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x10, // 0018: last_comp_version (0x10 = 16)
1568*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 001C: boot_cpuid_phys (0)
1569*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x08, // 0020: size_dt_strings (0x08)
1570*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x40, // 0024: size_dt_struct (0x40)
1571*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0028: rsvmap terminator (address = 0 high)
1572*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 002C: rsvmap terminator (address = 0 low)
1573*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0030: rsvmap terminator (size = 0 high)
1574*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0034: rsvmap terminator (size = 0 low)
1575*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x01, // 0038: FDT_BEGIN_NODE
1576*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 003C: node name ("") + padding
1577*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x03, // 0040: FDT_PROP
1578*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x04, // 0044: prop len (4)
1579*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0048: prop nameoff (0x00)
1580*bb4ee6a4SAndroid Build Coastguard Worker                 0x13, 0x57, 0x90, 0x24, // 004C: prop u32 value (0x13579024)
1581*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x01, // 0050: FDT_BEGIN_NODE
1582*bb4ee6a4SAndroid Build Coastguard Worker                 b'n', b'e', b's', b't', // 0054: Node name ("nested")
1583*bb4ee6a4SAndroid Build Coastguard Worker                 b'e', b'd', 0x00, 0x00, // 0058: "ed\0" + pad
1584*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x03, // 005C: FDT_PROP
1585*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x04, // 0060: prop len (4)
1586*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x04, // 0064: prop nameoff (0x04)
1587*bb4ee6a4SAndroid Build Coastguard Worker                 0x12, 0x12, 0x12, 0x12, // 0068: prop u32 value (0x12121212)
1588*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x02, // 006C: FDT_END_NODE ("nested")
1589*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x02, // 0070: FDT_END_NODE ("")
1590*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x09, // 0074: FDT_END
1591*bb4ee6a4SAndroid Build Coastguard Worker                 b'a', b'b', b'c', 0x00, // 0078: strings + 0x00: "abc"
1592*bb4ee6a4SAndroid Build Coastguard Worker                 b'd', b'e', b'f', 0x00, // 007C: strings + 0x04: "def"
1593*bb4ee6a4SAndroid Build Coastguard Worker             ]
1594*bb4ee6a4SAndroid Build Coastguard Worker         );
1595*bb4ee6a4SAndroid Build Coastguard Worker     }
1596*bb4ee6a4SAndroid Build Coastguard Worker 
1597*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
prop_name_string_reuse()1598*bb4ee6a4SAndroid Build Coastguard Worker     fn prop_name_string_reuse() {
1599*bb4ee6a4SAndroid Build Coastguard Worker         let mut fdt = Fdt::new(&[]);
1600*bb4ee6a4SAndroid Build Coastguard Worker         let root_node = fdt.root_mut();
1601*bb4ee6a4SAndroid Build Coastguard Worker         root_node.set_prop("abc", 0x13579024u32).unwrap();
1602*bb4ee6a4SAndroid Build Coastguard Worker         let nested = root_node.subnode_mut("nested").unwrap();
1603*bb4ee6a4SAndroid Build Coastguard Worker         nested.set_prop("abc", 0x12121212u32).unwrap(); // This should reuse the "abc" string.
1604*bb4ee6a4SAndroid Build Coastguard Worker         nested.set_prop("def", 0x12121212u32).unwrap();
1605*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
1606*bb4ee6a4SAndroid Build Coastguard Worker             fdt.finish().unwrap(),
1607*bb4ee6a4SAndroid Build Coastguard Worker             [
1608*bb4ee6a4SAndroid Build Coastguard Worker                 0xd0, 0x0d, 0xfe, 0xed, // 0000: magic (0xd00dfeed)
1609*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x90, // 0004: totalsize (0x90)
1610*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x38, // 0008: off_dt_struct (0x38)
1611*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x88, // 000C: off_dt_strings (0x88)
1612*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x28, // 0010: off_mem_rsvmap (0x28)
1613*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x11, // 0014: version (0x11 = 17)
1614*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x10, // 0018: last_comp_version (0x10 = 16)
1615*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 001C: boot_cpuid_phys (0)
1616*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x08, // 0020: size_dt_strings (0x08)
1617*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x50, // 0024: size_dt_struct (0x50)
1618*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0028: rsvmap terminator (address = 0 high)
1619*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 002C: rsvmap terminator (address = 0 low)
1620*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0030: rsvmap terminator (size = 0 high)
1621*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0034: rsvmap terminator (size = 0 low)
1622*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x01, // 0038: FDT_BEGIN_NODE
1623*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 003C: node name ("") + padding
1624*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x03, // 0040: FDT_PROP
1625*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x04, // 0044: prop len (4)
1626*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0048: prop nameoff (0x00)
1627*bb4ee6a4SAndroid Build Coastguard Worker                 0x13, 0x57, 0x90, 0x24, // 004C: prop u32 value (0x13579024)
1628*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x01, // 0050: FDT_BEGIN_NODE
1629*bb4ee6a4SAndroid Build Coastguard Worker                 b'n', b'e', b's', b't', // 0054: Node name ("nested")
1630*bb4ee6a4SAndroid Build Coastguard Worker                 b'e', b'd', 0x00, 0x00, // 0058: "ed\0" + pad
1631*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x03, // 005C: FDT_PROP
1632*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x04, // 0060: prop len (4)
1633*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x00, // 0064: prop nameoff (0x00 - reuse)
1634*bb4ee6a4SAndroid Build Coastguard Worker                 0x12, 0x12, 0x12, 0x12, // 0068: prop u32 value (0x12121212)
1635*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x03, // 006C: FDT_PROP
1636*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x04, // 0070: prop len (4)
1637*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x04, // 0074: prop nameoff (0x04)
1638*bb4ee6a4SAndroid Build Coastguard Worker                 0x12, 0x12, 0x12, 0x12, // 0078: prop u32 value (0x12121212)
1639*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x02, // 007C: FDT_END_NODE ("nested")
1640*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x02, // 0080: FDT_END_NODE ("")
1641*bb4ee6a4SAndroid Build Coastguard Worker                 0x00, 0x00, 0x00, 0x09, // 0084: FDT_END
1642*bb4ee6a4SAndroid Build Coastguard Worker                 b'a', b'b', b'c', 0x00, // 0088: strings + 0x00: "abc"
1643*bb4ee6a4SAndroid Build Coastguard Worker                 b'd', b'e', b'f', 0x00, // 008C: strings + 0x04: "def"
1644*bb4ee6a4SAndroid Build Coastguard Worker             ]
1645*bb4ee6a4SAndroid Build Coastguard Worker         );
1646*bb4ee6a4SAndroid Build Coastguard Worker     }
1647*bb4ee6a4SAndroid Build Coastguard Worker 
1648*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
invalid_node_name_nul()1649*bb4ee6a4SAndroid Build Coastguard Worker     fn invalid_node_name_nul() {
1650*bb4ee6a4SAndroid Build Coastguard Worker         let mut fdt = Fdt::new(&[]);
1651*bb4ee6a4SAndroid Build Coastguard Worker         let root_node = fdt.root_mut();
1652*bb4ee6a4SAndroid Build Coastguard Worker         root_node
1653*bb4ee6a4SAndroid Build Coastguard Worker             .subnode_mut("abc\0def")
1654*bb4ee6a4SAndroid Build Coastguard Worker             .expect_err("node name with embedded NUL");
1655*bb4ee6a4SAndroid Build Coastguard Worker     }
1656*bb4ee6a4SAndroid Build Coastguard Worker 
1657*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
invalid_prop_name_nul()1658*bb4ee6a4SAndroid Build Coastguard Worker     fn invalid_prop_name_nul() {
1659*bb4ee6a4SAndroid Build Coastguard Worker         let mut fdt = Fdt::new(&[]);
1660*bb4ee6a4SAndroid Build Coastguard Worker         let root_node = fdt.root_mut();
1661*bb4ee6a4SAndroid Build Coastguard Worker         root_node
1662*bb4ee6a4SAndroid Build Coastguard Worker             .set_prop("abc\0def", 0u32)
1663*bb4ee6a4SAndroid Build Coastguard Worker             .expect_err("property name with embedded NUL");
1664*bb4ee6a4SAndroid Build Coastguard Worker     }
1665*bb4ee6a4SAndroid Build Coastguard Worker 
1666*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
invalid_prop_string_value_nul()1667*bb4ee6a4SAndroid Build Coastguard Worker     fn invalid_prop_string_value_nul() {
1668*bb4ee6a4SAndroid Build Coastguard Worker         let mut fdt = Fdt::new(&[]);
1669*bb4ee6a4SAndroid Build Coastguard Worker         let root_node = fdt.root_mut();
1670*bb4ee6a4SAndroid Build Coastguard Worker         root_node
1671*bb4ee6a4SAndroid Build Coastguard Worker             .set_prop("mystr", "abc\0def")
1672*bb4ee6a4SAndroid Build Coastguard Worker             .expect_err("string property value with embedded NUL");
1673*bb4ee6a4SAndroid Build Coastguard Worker     }
1674*bb4ee6a4SAndroid Build Coastguard Worker 
1675*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
invalid_prop_string_list_value_nul()1676*bb4ee6a4SAndroid Build Coastguard Worker     fn invalid_prop_string_list_value_nul() {
1677*bb4ee6a4SAndroid Build Coastguard Worker         let mut fdt = Fdt::new(&[]);
1678*bb4ee6a4SAndroid Build Coastguard Worker         let root_node = fdt.root_mut();
1679*bb4ee6a4SAndroid Build Coastguard Worker         let strs = ["test", "abc\0def"];
1680*bb4ee6a4SAndroid Build Coastguard Worker         root_node
1681*bb4ee6a4SAndroid Build Coastguard Worker             .set_prop("mystr", &strs)
1682*bb4ee6a4SAndroid Build Coastguard Worker             .expect_err("stringlist property value with embedded NUL");
1683*bb4ee6a4SAndroid Build Coastguard Worker     }
1684*bb4ee6a4SAndroid Build Coastguard Worker }
1685