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