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