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