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