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