xref: /aosp_15_r20/bootable/libbootloader/gbl/libfdt/src/lib.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
1 // Copyright 2023-2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! This library provides a few wrapper APIs for libfdt_c
16 
17 #![cfg_attr(not(test), no_std)]
18 
19 extern crate alloc;
20 extern crate libc;
21 
22 use arrayvec::ArrayVec;
23 use core::ffi::{c_int, CStr};
24 use core::mem::size_of;
25 use core::slice::{from_raw_parts, from_raw_parts_mut};
26 use liberror::{Error, Result};
27 use libfdt_bindgen::{
28     fdt_add_subnode_namelen, fdt_del_node, fdt_get_property, fdt_header, fdt_move, fdt_setprop,
29     fdt_setprop_placeholder, fdt_strerror, fdt_subnode_offset_namelen,
30 };
31 use libufdt_bindgen::ufdt_apply_multioverlay;
32 use zerocopy::{AsBytes, FromBytes, FromZeroes, Ref};
33 
34 /// Fdt header structure size.
35 pub const FDT_HEADER_SIZE: usize = size_of::<FdtHeader>();
36 const MAXIMUM_OVERLAYS_TO_APPLY: usize = 16;
37 const MAXIMUM_OVERLAYS_ERROR_MSG: &str = "At most 16 overlays are supported to apply at a time";
38 
39 /// Convert libfdt_c error code to Result
map_result(code: c_int) -> Result<c_int>40 fn map_result(code: c_int) -> Result<c_int> {
41     match code {
42         // SAFETY: Static null terminated string returned from libfdt_c API.
43         v if v < 0 => {
44             Err(Error::Other(Some(unsafe { CStr::from_ptr(fdt_strerror(v)).to_str().unwrap() })))
45         }
46         v => Ok(v),
47     }
48 }
49 
50 /// Convert libufdt_c error code to Result
map_result_libufdt(code: c_int) -> Result<c_int>51 fn map_result_libufdt(code: c_int) -> Result<c_int> {
52     match code {
53         v if v < 0 => Err(Error::Other(Some("Failed to execute libufdt call"))),
54         v => Ok(v),
55     }
56 }
57 
58 /// Check header.
fdt_check_header(header: &[u8]) -> Result<()>59 fn fdt_check_header(header: &[u8]) -> Result<()> {
60     // SAFETY:
61     // `fdt_check_header` is only access the memory pointed to by `header` during this call and
62     // not store the pointer for later use. `header` remains valid for the duration of this call.
63     map_result(unsafe { libfdt_bindgen::fdt_check_header(header.as_ptr() as *const _) })?;
64     Ok(())
65 }
66 
67 /// Check header and verified that totalsize does not exceed buffer size.
fdt_check_buffer(fdt: &[u8]) -> Result<()>68 fn fdt_check_buffer(fdt: &[u8]) -> Result<()> {
69     match FdtHeader::from_bytes_ref(fdt)?.totalsize() <= fdt.len() {
70         true => Ok(()),
71         _ => Err(Error::InvalidInput),
72     }
73 }
74 
75 /// Wrapper of fdt_add_subnode_namelen()
fdt_add_subnode(fdt: &mut [u8], parent: c_int, name: &str) -> Result<c_int>76 fn fdt_add_subnode(fdt: &mut [u8], parent: c_int, name: &str) -> Result<c_int> {
77     // SAFETY: API from libfdt_c.
78     map_result(unsafe {
79         fdt_add_subnode_namelen(
80             fdt.as_mut_ptr() as *mut _,
81             parent,
82             name.as_ptr() as *const _,
83             name.len().try_into()?,
84         )
85     })
86 }
87 
88 /// Wrapper of fdt_subnode_offset_namelen()
fdt_subnode_offset(fdt: &[u8], parent: c_int, name: &str) -> Result<c_int>89 fn fdt_subnode_offset(fdt: &[u8], parent: c_int, name: &str) -> Result<c_int> {
90     // SAFETY: API from libfdt_c.
91     map_result(unsafe {
92         fdt_subnode_offset_namelen(
93             fdt.as_ptr() as *const _,
94             parent,
95             name.as_ptr() as *const _,
96             name.len().try_into()?,
97         )
98     })
99 }
100 
101 /// Rust wrapper for the FDT header data.
102 #[repr(transparent)]
103 #[derive(Debug, Copy, Clone, AsBytes, FromBytes, FromZeroes, PartialEq)]
104 pub struct FdtHeader(fdt_header);
105 
106 impl FdtHeader {
107     /// Return the totalsize field.
totalsize(&self) -> usize108     pub fn totalsize(&self) -> usize {
109         u32::from_be(self.0.totalsize) as usize
110     }
111 
112     /// Return the minimal size of the FDT. Disregard trailing free space.
actual_size(&self) -> usize113     pub fn actual_size(&self) -> usize {
114         u32::from_be(self.0.off_dt_strings)
115             .checked_add(u32::from_be(self.0.size_dt_strings))
116             .unwrap() as usize
117     }
118 
119     /// Update the totalsize field.
set_totalsize(&mut self, value: u32)120     pub fn set_totalsize(&mut self, value: u32) {
121         self.0.totalsize = value.to_be();
122     }
123 
124     /// Cast a bytes into a reference of FDT header
from_bytes_ref(buffer: &[u8]) -> Result<&FdtHeader>125     pub fn from_bytes_ref(buffer: &[u8]) -> Result<&FdtHeader> {
126         fdt_check_header(buffer)?;
127 
128         Ok(Ref::<_, FdtHeader>::new_from_prefix(buffer)
129             .ok_or(Error::BufferTooSmall(Some(FDT_HEADER_SIZE)))?
130             .0
131             .into_ref())
132     }
133 
134     /// Cast a bytes into a mutable reference of FDT header.
from_bytes_mut(buffer: &mut [u8]) -> Result<&mut FdtHeader>135     pub fn from_bytes_mut(buffer: &mut [u8]) -> Result<&mut FdtHeader> {
136         fdt_check_header(buffer)?;
137 
138         Ok(Ref::<_, FdtHeader>::new_from_prefix(buffer)
139             .ok_or(Error::BufferTooSmall(Some(FDT_HEADER_SIZE)))?
140             .0
141             .into_mut())
142     }
143 
144     /// Get FDT header and raw bytes from a raw pointer.
145     ///
146     /// Caller should guarantee that
147     ///   1. `ptr` contains a valid FDT.
148     ///   2. The buffer remains valid as long as the returned references are in use.
from_raw(ptr: *const u8) -> Result<(&'static FdtHeader, &'static [u8])>149     pub unsafe fn from_raw(ptr: *const u8) -> Result<(&'static FdtHeader, &'static [u8])> {
150         // SAFETY: By safety requirement of this function, `ptr` points to a valid FDT and remains
151         // valid when in use.
152         unsafe {
153             let header_bytes = from_raw_parts(ptr, FDT_HEADER_SIZE);
154             let header = Self::from_bytes_ref(header_bytes)?;
155             Ok((header, from_raw_parts(ptr, header.totalsize())))
156         }
157     }
158 }
159 
160 /// Object for managing an FDT.
161 pub struct Fdt<T>(T);
162 
163 /// Read only APIs.
164 impl<'a, T: AsRef<[u8]> + 'a> Fdt<T> {
165     /// Creates a new [Fdt] wrapping the contents of `init`.
new(init: T) -> Result<Self>166     pub fn new(init: T) -> Result<Self> {
167         fdt_check_buffer(init.as_ref())?;
168         Ok(Fdt(init))
169     }
170 
171     /// Returns the [FdtHeader], or an error if the underlying buffer was invalid.
header_ref(&self) -> Result<&FdtHeader>172     pub fn header_ref(&self) -> Result<&FdtHeader> {
173         FdtHeader::from_bytes_ref(self.0.as_ref())
174     }
175 
176     /// Returns the totalsize according to FDT header. Trailing free space is included.
size(&self) -> Result<usize>177     pub fn size(&self) -> Result<usize> {
178         Ok(self.header_ref()?.totalsize())
179     }
180 
181     /// Get a property from an existing node.
get_property(&self, path: &str, name: &CStr) -> Result<&'a [u8]>182     pub fn get_property(&self, path: &str, name: &CStr) -> Result<&'a [u8]> {
183         let node = self.find_node(path)?;
184         let mut len: c_int = 0;
185         // SAFETY: API from libfdt_c.
186         let ptr = unsafe {
187             fdt_get_property(
188                 self.0.as_ref().as_ptr() as *const _,
189                 node,
190                 name.to_bytes_with_nul().as_ptr() as *const _,
191                 &mut len as *mut _,
192             )
193         };
194         // SAFETY: Buffer returned by API from libfdt_c.
195         match unsafe { ptr.as_ref() } {
196             // SAFETY: Buffer returned by API from libfdt_c.
197             Some(v) => Ok(unsafe {
198                 from_raw_parts(
199                     v.data.as_ptr() as *const u8,
200                     u32::from_be(v.len).try_into().or(Err(Error::Other(None)))?,
201                 )
202             }),
203             _ => Err(map_result(len).unwrap_err()),
204         }
205     }
206 
207     /// Find the offset of a node by a given node path.
find_node(&self, path: &str) -> Result<c_int>208     fn find_node(&self, path: &str) -> Result<c_int> {
209         let mut curr: c_int = 0;
210         for name in path.split('/') {
211             if name.len() == 0 {
212                 continue;
213             }
214             curr = fdt_subnode_offset(self.0.as_ref(), curr, name)?;
215         }
216         Ok(curr)
217     }
218 }
219 
220 /// APIs when data can be modified.
221 impl<T: AsMut<[u8]> + AsRef<[u8]>> Fdt<T> {
222     /// Creates a new mut [Fdt] wrapping the contents of `init`.
new_mut(init: T) -> Result<Self>223     pub fn new_mut(init: T) -> Result<Self> {
224         let mut fdt = Fdt::new(init)?;
225         let new_size: u32 = fdt.as_mut().len().try_into().or(Err(Error::Other(None)))?;
226         fdt.header_mut()?.set_totalsize(new_size);
227         Ok(fdt)
228     }
229 
230     /// Creates a mutable [Fdt] copied from `init`.
new_from_init(mut fdt: T, init: &[u8]) -> Result<Self>231     pub fn new_from_init(mut fdt: T, init: &[u8]) -> Result<Self> {
232         fdt_check_buffer(init)?;
233         // SAFETY: API from libfdt_c.
234         map_result(unsafe {
235             fdt_move(
236                 init.as_ptr() as *const _,
237                 fdt.as_mut().as_ptr() as *mut _,
238                 fdt.as_mut().len().try_into().or(Err(Error::Other(None)))?,
239             )
240         })?;
241         let new_size: u32 = fdt.as_mut().len().try_into().or(Err(Error::Other(None)))?;
242         let mut ret = Fdt::new(fdt)?;
243         ret.header_mut()?.set_totalsize(new_size);
244         Ok(ret)
245     }
246 
247     /// Parse and get the FDT header.
header_mut(&mut self) -> Result<&mut FdtHeader>248     fn header_mut(&mut self) -> Result<&mut FdtHeader> {
249         FdtHeader::from_bytes_mut(self.0.as_mut())
250     }
251 
252     /// Reduce the total size field in the header to minimum that will fit existing content.
253     /// No more data can be added to the FDT. This should be called after all modification is
254     /// done and before passing to the kernel. This is to prevent kernel hang when FDT size is too
255     /// big.
shrink_to_fit(&mut self) -> Result<()>256     pub fn shrink_to_fit(&mut self) -> Result<()> {
257         let actual = self.header_ref()?.actual_size();
258         self.header_mut()?.set_totalsize(actual.try_into().unwrap());
259         Ok(())
260     }
261 
262     /// Delete node by `path``. Fail if node doesn't exist.
delete_node(&mut self, path: &str) -> Result<()>263     pub fn delete_node(&mut self, path: &str) -> Result<()> {
264         let node = self.find_node(path)?;
265         // SAFETY:
266         // * `self.0` is guaranteed to be a proper fdt header reference
267         // * `node` is offset of the node to delete within `self.0` fdt buffer
268         map_result(unsafe { fdt_del_node(self.0.as_mut().as_mut_ptr() as *mut _, node) })?;
269         Ok(())
270     }
271 
272     /// Set the value of a node's property. Create the node and property if it doesn't exist.
set_property(&mut self, path: &str, name: &CStr, val: &[u8]) -> Result<()>273     pub fn set_property(&mut self, path: &str, name: &CStr, val: &[u8]) -> Result<()> {
274         let node = self.find_or_add_node(path)?;
275         // SAFETY: API from libfdt_c.
276         map_result(unsafe {
277             fdt_setprop(
278                 self.0.as_mut().as_mut_ptr() as *mut _,
279                 node,
280                 name.to_bytes_with_nul().as_ptr() as *const _,
281                 val.as_ptr() as *const _,
282                 val.len().try_into().or(Err(Error::Other(None)))?,
283             )
284         })?;
285         Ok(())
286     }
287 
288     /// Wrapper/equivalent of fdt_setprop_placeholder.
289     /// It creates/resizes a node's property to the given size and returns the buffer for caller
290     /// to modify content.
set_property_placeholder( &mut self, path: &str, name: &CStr, len: usize, ) -> Result<&mut [u8]>291     pub fn set_property_placeholder(
292         &mut self,
293         path: &str,
294         name: &CStr,
295         len: usize,
296     ) -> Result<&mut [u8]> {
297         let node = self.find_or_add_node(path)?;
298         let mut out_ptr: *mut u8 = core::ptr::null_mut();
299         // SAFETY: API from libfdt_c.
300         map_result(unsafe {
301             fdt_setprop_placeholder(
302                 self.0.as_mut().as_mut_ptr() as *mut _,
303                 node,
304                 name.to_bytes_with_nul().as_ptr() as *const _,
305                 len.try_into().or(Err(Error::Other(None)))?,
306                 &mut out_ptr as *mut *mut u8 as *mut _,
307             )
308         })?;
309         assert!(!out_ptr.is_null());
310         // SAFETY: Buffer returned by API from libfdt_c.
311         Ok(unsafe { from_raw_parts_mut(out_ptr, len) })
312     }
313 
314     /// Wrapper/equivalent of ufdt_apply_multioverlay.
315     /// It extend current FDT buffer by applying passed overlays.
multioverlay_apply(&mut self, overlays: &[&[u8]]) -> Result<()>316     pub fn multioverlay_apply(&mut self, overlays: &[&[u8]]) -> Result<()> {
317         // Avoid shrinking device tree or doing any other actions in case nothing to apply.
318         if overlays.is_empty() {
319             return Ok(());
320         }
321         if overlays.len() > MAXIMUM_OVERLAYS_TO_APPLY {
322             return Err(Error::Other(Some(MAXIMUM_OVERLAYS_ERROR_MSG)));
323         }
324 
325         self.shrink_to_fit()?;
326 
327         // Convert input fat references into the raw pointers.
328         let pointers: ArrayVec<_, MAXIMUM_OVERLAYS_TO_APPLY> =
329             overlays.iter().map(|&slice| slice.as_ptr()).collect();
330 
331         // SAFETY: The `ufdt_apply_multioverlay` function guarantees that `self.0` is accessed
332         // within the specified length boundaries. The `pointers` are non-null and are accessed
333         // by indexes only within the provided length.
334         map_result_libufdt(unsafe {
335             ufdt_apply_multioverlay(
336                 self.0.as_mut().as_mut_ptr() as *mut _,
337                 self.0.as_ref().len(),
338                 pointers.as_ptr().cast(),
339                 overlays.len(),
340             )
341         })?;
342 
343         Ok(())
344     }
345 
346     /// Find the offset of a node by a given node path. Add if node does not exist.
find_or_add_node(&mut self, path: &str) -> Result<c_int>347     fn find_or_add_node(&mut self, path: &str) -> Result<c_int> {
348         let mut curr: c_int = 0;
349         for name in path.split('/') {
350             if name.len() == 0 {
351                 continue;
352             }
353             curr = match fdt_subnode_offset(self.0.as_ref(), curr, name) {
354                 Ok(v) => v,
355                 _ => fdt_add_subnode(self.0.as_mut(), curr, name)?,
356             };
357         }
358         Ok(curr)
359     }
360 }
361 
362 impl<T: AsMut<[u8]>> AsMut<[u8]> for Fdt<T> {
as_mut(&mut self) -> &mut [u8]363     fn as_mut(&mut self) -> &mut [u8] {
364         self.0.as_mut()
365     }
366 }
367 
368 impl<T: AsRef<[u8]>> AsRef<[u8]> for Fdt<T> {
as_ref(&self) -> &[u8]369     fn as_ref(&self) -> &[u8] {
370         self.0.as_ref()
371     }
372 }
373 
374 #[cfg(test)]
375 mod test {
376     use super::*;
377 
378     // Fdt is required to be 8 bytes aligned. Buffer to test alignment-related logic.
379     #[repr(align(8))]
380     struct AlignedBytes<const N: usize>([u8; N]);
381 
382     /// Checks to verify `overlay_*_by_path`/`overlay_*_by_reference` are successfully applied
check_overlays_are_applied(fdt: &[u8])383     fn check_overlays_are_applied(fdt: &[u8]) {
384         let fdt = Fdt::new(fdt).unwrap();
385 
386         assert_eq!(
387             CStr::from_bytes_with_nul(
388                 fdt.get_property("/dev-2/dev-2.2/dev-2.2.1", c"property-1").unwrap()
389             )
390             .unwrap()
391             .to_str()
392             .unwrap(),
393             "overlay1-property-1-value",
394             "overlay_modify: failed to modify \"property-1\" in \"/dev-2/dev-2.2/dev-2.2.1\""
395         );
396         assert_eq!(
397             CStr::from_bytes_with_nul(
398                 fdt.get_property("/dev-1/overlay1-new-node", c"overlay1-new-node-property")
399                     .unwrap()
400             )
401             .unwrap()
402             .to_str()
403             .unwrap(),
404             "overlay1-new-node-property-value",
405             "overlay_modify: failed to add \"overlay1-new-node\" to \"/dev-1\""
406         );
407         assert_eq!(
408             CStr::from_bytes_with_nul(
409                 fdt.get_property("/dev-4", c"overlay1-root-node-property").unwrap()
410             )
411             .unwrap()
412             .to_str()
413             .unwrap(),
414             "overlay1-root-node-property-value",
415             "overlay_modify: failed to add \"/dev-4/overlay1-root-node-property\""
416         );
417         assert_eq!(
418             CStr::from_bytes_with_nul(
419                 fdt.get_property("/dev-2/dev-2.2/dev-2.2.1", c"overlay1-new-property").unwrap()
420             )
421             .unwrap()
422             .to_str()
423             .unwrap(),
424             "overlay2-new-property-value",
425             "overlay_modify2: failed to modify \"overlay1-new-property\" in \"/dev-2/dev-2.2/dev-2.2.1\""
426         );
427         assert_eq!(
428             CStr::from_bytes_with_nul(
429                 fdt.get_property("/dev-4", c"overlay2-root-node-property").unwrap()
430             )
431             .unwrap()
432             .to_str()
433             .unwrap(),
434             "overlay2-root-node-property-value",
435             "overlay_modify2: failed to add \"overlay2-root-node-property\" to \"/dev-4\""
436         );
437     }
438 
439     #[test]
test_new_from_invalid_fdt()440     fn test_new_from_invalid_fdt() {
441         let mut init = include_bytes!("../test/data/base.dtb").to_vec();
442         let mut fdt_buf = vec![0u8; init.len()];
443         // Invalid total size
444         assert!(Fdt::new_from_init(&mut fdt_buf[..], &init[..init.len() - 1]).is_err());
445         // Invalid FDT
446         init[..4].fill(0);
447         assert!(Fdt::new_from_init(&mut fdt_buf[..], &init[..]).is_err());
448     }
449 
450     #[test]
test_get_property()451     fn test_get_property() {
452         let init = include_bytes!("../test/data/base.dtb").to_vec();
453         let mut fdt_buf = vec![0u8; init.len()];
454         let fdt = Fdt::new_from_init(&mut fdt_buf[..], &init[..]).unwrap();
455 
456         assert_eq!(
457             CStr::from_bytes_with_nul(fdt.get_property("/", c"info").unwrap())
458                 .unwrap()
459                 .to_str()
460                 .unwrap(),
461             "test device tree"
462         );
463         assert_eq!(
464             CStr::from_bytes_with_nul(
465                 fdt.get_property("/dev-2/dev-2.2/dev-2.2.1", c"property-1").unwrap()
466             )
467             .unwrap()
468             .to_str()
469             .unwrap(),
470             "dev-2.2.1-property-1"
471         );
472 
473         // Non eixsts
474         assert!(fdt.get_property("/", c"non-existent").is_err());
475     }
476 
477     #[test]
test_set_property()478     fn test_set_property() {
479         let init = include_bytes!("../test/data/base.dtb").to_vec();
480         let mut fdt_buf = vec![0u8; init.len() + 512];
481         let mut fdt = Fdt::new_from_init(&mut fdt_buf[..], &init[..]).unwrap();
482         let data = vec![0x11u8, 0x22u8, 0x33u8];
483         fdt.set_property("/new-node", c"custom", &data).unwrap();
484         assert_eq!(fdt.get_property("/new-node", c"custom").unwrap().to_vec(), data);
485     }
486 
487     #[test]
test_delete_node()488     fn test_delete_node() {
489         let init = include_bytes!("../test/data/base.dtb").to_vec();
490         let mut fdt_buf = vec![0u8; init.len()];
491         let mut fdt = Fdt::new_from_init(&mut fdt_buf[..], &init[..]).unwrap();
492 
493         assert_eq!(
494             CStr::from_bytes_with_nul(
495                 fdt.get_property("/dev-2/dev-2.2/dev-2.2.1", c"property-1").unwrap()
496             )
497             .unwrap()
498             .to_str()
499             .unwrap(),
500             "dev-2.2.1-property-1"
501         );
502 
503         fdt.delete_node("dev-2").unwrap();
504 
505         assert!(
506             fdt.get_property("/dev-2/dev-2.2/dev-2.2.1", c"property-1").is_err(),
507             "dev-2.2.1-property-1 expected to be deleted"
508         );
509     }
510 
511     #[test]
test_delete_nost_existed_node_is_failed()512     fn test_delete_nost_existed_node_is_failed() {
513         let init = include_bytes!("../test/data/base.dtb").to_vec();
514         let mut fdt_buf = vec![0u8; init.len()];
515         let mut fdt = Fdt::new_from_init(&mut fdt_buf[..], &init[..]).unwrap();
516 
517         assert!(
518             fdt.delete_node("/non-existent").is_err(),
519             "expected failed to delete non existent node"
520         );
521     }
522 
523     #[test]
test_set_property_placeholder()524     fn test_set_property_placeholder() {
525         let init = include_bytes!("../test/data/base.dtb").to_vec();
526         let mut fdt_buf = vec![0u8; init.len() + 512];
527         let mut fdt = Fdt::new_from_init(&mut fdt_buf[..], &init[..]).unwrap();
528         let data = vec![0x11u8, 0x22u8, 0x33u8, 0x44u8, 0x55u8];
529         let payload = fdt.set_property_placeholder("/new-node", c"custom", data.len()).unwrap();
530         payload.clone_from_slice(&data[..]);
531         assert_eq!(fdt.get_property("/new-node", c"custom").unwrap().to_vec(), data);
532     }
533 
534     #[test]
test_header_from_bytes()535     fn test_header_from_bytes() {
536         let init = include_bytes!("../test/data/base.dtb").to_vec();
537         let header = FdtHeader::from_bytes_ref(&init[..]).unwrap();
538 
539         assert_eq!(header.totalsize(), init.len());
540     }
541 
542     #[test]
test_header_from_bytes_wrong_alignment()543     fn test_header_from_bytes_wrong_alignment() {
544         let init = include_bytes!("../test/data/base.dtb").to_vec();
545 
546         const HEADER_SIZE: usize = size_of::<FdtHeader>();
547         let mut bytes = AlignedBytes([0u8; HEADER_SIZE + 1]);
548 
549         // Guaranteed not to be 8 bytes aligned.
550         let (_, unaligned) = bytes.0.split_at_mut(1);
551         unaligned.copy_from_slice(&init[..HEADER_SIZE]);
552 
553         assert!(FdtHeader::from_bytes_ref(unaligned).is_err());
554     }
555 
556     #[test]
test_header_from_raw()557     fn test_header_from_raw() {
558         let init = include_bytes!("../test/data/base.dtb").to_vec();
559         // Pointer points to `init`
560         let (header, bytes) = unsafe { FdtHeader::from_raw(init.as_ptr()).unwrap() };
561         assert_eq!(header.totalsize(), init.len());
562         assert_eq!(bytes.to_vec(), init);
563     }
564 
565     #[test]
test_header_from_raw_invalid()566     fn test_header_from_raw_invalid() {
567         let mut init = include_bytes!("../test/data/base.dtb").to_vec();
568         init[..4].fill(0);
569         // Pointer points to `init`
570         assert!(unsafe { FdtHeader::from_raw(init.as_ptr()).is_err() });
571     }
572 
573     #[test]
test_fdt_shrink_to_fit()574     fn test_fdt_shrink_to_fit() {
575         let init = include_bytes!("../test/data/base.dtb").to_vec();
576         let mut fdt_buf = vec![0u8; init.len() + 512];
577         let fdt_buf_len = fdt_buf.len();
578         let mut fdt = Fdt::new_from_init(&mut fdt_buf[..], &init[..]).unwrap();
579         assert_eq!(fdt.size().unwrap(), fdt_buf_len);
580         fdt.shrink_to_fit().unwrap();
581         assert_eq!(fdt.size().unwrap(), init.len());
582     }
583 
584     #[test]
test_fdt_multioverlay_apply_by_path()585     fn test_fdt_multioverlay_apply_by_path() {
586         let base = include_bytes!("../test/data/base.dtb").to_vec();
587         let overlay_modify = include_bytes!("../test/data/overlay_by_path.dtbo").to_vec();
588         let overlay_modify2 = include_bytes!("../test/data/overlay_2_by_path.dtbo").to_vec();
589 
590         let mut fdt_buf = vec![0u8; base.len() + overlay_modify.len() + overlay_modify2.len()];
591         let mut fdt = Fdt::new_from_init(&mut fdt_buf[..], &base[..]).unwrap();
592 
593         fdt.multioverlay_apply(&[&overlay_modify[..] as _, &overlay_modify2[..] as _]).unwrap();
594         fdt.shrink_to_fit().unwrap();
595 
596         check_overlays_are_applied(fdt.0);
597     }
598 
599     #[test]
test_fdt_multioverlay_apply_by_path_separately()600     fn test_fdt_multioverlay_apply_by_path_separately() {
601         let base = include_bytes!("../test/data/base.dtb").to_vec();
602         let overlay_modify = include_bytes!("../test/data/overlay_by_path.dtbo").to_vec();
603         let overlay_modify2 = include_bytes!("../test/data/overlay_2_by_path.dtbo").to_vec();
604 
605         let mut fdt_buf = vec![0u8; base.len() + overlay_modify.len() + overlay_modify2.len()];
606         let mut fdt = Fdt::new_from_init(&mut fdt_buf[..], &base[..]).unwrap();
607 
608         fdt.multioverlay_apply(&[&overlay_modify[..] as _]).unwrap();
609         fdt.multioverlay_apply(&[&overlay_modify2[..] as _]).unwrap();
610         fdt.shrink_to_fit().unwrap();
611 
612         check_overlays_are_applied(fdt.0);
613     }
614 
615     // TODO(b/362486327): symbols from overlay are not added to the result tree
616     // so cannot refer to them.
617     #[ignore]
618     #[test]
test_fdt_multioverlay_apply_by_reference()619     fn test_fdt_multioverlay_apply_by_reference() {
620         let base = include_bytes!("../test/data/base.dtb").to_vec();
621         let overlay_modify = include_bytes!("../test/data/overlay_by_reference.dtbo").to_vec();
622         let overlay_modify2 = include_bytes!("../test/data/overlay_2_by_reference.dtbo").to_vec();
623 
624         let mut fdt_buf = vec![0u8; base.len() + overlay_modify.len() + overlay_modify2.len()];
625         let mut fdt = Fdt::new_from_init(&mut fdt_buf[..], &base[..]).unwrap();
626 
627         fdt.multioverlay_apply(&[&overlay_modify[..] as _, &overlay_modify2[..] as _]).unwrap();
628         fdt.shrink_to_fit().unwrap();
629 
630         check_overlays_are_applied(fdt.0);
631     }
632 
633     // TODO(b/362486327): symbols from overlay are not added to the result tree
634     // so cannot refer to them.
635     #[ignore]
636     #[test]
test_fdt_multioverlay_apply_by_reference_separately()637     fn test_fdt_multioverlay_apply_by_reference_separately() {
638         let base = include_bytes!("../test/data/base.dtb").to_vec();
639         let overlay_modify = include_bytes!("../test/data/overlay_by_reference.dtbo").to_vec();
640         let overlay_modify2 = include_bytes!("../test/data/overlay_2_by_reference.dtbo").to_vec();
641 
642         let mut fdt_buf = vec![0u8; base.len() + overlay_modify.len() + overlay_modify2.len()];
643         let mut fdt = Fdt::new_from_init(&mut fdt_buf[..], &base[..]).unwrap();
644 
645         fdt.multioverlay_apply(&[&overlay_modify[..] as _]).unwrap();
646         fdt.multioverlay_apply(&[&overlay_modify2[..] as _]).unwrap();
647         fdt.shrink_to_fit().unwrap();
648 
649         check_overlays_are_applied(fdt.0);
650     }
651 
652     #[test]
test_fdt_multioverlay_apply_not_enough_space()653     fn test_fdt_multioverlay_apply_not_enough_space() {
654         let init = include_bytes!("../test/data/base.dtb").to_vec();
655         let overlay_basic = include_bytes!("../test/data/overlay_by_path.dtbo").to_vec();
656 
657         let mut fdt_buf = vec![0u8; init.len()];
658         let mut fdt = Fdt::new_from_init(&mut fdt_buf[..], &init[..]).unwrap();
659 
660         assert!(
661             fdt.multioverlay_apply(&[&overlay_basic[..]]).is_err(),
662             "expected the problem is catched when not enough space in the main fdt buffer"
663         );
664     }
665 
666     #[test]
test_fdt_multioverlay_apply_corrupted()667     fn test_fdt_multioverlay_apply_corrupted() {
668         let init = include_bytes!("../test/data/base.dtb").to_vec();
669         let overlay_corrupted: Vec<u8> = include_bytes!("../test/data/overlay_by_path.dtbo")
670             .to_vec()
671             .iter()
672             .copied()
673             .rev()
674             .collect();
675 
676         let mut fdt_buf = vec![0u8; init.len() + overlay_corrupted.len()];
677         let mut fdt = Fdt::new_from_init(&mut fdt_buf[..], &init[..]).unwrap();
678 
679         assert!(
680             fdt.multioverlay_apply(&[&overlay_corrupted[..]]).is_err(),
681             "expected the problem is catched when applying corrupted overlay"
682         );
683     }
684 
685     #[test]
test_fdt_multioverlay_apply_with_wrong_target_path()686     fn test_fdt_multioverlay_apply_with_wrong_target_path() {
687         let init = include_bytes!("../test/data/base.dtb").to_vec();
688         let overlay_wrong_path = include_bytes!("../test/data/overlay_wrong_path.dtbo").to_vec();
689 
690         let mut fdt_buf = vec![0u8; init.len()];
691         let mut fdt = Fdt::new_from_init(&mut fdt_buf[..], &init[..]).unwrap();
692 
693         assert!(
694             fdt.multioverlay_apply(&[&overlay_wrong_path[..]]).is_err(),
695             "expected the problem is catched when applying overlay with wrong target path"
696         );
697     }
698 
699     #[test]
test_fdt_multioverlay_apply_maximum_amount_of_overlays_handled()700     fn test_fdt_multioverlay_apply_maximum_amount_of_overlays_handled() {
701         let init = include_bytes!("../test/data/base.dtb").to_vec();
702         let too_many_overlays = &[&[] as &[u8]; MAXIMUM_OVERLAYS_TO_APPLY + 1];
703 
704         let mut fdt_buf = vec![0u8; init.len()];
705         let mut fdt = Fdt::new_from_init(&mut fdt_buf[..], &init[..]).unwrap();
706 
707         assert_eq!(
708             fdt.multioverlay_apply(too_many_overlays),
709             Err(Error::Other(Some(MAXIMUM_OVERLAYS_ERROR_MSG))),
710             "too many overlays isn't handled"
711         );
712     }
713 }
714