• 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 use gbl_storage::BlockIo;
16 use gbl_storage_testlib::TestBlockIo;
17 use libgbl::{BootImages, FuchsiaBootImages, GblBuilder, GblOps, GblOpsError};
18 use std::{collections::VecDeque, vec::Vec};
19 
20 extern crate avb_sysdeps;
21 
22 struct GblTestBlockIo {
23     io: TestBlockIo,
24     max_gpt_entries: u64,
25 }
26 
27 /// `TestGblOps` provides mock implementation of GblOps for integration test.
28 #[derive(Default)]
29 struct TestGblOps<'a> {
30     block_io: Vec<GblTestBlockIo>,
31     console_out: VecDeque<u8>,
32     boot_cb: Option<MustUse<&'a mut dyn FnMut(BootImages)>>,
33 }
34 
35 impl TestGblOps<'_> {
36     /// Adds a new block device.
add_block_device<T: AsRef<[u8]>>( &mut self, alignment: u64, block_size: u64, max_gpt_entries: u64, data: T, )37     pub(crate) fn add_block_device<T: AsRef<[u8]>>(
38         &mut self,
39         alignment: u64,
40         block_size: u64,
41         max_gpt_entries: u64,
42         data: T,
43     ) {
44         self.block_io.push(GblTestBlockIo {
45             io: TestBlockIo::new(alignment, block_size, data.as_ref().into()),
46             max_gpt_entries,
47         })
48     }
49 }
50 
51 impl GblOps for TestGblOps<'_> {
visit_block_devices( &mut self, f: &mut dyn FnMut(&mut dyn BlockIo, u64, u64), ) -> Result<(), GblOpsError>52     fn visit_block_devices(
53         &mut self,
54         f: &mut dyn FnMut(&mut dyn BlockIo, u64, u64),
55     ) -> Result<(), GblOpsError> {
56         for (idx, ele) in self.block_io.iter_mut().enumerate() {
57             f(&mut ele.io, idx.try_into().unwrap(), ele.max_gpt_entries);
58         }
59         Ok(())
60     }
61 
console_put_char(&mut self, ch: u8) -> Result<(), GblOpsError>62     fn console_put_char(&mut self, ch: u8) -> Result<(), GblOpsError> {
63         Ok(self.console_out.push_back(ch))
64     }
65 
should_stop_in_fastboot(&mut self) -> Result<bool, GblOpsError>66     fn should_stop_in_fastboot(&mut self) -> Result<bool, GblOpsError> {
67         Ok(false)
68     }
69 
boot(&mut self, boot_images: BootImages) -> Result<(), GblOpsError>70     fn boot(&mut self, boot_images: BootImages) -> Result<(), GblOpsError> {
71         Ok((self.boot_cb.as_mut().unwrap().get())(boot_images))
72     }
73 }
74 
75 /// `MustUse` wraps an object and checks that it is accessed at least once before it's dropped.
76 /// In this integration test, it is mainly used to check that test provided ops callbacks are run.
77 struct MustUse<T: ?Sized> {
78     used: bool,
79     val: T,
80 }
81 
82 impl<T: ?Sized> MustUse<T> {
83     /// Create a new instance.
new(val: T) -> Self where T: Sized,84     fn new(val: T) -> Self
85     where
86         T: Sized,
87     {
88         Self { used: false, val: val }
89     }
90 
91     /// Returns a mutable reference to the object.
get(&mut self) -> &mut T92     fn get(&mut self) -> &mut T {
93         self.used = true;
94         &mut self.val
95     }
96 }
97 
98 impl<T: ?Sized> Drop for MustUse<T> {
drop(&mut self)99     fn drop(&mut self) {
100         assert!(self.used)
101     }
102 }
103 
104 #[cfg(test)]
105 mod tests {
106     use super::*;
107 
108     #[test]
test_zircon_load_and_boot()109     fn test_zircon_load_and_boot() {
110         // TODO(b/334962583): Invocation test only. Update this test once
111         // `Gbl::zircon_load_and_boot()` is implemented.
112         let mut boot_cb = |boot_images: BootImages| {
113             let BootImages::Fuchsia(FuchsiaBootImages { zbi_kernel, zbi_items }) = boot_images
114             else {
115                 panic!("Wrong image type");
116             };
117             assert_eq!(zbi_kernel, include_bytes!("../testdata/zircon_a.bin"));
118             assert_eq!(zbi_items, []);
119         };
120         let mut ops: TestGblOps = Default::default();
121         ops.add_block_device(512, 512, 128, include_bytes!("../testdata/zircon_gpt.bin"));
122         ops.boot_cb = Some(MustUse::new(&mut boot_cb));
123         let mut gbl = GblBuilder::new(&mut ops).build();
124         let mut load_buffer = vec![0u8; 64 * 1024];
125         let _ = gbl.zircon_load_and_boot(&mut load_buffer[..]);
126     }
127 }
128