xref: /aosp_15_r20/bootable/libbootloader/gbl/libgbl/src/lib.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
1*5225e6b1SAndroid Build Coastguard Worker // Copyright 2023, The Android Open Source Project
2*5225e6b1SAndroid Build Coastguard Worker //
3*5225e6b1SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*5225e6b1SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*5225e6b1SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*5225e6b1SAndroid Build Coastguard Worker //
7*5225e6b1SAndroid Build Coastguard Worker //     http://www.apache.org/licenses/LICENSE-2.0
8*5225e6b1SAndroid Build Coastguard Worker //
9*5225e6b1SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*5225e6b1SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*5225e6b1SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*5225e6b1SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*5225e6b1SAndroid Build Coastguard Worker // limitations under the License.
14*5225e6b1SAndroid Build Coastguard Worker 
15*5225e6b1SAndroid Build Coastguard Worker //! # Generic Boot Loader (gbl) Library
16*5225e6b1SAndroid Build Coastguard Worker //!
17*5225e6b1SAndroid Build Coastguard Worker //! TODO: b/312610098 - add documentation.
18*5225e6b1SAndroid Build Coastguard Worker //!
19*5225e6b1SAndroid Build Coastguard Worker //! The intended users of this library are firmware, bootloader, and bring-up teams at OEMs and SOC
20*5225e6b1SAndroid Build Coastguard Worker //! Vendors
21*5225e6b1SAndroid Build Coastguard Worker //!
22*5225e6b1SAndroid Build Coastguard Worker //! This library is `no_std` as it is intended for use in bootloaders that typically will not
23*5225e6b1SAndroid Build Coastguard Worker //! support the Rust standard library. However, it does require `alloc` with a global allocator,
24*5225e6b1SAndroid Build Coastguard Worker //! currently used for:
25*5225e6b1SAndroid Build Coastguard Worker //! * libavb
26*5225e6b1SAndroid Build Coastguard Worker //! * kernel decompression
27*5225e6b1SAndroid Build Coastguard Worker 
28*5225e6b1SAndroid Build Coastguard Worker #![cfg_attr(not(any(test, android_dylib)), no_std)]
29*5225e6b1SAndroid Build Coastguard Worker // TODO: b/312610985 - return warning for unused partitions
30*5225e6b1SAndroid Build Coastguard Worker #![allow(async_fn_in_trait)]
31*5225e6b1SAndroid Build Coastguard Worker // Needed for MaybeUninit::fill() experimental API
32*5225e6b1SAndroid Build Coastguard Worker #![feature(maybe_uninit_fill)]
33*5225e6b1SAndroid Build Coastguard Worker extern crate avb;
34*5225e6b1SAndroid Build Coastguard Worker extern crate core;
35*5225e6b1SAndroid Build Coastguard Worker extern crate gbl_storage;
36*5225e6b1SAndroid Build Coastguard Worker extern crate spin;
37*5225e6b1SAndroid Build Coastguard Worker extern crate zbi;
38*5225e6b1SAndroid Build Coastguard Worker 
39*5225e6b1SAndroid Build Coastguard Worker use avb::{HashtreeErrorMode, SlotVerifyData, SlotVerifyError, SlotVerifyFlags};
40*5225e6b1SAndroid Build Coastguard Worker use core::ffi::CStr;
41*5225e6b1SAndroid Build Coastguard Worker use core::marker::PhantomData;
42*5225e6b1SAndroid Build Coastguard Worker 
43*5225e6b1SAndroid Build Coastguard Worker pub mod android_boot;
44*5225e6b1SAndroid Build Coastguard Worker pub mod boot_mode;
45*5225e6b1SAndroid Build Coastguard Worker pub mod boot_reason;
46*5225e6b1SAndroid Build Coastguard Worker pub mod constants;
47*5225e6b1SAndroid Build Coastguard Worker pub mod decompress;
48*5225e6b1SAndroid Build Coastguard Worker pub mod device_tree;
49*5225e6b1SAndroid Build Coastguard Worker pub mod error;
50*5225e6b1SAndroid Build Coastguard Worker pub mod fastboot;
51*5225e6b1SAndroid Build Coastguard Worker pub mod fuchsia_boot;
52*5225e6b1SAndroid Build Coastguard Worker pub mod gbl_avb;
53*5225e6b1SAndroid Build Coastguard Worker pub mod ops;
54*5225e6b1SAndroid Build Coastguard Worker pub mod partition;
55*5225e6b1SAndroid Build Coastguard Worker 
56*5225e6b1SAndroid Build Coastguard Worker /// The 'slots' module, containing types and traits for
57*5225e6b1SAndroid Build Coastguard Worker /// querying and modifying slotted boot behavior.
58*5225e6b1SAndroid Build Coastguard Worker pub mod slots;
59*5225e6b1SAndroid Build Coastguard Worker 
60*5225e6b1SAndroid Build Coastguard Worker mod image_buffer;
61*5225e6b1SAndroid Build Coastguard Worker mod overlap;
62*5225e6b1SAndroid Build Coastguard Worker 
63*5225e6b1SAndroid Build Coastguard Worker use slots::{BootTarget, BootToken, Cursor, OneShot, SuffixBytes, UnbootableReason};
64*5225e6b1SAndroid Build Coastguard Worker 
65*5225e6b1SAndroid Build Coastguard Worker pub use avb::Descriptor;
66*5225e6b1SAndroid Build Coastguard Worker pub use boot_mode::BootMode;
67*5225e6b1SAndroid Build Coastguard Worker pub use boot_reason::KnownBootReason;
68*5225e6b1SAndroid Build Coastguard Worker pub use error::{IntegrationError, Result};
69*5225e6b1SAndroid Build Coastguard Worker use liberror::Error;
70*5225e6b1SAndroid Build Coastguard Worker pub use ops::{GblOps, Os};
71*5225e6b1SAndroid Build Coastguard Worker 
72*5225e6b1SAndroid Build Coastguard Worker use overlap::is_overlap;
73*5225e6b1SAndroid Build Coastguard Worker 
74*5225e6b1SAndroid Build Coastguard Worker // TODO: b/312607649 - Replace placeholders with actual structures: https://r.android.com/2721974, etc
75*5225e6b1SAndroid Build Coastguard Worker /// TODO: b/312607649 - placeholder type
76*5225e6b1SAndroid Build Coastguard Worker pub struct Partition {}
77*5225e6b1SAndroid Build Coastguard Worker /// TODO: b/312607649 - placeholder type
78*5225e6b1SAndroid Build Coastguard Worker pub struct InfoStruct {}
79*5225e6b1SAndroid Build Coastguard Worker 
80*5225e6b1SAndroid Build Coastguard Worker /// Structure representing partition and optional address it is required to be loaded.
81*5225e6b1SAndroid Build Coastguard Worker /// If no address is provided GBL will use default one.
82*5225e6b1SAndroid Build Coastguard Worker pub struct PartitionRamMap<'b, 'c> {
83*5225e6b1SAndroid Build Coastguard Worker     /// Partition details
84*5225e6b1SAndroid Build Coastguard Worker     pub partition: &'b Partition,
85*5225e6b1SAndroid Build Coastguard Worker 
86*5225e6b1SAndroid Build Coastguard Worker     /// Optional memory region to load partitions.
87*5225e6b1SAndroid Build Coastguard Worker     /// If it's not provided default values will be used.
88*5225e6b1SAndroid Build Coastguard Worker     pub address: Option<&'c mut [u8]>,
89*5225e6b1SAndroid Build Coastguard Worker }
90*5225e6b1SAndroid Build Coastguard Worker 
91*5225e6b1SAndroid Build Coastguard Worker /// Boot Image in memory
92*5225e6b1SAndroid Build Coastguard Worker #[allow(dead_code)]
93*5225e6b1SAndroid Build Coastguard Worker pub struct BootImage<'a>(&'a mut [u8]);
94*5225e6b1SAndroid Build Coastguard Worker 
95*5225e6b1SAndroid Build Coastguard Worker /// Vendor Boot Image in memory
96*5225e6b1SAndroid Build Coastguard Worker pub struct VendorBootImage<'a>(&'a mut [u8]);
97*5225e6b1SAndroid Build Coastguard Worker 
98*5225e6b1SAndroid Build Coastguard Worker /// Init Boot Image in memory
99*5225e6b1SAndroid Build Coastguard Worker pub struct InitBootImage<'a>(&'a mut [u8]);
100*5225e6b1SAndroid Build Coastguard Worker 
101*5225e6b1SAndroid Build Coastguard Worker /// Kernel Image in memory
102*5225e6b1SAndroid Build Coastguard Worker #[allow(dead_code)]
103*5225e6b1SAndroid Build Coastguard Worker pub struct KernelImage<'a>(&'a mut [u8]);
104*5225e6b1SAndroid Build Coastguard Worker 
105*5225e6b1SAndroid Build Coastguard Worker /// Ramdisk in memory
106*5225e6b1SAndroid Build Coastguard Worker pub struct Ramdisk<'a>(&'a mut [u8]);
107*5225e6b1SAndroid Build Coastguard Worker /// Bootconfig in memory
108*5225e6b1SAndroid Build Coastguard Worker #[allow(dead_code)]
109*5225e6b1SAndroid Build Coastguard Worker pub struct Bootconfig<'a>(&'a mut [u8]);
110*5225e6b1SAndroid Build Coastguard Worker /// DTB in memory
111*5225e6b1SAndroid Build Coastguard Worker #[allow(dead_code)]
112*5225e6b1SAndroid Build Coastguard Worker pub struct Dtb<'a>(&'a mut [u8]);
113*5225e6b1SAndroid Build Coastguard Worker 
114*5225e6b1SAndroid Build Coastguard Worker /// Create Boot Image from corresponding partition for `partitions_ram_map` and `avb_descriptors`
115*5225e6b1SAndroid Build Coastguard Worker /// lists
get_boot_image<'a: 'b, 'b: 'c, 'c, 'd>( partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>], ) -> (Option<BootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>])116*5225e6b1SAndroid Build Coastguard Worker pub fn get_boot_image<'a: 'b, 'b: 'c, 'c, 'd>(
117*5225e6b1SAndroid Build Coastguard Worker     partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>],
118*5225e6b1SAndroid Build Coastguard Worker ) -> (Option<BootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>]) {
119*5225e6b1SAndroid Build Coastguard Worker     match partitions_ram_map.len() {
120*5225e6b1SAndroid Build Coastguard Worker         0 => (None, partitions_ram_map),
121*5225e6b1SAndroid Build Coastguard Worker         _ => {
122*5225e6b1SAndroid Build Coastguard Worker             let (partition_map, tail) = partitions_ram_map.split_first_mut().unwrap();
123*5225e6b1SAndroid Build Coastguard Worker             (partition_map.address.take().map(BootImage), tail)
124*5225e6b1SAndroid Build Coastguard Worker         }
125*5225e6b1SAndroid Build Coastguard Worker     }
126*5225e6b1SAndroid Build Coastguard Worker }
127*5225e6b1SAndroid Build Coastguard Worker 
128*5225e6b1SAndroid Build Coastguard Worker /// Create Vendor Boot Image from corresponding partition for `partitions_ram_map` and
129*5225e6b1SAndroid Build Coastguard Worker /// `avb_descriptors` lists
get_vendor_boot_image<'a: 'b, 'b: 'c, 'c, 'd>( partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>], ) -> (Option<VendorBootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>])130*5225e6b1SAndroid Build Coastguard Worker pub fn get_vendor_boot_image<'a: 'b, 'b: 'c, 'c, 'd>(
131*5225e6b1SAndroid Build Coastguard Worker     partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>],
132*5225e6b1SAndroid Build Coastguard Worker ) -> (Option<VendorBootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>]) {
133*5225e6b1SAndroid Build Coastguard Worker     match partitions_ram_map.len() {
134*5225e6b1SAndroid Build Coastguard Worker         0 => (None, partitions_ram_map),
135*5225e6b1SAndroid Build Coastguard Worker         _ => {
136*5225e6b1SAndroid Build Coastguard Worker             let (partition_map, tail) = partitions_ram_map.split_first_mut().unwrap();
137*5225e6b1SAndroid Build Coastguard Worker             (partition_map.address.take().map(VendorBootImage), tail)
138*5225e6b1SAndroid Build Coastguard Worker         }
139*5225e6b1SAndroid Build Coastguard Worker     }
140*5225e6b1SAndroid Build Coastguard Worker }
141*5225e6b1SAndroid Build Coastguard Worker 
142*5225e6b1SAndroid Build Coastguard Worker /// Create Init Boot Image from corresponding partition for `partitions` and `avb_descriptors` lists
get_init_boot_image<'a: 'b, 'b: 'c, 'c, 'd>( partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>], ) -> (Option<InitBootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>])143*5225e6b1SAndroid Build Coastguard Worker pub fn get_init_boot_image<'a: 'b, 'b: 'c, 'c, 'd>(
144*5225e6b1SAndroid Build Coastguard Worker     partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>],
145*5225e6b1SAndroid Build Coastguard Worker ) -> (Option<InitBootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>]) {
146*5225e6b1SAndroid Build Coastguard Worker     match partitions_ram_map.len() {
147*5225e6b1SAndroid Build Coastguard Worker         0 => (None, partitions_ram_map),
148*5225e6b1SAndroid Build Coastguard Worker         _ => {
149*5225e6b1SAndroid Build Coastguard Worker             let (partition_map, tail) = partitions_ram_map.split_first_mut().unwrap();
150*5225e6b1SAndroid Build Coastguard Worker             (partition_map.address.take().map(InitBootImage), tail)
151*5225e6b1SAndroid Build Coastguard Worker         }
152*5225e6b1SAndroid Build Coastguard Worker     }
153*5225e6b1SAndroid Build Coastguard Worker }
154*5225e6b1SAndroid Build Coastguard Worker 
155*5225e6b1SAndroid Build Coastguard Worker /// Create separate image types from [avb::Descriptor]
get_images<'a: 'b, 'b: 'c, 'c, 'd>( partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>], ) -> ( Option<BootImage<'c>>, Option<InitBootImage<'c>>, Option<VendorBootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>], )156*5225e6b1SAndroid Build Coastguard Worker pub fn get_images<'a: 'b, 'b: 'c, 'c, 'd>(
157*5225e6b1SAndroid Build Coastguard Worker     partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>],
158*5225e6b1SAndroid Build Coastguard Worker ) -> (
159*5225e6b1SAndroid Build Coastguard Worker     Option<BootImage<'c>>,
160*5225e6b1SAndroid Build Coastguard Worker     Option<InitBootImage<'c>>,
161*5225e6b1SAndroid Build Coastguard Worker     Option<VendorBootImage<'c>>,
162*5225e6b1SAndroid Build Coastguard Worker     &'a mut [PartitionRamMap<'b, 'c>],
163*5225e6b1SAndroid Build Coastguard Worker ) {
164*5225e6b1SAndroid Build Coastguard Worker     let (boot_image, partitions_ram_map) = get_boot_image(partitions_ram_map);
165*5225e6b1SAndroid Build Coastguard Worker     let (init_boot_image, partitions_ram_map) = get_init_boot_image(partitions_ram_map);
166*5225e6b1SAndroid Build Coastguard Worker     let (vendor_boot_image, partitions_ram_map) = get_vendor_boot_image(partitions_ram_map);
167*5225e6b1SAndroid Build Coastguard Worker     (boot_image, init_boot_image, vendor_boot_image, partitions_ram_map)
168*5225e6b1SAndroid Build Coastguard Worker }
169*5225e6b1SAndroid Build Coastguard Worker 
170*5225e6b1SAndroid Build Coastguard Worker /// GBL object that provides implementation of helpers for boot process.
171*5225e6b1SAndroid Build Coastguard Worker pub struct Gbl<'a, 'd, G>
172*5225e6b1SAndroid Build Coastguard Worker where
173*5225e6b1SAndroid Build Coastguard Worker     G: GblOps<'a, 'd>,
174*5225e6b1SAndroid Build Coastguard Worker {
175*5225e6b1SAndroid Build Coastguard Worker     ops: &'a mut G,
176*5225e6b1SAndroid Build Coastguard Worker     boot_token: Option<BootToken>,
177*5225e6b1SAndroid Build Coastguard Worker     _get_image_buffer_lifetime: PhantomData<&'d ()>,
178*5225e6b1SAndroid Build Coastguard Worker }
179*5225e6b1SAndroid Build Coastguard Worker 
180*5225e6b1SAndroid Build Coastguard Worker // TODO(b/312610985): Investigate whether to deprecate this and remove this allow.
181*5225e6b1SAndroid Build Coastguard Worker #[allow(unused_variables)]
182*5225e6b1SAndroid Build Coastguard Worker impl<'a, 'f, G> Gbl<'a, 'f, G>
183*5225e6b1SAndroid Build Coastguard Worker where
184*5225e6b1SAndroid Build Coastguard Worker     G: GblOps<'a, 'f>,
185*5225e6b1SAndroid Build Coastguard Worker {
186*5225e6b1SAndroid Build Coastguard Worker     /// Returns a new [Gbl] object.
187*5225e6b1SAndroid Build Coastguard Worker     ///
188*5225e6b1SAndroid Build Coastguard Worker     /// # Arguments
189*5225e6b1SAndroid Build Coastguard Worker     /// * `ops` - the [GblOps] callbacks to use
new(ops: &'a mut G) -> Self190*5225e6b1SAndroid Build Coastguard Worker     pub fn new(ops: &'a mut G) -> Self {
191*5225e6b1SAndroid Build Coastguard Worker         Self { ops, boot_token: Some(BootToken(())), _get_image_buffer_lifetime: PhantomData }
192*5225e6b1SAndroid Build Coastguard Worker     }
193*5225e6b1SAndroid Build Coastguard Worker 
194*5225e6b1SAndroid Build Coastguard Worker     /// Verify + Load Image Into memory
195*5225e6b1SAndroid Build Coastguard Worker     ///
196*5225e6b1SAndroid Build Coastguard Worker     /// Load from disk, validate with AVB
197*5225e6b1SAndroid Build Coastguard Worker     ///
198*5225e6b1SAndroid Build Coastguard Worker     /// # Arguments
199*5225e6b1SAndroid Build Coastguard Worker     /// * `avb_ops` - implementation for `avb::Ops`
200*5225e6b1SAndroid Build Coastguard Worker     /// * `partitions_to_verify` - names of all the partitions to verify with libavb.
201*5225e6b1SAndroid Build Coastguard Worker     /// * `slot_verify_flags` - AVB slot verification flags
202*5225e6b1SAndroid Build Coastguard Worker     /// * `boot_target` - [Optional] Boot Target
203*5225e6b1SAndroid Build Coastguard Worker     ///
204*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
205*5225e6b1SAndroid Build Coastguard Worker     /// * `Ok(SlotVerifyData)` - avb verification data
206*5225e6b1SAndroid Build Coastguard Worker     /// * `Err(Error)` - on failure
load_and_verify_image<'b>( &mut self, avb_ops: &mut impl avb::Ops<'b>, partitions_to_verify: &[&CStr], slot_verify_flags: SlotVerifyFlags, boot_target: Option<BootTarget>, ) -> Result<SlotVerifyData<'b>>207*5225e6b1SAndroid Build Coastguard Worker     pub fn load_and_verify_image<'b>(
208*5225e6b1SAndroid Build Coastguard Worker         &mut self,
209*5225e6b1SAndroid Build Coastguard Worker         avb_ops: &mut impl avb::Ops<'b>,
210*5225e6b1SAndroid Build Coastguard Worker         partitions_to_verify: &[&CStr],
211*5225e6b1SAndroid Build Coastguard Worker         slot_verify_flags: SlotVerifyFlags,
212*5225e6b1SAndroid Build Coastguard Worker         boot_target: Option<BootTarget>,
213*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<SlotVerifyData<'b>> {
214*5225e6b1SAndroid Build Coastguard Worker         let bytes: SuffixBytes =
215*5225e6b1SAndroid Build Coastguard Worker             if let Some(tgt) = boot_target { tgt.suffix().into() } else { Default::default() };
216*5225e6b1SAndroid Build Coastguard Worker 
217*5225e6b1SAndroid Build Coastguard Worker         let avb_suffix = CStr::from_bytes_until_nul(&bytes).map_err(Error::from)?;
218*5225e6b1SAndroid Build Coastguard Worker 
219*5225e6b1SAndroid Build Coastguard Worker         Ok(avb::slot_verify(
220*5225e6b1SAndroid Build Coastguard Worker             avb_ops,
221*5225e6b1SAndroid Build Coastguard Worker             partitions_to_verify,
222*5225e6b1SAndroid Build Coastguard Worker             Some(avb_suffix),
223*5225e6b1SAndroid Build Coastguard Worker             slot_verify_flags,
224*5225e6b1SAndroid Build Coastguard Worker             HashtreeErrorMode::AVB_HASHTREE_ERROR_MODE_EIO,
225*5225e6b1SAndroid Build Coastguard Worker         )
226*5225e6b1SAndroid Build Coastguard Worker         .map_err(|v| v.without_verify_data())?)
227*5225e6b1SAndroid Build Coastguard Worker     }
228*5225e6b1SAndroid Build Coastguard Worker 
229*5225e6b1SAndroid Build Coastguard Worker     /// Load Slot Manager Interface
230*5225e6b1SAndroid Build Coastguard Worker     ///
231*5225e6b1SAndroid Build Coastguard Worker     /// The default implementation loads from the `durable_boot` partition
232*5225e6b1SAndroid Build Coastguard Worker     /// and writes changes back on the destruction of the cursor.
233*5225e6b1SAndroid Build Coastguard Worker     ///
234*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
235*5225e6b1SAndroid Build Coastguard Worker     ///
236*5225e6b1SAndroid Build Coastguard Worker     /// * `Ok(Cursor)` - Cursor object that manages a Manager
237*5225e6b1SAndroid Build Coastguard Worker     /// * `Err(Error)` - on failure
load_slot_interface( &'a mut self, persist: &'a mut dyn FnMut(&mut [u8]) -> core::result::Result<(), Error>, ) -> Result<Cursor<'a>>238*5225e6b1SAndroid Build Coastguard Worker     pub fn load_slot_interface(
239*5225e6b1SAndroid Build Coastguard Worker         &'a mut self,
240*5225e6b1SAndroid Build Coastguard Worker         persist: &'a mut dyn FnMut(&mut [u8]) -> core::result::Result<(), Error>,
241*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<Cursor<'a>> {
242*5225e6b1SAndroid Build Coastguard Worker         let boot_token = self.boot_token.take().ok_or(Error::OperationProhibited)?;
243*5225e6b1SAndroid Build Coastguard Worker         self.ops.load_slot_interface(persist, boot_token)
244*5225e6b1SAndroid Build Coastguard Worker     }
245*5225e6b1SAndroid Build Coastguard Worker 
246*5225e6b1SAndroid Build Coastguard Worker     /// Info Load
247*5225e6b1SAndroid Build Coastguard Worker     ///
248*5225e6b1SAndroid Build Coastguard Worker     /// Unpack boot image in RAM
249*5225e6b1SAndroid Build Coastguard Worker     ///
250*5225e6b1SAndroid Build Coastguard Worker     /// # Arguments
251*5225e6b1SAndroid Build Coastguard Worker     ///   * `boot_image_buffer` - Buffer that contains (Optionally Verified) Boot Image
252*5225e6b1SAndroid Build Coastguard Worker     ///   * `boot_mode` - Boot Mode
253*5225e6b1SAndroid Build Coastguard Worker     ///   * `boot_target` - [Optional] Boot Target
254*5225e6b1SAndroid Build Coastguard Worker     ///
255*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
256*5225e6b1SAndroid Build Coastguard Worker     ///
257*5225e6b1SAndroid Build Coastguard Worker     /// * `Ok(InfoStruct)` - Info Struct (Concatenated kernel commandline - includes slot,
258*5225e6b1SAndroid Build Coastguard Worker     /// bootconfig selection, normal_mode, Concatenated bootconfig) on success
259*5225e6b1SAndroid Build Coastguard Worker     /// * `Err(Error)` - on failure
unpack_boot_image( &self, boot_image_buffer: &BootImage, boot_target: Option<BootTarget>, ) -> Result<InfoStruct>260*5225e6b1SAndroid Build Coastguard Worker     pub fn unpack_boot_image(
261*5225e6b1SAndroid Build Coastguard Worker         &self,
262*5225e6b1SAndroid Build Coastguard Worker         boot_image_buffer: &BootImage,
263*5225e6b1SAndroid Build Coastguard Worker         boot_target: Option<BootTarget>,
264*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<InfoStruct> {
265*5225e6b1SAndroid Build Coastguard Worker         unimplemented!();
266*5225e6b1SAndroid Build Coastguard Worker     }
267*5225e6b1SAndroid Build Coastguard Worker 
268*5225e6b1SAndroid Build Coastguard Worker     /// Kernel Load
269*5225e6b1SAndroid Build Coastguard Worker     ///
270*5225e6b1SAndroid Build Coastguard Worker     /// Prepare kernel in RAM for booting
271*5225e6b1SAndroid Build Coastguard Worker     ///
272*5225e6b1SAndroid Build Coastguard Worker     /// # Arguments
273*5225e6b1SAndroid Build Coastguard Worker     ///   * `info` - Info Struct from Info Load
274*5225e6b1SAndroid Build Coastguard Worker     ///   * `image_buffer` - Buffer that contains (Verified) Boot Image
275*5225e6b1SAndroid Build Coastguard Worker     ///   * `load_buffer` - Kernel Load buffer
276*5225e6b1SAndroid Build Coastguard Worker     ///
277*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
278*5225e6b1SAndroid Build Coastguard Worker     ///
279*5225e6b1SAndroid Build Coastguard Worker     /// * `Ok(())` - on success
280*5225e6b1SAndroid Build Coastguard Worker     /// * `Err(Error)` - on failure
kernel_load<'b>( &self, info: &InfoStruct, image_buffer: BootImage, load_buffer: &'b mut [u8], ) -> Result<KernelImage<'b>>281*5225e6b1SAndroid Build Coastguard Worker     pub fn kernel_load<'b>(
282*5225e6b1SAndroid Build Coastguard Worker         &self,
283*5225e6b1SAndroid Build Coastguard Worker         info: &InfoStruct,
284*5225e6b1SAndroid Build Coastguard Worker         image_buffer: BootImage,
285*5225e6b1SAndroid Build Coastguard Worker         load_buffer: &'b mut [u8],
286*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<KernelImage<'b>> {
287*5225e6b1SAndroid Build Coastguard Worker         unimplemented!();
288*5225e6b1SAndroid Build Coastguard Worker     }
289*5225e6b1SAndroid Build Coastguard Worker 
290*5225e6b1SAndroid Build Coastguard Worker     /// Ramdisk + Bootconfig Load
291*5225e6b1SAndroid Build Coastguard Worker     ///
292*5225e6b1SAndroid Build Coastguard Worker     /// Kernel Load
293*5225e6b1SAndroid Build Coastguard Worker     /// (Could break this into a RD and Bootconfig specific function each, TBD)
294*5225e6b1SAndroid Build Coastguard Worker     /// Prepare ramdisk/bootconfig in RAM for booting
295*5225e6b1SAndroid Build Coastguard Worker     ///
296*5225e6b1SAndroid Build Coastguard Worker     /// # Arguments
297*5225e6b1SAndroid Build Coastguard Worker     ///   * `info` - Info Struct from Info Load
298*5225e6b1SAndroid Build Coastguard Worker     ///   * `vendor_boot_image` - Buffer that contains (Verified) Vendor Boot Image
299*5225e6b1SAndroid Build Coastguard Worker     ///   * `init_boot_image` - Buffer that contains (Verified) Init Boot Image
300*5225e6b1SAndroid Build Coastguard Worker     ///   * `ramdisk_load_buffer` - Ramdisk Load buffer (not compressed). It will be filled with
301*5225e6b1SAndroid Build Coastguard Worker     ///     a concatenation of `vendor_boot_image`, `init_boot_image` and bootconfig at the end.
302*5225e6b1SAndroid Build Coastguard Worker     ///
303*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
304*5225e6b1SAndroid Build Coastguard Worker     ///
305*5225e6b1SAndroid Build Coastguard Worker     /// * `Ok(&str)` - on success returns Kernel command line
306*5225e6b1SAndroid Build Coastguard Worker     /// * `Err(Error)` - on failure
ramdisk_bootconfig_load( &self, info: &InfoStruct, vendor_boot_image: &VendorBootImage, init_boot_image: &InitBootImage, ramdisk: &mut Ramdisk, ) -> Result<&'static str>307*5225e6b1SAndroid Build Coastguard Worker     pub fn ramdisk_bootconfig_load(
308*5225e6b1SAndroid Build Coastguard Worker         &self,
309*5225e6b1SAndroid Build Coastguard Worker         info: &InfoStruct,
310*5225e6b1SAndroid Build Coastguard Worker         vendor_boot_image: &VendorBootImage,
311*5225e6b1SAndroid Build Coastguard Worker         init_boot_image: &InitBootImage,
312*5225e6b1SAndroid Build Coastguard Worker         ramdisk: &mut Ramdisk,
313*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<&'static str> {
314*5225e6b1SAndroid Build Coastguard Worker         unimplemented!();
315*5225e6b1SAndroid Build Coastguard Worker     }
316*5225e6b1SAndroid Build Coastguard Worker 
317*5225e6b1SAndroid Build Coastguard Worker     /// DTB Update And Load
318*5225e6b1SAndroid Build Coastguard Worker     ///
319*5225e6b1SAndroid Build Coastguard Worker     /// Prepare DTB in RAM for booting
320*5225e6b1SAndroid Build Coastguard Worker     ///
321*5225e6b1SAndroid Build Coastguard Worker     /// # Arguments
322*5225e6b1SAndroid Build Coastguard Worker     ///   * `info` - Info Struct from Info Load
323*5225e6b1SAndroid Build Coastguard Worker     ///   * `vendor_boot_image_buffer` - Buffer that contains (Verified) Vendor Boot Image
324*5225e6b1SAndroid Build Coastguard Worker     ///
325*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
326*5225e6b1SAndroid Build Coastguard Worker     ///
327*5225e6b1SAndroid Build Coastguard Worker     /// * `Ok()` - on success
328*5225e6b1SAndroid Build Coastguard Worker     /// * `Err(Error)` - on failure
dtb_update_and_load( &self, info: &InfoStruct, vendor_boot_image_buffer: VendorBootImage, ) -> Result<Dtb>329*5225e6b1SAndroid Build Coastguard Worker     pub fn dtb_update_and_load(
330*5225e6b1SAndroid Build Coastguard Worker         &self,
331*5225e6b1SAndroid Build Coastguard Worker         info: &InfoStruct,
332*5225e6b1SAndroid Build Coastguard Worker         vendor_boot_image_buffer: VendorBootImage,
333*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<Dtb> {
334*5225e6b1SAndroid Build Coastguard Worker         unimplemented!();
335*5225e6b1SAndroid Build Coastguard Worker     }
336*5225e6b1SAndroid Build Coastguard Worker 
337*5225e6b1SAndroid Build Coastguard Worker     /// Kernel Jump
338*5225e6b1SAndroid Build Coastguard Worker     ///
339*5225e6b1SAndroid Build Coastguard Worker     ///
340*5225e6b1SAndroid Build Coastguard Worker     /// # Arguments
341*5225e6b1SAndroid Build Coastguard Worker     ///   * `kernel_load_buffer` - Kernel Load buffer
342*5225e6b1SAndroid Build Coastguard Worker     ///   * `ramdisk_bootconfi_load_buffer` - Concatenated Ramdisk, (Bootconfig if present) Load
343*5225e6b1SAndroid Build Coastguard Worker     ///   buffer
344*5225e6b1SAndroid Build Coastguard Worker     ///   * `dtb_load_buffer` - DTB Load buffer
345*5225e6b1SAndroid Build Coastguard Worker     ///   * `boot_token` - Consumable boot token
346*5225e6b1SAndroid Build Coastguard Worker     ///
347*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
348*5225e6b1SAndroid Build Coastguard Worker     ///
349*5225e6b1SAndroid Build Coastguard Worker     /// * doesn't return on success
350*5225e6b1SAndroid Build Coastguard Worker     /// * `Err(Error)` - on failure
351*5225e6b1SAndroid Build Coastguard Worker     // Nevertype could be used here when it is stable https://github.com/serde-rs/serde/issues/812
kernel_jump( &self, kernel_load_buffer: KernelImage, ramdisk_load_buffer: Ramdisk, dtb_load_buffer: Dtb, boot_token: BootToken, ) -> Result<()>352*5225e6b1SAndroid Build Coastguard Worker     pub fn kernel_jump(
353*5225e6b1SAndroid Build Coastguard Worker         &self,
354*5225e6b1SAndroid Build Coastguard Worker         kernel_load_buffer: KernelImage,
355*5225e6b1SAndroid Build Coastguard Worker         ramdisk_load_buffer: Ramdisk,
356*5225e6b1SAndroid Build Coastguard Worker         dtb_load_buffer: Dtb,
357*5225e6b1SAndroid Build Coastguard Worker         boot_token: BootToken,
358*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<()> {
359*5225e6b1SAndroid Build Coastguard Worker         unimplemented!();
360*5225e6b1SAndroid Build Coastguard Worker     }
361*5225e6b1SAndroid Build Coastguard Worker 
362*5225e6b1SAndroid Build Coastguard Worker     /// Load, verify, and boot
363*5225e6b1SAndroid Build Coastguard Worker     ///
364*5225e6b1SAndroid Build Coastguard Worker     /// Wrapper around the above functions for devices that don't need custom behavior between each
365*5225e6b1SAndroid Build Coastguard Worker     /// step
366*5225e6b1SAndroid Build Coastguard Worker     ///
367*5225e6b1SAndroid Build Coastguard Worker     /// Warning: If the call to load_verify_boot fails, the device MUST
368*5225e6b1SAndroid Build Coastguard Worker     ///          be restarted in order to make forward boot progress.
369*5225e6b1SAndroid Build Coastguard Worker     ///          Callers MAY log the error, enter an interactive mode,
370*5225e6b1SAndroid Build Coastguard Worker     ///          or take other actions before rebooting.
371*5225e6b1SAndroid Build Coastguard Worker     ///
372*5225e6b1SAndroid Build Coastguard Worker     /// # Arguments
373*5225e6b1SAndroid Build Coastguard Worker     /// * `avb_ops` - implementation for `avb::Ops` that would be borrowed in result to prevent
374*5225e6b1SAndroid Build Coastguard Worker     ///   changes to partitions until it is out of scope.
375*5225e6b1SAndroid Build Coastguard Worker     /// * `partitions_to_verify` - names of all the partitions to verify with libavb.
376*5225e6b1SAndroid Build Coastguard Worker     /// * `partitions_ram_map` - Partitions to verify and optional address for them to be loaded.
377*5225e6b1SAndroid Build Coastguard Worker     /// * `slot_verify_flags` - AVB slot verification flags
378*5225e6b1SAndroid Build Coastguard Worker     /// * `slot_cursor` - Cursor object that manages interactions with boot slot management
379*5225e6b1SAndroid Build Coastguard Worker     /// * `kernel_load_buffer` - Buffer for loading the kernel.
380*5225e6b1SAndroid Build Coastguard Worker     /// * `ramdisk_load_buffer` - Buffer for loading the ramdisk.
381*5225e6b1SAndroid Build Coastguard Worker     /// * `fdt` - Buffer containing a flattened device tree blob.
382*5225e6b1SAndroid Build Coastguard Worker     ///
383*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
384*5225e6b1SAndroid Build Coastguard Worker     /// * doesn't return on success
385*5225e6b1SAndroid Build Coastguard Worker     /// * `Err(Error)` - on failure
386*5225e6b1SAndroid Build Coastguard Worker     // Nevertype could be used here when it is stable https://github.com/serde-rs/serde/issues/812
387*5225e6b1SAndroid Build Coastguard Worker     #[allow(clippy::too_many_arguments)]
load_verify_boot<'b: 'c, 'c, 'd: 'b>( &mut self, avb_ops: &mut impl avb::Ops<'b>, partitions_to_verify: &[&CStr], partitions_ram_map: &'d mut [PartitionRamMap<'b, 'c>], slot_verify_flags: SlotVerifyFlags, slot_cursor: Cursor, kernel_load_buffer: &mut [u8], ramdisk_load_buffer: &mut [u8], fdt: &mut [u8], ) -> Result<()>388*5225e6b1SAndroid Build Coastguard Worker     pub fn load_verify_boot<'b: 'c, 'c, 'd: 'b>(
389*5225e6b1SAndroid Build Coastguard Worker         &mut self,
390*5225e6b1SAndroid Build Coastguard Worker         avb_ops: &mut impl avb::Ops<'b>,
391*5225e6b1SAndroid Build Coastguard Worker         partitions_to_verify: &[&CStr],
392*5225e6b1SAndroid Build Coastguard Worker         partitions_ram_map: &'d mut [PartitionRamMap<'b, 'c>],
393*5225e6b1SAndroid Build Coastguard Worker         slot_verify_flags: SlotVerifyFlags,
394*5225e6b1SAndroid Build Coastguard Worker         slot_cursor: Cursor,
395*5225e6b1SAndroid Build Coastguard Worker         kernel_load_buffer: &mut [u8],
396*5225e6b1SAndroid Build Coastguard Worker         ramdisk_load_buffer: &mut [u8],
397*5225e6b1SAndroid Build Coastguard Worker         fdt: &mut [u8],
398*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<()> {
399*5225e6b1SAndroid Build Coastguard Worker         let dtb = Dtb(&mut fdt[..]);
400*5225e6b1SAndroid Build Coastguard Worker         let mut ramdisk = Ramdisk(ramdisk_load_buffer);
401*5225e6b1SAndroid Build Coastguard Worker 
402*5225e6b1SAndroid Build Coastguard Worker         // Call the inner method which consumes the cursor
403*5225e6b1SAndroid Build Coastguard Worker         // in order to properly manager cursor lifetime
404*5225e6b1SAndroid Build Coastguard Worker         // and cleanup.
405*5225e6b1SAndroid Build Coastguard Worker         let (kernel_image, token) = self.lvb_inner(
406*5225e6b1SAndroid Build Coastguard Worker             avb_ops,
407*5225e6b1SAndroid Build Coastguard Worker             &mut ramdisk,
408*5225e6b1SAndroid Build Coastguard Worker             kernel_load_buffer,
409*5225e6b1SAndroid Build Coastguard Worker             partitions_to_verify,
410*5225e6b1SAndroid Build Coastguard Worker             partitions_ram_map,
411*5225e6b1SAndroid Build Coastguard Worker             slot_verify_flags,
412*5225e6b1SAndroid Build Coastguard Worker             slot_cursor,
413*5225e6b1SAndroid Build Coastguard Worker         )?;
414*5225e6b1SAndroid Build Coastguard Worker 
415*5225e6b1SAndroid Build Coastguard Worker         self.kernel_jump(kernel_image, ramdisk, dtb, token)
416*5225e6b1SAndroid Build Coastguard Worker     }
417*5225e6b1SAndroid Build Coastguard Worker 
is_unrecoverable_error(error: &IntegrationError) -> bool418*5225e6b1SAndroid Build Coastguard Worker     fn is_unrecoverable_error(error: &IntegrationError) -> bool {
419*5225e6b1SAndroid Build Coastguard Worker         // Note: these ifs are nested instead of chained because multiple
420*5225e6b1SAndroid Build Coastguard Worker         //       expressions in an if-let is an unstable features
421*5225e6b1SAndroid Build Coastguard Worker         if let IntegrationError::AvbSlotVerifyError(ref avb_error) = error {
422*5225e6b1SAndroid Build Coastguard Worker             // These are the AVB errors that are not recoverable on a subsequent attempt.
423*5225e6b1SAndroid Build Coastguard Worker             // If necessary in the future, this helper function can be moved to the GblOps trait
424*5225e6b1SAndroid Build Coastguard Worker             // and customized for platform specific behavior.
425*5225e6b1SAndroid Build Coastguard Worker             if matches!(
426*5225e6b1SAndroid Build Coastguard Worker                 avb_error,
427*5225e6b1SAndroid Build Coastguard Worker                 SlotVerifyError::Verification(_)
428*5225e6b1SAndroid Build Coastguard Worker                     | SlotVerifyError::PublicKeyRejected
429*5225e6b1SAndroid Build Coastguard Worker                     | SlotVerifyError::RollbackIndex
430*5225e6b1SAndroid Build Coastguard Worker             ) {
431*5225e6b1SAndroid Build Coastguard Worker                 return true;
432*5225e6b1SAndroid Build Coastguard Worker             }
433*5225e6b1SAndroid Build Coastguard Worker         }
434*5225e6b1SAndroid Build Coastguard Worker         false
435*5225e6b1SAndroid Build Coastguard Worker     }
436*5225e6b1SAndroid Build Coastguard Worker 
lvb_inner<'b: 'c, 'c, 'd: 'b, 'e>( &mut self, avb_ops: &mut impl avb::Ops<'b>, ramdisk: &mut Ramdisk, kernel_load_buffer: &'e mut [u8], partitions_to_verify: &[&CStr], partitions_ram_map: &'d mut [PartitionRamMap<'b, 'c>], slot_verify_flags: SlotVerifyFlags, slot_cursor: Cursor, ) -> Result<(KernelImage<'e>, BootToken)>437*5225e6b1SAndroid Build Coastguard Worker     fn lvb_inner<'b: 'c, 'c, 'd: 'b, 'e>(
438*5225e6b1SAndroid Build Coastguard Worker         &mut self,
439*5225e6b1SAndroid Build Coastguard Worker         avb_ops: &mut impl avb::Ops<'b>,
440*5225e6b1SAndroid Build Coastguard Worker         ramdisk: &mut Ramdisk,
441*5225e6b1SAndroid Build Coastguard Worker         kernel_load_buffer: &'e mut [u8],
442*5225e6b1SAndroid Build Coastguard Worker         partitions_to_verify: &[&CStr],
443*5225e6b1SAndroid Build Coastguard Worker         partitions_ram_map: &'d mut [PartitionRamMap<'b, 'c>],
444*5225e6b1SAndroid Build Coastguard Worker         slot_verify_flags: SlotVerifyFlags,
445*5225e6b1SAndroid Build Coastguard Worker         slot_cursor: Cursor,
446*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<(KernelImage<'e>, BootToken)> {
447*5225e6b1SAndroid Build Coastguard Worker         let oneshot_status = slot_cursor.ctx.get_oneshot_status();
448*5225e6b1SAndroid Build Coastguard Worker         slot_cursor.ctx.clear_oneshot_status();
449*5225e6b1SAndroid Build Coastguard Worker 
450*5225e6b1SAndroid Build Coastguard Worker         let boot_target = match oneshot_status {
451*5225e6b1SAndroid Build Coastguard Worker             None | Some(OneShot::Bootloader) => slot_cursor.ctx.get_boot_target()?,
452*5225e6b1SAndroid Build Coastguard Worker             Some(OneShot::Continue(recovery)) => BootTarget::Recovery(recovery),
453*5225e6b1SAndroid Build Coastguard Worker         };
454*5225e6b1SAndroid Build Coastguard Worker 
455*5225e6b1SAndroid Build Coastguard Worker         let verify_data = self
456*5225e6b1SAndroid Build Coastguard Worker             .load_and_verify_image(
457*5225e6b1SAndroid Build Coastguard Worker                 avb_ops,
458*5225e6b1SAndroid Build Coastguard Worker                 partitions_to_verify,
459*5225e6b1SAndroid Build Coastguard Worker                 slot_verify_flags,
460*5225e6b1SAndroid Build Coastguard Worker                 Some(boot_target),
461*5225e6b1SAndroid Build Coastguard Worker             )
462*5225e6b1SAndroid Build Coastguard Worker             .map_err(|e: IntegrationError| {
463*5225e6b1SAndroid Build Coastguard Worker                 if let BootTarget::NormalBoot(slot) = boot_target {
464*5225e6b1SAndroid Build Coastguard Worker                     if Self::is_unrecoverable_error(&e) {
465*5225e6b1SAndroid Build Coastguard Worker                         let _ = slot_cursor.ctx.set_slot_unbootable(
466*5225e6b1SAndroid Build Coastguard Worker                             slot.suffix,
467*5225e6b1SAndroid Build Coastguard Worker                             UnbootableReason::VerificationFailure,
468*5225e6b1SAndroid Build Coastguard Worker                         );
469*5225e6b1SAndroid Build Coastguard Worker                     } else {
470*5225e6b1SAndroid Build Coastguard Worker                         // Note: the call to mark_boot_attempt will fail if any of the following occur:
471*5225e6b1SAndroid Build Coastguard Worker                         // * the target was already Unbootable before the call to load_and_verify_image
472*5225e6b1SAndroid Build Coastguard Worker                         // * policy, I/O, or other errors in mark_boot_attempt
473*5225e6b1SAndroid Build Coastguard Worker                         //
474*5225e6b1SAndroid Build Coastguard Worker                         // We don't really care about those circumstances.
475*5225e6b1SAndroid Build Coastguard Worker                         // The call here is a best effort attempt to decrement tries remaining.
476*5225e6b1SAndroid Build Coastguard Worker                         let _ = slot_cursor.ctx.mark_boot_attempt();
477*5225e6b1SAndroid Build Coastguard Worker                     }
478*5225e6b1SAndroid Build Coastguard Worker                 }
479*5225e6b1SAndroid Build Coastguard Worker                 e
480*5225e6b1SAndroid Build Coastguard Worker             })?;
481*5225e6b1SAndroid Build Coastguard Worker 
482*5225e6b1SAndroid Build Coastguard Worker         let (boot_image, init_boot_image, vendor_boot_image, _) = get_images(partitions_ram_map);
483*5225e6b1SAndroid Build Coastguard Worker         let boot_image = boot_image.ok_or(Error::MissingImage)?;
484*5225e6b1SAndroid Build Coastguard Worker         let vendor_boot_image = vendor_boot_image.ok_or(Error::MissingImage)?;
485*5225e6b1SAndroid Build Coastguard Worker         let init_boot_image = init_boot_image.ok_or(Error::MissingImage)?;
486*5225e6b1SAndroid Build Coastguard Worker 
487*5225e6b1SAndroid Build Coastguard Worker         if is_overlap(&[
488*5225e6b1SAndroid Build Coastguard Worker             boot_image.0,
489*5225e6b1SAndroid Build Coastguard Worker             vendor_boot_image.0,
490*5225e6b1SAndroid Build Coastguard Worker             init_boot_image.0,
491*5225e6b1SAndroid Build Coastguard Worker             &ramdisk.0,
492*5225e6b1SAndroid Build Coastguard Worker             kernel_load_buffer,
493*5225e6b1SAndroid Build Coastguard Worker         ]) {
494*5225e6b1SAndroid Build Coastguard Worker             return Err(IntegrationError::UnificationError(Error::BufferOverlap));
495*5225e6b1SAndroid Build Coastguard Worker         }
496*5225e6b1SAndroid Build Coastguard Worker 
497*5225e6b1SAndroid Build Coastguard Worker         let info_struct = self.unpack_boot_image(&boot_image, Some(boot_target))?;
498*5225e6b1SAndroid Build Coastguard Worker 
499*5225e6b1SAndroid Build Coastguard Worker         let kernel_image = self.kernel_load(&info_struct, boot_image, kernel_load_buffer)?;
500*5225e6b1SAndroid Build Coastguard Worker 
501*5225e6b1SAndroid Build Coastguard Worker         let cmd_line = self.ramdisk_bootconfig_load(
502*5225e6b1SAndroid Build Coastguard Worker             &info_struct,
503*5225e6b1SAndroid Build Coastguard Worker             &vendor_boot_image,
504*5225e6b1SAndroid Build Coastguard Worker             &init_boot_image,
505*5225e6b1SAndroid Build Coastguard Worker             ramdisk,
506*5225e6b1SAndroid Build Coastguard Worker         )?;
507*5225e6b1SAndroid Build Coastguard Worker 
508*5225e6b1SAndroid Build Coastguard Worker         self.dtb_update_and_load(&info_struct, vendor_boot_image)?;
509*5225e6b1SAndroid Build Coastguard Worker 
510*5225e6b1SAndroid Build Coastguard Worker         let token = slot_cursor.ctx.mark_boot_attempt().map_err(|_| Error::OperationProhibited)?;
511*5225e6b1SAndroid Build Coastguard Worker 
512*5225e6b1SAndroid Build Coastguard Worker         Ok((kernel_image, token))
513*5225e6b1SAndroid Build Coastguard Worker     }
514*5225e6b1SAndroid Build Coastguard Worker }
515*5225e6b1SAndroid Build Coastguard Worker 
516*5225e6b1SAndroid Build Coastguard Worker #[cfg(test)]
517*5225e6b1SAndroid Build Coastguard Worker mod tests {
518*5225e6b1SAndroid Build Coastguard Worker     extern crate avb_sysdeps;
519*5225e6b1SAndroid Build Coastguard Worker     extern crate avb_test;
520*5225e6b1SAndroid Build Coastguard Worker     use super::*;
521*5225e6b1SAndroid Build Coastguard Worker     use crate::ops::test::FakeGblOps;
522*5225e6b1SAndroid Build Coastguard Worker     use avb::{CertPermanentAttributes, SlotVerifyError};
523*5225e6b1SAndroid Build Coastguard Worker     use avb_test::{FakeVbmetaKey, TestOps};
524*5225e6b1SAndroid Build Coastguard Worker     use std::{fs, path::Path};
525*5225e6b1SAndroid Build Coastguard Worker     use zerocopy::FromBytes;
526*5225e6b1SAndroid Build Coastguard Worker 
527*5225e6b1SAndroid Build Coastguard Worker     const TEST_ZIRCON_PARTITION_NAME: &str = "zircon_a";
528*5225e6b1SAndroid Build Coastguard Worker     const TEST_ZIRCON_PARTITION_NAME_CSTR: &CStr = c"zircon_a";
529*5225e6b1SAndroid Build Coastguard Worker     const TEST_ZIRCON_IMAGE_PATH: &str = "zircon_a.zbi";
530*5225e6b1SAndroid Build Coastguard Worker     const TEST_ZIRCON_VBMETA_PATH: &str = "zircon_a.vbmeta";
531*5225e6b1SAndroid Build Coastguard Worker     const TEST_ZIRCON_VBMETA_CERT_PATH: &str = "zircon_a.vbmeta.cert";
532*5225e6b1SAndroid Build Coastguard Worker     const TEST_PUBLIC_KEY_PATH: &str = "testkey_rsa4096_pub.bin";
533*5225e6b1SAndroid Build Coastguard Worker     const TEST_PERMANENT_ATTRIBUTES_PATH: &str = "cert_permanent_attributes.bin";
534*5225e6b1SAndroid Build Coastguard Worker     const TEST_PERMANENT_ATTRIBUTES_HASH_PATH: &str = "cert_permanent_attributes.hash";
535*5225e6b1SAndroid Build Coastguard Worker     const TEST_BAD_PERMANENT_ATTRIBUTES_PATH: &str = "cert_permanent_attributes.bad.bin";
536*5225e6b1SAndroid Build Coastguard Worker     const TEST_BAD_PERMANENT_ATTRIBUTES_HASH_PATH: &str = "cert_permanent_attributes.bad.hash";
537*5225e6b1SAndroid Build Coastguard Worker     const TEST_VBMETA_ROLLBACK_LOCATION: usize = 0; // Default value, we don't explicitly set this.
538*5225e6b1SAndroid Build Coastguard Worker     pub const TEST_CERT_PIK_VERSION: u64 = 42;
539*5225e6b1SAndroid Build Coastguard Worker     pub const TEST_CERT_PSK_VERSION: u64 = 42;
540*5225e6b1SAndroid Build Coastguard Worker 
541*5225e6b1SAndroid Build Coastguard Worker     /// Returns the contents of a test data file.
542*5225e6b1SAndroid Build Coastguard Worker     ///
543*5225e6b1SAndroid Build Coastguard Worker     /// Panicks if the requested file cannot be read.
544*5225e6b1SAndroid Build Coastguard Worker     ///
545*5225e6b1SAndroid Build Coastguard Worker     /// # Arguments
546*5225e6b1SAndroid Build Coastguard Worker     /// * `path`: file path relative to libgbl's `testdata/` directory.
testdata(path: &str) -> Vec<u8>547*5225e6b1SAndroid Build Coastguard Worker     fn testdata(path: &str) -> Vec<u8> {
548*5225e6b1SAndroid Build Coastguard Worker         let full_path = Path::new("external/gbl/libgbl/testdata").join(path);
549*5225e6b1SAndroid Build Coastguard Worker         fs::read(full_path).unwrap()
550*5225e6b1SAndroid Build Coastguard Worker     }
551*5225e6b1SAndroid Build Coastguard Worker 
552*5225e6b1SAndroid Build Coastguard Worker     /// Creates and returns a configured avb `TestOps`.
553*5225e6b1SAndroid Build Coastguard Worker     ///
554*5225e6b1SAndroid Build Coastguard Worker     /// The initial state will verify successfully with:
555*5225e6b1SAndroid Build Coastguard Worker     /// * a valid vbmeta image in the `vbmeta` partition, containing a hash descriptor for the
556*5225e6b1SAndroid Build Coastguard Worker     ///   `TEST_ZIRCON_PARTITION_NAME` partition
557*5225e6b1SAndroid Build Coastguard Worker     /// * an image in the `TEST_ZIRCON_PARTITION_NAME` partition matching the vbmeta hash
558*5225e6b1SAndroid Build Coastguard Worker     /// * no preloaded partition data
559*5225e6b1SAndroid Build Coastguard Worker     /// * a public key matching the vbmeta image
560*5225e6b1SAndroid Build Coastguard Worker     /// * a valid vbmeta rollback index
561*5225e6b1SAndroid Build Coastguard Worker     /// * a locked bootloader state
562*5225e6b1SAndroid Build Coastguard Worker     ///
563*5225e6b1SAndroid Build Coastguard Worker     /// The caller can modify any of this state as needed for their particular test.
test_avb_ops() -> TestOps<'static>564*5225e6b1SAndroid Build Coastguard Worker     fn test_avb_ops() -> TestOps<'static> {
565*5225e6b1SAndroid Build Coastguard Worker         let mut avb_ops = TestOps::default();
566*5225e6b1SAndroid Build Coastguard Worker 
567*5225e6b1SAndroid Build Coastguard Worker         avb_ops.add_partition(TEST_ZIRCON_PARTITION_NAME, testdata(TEST_ZIRCON_IMAGE_PATH));
568*5225e6b1SAndroid Build Coastguard Worker         avb_ops.add_partition("vbmeta", testdata(TEST_ZIRCON_VBMETA_PATH));
569*5225e6b1SAndroid Build Coastguard Worker         avb_ops.default_vbmeta_key = Some(FakeVbmetaKey::Avb {
570*5225e6b1SAndroid Build Coastguard Worker             public_key: testdata(TEST_PUBLIC_KEY_PATH),
571*5225e6b1SAndroid Build Coastguard Worker             public_key_metadata: None,
572*5225e6b1SAndroid Build Coastguard Worker         });
573*5225e6b1SAndroid Build Coastguard Worker         avb_ops.rollbacks.insert(TEST_VBMETA_ROLLBACK_LOCATION, Ok(0));
574*5225e6b1SAndroid Build Coastguard Worker         avb_ops.unlock_state = Ok(false);
575*5225e6b1SAndroid Build Coastguard Worker 
576*5225e6b1SAndroid Build Coastguard Worker         avb_ops
577*5225e6b1SAndroid Build Coastguard Worker     }
578*5225e6b1SAndroid Build Coastguard Worker 
579*5225e6b1SAndroid Build Coastguard Worker     /// Similar to `test_avb_ops()`, but with the avb_cert extension enabled.
test_avb_cert_ops() -> TestOps<'static>580*5225e6b1SAndroid Build Coastguard Worker     fn test_avb_cert_ops() -> TestOps<'static> {
581*5225e6b1SAndroid Build Coastguard Worker         let mut avb_ops = test_avb_ops();
582*5225e6b1SAndroid Build Coastguard Worker 
583*5225e6b1SAndroid Build Coastguard Worker         // Replace vbmeta with the cert-signed version.
584*5225e6b1SAndroid Build Coastguard Worker         avb_ops.add_partition("vbmeta", testdata(TEST_ZIRCON_VBMETA_CERT_PATH));
585*5225e6b1SAndroid Build Coastguard Worker 
586*5225e6b1SAndroid Build Coastguard Worker         // Tell `avb_ops` to use cert APIs and to route the default key through cert validation.
587*5225e6b1SAndroid Build Coastguard Worker         avb_ops.use_cert = true;
588*5225e6b1SAndroid Build Coastguard Worker         avb_ops.default_vbmeta_key = Some(FakeVbmetaKey::Cert);
589*5225e6b1SAndroid Build Coastguard Worker 
590*5225e6b1SAndroid Build Coastguard Worker         // Add the permanent attributes.
591*5225e6b1SAndroid Build Coastguard Worker         let perm_attr_bytes = testdata(TEST_PERMANENT_ATTRIBUTES_PATH);
592*5225e6b1SAndroid Build Coastguard Worker         let perm_attr_hash = testdata(TEST_PERMANENT_ATTRIBUTES_HASH_PATH);
593*5225e6b1SAndroid Build Coastguard Worker         avb_ops.cert_permanent_attributes =
594*5225e6b1SAndroid Build Coastguard Worker             Some(CertPermanentAttributes::read_from(&perm_attr_bytes[..]).unwrap());
595*5225e6b1SAndroid Build Coastguard Worker         avb_ops.cert_permanent_attributes_hash = Some(perm_attr_hash.try_into().unwrap());
596*5225e6b1SAndroid Build Coastguard Worker 
597*5225e6b1SAndroid Build Coastguard Worker         // Add the rollbacks for the cert keys.
598*5225e6b1SAndroid Build Coastguard Worker         avb_ops.rollbacks.insert(avb::CERT_PIK_VERSION_LOCATION, Ok(TEST_CERT_PIK_VERSION));
599*5225e6b1SAndroid Build Coastguard Worker         avb_ops.rollbacks.insert(avb::CERT_PSK_VERSION_LOCATION, Ok(TEST_CERT_PSK_VERSION));
600*5225e6b1SAndroid Build Coastguard Worker 
601*5225e6b1SAndroid Build Coastguard Worker         avb_ops
602*5225e6b1SAndroid Build Coastguard Worker     }
603*5225e6b1SAndroid Build Coastguard Worker 
604*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_load_and_verify_image_success()605*5225e6b1SAndroid Build Coastguard Worker     fn test_load_and_verify_image_success() {
606*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::default();
607*5225e6b1SAndroid Build Coastguard Worker         let mut gbl = Gbl::new(&mut gbl_ops);
608*5225e6b1SAndroid Build Coastguard Worker         let mut avb_ops = test_avb_ops();
609*5225e6b1SAndroid Build Coastguard Worker 
610*5225e6b1SAndroid Build Coastguard Worker         let res = gbl.load_and_verify_image(
611*5225e6b1SAndroid Build Coastguard Worker             &mut avb_ops,
612*5225e6b1SAndroid Build Coastguard Worker             &mut [&TEST_ZIRCON_PARTITION_NAME_CSTR],
613*5225e6b1SAndroid Build Coastguard Worker             SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE,
614*5225e6b1SAndroid Build Coastguard Worker             None,
615*5225e6b1SAndroid Build Coastguard Worker         );
616*5225e6b1SAndroid Build Coastguard Worker         assert!(res.is_ok());
617*5225e6b1SAndroid Build Coastguard Worker     }
618*5225e6b1SAndroid Build Coastguard Worker 
619*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_load_and_verify_image_verification_error()620*5225e6b1SAndroid Build Coastguard Worker     fn test_load_and_verify_image_verification_error() {
621*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::default();
622*5225e6b1SAndroid Build Coastguard Worker         let mut gbl = Gbl::new(&mut gbl_ops);
623*5225e6b1SAndroid Build Coastguard Worker         let mut avb_ops = test_avb_ops();
624*5225e6b1SAndroid Build Coastguard Worker 
625*5225e6b1SAndroid Build Coastguard Worker         // Modify the kernel image, it should now fail to validate against the vbmeta image.
626*5225e6b1SAndroid Build Coastguard Worker         avb_ops.partitions.get_mut(TEST_ZIRCON_PARTITION_NAME).unwrap().contents.as_mut_vec()[0] ^=
627*5225e6b1SAndroid Build Coastguard Worker             0x01;
628*5225e6b1SAndroid Build Coastguard Worker 
629*5225e6b1SAndroid Build Coastguard Worker         let res = gbl.load_and_verify_image(
630*5225e6b1SAndroid Build Coastguard Worker             &mut avb_ops,
631*5225e6b1SAndroid Build Coastguard Worker             &mut [&TEST_ZIRCON_PARTITION_NAME_CSTR],
632*5225e6b1SAndroid Build Coastguard Worker             SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE,
633*5225e6b1SAndroid Build Coastguard Worker             None,
634*5225e6b1SAndroid Build Coastguard Worker         );
635*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
636*5225e6b1SAndroid Build Coastguard Worker             res.unwrap_err(),
637*5225e6b1SAndroid Build Coastguard Worker             IntegrationError::AvbSlotVerifyError(SlotVerifyError::Verification(None))
638*5225e6b1SAndroid Build Coastguard Worker         );
639*5225e6b1SAndroid Build Coastguard Worker     }
640*5225e6b1SAndroid Build Coastguard Worker 
641*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_load_and_verify_image_io_error()642*5225e6b1SAndroid Build Coastguard Worker     fn test_load_and_verify_image_io_error() {
643*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::default();
644*5225e6b1SAndroid Build Coastguard Worker         let mut gbl = Gbl::new(&mut gbl_ops);
645*5225e6b1SAndroid Build Coastguard Worker         let mut avb_ops = test_avb_ops();
646*5225e6b1SAndroid Build Coastguard Worker 
647*5225e6b1SAndroid Build Coastguard Worker         // Erase the fake rollbacks, which will result in an I/O error when attempting to access.
648*5225e6b1SAndroid Build Coastguard Worker         avb_ops.rollbacks.clear();
649*5225e6b1SAndroid Build Coastguard Worker 
650*5225e6b1SAndroid Build Coastguard Worker         let res = gbl.load_and_verify_image(
651*5225e6b1SAndroid Build Coastguard Worker             &mut avb_ops,
652*5225e6b1SAndroid Build Coastguard Worker             &mut [&TEST_ZIRCON_PARTITION_NAME_CSTR],
653*5225e6b1SAndroid Build Coastguard Worker             SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE,
654*5225e6b1SAndroid Build Coastguard Worker             None,
655*5225e6b1SAndroid Build Coastguard Worker         );
656*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(res.unwrap_err(), IntegrationError::AvbSlotVerifyError(SlotVerifyError::Io));
657*5225e6b1SAndroid Build Coastguard Worker     }
658*5225e6b1SAndroid Build Coastguard Worker 
659*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_load_and_verify_image_with_cert_success()660*5225e6b1SAndroid Build Coastguard Worker     fn test_load_and_verify_image_with_cert_success() {
661*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::default();
662*5225e6b1SAndroid Build Coastguard Worker         let mut gbl = Gbl::new(&mut gbl_ops);
663*5225e6b1SAndroid Build Coastguard Worker         let mut avb_ops = test_avb_cert_ops();
664*5225e6b1SAndroid Build Coastguard Worker 
665*5225e6b1SAndroid Build Coastguard Worker         let res = gbl.load_and_verify_image(
666*5225e6b1SAndroid Build Coastguard Worker             &mut avb_ops,
667*5225e6b1SAndroid Build Coastguard Worker             &mut [&TEST_ZIRCON_PARTITION_NAME_CSTR],
668*5225e6b1SAndroid Build Coastguard Worker             SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE,
669*5225e6b1SAndroid Build Coastguard Worker             None,
670*5225e6b1SAndroid Build Coastguard Worker         );
671*5225e6b1SAndroid Build Coastguard Worker         assert!(res.is_ok());
672*5225e6b1SAndroid Build Coastguard Worker     }
673*5225e6b1SAndroid Build Coastguard Worker 
674*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_load_and_verify_image_with_cert_permanent_attribute_mismatch_error()675*5225e6b1SAndroid Build Coastguard Worker     fn test_load_and_verify_image_with_cert_permanent_attribute_mismatch_error() {
676*5225e6b1SAndroid Build Coastguard Worker         let mut gbl_ops = FakeGblOps::default();
677*5225e6b1SAndroid Build Coastguard Worker         let mut gbl = Gbl::new(&mut gbl_ops);
678*5225e6b1SAndroid Build Coastguard Worker         let mut avb_ops = test_avb_cert_ops();
679*5225e6b1SAndroid Build Coastguard Worker 
680*5225e6b1SAndroid Build Coastguard Worker         // Swap in the corrupted permanent attributes, which should cause the vbmeta image to fail
681*5225e6b1SAndroid Build Coastguard Worker         // validation due to key mismatch.
682*5225e6b1SAndroid Build Coastguard Worker         let perm_attr_bytes = testdata(TEST_BAD_PERMANENT_ATTRIBUTES_PATH);
683*5225e6b1SAndroid Build Coastguard Worker         let perm_attr_hash = testdata(TEST_BAD_PERMANENT_ATTRIBUTES_HASH_PATH);
684*5225e6b1SAndroid Build Coastguard Worker         avb_ops.cert_permanent_attributes =
685*5225e6b1SAndroid Build Coastguard Worker             Some(CertPermanentAttributes::read_from(&perm_attr_bytes[..]).unwrap());
686*5225e6b1SAndroid Build Coastguard Worker         avb_ops.cert_permanent_attributes_hash = Some(perm_attr_hash.try_into().unwrap());
687*5225e6b1SAndroid Build Coastguard Worker 
688*5225e6b1SAndroid Build Coastguard Worker         let res = gbl.load_and_verify_image(
689*5225e6b1SAndroid Build Coastguard Worker             &mut avb_ops,
690*5225e6b1SAndroid Build Coastguard Worker             &mut [&TEST_ZIRCON_PARTITION_NAME_CSTR],
691*5225e6b1SAndroid Build Coastguard Worker             SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE,
692*5225e6b1SAndroid Build Coastguard Worker             None,
693*5225e6b1SAndroid Build Coastguard Worker         );
694*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(
695*5225e6b1SAndroid Build Coastguard Worker             res.unwrap_err(),
696*5225e6b1SAndroid Build Coastguard Worker             IntegrationError::AvbSlotVerifyError(SlotVerifyError::PublicKeyRejected)
697*5225e6b1SAndroid Build Coastguard Worker         );
698*5225e6b1SAndroid Build Coastguard Worker     }
699*5225e6b1SAndroid Build Coastguard Worker }
700