xref: /aosp_15_r20/bootable/libbootloader/gbl/libgbl/src/device_tree.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
1*5225e6b1SAndroid Build Coastguard Worker // Copyright 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 //! GblOps trait that defines device tree components helpers.
16*5225e6b1SAndroid Build Coastguard Worker 
17*5225e6b1SAndroid Build Coastguard Worker use crate::{gbl_print, gbl_println, GblOps};
18*5225e6b1SAndroid Build Coastguard Worker use arrayvec::ArrayVec;
19*5225e6b1SAndroid Build Coastguard Worker use dttable::{DtTableImage, DtTableMetadata};
20*5225e6b1SAndroid Build Coastguard Worker use fdt::{Fdt, FdtHeader, FDT_HEADER_SIZE};
21*5225e6b1SAndroid Build Coastguard Worker use liberror::{Error, Result};
22*5225e6b1SAndroid Build Coastguard Worker use libutils::aligned_subslice;
23*5225e6b1SAndroid Build Coastguard Worker 
24*5225e6b1SAndroid Build Coastguard Worker /// Device tree alignment.
25*5225e6b1SAndroid Build Coastguard Worker pub const FDT_ALIGNMENT: usize = 8;
26*5225e6b1SAndroid Build Coastguard Worker /// Maximum amount of device tree components GBL can handle to select from.
27*5225e6b1SAndroid Build Coastguard Worker /// TODO(b/353272981): Use dynamic memory to store components. Currently
28*5225e6b1SAndroid Build Coastguard Worker /// DeviceTreeComponentsRegistry takes about 18kb of stack, which can be slow and dangerous.
29*5225e6b1SAndroid Build Coastguard Worker pub const MAXIMUM_DEVICE_TREE_COMPONENTS: usize = 256;
30*5225e6b1SAndroid Build Coastguard Worker /// Error message to fail in case of unsupported amount of device tree components.
31*5225e6b1SAndroid Build Coastguard Worker pub const MAXIMUM_DEVICE_TREE_COMPONENTS_ERROR_MSG: &str =
32*5225e6b1SAndroid Build Coastguard Worker     "At most 256 device components are supported to build the final one";
33*5225e6b1SAndroid Build Coastguard Worker 
34*5225e6b1SAndroid Build Coastguard Worker /// The source device tree component is coming from.
35*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, Eq, PartialEq, Debug)]
36*5225e6b1SAndroid Build Coastguard Worker pub enum DeviceTreeComponentSource {
37*5225e6b1SAndroid Build Coastguard Worker     /// Loaded from Boot partition.
38*5225e6b1SAndroid Build Coastguard Worker     Boot,
39*5225e6b1SAndroid Build Coastguard Worker     /// Loaded from Vendor Boot partition.
40*5225e6b1SAndroid Build Coastguard Worker     VendorBoot,
41*5225e6b1SAndroid Build Coastguard Worker     /// Loaded from DTB partition.
42*5225e6b1SAndroid Build Coastguard Worker     Dtb(DtTableMetadata),
43*5225e6b1SAndroid Build Coastguard Worker     /// Loaded from DTBO partition.
44*5225e6b1SAndroid Build Coastguard Worker     Dtbo(DtTableMetadata),
45*5225e6b1SAndroid Build Coastguard Worker }
46*5225e6b1SAndroid Build Coastguard Worker 
47*5225e6b1SAndroid Build Coastguard Worker impl core::fmt::Display for DeviceTreeComponentSource {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result48*5225e6b1SAndroid Build Coastguard Worker     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
49*5225e6b1SAndroid Build Coastguard Worker         match self {
50*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Boot => write!(f, "Boot"),
51*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::VendorBoot => write!(f, "VendorBoot"),
52*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Dtb(_) => write!(f, "Dtb"),
53*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Dtbo(_) => write!(f, "Dtbo"),
54*5225e6b1SAndroid Build Coastguard Worker         }
55*5225e6b1SAndroid Build Coastguard Worker     }
56*5225e6b1SAndroid Build Coastguard Worker }
57*5225e6b1SAndroid Build Coastguard Worker 
58*5225e6b1SAndroid Build Coastguard Worker /// Device tree component (device tree or overlay) to build the final one.
59*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, Eq, PartialEq, Debug)]
60*5225e6b1SAndroid Build Coastguard Worker pub struct DeviceTreeComponent<'a> {
61*5225e6b1SAndroid Build Coastguard Worker     /// Source the component is loaded from.
62*5225e6b1SAndroid Build Coastguard Worker     pub source: DeviceTreeComponentSource,
63*5225e6b1SAndroid Build Coastguard Worker     /// Device tree component payload. Must be 8 bytes aligned.
64*5225e6b1SAndroid Build Coastguard Worker     pub dt: &'a [u8],
65*5225e6b1SAndroid Build Coastguard Worker     /// Device tree component is selected.
66*5225e6b1SAndroid Build Coastguard Worker     pub selected: bool,
67*5225e6b1SAndroid Build Coastguard Worker }
68*5225e6b1SAndroid Build Coastguard Worker 
69*5225e6b1SAndroid Build Coastguard Worker /// Maintain, select and get the device tree components to build the final device tree.
70*5225e6b1SAndroid Build Coastguard Worker pub struct DeviceTreeComponentsRegistry<'a> {
71*5225e6b1SAndroid Build Coastguard Worker     components: ArrayVec<DeviceTreeComponent<'a>, MAXIMUM_DEVICE_TREE_COMPONENTS>,
72*5225e6b1SAndroid Build Coastguard Worker     /// `selected_overlays` array is used to return selected overlays as a sequential reference
73*5225e6b1SAndroid Build Coastguard Worker     /// slice. It must only be used within the `selected()` method and must not be assumed
74*5225e6b1SAndroid Build Coastguard Worker     /// valid elsewhere.
75*5225e6b1SAndroid Build Coastguard Worker     selected_overlays: ArrayVec<&'a [u8], MAXIMUM_DEVICE_TREE_COMPONENTS>,
76*5225e6b1SAndroid Build Coastguard Worker }
77*5225e6b1SAndroid Build Coastguard Worker 
78*5225e6b1SAndroid Build Coastguard Worker impl<'a> DeviceTreeComponent<'a> {
79*5225e6b1SAndroid Build Coastguard Worker     /// Whether device tree component is base device tree or overlay.
is_base_device_tree(&self) -> bool80*5225e6b1SAndroid Build Coastguard Worker     pub fn is_base_device_tree(&self) -> bool {
81*5225e6b1SAndroid Build Coastguard Worker         matches!(
82*5225e6b1SAndroid Build Coastguard Worker             self.source,
83*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Boot
84*5225e6b1SAndroid Build Coastguard Worker                 | DeviceTreeComponentSource::VendorBoot
85*5225e6b1SAndroid Build Coastguard Worker                 | DeviceTreeComponentSource::Dtb(_)
86*5225e6b1SAndroid Build Coastguard Worker         )
87*5225e6b1SAndroid Build Coastguard Worker     }
88*5225e6b1SAndroid Build Coastguard Worker }
89*5225e6b1SAndroid Build Coastguard Worker 
90*5225e6b1SAndroid Build Coastguard Worker impl<'a> DeviceTreeComponentsRegistry<'a> {
91*5225e6b1SAndroid Build Coastguard Worker     /// Create new empty DeviceTreeComponentsRegistry.
new() -> Self92*5225e6b1SAndroid Build Coastguard Worker     pub fn new() -> Self {
93*5225e6b1SAndroid Build Coastguard Worker         DeviceTreeComponentsRegistry {
94*5225e6b1SAndroid Build Coastguard Worker             components: ArrayVec::new(),
95*5225e6b1SAndroid Build Coastguard Worker             selected_overlays: ArrayVec::new(),
96*5225e6b1SAndroid Build Coastguard Worker         }
97*5225e6b1SAndroid Build Coastguard Worker     }
98*5225e6b1SAndroid Build Coastguard Worker 
99*5225e6b1SAndroid Build Coastguard Worker     /// Load device tree components from a dt table image. Ensure components are 8 bytes
100*5225e6b1SAndroid Build Coastguard Worker     /// aligned by using provided buffer to cut from. Returns remain buffer.
append_from_dttable<'b>( &mut self, is_dtb: bool, dttable: &DtTableImage<'b>, buffer: &'a mut [u8], ) -> Result<&'a mut [u8]>101*5225e6b1SAndroid Build Coastguard Worker     fn append_from_dttable<'b>(
102*5225e6b1SAndroid Build Coastguard Worker         &mut self,
103*5225e6b1SAndroid Build Coastguard Worker         is_dtb: bool,
104*5225e6b1SAndroid Build Coastguard Worker         dttable: &DtTableImage<'b>,
105*5225e6b1SAndroid Build Coastguard Worker         buffer: &'a mut [u8],
106*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<&'a mut [u8]> {
107*5225e6b1SAndroid Build Coastguard Worker         if dttable.entries_count() > self.components.remaining_capacity() {
108*5225e6b1SAndroid Build Coastguard Worker             return Err(Error::Other(Some(MAXIMUM_DEVICE_TREE_COMPONENTS_ERROR_MSG)));
109*5225e6b1SAndroid Build Coastguard Worker         }
110*5225e6b1SAndroid Build Coastguard Worker 
111*5225e6b1SAndroid Build Coastguard Worker         let mut remains = buffer;
112*5225e6b1SAndroid Build Coastguard Worker         for entry in dttable.entries() {
113*5225e6b1SAndroid Build Coastguard Worker             // TODO(b/374336105): Find a better way to handle 8-bytes alignment rather than copy.
114*5225e6b1SAndroid Build Coastguard Worker             let (aligned_buffer, rest) = aligned_subslice(remains, FDT_ALIGNMENT)?
115*5225e6b1SAndroid Build Coastguard Worker                 .split_at_mut_checked(entry.dtb.len())
116*5225e6b1SAndroid Build Coastguard Worker                 .ok_or(Error::Other(Some(
117*5225e6b1SAndroid Build Coastguard Worker                     "Provided buffer is too small to ensure dttable entry is aligned",
118*5225e6b1SAndroid Build Coastguard Worker                 )))?;
119*5225e6b1SAndroid Build Coastguard Worker             aligned_buffer.copy_from_slice(entry.dtb);
120*5225e6b1SAndroid Build Coastguard Worker 
121*5225e6b1SAndroid Build Coastguard Worker             self.components.push(DeviceTreeComponent {
122*5225e6b1SAndroid Build Coastguard Worker                 source: if is_dtb {
123*5225e6b1SAndroid Build Coastguard Worker                     DeviceTreeComponentSource::Dtb(entry.metadata)
124*5225e6b1SAndroid Build Coastguard Worker                 } else {
125*5225e6b1SAndroid Build Coastguard Worker                     DeviceTreeComponentSource::Dtbo(entry.metadata)
126*5225e6b1SAndroid Build Coastguard Worker                 },
127*5225e6b1SAndroid Build Coastguard Worker                 dt: aligned_buffer,
128*5225e6b1SAndroid Build Coastguard Worker                 selected: false,
129*5225e6b1SAndroid Build Coastguard Worker             });
130*5225e6b1SAndroid Build Coastguard Worker 
131*5225e6b1SAndroid Build Coastguard Worker             remains = rest;
132*5225e6b1SAndroid Build Coastguard Worker         }
133*5225e6b1SAndroid Build Coastguard Worker 
134*5225e6b1SAndroid Build Coastguard Worker         Ok(remains)
135*5225e6b1SAndroid Build Coastguard Worker     }
136*5225e6b1SAndroid Build Coastguard Worker 
137*5225e6b1SAndroid Build Coastguard Worker     /// Load device tree components from a dtbo image. Ensure components are 8 bytes
138*5225e6b1SAndroid Build Coastguard Worker     /// aligned by using provided `buffer` to cut from. Returns remain buffer.
append_from_dtbo<'b>( &mut self, dttable: &DtTableImage<'b>, buffer: &'a mut [u8], ) -> Result<&'a mut [u8]>139*5225e6b1SAndroid Build Coastguard Worker     pub fn append_from_dtbo<'b>(
140*5225e6b1SAndroid Build Coastguard Worker         &mut self,
141*5225e6b1SAndroid Build Coastguard Worker         dttable: &DtTableImage<'b>,
142*5225e6b1SAndroid Build Coastguard Worker         buffer: &'a mut [u8],
143*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<&'a mut [u8]> {
144*5225e6b1SAndroid Build Coastguard Worker         self.append_from_dttable(false, dttable, buffer)
145*5225e6b1SAndroid Build Coastguard Worker     }
146*5225e6b1SAndroid Build Coastguard Worker 
147*5225e6b1SAndroid Build Coastguard Worker     /// Append additional device trees from the buffer, where they are stored sequentially.
148*5225e6b1SAndroid Build Coastguard Worker     /// Ensure components are 8 bytes aligned by using provided buffer to cut from. Returns remain
149*5225e6b1SAndroid Build Coastguard Worker     /// buffer.
150*5225e6b1SAndroid Build Coastguard Worker     /// TODO(b/363244924): Remove after partners migrated to DTB.
append_from_multifdt_buffer<'b, 'c>( &mut self, ops: &mut impl GblOps<'b, 'c>, source: DeviceTreeComponentSource, data: &'a [u8], buffer: &'a mut [u8], ) -> Result<&'a mut [u8]>151*5225e6b1SAndroid Build Coastguard Worker     fn append_from_multifdt_buffer<'b, 'c>(
152*5225e6b1SAndroid Build Coastguard Worker         &mut self,
153*5225e6b1SAndroid Build Coastguard Worker         ops: &mut impl GblOps<'b, 'c>,
154*5225e6b1SAndroid Build Coastguard Worker         source: DeviceTreeComponentSource,
155*5225e6b1SAndroid Build Coastguard Worker         data: &'a [u8],
156*5225e6b1SAndroid Build Coastguard Worker         buffer: &'a mut [u8],
157*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<&'a mut [u8]> {
158*5225e6b1SAndroid Build Coastguard Worker         let mut components_added = 0;
159*5225e6b1SAndroid Build Coastguard Worker         let mut data_remains = data;
160*5225e6b1SAndroid Build Coastguard Worker         let mut buffer_remains = buffer;
161*5225e6b1SAndroid Build Coastguard Worker         while data_remains.len() >= FDT_HEADER_SIZE {
162*5225e6b1SAndroid Build Coastguard Worker             let aligned_buffer = aligned_subslice(buffer_remains, FDT_ALIGNMENT)?;
163*5225e6b1SAndroid Build Coastguard Worker 
164*5225e6b1SAndroid Build Coastguard Worker             let header_slice = aligned_buffer.get_mut(..FDT_HEADER_SIZE).ok_or(Error::Other(
165*5225e6b1SAndroid Build Coastguard Worker                 Some("Provided buffer is too small to ensure multidt entry is aligned"),
166*5225e6b1SAndroid Build Coastguard Worker             ))?;
167*5225e6b1SAndroid Build Coastguard Worker             // Fdt header must be aligned, so copy to an aligned buffer.
168*5225e6b1SAndroid Build Coastguard Worker             header_slice.copy_from_slice(&data_remains[..FDT_HEADER_SIZE]);
169*5225e6b1SAndroid Build Coastguard Worker             let next_fdt_size = FdtHeader::from_bytes_ref(header_slice)?.totalsize();
170*5225e6b1SAndroid Build Coastguard Worker 
171*5225e6b1SAndroid Build Coastguard Worker             if self.components.is_full() {
172*5225e6b1SAndroid Build Coastguard Worker                 return Err(Error::Other(Some(MAXIMUM_DEVICE_TREE_COMPONENTS_ERROR_MSG)));
173*5225e6b1SAndroid Build Coastguard Worker             }
174*5225e6b1SAndroid Build Coastguard Worker 
175*5225e6b1SAndroid Build Coastguard Worker             // Cut fdt and temporary buffers to make sure result fdt is 8 bytes aligned
176*5225e6b1SAndroid Build Coastguard Worker             let (data_buffer, data_buffer_remains) =
177*5225e6b1SAndroid Build Coastguard Worker                 data_remains.split_at_checked(next_fdt_size).ok_or(Error::Other(Some(
178*5225e6b1SAndroid Build Coastguard Worker                     "Multidt structure has a valid header but doesn't have a device tree payload",
179*5225e6b1SAndroid Build Coastguard Worker                 )))?;
180*5225e6b1SAndroid Build Coastguard Worker             let (aligned_buffer, aligned_buffer_remains) =
181*5225e6b1SAndroid Build Coastguard Worker                 aligned_buffer.split_at_mut_checked(next_fdt_size).ok_or(Error::Other(Some(
182*5225e6b1SAndroid Build Coastguard Worker                     "Provided buffer is too small to ensure multidt entry is aligned",
183*5225e6b1SAndroid Build Coastguard Worker                 )))?;
184*5225e6b1SAndroid Build Coastguard Worker             aligned_buffer.copy_from_slice(data_buffer);
185*5225e6b1SAndroid Build Coastguard Worker 
186*5225e6b1SAndroid Build Coastguard Worker             Fdt::new(&aligned_buffer)?;
187*5225e6b1SAndroid Build Coastguard Worker             self.components.push(DeviceTreeComponent {
188*5225e6b1SAndroid Build Coastguard Worker                 source: source,
189*5225e6b1SAndroid Build Coastguard Worker                 dt: &aligned_buffer[..],
190*5225e6b1SAndroid Build Coastguard Worker                 selected: false,
191*5225e6b1SAndroid Build Coastguard Worker             });
192*5225e6b1SAndroid Build Coastguard Worker 
193*5225e6b1SAndroid Build Coastguard Worker             components_added += 1;
194*5225e6b1SAndroid Build Coastguard Worker             data_remains = data_buffer_remains;
195*5225e6b1SAndroid Build Coastguard Worker             buffer_remains = aligned_buffer_remains;
196*5225e6b1SAndroid Build Coastguard Worker         }
197*5225e6b1SAndroid Build Coastguard Worker 
198*5225e6b1SAndroid Build Coastguard Worker         if components_added > 0 {
199*5225e6b1SAndroid Build Coastguard Worker             gbl_println!(
200*5225e6b1SAndroid Build Coastguard Worker                 ops,
201*5225e6b1SAndroid Build Coastguard Worker                 "WARNING: {} additional device trees detected in {}. This is only temporarily \
202*5225e6b1SAndroid Build Coastguard Worker                 supported in GBL. Please migrate to the DTB partition to provide multiple device \
203*5225e6b1SAndroid Build Coastguard Worker                 trees for selection.",
204*5225e6b1SAndroid Build Coastguard Worker                 components_added,
205*5225e6b1SAndroid Build Coastguard Worker                 source,
206*5225e6b1SAndroid Build Coastguard Worker             );
207*5225e6b1SAndroid Build Coastguard Worker         }
208*5225e6b1SAndroid Build Coastguard Worker 
209*5225e6b1SAndroid Build Coastguard Worker         Ok(buffer_remains)
210*5225e6b1SAndroid Build Coastguard Worker     }
211*5225e6b1SAndroid Build Coastguard Worker 
212*5225e6b1SAndroid Build Coastguard Worker     /// Append device tree components from provided buffer prefix. `fdt` must be a 8 bytes aligned
213*5225e6b1SAndroid Build Coastguard Worker     /// valid fdt buffer. `fdt` may also have multiple fdt buffers placed sequentially. Ensure each
214*5225e6b1SAndroid Build Coastguard Worker     /// of such components are 8 bytes aligned by using provided `buffer` to cut from. Returns
215*5225e6b1SAndroid Build Coastguard Worker     /// remain buffer.
216*5225e6b1SAndroid Build Coastguard Worker     /// TODO(b/363244924): Remove multiple fdt support after partners migrated to DTB.
append<'b, 'c>( &mut self, ops: &mut impl GblOps<'b, 'c>, source: DeviceTreeComponentSource, fdt: &'a [u8], buffer: &'a mut [u8], ) -> Result<&'a mut [u8]>217*5225e6b1SAndroid Build Coastguard Worker     pub fn append<'b, 'c>(
218*5225e6b1SAndroid Build Coastguard Worker         &mut self,
219*5225e6b1SAndroid Build Coastguard Worker         ops: &mut impl GblOps<'b, 'c>,
220*5225e6b1SAndroid Build Coastguard Worker         source: DeviceTreeComponentSource,
221*5225e6b1SAndroid Build Coastguard Worker         fdt: &'a [u8],
222*5225e6b1SAndroid Build Coastguard Worker         buffer: &'a mut [u8],
223*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<&'a mut [u8]> {
224*5225e6b1SAndroid Build Coastguard Worker         if self.components.is_full() {
225*5225e6b1SAndroid Build Coastguard Worker             return Err(Error::Other(Some(MAXIMUM_DEVICE_TREE_COMPONENTS_ERROR_MSG)));
226*5225e6b1SAndroid Build Coastguard Worker         }
227*5225e6b1SAndroid Build Coastguard Worker 
228*5225e6b1SAndroid Build Coastguard Worker         let header = FdtHeader::from_bytes_ref(fdt)?;
229*5225e6b1SAndroid Build Coastguard Worker         let (fdt_buffer, fdt_remains) = fdt.split_at(header.totalsize());
230*5225e6b1SAndroid Build Coastguard Worker         self.components.push(DeviceTreeComponent {
231*5225e6b1SAndroid Build Coastguard Worker             source: source,
232*5225e6b1SAndroid Build Coastguard Worker             dt: fdt_buffer,
233*5225e6b1SAndroid Build Coastguard Worker             selected: false,
234*5225e6b1SAndroid Build Coastguard Worker         });
235*5225e6b1SAndroid Build Coastguard Worker 
236*5225e6b1SAndroid Build Coastguard Worker         // TODO(b/363244924): Remove after partners migrated to DTB.
237*5225e6b1SAndroid Build Coastguard Worker         self.append_from_multifdt_buffer(ops, source, fdt_remains, buffer)
238*5225e6b1SAndroid Build Coastguard Worker     }
239*5225e6b1SAndroid Build Coastguard Worker 
240*5225e6b1SAndroid Build Coastguard Worker     /// Default implementation of selected logic in case external one isn't provided.
241*5225e6b1SAndroid Build Coastguard Worker     /// Only base device tree is supported to choose from. Otherwise fail. No overlays will be
242*5225e6b1SAndroid Build Coastguard Worker     /// selected.
autoselect(&mut self) -> Result<()>243*5225e6b1SAndroid Build Coastguard Worker     pub fn autoselect(&mut self) -> Result<()> {
244*5225e6b1SAndroid Build Coastguard Worker         let base_device_tree_count =
245*5225e6b1SAndroid Build Coastguard Worker             self.components.iter().filter(|component| component.is_base_device_tree()).count();
246*5225e6b1SAndroid Build Coastguard Worker         if base_device_tree_count > 1 {
247*5225e6b1SAndroid Build Coastguard Worker             return Err(Error::Other(Some(
248*5225e6b1SAndroid Build Coastguard Worker                 "Base device tree autoselection isn't supported if multiple device trees are \
249*5225e6b1SAndroid Build Coastguard Worker                 provided",
250*5225e6b1SAndroid Build Coastguard Worker             )));
251*5225e6b1SAndroid Build Coastguard Worker         }
252*5225e6b1SAndroid Build Coastguard Worker 
253*5225e6b1SAndroid Build Coastguard Worker         let base = self
254*5225e6b1SAndroid Build Coastguard Worker             .components
255*5225e6b1SAndroid Build Coastguard Worker             .iter_mut()
256*5225e6b1SAndroid Build Coastguard Worker             .find(|component| component.is_base_device_tree())
257*5225e6b1SAndroid Build Coastguard Worker             .ok_or(Error::Other(Some("0 base device trees to autoselect from")))?;
258*5225e6b1SAndroid Build Coastguard Worker         base.selected = true;
259*5225e6b1SAndroid Build Coastguard Worker 
260*5225e6b1SAndroid Build Coastguard Worker         Ok(())
261*5225e6b1SAndroid Build Coastguard Worker     }
262*5225e6b1SAndroid Build Coastguard Worker 
263*5225e6b1SAndroid Build Coastguard Worker     /// Return selected base device tree and overlays to apply. Fail in case selection isn't
264*5225e6b1SAndroid Build Coastguard Worker     /// correct. For correctness rules refer to `GblOps.select_device_trees` requirements.
selected(&mut self) -> Result<(&[u8], &[&[u8]])>265*5225e6b1SAndroid Build Coastguard Worker     pub fn selected(&mut self) -> Result<(&[u8], &[&[u8]])> {
266*5225e6b1SAndroid Build Coastguard Worker         let base_device_tree_count = self
267*5225e6b1SAndroid Build Coastguard Worker             .components
268*5225e6b1SAndroid Build Coastguard Worker             .iter()
269*5225e6b1SAndroid Build Coastguard Worker             .filter(|component| component.is_base_device_tree() && component.selected)
270*5225e6b1SAndroid Build Coastguard Worker             .count();
271*5225e6b1SAndroid Build Coastguard Worker         if base_device_tree_count > 1 {
272*5225e6b1SAndroid Build Coastguard Worker             return Err(Error::Other(Some("More than 1 base device tree is selected")));
273*5225e6b1SAndroid Build Coastguard Worker         }
274*5225e6b1SAndroid Build Coastguard Worker 
275*5225e6b1SAndroid Build Coastguard Worker         let base = self
276*5225e6b1SAndroid Build Coastguard Worker             .components
277*5225e6b1SAndroid Build Coastguard Worker             .iter()
278*5225e6b1SAndroid Build Coastguard Worker             .find(|component| component.is_base_device_tree() && component.selected)
279*5225e6b1SAndroid Build Coastguard Worker             .ok_or(Error::Other(Some("0 base device trees are selected")))?;
280*5225e6b1SAndroid Build Coastguard Worker 
281*5225e6b1SAndroid Build Coastguard Worker         self.selected_overlays = self
282*5225e6b1SAndroid Build Coastguard Worker             .components
283*5225e6b1SAndroid Build Coastguard Worker             .iter()
284*5225e6b1SAndroid Build Coastguard Worker             .filter(|component| !component.is_base_device_tree() && component.selected)
285*5225e6b1SAndroid Build Coastguard Worker             .map(|component| component.dt)
286*5225e6b1SAndroid Build Coastguard Worker             .collect();
287*5225e6b1SAndroid Build Coastguard Worker 
288*5225e6b1SAndroid Build Coastguard Worker         Ok((base.dt, &self.selected_overlays[..]))
289*5225e6b1SAndroid Build Coastguard Worker     }
290*5225e6b1SAndroid Build Coastguard Worker 
291*5225e6b1SAndroid Build Coastguard Worker     /// Iterator over components.
components(&self) -> impl Iterator<Item = &DeviceTreeComponent<'a>>292*5225e6b1SAndroid Build Coastguard Worker     pub fn components(&self) -> impl Iterator<Item = &DeviceTreeComponent<'a>> {
293*5225e6b1SAndroid Build Coastguard Worker         self.components.iter()
294*5225e6b1SAndroid Build Coastguard Worker     }
295*5225e6b1SAndroid Build Coastguard Worker 
296*5225e6b1SAndroid Build Coastguard Worker     /// Mutable iterator over components.
components_mut(&mut self) -> impl Iterator<Item = &mut DeviceTreeComponent<'a>>297*5225e6b1SAndroid Build Coastguard Worker     pub fn components_mut(&mut self) -> impl Iterator<Item = &mut DeviceTreeComponent<'a>> {
298*5225e6b1SAndroid Build Coastguard Worker         self.components.iter_mut()
299*5225e6b1SAndroid Build Coastguard Worker     }
300*5225e6b1SAndroid Build Coastguard Worker }
301*5225e6b1SAndroid Build Coastguard Worker 
302*5225e6b1SAndroid Build Coastguard Worker #[cfg(test)]
303*5225e6b1SAndroid Build Coastguard Worker pub(crate) mod test {
304*5225e6b1SAndroid Build Coastguard Worker     use super::*;
305*5225e6b1SAndroid Build Coastguard Worker     use crate::ops::test::FakeGblOps;
306*5225e6b1SAndroid Build Coastguard Worker 
307*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_components_registry_empty()308*5225e6b1SAndroid Build Coastguard Worker     fn test_components_registry_empty() {
309*5225e6b1SAndroid Build Coastguard Worker         let registry = DeviceTreeComponentsRegistry::new();
310*5225e6b1SAndroid Build Coastguard Worker 
311*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(registry.components().count(), 0);
312*5225e6b1SAndroid Build Coastguard Worker     }
313*5225e6b1SAndroid Build Coastguard Worker 
314*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_components_registry_append_component()315*5225e6b1SAndroid Build Coastguard Worker     fn test_components_registry_append_component() {
316*5225e6b1SAndroid Build Coastguard Worker         let dt = include_bytes!("../../libfdt/test/data/base.dtb").to_vec();
317*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = vec![0u8; 2 * 1024 * 1024]; // 2 MB
318*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&[]);
319*5225e6b1SAndroid Build Coastguard Worker         let mut registry = DeviceTreeComponentsRegistry::new();
320*5225e6b1SAndroid Build Coastguard Worker 
321*5225e6b1SAndroid Build Coastguard Worker         registry
322*5225e6b1SAndroid Build Coastguard Worker             .append(&mut gbl_ops, DeviceTreeComponentSource::Boot, &dt[..], &mut buffer)
323*5225e6b1SAndroid Build Coastguard Worker             .unwrap();
324*5225e6b1SAndroid Build Coastguard Worker 
325*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(registry.components().count(), 1);
326*5225e6b1SAndroid Build Coastguard Worker 
327*5225e6b1SAndroid Build Coastguard Worker         let component = registry.components().next().unwrap();
328*5225e6b1SAndroid Build Coastguard Worker 
329*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
330*5225e6b1SAndroid Build Coastguard Worker             component,
331*5225e6b1SAndroid Build Coastguard Worker             &DeviceTreeComponent {
332*5225e6b1SAndroid Build Coastguard Worker                 source: DeviceTreeComponentSource::Boot,
333*5225e6b1SAndroid Build Coastguard Worker                 dt: &dt[..],
334*5225e6b1SAndroid Build Coastguard Worker                 selected: false,
335*5225e6b1SAndroid Build Coastguard Worker             }
336*5225e6b1SAndroid Build Coastguard Worker         );
337*5225e6b1SAndroid Build Coastguard Worker         assert!(component.is_base_device_tree());
338*5225e6b1SAndroid Build Coastguard Worker     }
339*5225e6b1SAndroid Build Coastguard Worker 
340*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_components_registry_append_too_many_components()341*5225e6b1SAndroid Build Coastguard Worker     fn test_components_registry_append_too_many_components() {
342*5225e6b1SAndroid Build Coastguard Worker         let dt = include_bytes!("../../libfdt/test/data/base.dtb").to_vec();
343*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = vec![0u8; 2 * 1024 * 1024]; // 2 MB
344*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&[]);
345*5225e6b1SAndroid Build Coastguard Worker         let mut registry = DeviceTreeComponentsRegistry::new();
346*5225e6b1SAndroid Build Coastguard Worker 
347*5225e6b1SAndroid Build Coastguard Worker         let mut current_buffer = &mut buffer[..];
348*5225e6b1SAndroid Build Coastguard Worker         // Fill the whole reserved space
349*5225e6b1SAndroid Build Coastguard Worker         for _ in 0..MAXIMUM_DEVICE_TREE_COMPONENTS {
350*5225e6b1SAndroid Build Coastguard Worker             current_buffer = registry
351*5225e6b1SAndroid Build Coastguard Worker                 .append(&mut gbl_ops, DeviceTreeComponentSource::Boot, &dt[..], current_buffer)
352*5225e6b1SAndroid Build Coastguard Worker                 .unwrap();
353*5225e6b1SAndroid Build Coastguard Worker         }
354*5225e6b1SAndroid Build Coastguard Worker 
355*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
356*5225e6b1SAndroid Build Coastguard Worker             registry.append(&mut gbl_ops, DeviceTreeComponentSource::Boot, &dt[..], current_buffer),
357*5225e6b1SAndroid Build Coastguard Worker             Err(Error::Other(Some(MAXIMUM_DEVICE_TREE_COMPONENTS_ERROR_MSG)))
358*5225e6b1SAndroid Build Coastguard Worker         );
359*5225e6b1SAndroid Build Coastguard Worker     }
360*5225e6b1SAndroid Build Coastguard Worker 
361*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_components_append_from_dtbo()362*5225e6b1SAndroid Build Coastguard Worker     fn test_components_append_from_dtbo() {
363*5225e6b1SAndroid Build Coastguard Worker         let dttable = include_bytes!("../../libdttable/test/data/dttable.img").to_vec();
364*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = vec![0u8; 2 * 1024 * 1024]; // 2 MB
365*5225e6b1SAndroid Build Coastguard Worker         let mut registry = DeviceTreeComponentsRegistry::new();
366*5225e6b1SAndroid Build Coastguard Worker 
367*5225e6b1SAndroid Build Coastguard Worker         let table = DtTableImage::from_bytes(&dttable[..]).unwrap();
368*5225e6b1SAndroid Build Coastguard Worker         registry.append_from_dtbo(&table, &mut buffer[..]).unwrap();
369*5225e6b1SAndroid Build Coastguard Worker 
370*5225e6b1SAndroid Build Coastguard Worker         // Check data is loaded
371*5225e6b1SAndroid Build Coastguard Worker         let components: Vec<_> = registry.components().cloned().collect();
372*5225e6b1SAndroid Build Coastguard Worker         let expected_components: Vec<DeviceTreeComponent> = table
373*5225e6b1SAndroid Build Coastguard Worker             .entries()
374*5225e6b1SAndroid Build Coastguard Worker             .map(|e| DeviceTreeComponent {
375*5225e6b1SAndroid Build Coastguard Worker                 source: DeviceTreeComponentSource::Dtbo(e.metadata),
376*5225e6b1SAndroid Build Coastguard Worker                 dt: e.dtb,
377*5225e6b1SAndroid Build Coastguard Worker                 selected: false,
378*5225e6b1SAndroid Build Coastguard Worker             })
379*5225e6b1SAndroid Build Coastguard Worker             .collect();
380*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(components, expected_components);
381*5225e6b1SAndroid Build Coastguard Worker 
382*5225e6b1SAndroid Build Coastguard Worker         // Check data is aligned
383*5225e6b1SAndroid Build Coastguard Worker         registry.components().for_each(|c| assert!(c.dt.as_ptr().align_offset(FDT_ALIGNMENT) == 0));
384*5225e6b1SAndroid Build Coastguard Worker     }
385*5225e6b1SAndroid Build Coastguard Worker 
386*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_components_returns_selected()387*5225e6b1SAndroid Build Coastguard Worker     fn test_components_returns_selected() {
388*5225e6b1SAndroid Build Coastguard Worker         let dt = include_bytes!("../../libfdt/test/data/base.dtb").to_vec();
389*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = vec![0u8; 2 * 1024 * 1024]; // 2 MB
390*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&[]);
391*5225e6b1SAndroid Build Coastguard Worker         let mut registry = DeviceTreeComponentsRegistry::new();
392*5225e6b1SAndroid Build Coastguard Worker 
393*5225e6b1SAndroid Build Coastguard Worker         let sources = [
394*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::VendorBoot,
395*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Boot,
396*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Dtbo(Default::default()),
397*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Dtbo(Default::default()),
398*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Dtbo(Default::default()),
399*5225e6b1SAndroid Build Coastguard Worker         ];
400*5225e6b1SAndroid Build Coastguard Worker         let mut current_buffer = &mut buffer[..];
401*5225e6b1SAndroid Build Coastguard Worker         for source in sources.iter() {
402*5225e6b1SAndroid Build Coastguard Worker             current_buffer = registry.append(&mut gbl_ops, *source, &dt, current_buffer).unwrap();
403*5225e6b1SAndroid Build Coastguard Worker         }
404*5225e6b1SAndroid Build Coastguard Worker 
405*5225e6b1SAndroid Build Coastguard Worker         // Select base device tree
406*5225e6b1SAndroid Build Coastguard Worker         registry.components_mut().nth(1).unwrap().selected = true;
407*5225e6b1SAndroid Build Coastguard Worker         // Select first overlay
408*5225e6b1SAndroid Build Coastguard Worker         registry.components_mut().nth(2).unwrap().selected = true;
409*5225e6b1SAndroid Build Coastguard Worker         // Select second overlay
410*5225e6b1SAndroid Build Coastguard Worker         registry.components_mut().nth(3).unwrap().selected = true;
411*5225e6b1SAndroid Build Coastguard Worker 
412*5225e6b1SAndroid Build Coastguard Worker         let expected_overlays =
413*5225e6b1SAndroid Build Coastguard Worker             &[registry.components().nth(2).unwrap().dt, registry.components().nth(3).unwrap().dt];
414*5225e6b1SAndroid Build Coastguard Worker         // Expected selected data
415*5225e6b1SAndroid Build Coastguard Worker         let expected_selected = (registry.components().nth(1).unwrap().dt, &expected_overlays[..]);
416*5225e6b1SAndroid Build Coastguard Worker 
417*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(registry.selected().unwrap(), expected_selected);
418*5225e6b1SAndroid Build Coastguard Worker     }
419*5225e6b1SAndroid Build Coastguard Worker 
420*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_components_returns_selected_no_overlays()421*5225e6b1SAndroid Build Coastguard Worker     fn test_components_returns_selected_no_overlays() {
422*5225e6b1SAndroid Build Coastguard Worker         let dt = include_bytes!("../../libfdt/test/data/base.dtb").to_vec();
423*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = vec![0u8; 2 * 1024 * 1024]; // 2 MB
424*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&[]);
425*5225e6b1SAndroid Build Coastguard Worker         let mut registry = DeviceTreeComponentsRegistry::new();
426*5225e6b1SAndroid Build Coastguard Worker 
427*5225e6b1SAndroid Build Coastguard Worker         let sources = [
428*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::VendorBoot,
429*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Boot,
430*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Dtbo(Default::default()),
431*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Dtbo(Default::default()),
432*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Dtbo(Default::default()),
433*5225e6b1SAndroid Build Coastguard Worker         ];
434*5225e6b1SAndroid Build Coastguard Worker         let mut current_buffer = &mut buffer[..];
435*5225e6b1SAndroid Build Coastguard Worker         for source in sources.iter() {
436*5225e6b1SAndroid Build Coastguard Worker             current_buffer = registry.append(&mut gbl_ops, *source, &dt, current_buffer).unwrap();
437*5225e6b1SAndroid Build Coastguard Worker         }
438*5225e6b1SAndroid Build Coastguard Worker 
439*5225e6b1SAndroid Build Coastguard Worker         // Select base device tree
440*5225e6b1SAndroid Build Coastguard Worker         registry.components_mut().nth(1).unwrap().selected = true;
441*5225e6b1SAndroid Build Coastguard Worker 
442*5225e6b1SAndroid Build Coastguard Worker         // Expected selected data
443*5225e6b1SAndroid Build Coastguard Worker         let expected_selected = (registry.components().nth(1).unwrap().dt, &[][..]);
444*5225e6b1SAndroid Build Coastguard Worker 
445*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(registry.selected().unwrap(), expected_selected);
446*5225e6b1SAndroid Build Coastguard Worker     }
447*5225e6b1SAndroid Build Coastguard Worker 
448*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_components_returns_no_base_device_tree_failed()449*5225e6b1SAndroid Build Coastguard Worker     fn test_components_returns_no_base_device_tree_failed() {
450*5225e6b1SAndroid Build Coastguard Worker         let dt = include_bytes!("../../libfdt/test/data/base.dtb").to_vec();
451*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = vec![0u8; 2 * 1024 * 1024]; // 2 MB
452*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&[]);
453*5225e6b1SAndroid Build Coastguard Worker         let mut registry = DeviceTreeComponentsRegistry::new();
454*5225e6b1SAndroid Build Coastguard Worker 
455*5225e6b1SAndroid Build Coastguard Worker         let sources = [
456*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::VendorBoot,
457*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Boot,
458*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Dtbo(Default::default()),
459*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Dtbo(Default::default()),
460*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Dtbo(Default::default()),
461*5225e6b1SAndroid Build Coastguard Worker         ];
462*5225e6b1SAndroid Build Coastguard Worker         let mut current_buffer = &mut buffer[..];
463*5225e6b1SAndroid Build Coastguard Worker         for source in sources.iter() {
464*5225e6b1SAndroid Build Coastguard Worker             current_buffer = registry.append(&mut gbl_ops, *source, &dt, current_buffer).unwrap();
465*5225e6b1SAndroid Build Coastguard Worker         }
466*5225e6b1SAndroid Build Coastguard Worker 
467*5225e6b1SAndroid Build Coastguard Worker         // Select first overlay
468*5225e6b1SAndroid Build Coastguard Worker         registry.components_mut().nth(2).unwrap().selected = true;
469*5225e6b1SAndroid Build Coastguard Worker         // Select second overlay
470*5225e6b1SAndroid Build Coastguard Worker         registry.components_mut().nth(3).unwrap().selected = true;
471*5225e6b1SAndroid Build Coastguard Worker 
472*5225e6b1SAndroid Build Coastguard Worker         assert!(registry.selected().is_err());
473*5225e6b1SAndroid Build Coastguard Worker     }
474*5225e6b1SAndroid Build Coastguard Worker 
475*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_components_returns_multiple_base_device_trees_failed()476*5225e6b1SAndroid Build Coastguard Worker     fn test_components_returns_multiple_base_device_trees_failed() {
477*5225e6b1SAndroid Build Coastguard Worker         let dt = include_bytes!("../../libfdt/test/data/base.dtb").to_vec();
478*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = vec![0u8; 2 * 1024 * 1024]; // 2 MB
479*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&[]);
480*5225e6b1SAndroid Build Coastguard Worker         let mut registry = DeviceTreeComponentsRegistry::new();
481*5225e6b1SAndroid Build Coastguard Worker 
482*5225e6b1SAndroid Build Coastguard Worker         let sources = [
483*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::VendorBoot,
484*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Boot,
485*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Dtbo(Default::default()),
486*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Dtbo(Default::default()),
487*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Dtbo(Default::default()),
488*5225e6b1SAndroid Build Coastguard Worker         ];
489*5225e6b1SAndroid Build Coastguard Worker         let mut current_buffer = &mut buffer[..];
490*5225e6b1SAndroid Build Coastguard Worker         for source in sources.iter() {
491*5225e6b1SAndroid Build Coastguard Worker             current_buffer = registry.append(&mut gbl_ops, *source, &dt, current_buffer).unwrap();
492*5225e6b1SAndroid Build Coastguard Worker         }
493*5225e6b1SAndroid Build Coastguard Worker 
494*5225e6b1SAndroid Build Coastguard Worker         // Select first base device tree
495*5225e6b1SAndroid Build Coastguard Worker         registry.components_mut().nth(0).unwrap().selected = true;
496*5225e6b1SAndroid Build Coastguard Worker         // Select second base device tree
497*5225e6b1SAndroid Build Coastguard Worker         registry.components_mut().nth(1).unwrap().selected = true;
498*5225e6b1SAndroid Build Coastguard Worker 
499*5225e6b1SAndroid Build Coastguard Worker         assert!(registry.selected().is_err());
500*5225e6b1SAndroid Build Coastguard Worker     }
501*5225e6b1SAndroid Build Coastguard Worker 
502*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_components_autoselect()503*5225e6b1SAndroid Build Coastguard Worker     fn test_components_autoselect() {
504*5225e6b1SAndroid Build Coastguard Worker         let dt = include_bytes!("../../libfdt/test/data/base.dtb").to_vec();
505*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = vec![0u8; 2 * 1024 * 1024]; // 2 MB
506*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&[]);
507*5225e6b1SAndroid Build Coastguard Worker         let mut registry = DeviceTreeComponentsRegistry::new();
508*5225e6b1SAndroid Build Coastguard Worker 
509*5225e6b1SAndroid Build Coastguard Worker         let sources = [
510*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::VendorBoot,
511*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Dtbo(Default::default()),
512*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Dtbo(Default::default()),
513*5225e6b1SAndroid Build Coastguard Worker             DeviceTreeComponentSource::Dtbo(Default::default()),
514*5225e6b1SAndroid Build Coastguard Worker         ];
515*5225e6b1SAndroid Build Coastguard Worker         let mut current_buffer = &mut buffer[..];
516*5225e6b1SAndroid Build Coastguard Worker         for source in sources.iter() {
517*5225e6b1SAndroid Build Coastguard Worker             current_buffer = registry.append(&mut gbl_ops, *source, &dt, current_buffer).unwrap();
518*5225e6b1SAndroid Build Coastguard Worker         }
519*5225e6b1SAndroid Build Coastguard Worker 
520*5225e6b1SAndroid Build Coastguard Worker         assert!(registry.autoselect().is_ok());
521*5225e6b1SAndroid Build Coastguard Worker 
522*5225e6b1SAndroid Build Coastguard Worker         // Expected auto selected data
523*5225e6b1SAndroid Build Coastguard Worker         let expected_selected = (registry.components().nth(0).unwrap().dt, &[][..]);
524*5225e6b1SAndroid Build Coastguard Worker 
525*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(registry.selected().unwrap(), expected_selected);
526*5225e6b1SAndroid Build Coastguard Worker     }
527*5225e6b1SAndroid Build Coastguard Worker 
528*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_components_autoselect_no_overlays()529*5225e6b1SAndroid Build Coastguard Worker     fn test_components_autoselect_no_overlays() {
530*5225e6b1SAndroid Build Coastguard Worker         let dt = include_bytes!("../../libfdt/test/data/base.dtb").to_vec();
531*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = vec![0u8; 2 * 1024 * 1024]; // 2 MB
532*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&[]);
533*5225e6b1SAndroid Build Coastguard Worker         let mut registry = DeviceTreeComponentsRegistry::new();
534*5225e6b1SAndroid Build Coastguard Worker 
535*5225e6b1SAndroid Build Coastguard Worker         registry
536*5225e6b1SAndroid Build Coastguard Worker             .append(&mut gbl_ops, DeviceTreeComponentSource::VendorBoot, &dt[..], &mut buffer)
537*5225e6b1SAndroid Build Coastguard Worker             .unwrap();
538*5225e6b1SAndroid Build Coastguard Worker 
539*5225e6b1SAndroid Build Coastguard Worker         assert!(registry.autoselect().is_ok());
540*5225e6b1SAndroid Build Coastguard Worker 
541*5225e6b1SAndroid Build Coastguard Worker         // Expected auto selected data
542*5225e6b1SAndroid Build Coastguard Worker         let expected_selected = (registry.components().nth(0).unwrap().dt, &[][..]);
543*5225e6b1SAndroid Build Coastguard Worker 
544*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(registry.selected().unwrap(), expected_selected);
545*5225e6b1SAndroid Build Coastguard Worker     }
546*5225e6b1SAndroid Build Coastguard Worker 
547*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_components_autoselect_multiple_base_device_trees_failed()548*5225e6b1SAndroid Build Coastguard Worker     fn test_components_autoselect_multiple_base_device_trees_failed() {
549*5225e6b1SAndroid Build Coastguard Worker         let dt = include_bytes!("../../libfdt/test/data/base.dtb").to_vec();
550*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = vec![0u8; 2 * 1024 * 1024]; // 2 MB
551*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&[]);
552*5225e6b1SAndroid Build Coastguard Worker         let mut registry = DeviceTreeComponentsRegistry::new();
553*5225e6b1SAndroid Build Coastguard Worker 
554*5225e6b1SAndroid Build Coastguard Worker         let mut current_buffer = &mut buffer[..];
555*5225e6b1SAndroid Build Coastguard Worker         current_buffer = registry
556*5225e6b1SAndroid Build Coastguard Worker             .append(&mut gbl_ops, DeviceTreeComponentSource::VendorBoot, &dt[..], current_buffer)
557*5225e6b1SAndroid Build Coastguard Worker             .unwrap();
558*5225e6b1SAndroid Build Coastguard Worker         registry
559*5225e6b1SAndroid Build Coastguard Worker             .append(&mut gbl_ops, DeviceTreeComponentSource::Boot, &dt[..], current_buffer)
560*5225e6b1SAndroid Build Coastguard Worker             .unwrap();
561*5225e6b1SAndroid Build Coastguard Worker 
562*5225e6b1SAndroid Build Coastguard Worker         assert!(registry.autoselect().is_err());
563*5225e6b1SAndroid Build Coastguard Worker     }
564*5225e6b1SAndroid Build Coastguard Worker 
565*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_components_autoselect_no_base_device_trees_failed()566*5225e6b1SAndroid Build Coastguard Worker     fn test_components_autoselect_no_base_device_trees_failed() {
567*5225e6b1SAndroid Build Coastguard Worker         let dt = include_bytes!("../../libfdt/test/data/base.dtb").to_vec();
568*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = vec![0u8; 2 * 1024 * 1024]; // 2 MB
569*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&[]);
570*5225e6b1SAndroid Build Coastguard Worker         let mut registry = DeviceTreeComponentsRegistry::new();
571*5225e6b1SAndroid Build Coastguard Worker 
572*5225e6b1SAndroid Build Coastguard Worker         registry
573*5225e6b1SAndroid Build Coastguard Worker             .append(
574*5225e6b1SAndroid Build Coastguard Worker                 &mut gbl_ops,
575*5225e6b1SAndroid Build Coastguard Worker                 DeviceTreeComponentSource::Dtbo(Default::default()),
576*5225e6b1SAndroid Build Coastguard Worker                 &dt[..],
577*5225e6b1SAndroid Build Coastguard Worker                 &mut buffer,
578*5225e6b1SAndroid Build Coastguard Worker             )
579*5225e6b1SAndroid Build Coastguard Worker             .unwrap();
580*5225e6b1SAndroid Build Coastguard Worker 
581*5225e6b1SAndroid Build Coastguard Worker         assert!(registry.autoselect().is_err());
582*5225e6b1SAndroid Build Coastguard Worker     }
583*5225e6b1SAndroid Build Coastguard Worker 
584*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_components_append_from_multifd()585*5225e6b1SAndroid Build Coastguard Worker     fn test_components_append_from_multifd() {
586*5225e6b1SAndroid Build Coastguard Worker         let half = include_bytes!("../../libfdt/test/data/base.dtb").to_vec();
587*5225e6b1SAndroid Build Coastguard Worker         let dt = [half.clone(), half].concat();
588*5225e6b1SAndroid Build Coastguard Worker         let mut buffer = vec![0u8; 2 * 1024 * 1024]; // 2 MB
589*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::new(&[]);
590*5225e6b1SAndroid Build Coastguard Worker         let mut registry = DeviceTreeComponentsRegistry::new();
591*5225e6b1SAndroid Build Coastguard Worker 
592*5225e6b1SAndroid Build Coastguard Worker         registry
593*5225e6b1SAndroid Build Coastguard Worker             .append(&mut gbl_ops, DeviceTreeComponentSource::VendorBoot, &dt[..], &mut buffer)
594*5225e6b1SAndroid Build Coastguard Worker             .unwrap();
595*5225e6b1SAndroid Build Coastguard Worker 
596*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(registry.components().count(), 2);
597*5225e6b1SAndroid Build Coastguard Worker     }
598*5225e6b1SAndroid Build Coastguard Worker }
599