xref: /aosp_15_r20/bootable/libbootloader/gbl/efi/src/ops.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Implements [Gbl::Ops] for the EFI environment.
16 
17 use crate::{
18     efi,
19     efi_blocks::EfiGblDisk,
20     utils::{get_efi_fdt, wait_key_stroke},
21 };
22 use alloc::{
23     alloc::{alloc, handle_alloc_error, Layout},
24     vec::Vec,
25 };
26 use arrayvec::ArrayVec;
27 use core::{
28     cmp::min, ffi::CStr, fmt::Write, mem::MaybeUninit, num::NonZeroUsize, ops::DerefMut, ptr::null,
29     slice::from_raw_parts_mut,
30 };
31 use efi::{
32     efi_print, efi_println,
33     protocol::{
34         dt_fixup::DtFixupProtocol, gbl_efi_ab_slot::GblSlotProtocol, gbl_efi_avb::GblAvbProtocol,
35         gbl_efi_fastboot::GblFastbootProtocol, gbl_efi_image_loading::GblImageLoadingProtocol,
36         gbl_efi_os_configuration::GblOsConfigurationProtocol,
37     },
38     EfiEntry,
39 };
40 use efi_types::{
41     GblEfiAvbKeyValidationStatus, GblEfiAvbVerificationResult, GblEfiBootReason,
42     GblEfiDeviceTreeMetadata, GblEfiImageInfo, GblEfiVerifiedDeviceTree,
43     GBL_EFI_BOOT_REASON_BOOTLOADER, GBL_EFI_BOOT_REASON_COLD, GBL_EFI_BOOT_REASON_FASTBOOTD,
44     GBL_EFI_BOOT_REASON_RECOVERY, PARTITION_NAME_LEN_U16,
45 };
46 use fdt::Fdt;
47 use gbl_storage::{BlockIo, Disk, Gpt, SliceMaybeUninit};
48 use liberror::{Error, Result};
49 use libgbl::{
50     constants::{ImageName, BOOTCMD_SIZE},
51     device_tree::{
52         DeviceTreeComponent, DeviceTreeComponentSource, DeviceTreeComponentsRegistry,
53         MAXIMUM_DEVICE_TREE_COMPONENTS,
54     },
55     gbl_avb::state::{BootStateColor, KeyValidationStatus},
56     ops::{
57         AvbIoError, AvbIoResult, CertPermanentAttributes, ImageBuffer, RebootReason, Slot,
58         SlotsMetadata, SHA256_DIGEST_SIZE,
59     },
60     partition::GblDisk,
61     slots::{BootToken, Cursor},
62     GblOps, Os, Result as GblResult,
63 };
64 use safemath::SafeNum;
65 use zbi::ZbiContainer;
66 use zerocopy::AsBytes;
67 
to_avb_validation_status_or_panic(status: GblEfiAvbKeyValidationStatus) -> KeyValidationStatus68 fn to_avb_validation_status_or_panic(status: GblEfiAvbKeyValidationStatus) -> KeyValidationStatus {
69     match status {
70         efi_types::GBL_EFI_AVB_KEY_VALIDATION_STATUS_VALID => KeyValidationStatus::Valid,
71         efi_types::GBL_EFI_AVB_KEY_VALIDATION_STATUS_VALID_CUSTOM_KEY => {
72             KeyValidationStatus::ValidCustomKey
73         }
74         efi_types::GBL_EFI_AVB_KEY_VALIDATION_STATUS_INVALID => KeyValidationStatus::Invalid,
75         _ => panic!("Unrecognized avb key validation status: {}", status),
76     }
77 }
78 
avb_color_to_efi_color(color: BootStateColor) -> u3279 fn avb_color_to_efi_color(color: BootStateColor) -> u32 {
80     match color {
81         BootStateColor::Green => efi_types::GBL_EFI_AVB_BOOT_STATE_COLOR_GREEN,
82         BootStateColor::Yellow => efi_types::GBL_EFI_AVB_BOOT_STATE_COLOR_YELLOW,
83         BootStateColor::Orange => efi_types::GBL_EFI_AVB_BOOT_STATE_COLOR_ORANGE,
84         BootStateColor::RedEio => efi_types::GBL_EFI_AVB_BOOT_STATE_COLOR_RED_EIO,
85         BootStateColor::Red => efi_types::GBL_EFI_AVB_BOOT_STATE_COLOR_RED,
86     }
87 }
88 
dt_component_to_efi_dt(component: &DeviceTreeComponent) -> GblEfiVerifiedDeviceTree89 fn dt_component_to_efi_dt(component: &DeviceTreeComponent) -> GblEfiVerifiedDeviceTree {
90     let metadata = match component.source {
91         DeviceTreeComponentSource::Dtb(m) | DeviceTreeComponentSource::Dtbo(m) => m,
92         _ => Default::default(),
93     };
94 
95     GblEfiVerifiedDeviceTree {
96         metadata: GblEfiDeviceTreeMetadata {
97             source: match component.source {
98                 DeviceTreeComponentSource::Boot => efi_types::GBL_EFI_DEVICE_TREE_SOURCE_BOOT,
99                 DeviceTreeComponentSource::VendorBoot => {
100                     efi_types::GBL_EFI_DEVICE_TREE_SOURCE_VENDOR_BOOT
101                 }
102                 DeviceTreeComponentSource::Dtb(_) => efi_types::GBL_EFI_DEVICE_TREE_SOURCE_DTB,
103                 DeviceTreeComponentSource::Dtbo(_) => efi_types::GBL_EFI_DEVICE_TREE_SOURCE_DTBO,
104             },
105             id: metadata.id,
106             rev: metadata.rev,
107             custom: metadata.custom,
108             reserved: Default::default(),
109         },
110         device_tree: component.dt.as_ptr() as _,
111         selected: component.selected,
112     }
113 }
114 
efi_error_to_avb_error(error: Error) -> AvbIoError115 fn efi_error_to_avb_error(error: Error) -> AvbIoError {
116     match error {
117         // EFI_STATUS_OUT_OF_RESOURCES
118         Error::OutOfResources => AvbIoError::Oom,
119         // EFI_STATUS_DEVICE_ERROR
120         Error::DeviceError => AvbIoError::Io,
121         // EFI_STATUS_NOT_FOUND
122         Error::NotFound => AvbIoError::NoSuchValue,
123         // EFI_STATUS_END_OF_FILE
124         Error::EndOfFile => AvbIoError::RangeOutsidePartition,
125         // EFI_STATUS_INVALID_PARAMETER
126         Error::InvalidInput => AvbIoError::InvalidValueSize,
127         // EFI_STATUS_BUFFER_TOO_SMALL
128         Error::BufferTooSmall(required) => {
129             AvbIoError::InsufficientSpace(required.unwrap_or_default())
130         }
131         // EFI_STATUS_UNSUPPORTED
132         Error::Unsupported => AvbIoError::NotImplemented,
133         _ => AvbIoError::NotImplemented,
134     }
135 }
136 
137 pub struct Ops<'a, 'b> {
138     pub efi_entry: &'a EfiEntry,
139     pub disks: &'b [EfiGblDisk<'a>],
140     pub zbi_bootloader_files_buffer: Vec<u8>,
141     pub os: Option<Os>,
142 }
143 
144 impl<'a, 'b> Ops<'a, 'b> {
145     /// Creates a new instance of [Ops]
new(efi_entry: &'a EfiEntry, disks: &'b [EfiGblDisk<'a>], os: Option<Os>) -> Self146     pub fn new(efi_entry: &'a EfiEntry, disks: &'b [EfiGblDisk<'a>], os: Option<Os>) -> Self {
147         Self { efi_entry, disks, zbi_bootloader_files_buffer: Default::default(), os }
148     }
149 
150     /// Gets the property of an FDT node from EFI FDT.
151     ///
152     /// Returns `None` if fail to get the node
get_efi_fdt_prop(&self, path: &str, prop: &CStr) -> Option<&'a [u8]>153     fn get_efi_fdt_prop(&self, path: &str, prop: &CStr) -> Option<&'a [u8]> {
154         let (_, fdt_bytes) = get_efi_fdt(&self.efi_entry)?;
155         let fdt = Fdt::new(fdt_bytes).ok()?;
156         fdt.get_property(path, prop).ok()
157     }
158 
159     /// Get buffer for partition loading and verification.
160     /// Uses GBL EFI ImageLoading protocol.
161     ///
162     /// # Arguments
163     /// * `image_name` - image name to differentiate the buffer properties. Processing is limited
164     /// to first [PARTITION_NAME_LEN_U16] symbols, and the remaining will be ignored.
165     /// * `size` - requested buffer size
166     ///
167     /// # Return
168     /// * Ok(ImageBuffer) - Return buffer for partition loading and verification.
169     /// * Err(_) - on error
get_buffer_image_loading( &mut self, image_name: &str, size: NonZeroUsize, ) -> GblResult<ImageBuffer<'static>>170     fn get_buffer_image_loading(
171         &mut self,
172         image_name: &str,
173         size: NonZeroUsize,
174     ) -> GblResult<ImageBuffer<'static>> {
175         let mut image_type = [0u16; PARTITION_NAME_LEN_U16];
176         image_type.iter_mut().zip(image_name.encode_utf16()).for_each(|(dst, src)| {
177             *dst = src;
178         });
179         let image_info = GblEfiImageInfo { ImageType: image_type, SizeBytes: size.get() };
180         let efi_image_buffer = self
181             .efi_entry
182             .system_table()
183             .boot_services()
184             .find_first_and_open::<GblImageLoadingProtocol>()?
185             .get_buffer(&image_info)?;
186 
187         // EfiImageBuffer -> ImageBuffer
188         // Make sure not to drop efi_image_buffer since we transferred ownership to ImageBuffer
189         let buffer = efi_image_buffer.take();
190         Ok(ImageBuffer::new(buffer))
191     }
192 
193     /// Get buffer for partition loading and verification.
194     /// Uses provided allocator.
195     ///
196     /// # Arguments
197     /// * `image_name` - image name to differentiate the buffer properties
198     /// * `size` - requested buffer size
199     ///
200     /// # Return
201     /// * Ok(ImageBuffer) - Return buffer for partition loading and verification.
202     /// * Err(_) - on error
203     // SAFETY:
204     // Allocated buffer is leaked intentionally. ImageBuffer is assumed to reference static memory.
205     // ImageBuffer is not expected to be released, and is allocated to hold data necessary for next
206     // boot stage (kernel boot). All allocated buffers are expected to be used by kernel.
allocate_image_buffer(image_name: &str, size: NonZeroUsize) -> Result<ImageBuffer<'static>>207     fn allocate_image_buffer(image_name: &str, size: NonZeroUsize) -> Result<ImageBuffer<'static>> {
208         let size = match image_name {
209             "ramdisk" => (SafeNum::from(size.get()) + BOOTCMD_SIZE).try_into()?,
210             _ => size.get(),
211         };
212         // Check for `from_raw_parts_mut()` safety requirements.
213         assert!(size < isize::MAX.try_into().unwrap());
214         let align = ImageName::try_from(image_name).map(|i| i.alignment()).unwrap_or(1);
215 
216         let layout = Layout::from_size_align(size, align).or(Err(Error::InvalidAlignment))?;
217         // SAFETY:
218         // `layout.size()` is checked to be not zero.
219         let ptr = unsafe { alloc(layout) } as *mut MaybeUninit<u8>;
220         if ptr.is_null() {
221             handle_alloc_error(layout);
222         }
223 
224         // SAFETY:
225         // `ptr` is checked to be not Null.
226         // `ptr` is a valid pointer to start of a single memory region of `size`-bytes because it
227         // was just returned by alloc. Buffer alignment requirement for u8 is 1-byte which is
228         // always the case.
229         // `alloc()` makes sure there is no other allocation of the same memory region until
230         // current one is released.
231         // `size` is a valid size of the memory region since `alloc()` succeeded.
232         //
233         // Total size of buffer is not greater than `isize::MAX` since it is checked at the
234         // beginning of the function.
235         //
236         // `ptr + size` doesn't wrap since it is returned from alloc and it didn't fail.
237         let buf = unsafe { from_raw_parts_mut(ptr, size) };
238 
239         Ok(ImageBuffer::new(buf))
240     }
241 }
242 
243 impl Write for Ops<'_, '_> {
write_str(&mut self, s: &str) -> core::fmt::Result244     fn write_str(&mut self, s: &str) -> core::fmt::Result {
245         efi_print!(self.efi_entry, "{}", s);
246         Ok(())
247     }
248 }
249 
250 impl<'a, 'b, 'd> GblOps<'b, 'd> for Ops<'a, 'b> {
console_out(&mut self) -> Option<&mut dyn Write>251     fn console_out(&mut self) -> Option<&mut dyn Write> {
252         Some(self)
253     }
254 
255     /// UEFI console uses \r\n newline.
console_newline(&self) -> &'static str256     fn console_newline(&self) -> &'static str {
257         "\r\n"
258     }
259 
should_stop_in_fastboot(&mut self) -> Result<bool>260     fn should_stop_in_fastboot(&mut self) -> Result<bool> {
261         // TODO(b/349829690): also query GblSlotProtocol.get_boot_reason() for board-specific
262         // fastboot triggers.
263 
264         // TODO(b/366520234): Switch to use GblSlotProtocol.should_stop_in_fastboot once available.
265         match self.get_efi_fdt_prop("gbl", c"stop-in-fastboot") {
266             Some(v) => return Ok(*v.get(0).unwrap_or(&0) == 1),
267             _ => {}
268         }
269 
270         efi_println!(self.efi_entry, "Press Backspace to enter fastboot");
271         let found = wait_key_stroke(
272             self.efi_entry,
273             |key| key.unicode_char == 0x08 || (key.unicode_char == 0x0 && key.scan_code == 0x08),
274             2000,
275         );
276         if matches!(found, Ok(true)) {
277             efi_println!(self.efi_entry, "Backspace pressed, entering fastboot");
278         }
279         // TODO(b/358377120): pass the UEFI error when liberror::Error support lands.
280         found.or(Err(Error::Other(Some("wait for key stroke error"))))
281     }
282 
283     /// Reboots the system into the last set boot mode.
reboot(&mut self)284     fn reboot(&mut self) {
285         self.efi_entry.system_table().runtime_services().cold_reset();
286     }
287 
disks( &self, ) -> &'b [GblDisk< Disk<impl BlockIo + 'b, impl DerefMut<Target = [u8]> + 'b>, Gpt<impl DerefMut<Target = [u8]> + 'b>, >]288     fn disks(
289         &self,
290     ) -> &'b [GblDisk<
291         Disk<impl BlockIo + 'b, impl DerefMut<Target = [u8]> + 'b>,
292         Gpt<impl DerefMut<Target = [u8]> + 'b>,
293     >] {
294         self.disks
295     }
296 
expected_os(&mut self) -> Result<Option<Os>>297     fn expected_os(&mut self) -> Result<Option<Os>> {
298         Ok(self.os)
299     }
300 
zircon_add_device_zbi_items( &mut self, container: &mut ZbiContainer<&mut [u8]>, ) -> Result<()>301     fn zircon_add_device_zbi_items(
302         &mut self,
303         container: &mut ZbiContainer<&mut [u8]>,
304     ) -> Result<()> {
305         // TODO(b/353272981): Switch to use OS configuration protocol once it is implemented on
306         // existing platforms such as VIM3.
307         Ok(match self.get_efi_fdt_prop("zircon", c"zbi-blob") {
308             Some(blob) => container.extend_unaligned(blob).map_err(|_| "Failed to append ZBI")?,
309             _ => efi_println!(self.efi_entry, "No device ZBI items.\r\n"),
310         })
311     }
312 
get_zbi_bootloader_files_buffer(&mut self) -> Option<&mut [u8]>313     fn get_zbi_bootloader_files_buffer(&mut self) -> Option<&mut [u8]> {
314         // Switches to use get_image_buffer once available.
315         const DEFAULT_SIZE: usize = 4096;
316         if self.zbi_bootloader_files_buffer.is_empty() {
317             self.zbi_bootloader_files_buffer.resize(DEFAULT_SIZE, 0);
318         }
319         Some(self.zbi_bootloader_files_buffer.as_mut_slice())
320     }
321 
load_slot_interface<'c>( &'c mut self, _: &'c mut dyn FnMut(&mut [u8]) -> Result<()>, _: BootToken, ) -> GblResult<Cursor<'c>>322     fn load_slot_interface<'c>(
323         &'c mut self,
324         _: &'c mut dyn FnMut(&mut [u8]) -> Result<()>,
325         _: BootToken,
326     ) -> GblResult<Cursor<'c>> {
327         unimplemented!();
328     }
329 
avb_read_is_device_unlocked(&mut self) -> AvbIoResult<bool>330     fn avb_read_is_device_unlocked(&mut self) -> AvbIoResult<bool> {
331         match self.efi_entry.system_table().boot_services().find_first_and_open::<GblAvbProtocol>()
332         {
333             Ok(protocol) => protocol.read_is_device_unlocked().map_err(efi_error_to_avb_error),
334             Err(_) => Err(AvbIoError::NotImplemented),
335         }
336     }
337 
avb_read_rollback_index(&mut self, rollback_index_location: usize) -> AvbIoResult<u64>338     fn avb_read_rollback_index(&mut self, rollback_index_location: usize) -> AvbIoResult<u64> {
339         match self.efi_entry.system_table().boot_services().find_first_and_open::<GblAvbProtocol>()
340         {
341             Ok(protocol) => protocol
342                 .read_rollback_index(rollback_index_location)
343                 .map_err(efi_error_to_avb_error),
344             Err(_) => Err(AvbIoError::NotImplemented),
345         }
346     }
347 
avb_write_rollback_index( &mut self, rollback_index_location: usize, index: u64, ) -> AvbIoResult<()>348     fn avb_write_rollback_index(
349         &mut self,
350         rollback_index_location: usize,
351         index: u64,
352     ) -> AvbIoResult<()> {
353         match self.efi_entry.system_table().boot_services().find_first_and_open::<GblAvbProtocol>()
354         {
355             Ok(protocol) => protocol
356                 .write_rollback_index(rollback_index_location, index)
357                 .map_err(efi_error_to_avb_error),
358             Err(_) => Err(AvbIoError::NotImplemented),
359         }
360     }
361 
avb_read_persistent_value(&mut self, name: &CStr, value: &mut [u8]) -> AvbIoResult<usize>362     fn avb_read_persistent_value(&mut self, name: &CStr, value: &mut [u8]) -> AvbIoResult<usize> {
363         match self.efi_entry.system_table().boot_services().find_first_and_open::<GblAvbProtocol>()
364         {
365             Ok(protocol) => {
366                 protocol.read_persistent_value(name, value).map_err(efi_error_to_avb_error)
367             }
368             Err(_) => Err(AvbIoError::NotImplemented),
369         }
370     }
371 
avb_write_persistent_value(&mut self, name: &CStr, value: &[u8]) -> AvbIoResult<()>372     fn avb_write_persistent_value(&mut self, name: &CStr, value: &[u8]) -> AvbIoResult<()> {
373         match self.efi_entry.system_table().boot_services().find_first_and_open::<GblAvbProtocol>()
374         {
375             Ok(protocol) => {
376                 protocol.write_persistent_value(name, Some(value)).map_err(efi_error_to_avb_error)
377             }
378             Err(_) => Err(AvbIoError::NotImplemented),
379         }
380     }
381 
avb_erase_persistent_value(&mut self, name: &CStr) -> AvbIoResult<()>382     fn avb_erase_persistent_value(&mut self, name: &CStr) -> AvbIoResult<()> {
383         match self.efi_entry.system_table().boot_services().find_first_and_open::<GblAvbProtocol>()
384         {
385             Ok(protocol) => {
386                 protocol.write_persistent_value(name, None).map_err(efi_error_to_avb_error)
387             }
388             Err(_) => Err(AvbIoError::NotImplemented),
389         }
390     }
391 
avb_validate_vbmeta_public_key( &self, public_key: &[u8], public_key_metadata: Option<&[u8]>, ) -> AvbIoResult<KeyValidationStatus>392     fn avb_validate_vbmeta_public_key(
393         &self,
394         public_key: &[u8],
395         public_key_metadata: Option<&[u8]>,
396     ) -> AvbIoResult<KeyValidationStatus> {
397         match self.efi_entry.system_table().boot_services().find_first_and_open::<GblAvbProtocol>()
398         {
399             Ok(protocol) => protocol
400                 .validate_vbmeta_public_key(public_key, public_key_metadata)
401                 .map(to_avb_validation_status_or_panic)
402                 .map_err(efi_error_to_avb_error),
403             Err(_) => Err(AvbIoError::NotImplemented),
404         }
405     }
406 
avb_cert_read_permanent_attributes( &mut self, attributes: &mut CertPermanentAttributes, ) -> AvbIoResult<()>407     fn avb_cert_read_permanent_attributes(
408         &mut self,
409         attributes: &mut CertPermanentAttributes,
410     ) -> AvbIoResult<()> {
411         // TODO(b/337846185): Switch to use GBL Verified Boot EFI protocol when available.
412         let perm_attr = self
413             .get_efi_fdt_prop("gbl", c"avb-cert-permanent-attributes")
414             .ok_or(AvbIoError::NotImplemented)?;
415         attributes.as_bytes_mut().clone_from_slice(perm_attr);
416         Ok(())
417     }
418 
avb_cert_read_permanent_attributes_hash(&mut self) -> AvbIoResult<[u8; SHA256_DIGEST_SIZE]>419     fn avb_cert_read_permanent_attributes_hash(&mut self) -> AvbIoResult<[u8; SHA256_DIGEST_SIZE]> {
420         // TODO(b/337846185): Switch to use GBL Verified Boot EFI protocol when available.
421         let hash = self
422             .get_efi_fdt_prop("gbl", c"avb-cert-permanent-attributes-hash")
423             .ok_or(AvbIoError::NotImplemented)?;
424         Ok(hash.try_into().map_err(|_| AvbIoError::Io)?)
425     }
426 
avb_handle_verification_result( &mut self, color: BootStateColor, digest: Option<&CStr>, boot_os_version: Option<&[u8]>, boot_security_patch: Option<&[u8]>, system_os_version: Option<&[u8]>, system_security_patch: Option<&[u8]>, vendor_os_version: Option<&[u8]>, vendor_security_patch: Option<&[u8]>, ) -> AvbIoResult<()>427     fn avb_handle_verification_result(
428         &mut self,
429         color: BootStateColor,
430         digest: Option<&CStr>,
431         boot_os_version: Option<&[u8]>,
432         boot_security_patch: Option<&[u8]>,
433         system_os_version: Option<&[u8]>,
434         system_security_patch: Option<&[u8]>,
435         vendor_os_version: Option<&[u8]>,
436         vendor_security_patch: Option<&[u8]>,
437     ) -> AvbIoResult<()> {
438         match self.efi_entry.system_table().boot_services().find_first_and_open::<GblAvbProtocol>()
439         {
440             Ok(protocol) => protocol
441                 .handle_verification_result(&GblEfiAvbVerificationResult {
442                     color: avb_color_to_efi_color(color),
443                     digest: digest.map_or(null(), |p| p.as_ptr() as _),
444                     boot_version: boot_os_version.map_or(null(), |p| p.as_ptr()),
445                     boot_security_patch: boot_security_patch.map_or(null(), |p| p.as_ptr()),
446                     system_version: system_os_version.map_or(null(), |p| p.as_ptr()),
447                     system_security_patch: system_security_patch.map_or(null(), |p| p.as_ptr()),
448                     vendor_version: vendor_os_version.map_or(null(), |p| p.as_ptr()),
449                     vendor_security_patch: vendor_security_patch.map_or(null(), |p| p.as_ptr()),
450                 })
451                 .map_err(efi_error_to_avb_error),
452             _ => Ok(()),
453         }
454     }
455 
get_image_buffer( &mut self, image_name: &str, size: NonZeroUsize, ) -> GblResult<ImageBuffer<'d>>456     fn get_image_buffer(
457         &mut self,
458         image_name: &str,
459         size: NonZeroUsize,
460     ) -> GblResult<ImageBuffer<'d>> {
461         self.get_buffer_image_loading(image_name, size)
462             .or(Self::allocate_image_buffer(image_name, size)
463                 .map_err(|e| libgbl::IntegrationError::UnificationError(e)))
464     }
465 
get_custom_device_tree(&mut self) -> Option<&'a [u8]>466     fn get_custom_device_tree(&mut self) -> Option<&'a [u8]> {
467         // On Cuttlefish, the device tree comes from the UEFI config tables.
468         // TODO(b/353272981): once we've settled on the device tree UEFI protocol, use that
469         // instead to provide a Cuttlefish-specific backend.
470         Some(get_efi_fdt(&self.efi_entry)?.1)
471     }
472 
fixup_os_commandline<'c>( &mut self, commandline: &CStr, fixup_buffer: &'c mut [u8], ) -> Result<Option<&'c str>>473     fn fixup_os_commandline<'c>(
474         &mut self,
475         commandline: &CStr,
476         fixup_buffer: &'c mut [u8],
477     ) -> Result<Option<&'c str>> {
478         Ok(
479             match self
480                 .efi_entry
481                 .system_table()
482                 .boot_services()
483                 .find_first_and_open::<GblOsConfigurationProtocol>()
484             {
485                 Ok(protocol) => {
486                     protocol.fixup_kernel_commandline(commandline, fixup_buffer)?;
487                     Some(CStr::from_bytes_until_nul(&fixup_buffer[..])?.to_str()?)
488                 }
489                 _ => None,
490             },
491         )
492     }
493 
fixup_bootconfig<'c>( &mut self, bootconfig: &[u8], fixup_buffer: &'c mut [u8], ) -> Result<Option<&'c [u8]>>494     fn fixup_bootconfig<'c>(
495         &mut self,
496         bootconfig: &[u8],
497         fixup_buffer: &'c mut [u8],
498     ) -> Result<Option<&'c [u8]>> {
499         Ok(
500             match self
501                 .efi_entry
502                 .system_table()
503                 .boot_services()
504                 .find_first_and_open::<GblOsConfigurationProtocol>()
505             {
506                 Ok(protocol) => {
507                     let fixup_size = protocol.fixup_bootconfig(bootconfig, fixup_buffer)?;
508                     Some(&fixup_buffer[..fixup_size])
509                 }
510                 _ => None,
511             },
512         )
513     }
514 
fixup_device_tree(&mut self, device_tree: &mut [u8]) -> Result<()>515     fn fixup_device_tree(&mut self, device_tree: &mut [u8]) -> Result<()> {
516         if let Ok(protocol) =
517             self.efi_entry.system_table().boot_services().find_first_and_open::<DtFixupProtocol>()
518         {
519             protocol.fixup(device_tree)?;
520         }
521 
522         Ok(())
523     }
524 
select_device_trees( &mut self, components_registry: &mut DeviceTreeComponentsRegistry, ) -> Result<()>525     fn select_device_trees(
526         &mut self,
527         components_registry: &mut DeviceTreeComponentsRegistry,
528     ) -> Result<()> {
529         match self
530             .efi_entry
531             .system_table()
532             .boot_services()
533             .find_first_and_open::<GblOsConfigurationProtocol>()
534         {
535             Ok(protocol) => {
536                 // Protocol detected, convert to UEFI types.
537                 let mut uefi_components: ArrayVec<_, MAXIMUM_DEVICE_TREE_COMPONENTS> =
538                     components_registry
539                         .components()
540                         .map(|component| dt_component_to_efi_dt(component))
541                         .collect();
542 
543                 protocol.select_device_trees(&mut uefi_components[..])?;
544 
545                 // Propagate selections to the components_registry.
546                 components_registry
547                     .components_mut()
548                     .zip(uefi_components.iter_mut())
549                     .enumerate()
550                     .for_each(|(index, (component, uefi_component))| {
551                         if uefi_component.selected {
552                             efi_println!(
553                                 self.efi_entry,
554                                 "Device tree component at index {} got selected by UEFI call. \
555                                 Source: {}",
556                                 index,
557                                 component.source
558                             );
559                         }
560                         component.selected = uefi_component.selected;
561                     });
562 
563                 Ok(())
564             }
565             _ => components_registry.autoselect(),
566         }
567     }
568 
fastboot_variable<'arg>( &mut self, name: &CStr, args: impl Iterator<Item = &'arg CStr> + Clone, out: &mut [u8], ) -> Result<usize>569     fn fastboot_variable<'arg>(
570         &mut self,
571         name: &CStr,
572         args: impl Iterator<Item = &'arg CStr> + Clone,
573         out: &mut [u8],
574     ) -> Result<usize> {
575         self.efi_entry
576             .system_table()
577             .boot_services()
578             .find_first_and_open::<GblFastbootProtocol>()?
579             .get_var(name, args, out)
580     }
581 
fastboot_visit_all_variables(&mut self, cb: impl FnMut(&[&CStr], &CStr)) -> Result<()>582     fn fastboot_visit_all_variables(&mut self, cb: impl FnMut(&[&CStr], &CStr)) -> Result<()> {
583         self.efi_entry
584             .system_table()
585             .boot_services()
586             .find_first_and_open::<GblFastbootProtocol>()?
587             .get_var_all(cb)
588     }
589 
slots_metadata(&mut self) -> Result<SlotsMetadata>590     fn slots_metadata(&mut self) -> Result<SlotsMetadata> {
591         Ok(SlotsMetadata {
592             slot_count: self
593                 .efi_entry
594                 .system_table()
595                 .boot_services()
596                 .find_first_and_open::<GblSlotProtocol>()?
597                 .load_boot_data()?
598                 .slot_count
599                 .try_into()
600                 .unwrap(),
601         })
602     }
603 
get_current_slot(&mut self) -> Result<Slot>604     fn get_current_slot(&mut self) -> Result<Slot> {
605         // TODO(b/363075013): Refactors the opening of slot protocol into a common helper once
606         // `MockBootServices::find_first_and_open` is updated to return Protocol<'_, T>.
607         self.efi_entry
608             .system_table()
609             .boot_services()
610             .find_first_and_open::<GblSlotProtocol>()?
611             .get_current_slot()?
612             .try_into()
613     }
614 
get_next_slot(&mut self, mark_boot_attempt: bool) -> Result<Slot>615     fn get_next_slot(&mut self, mark_boot_attempt: bool) -> Result<Slot> {
616         self.efi_entry
617             .system_table()
618             .boot_services()
619             .find_first_and_open::<GblSlotProtocol>()?
620             .get_next_slot(mark_boot_attempt)?
621             .try_into()
622     }
623 
set_active_slot(&mut self, slot: u8) -> Result<()>624     fn set_active_slot(&mut self, slot: u8) -> Result<()> {
625         self.efi_entry
626             .system_table()
627             .boot_services()
628             .find_first_and_open::<GblSlotProtocol>()?
629             .set_active_slot(slot)
630     }
631 
set_reboot_reason(&mut self, reason: RebootReason) -> Result<()>632     fn set_reboot_reason(&mut self, reason: RebootReason) -> Result<()> {
633         self.efi_entry
634             .system_table()
635             .boot_services()
636             .find_first_and_open::<GblSlotProtocol>()?
637             .set_boot_reason(gbl_to_efi_boot_reason(reason), b"")
638     }
639 
get_reboot_reason(&mut self) -> Result<RebootReason>640     fn get_reboot_reason(&mut self) -> Result<RebootReason> {
641         let mut subreason = [0u8; 128];
642         self.efi_entry
643             .system_table()
644             .boot_services()
645             .find_first_and_open::<GblSlotProtocol>()?
646             .get_boot_reason(&mut subreason[..])
647             .map(|(v, _)| efi_to_gbl_boot_reason(v))
648     }
649 }
650 
651 /// Converts a [GblEfiBootReason] to [RebootReason].
efi_to_gbl_boot_reason(reason: GblEfiBootReason) -> RebootReason652 fn efi_to_gbl_boot_reason(reason: GblEfiBootReason) -> RebootReason {
653     match reason {
654         GBL_EFI_BOOT_REASON_RECOVERY => RebootReason::Recovery,
655         GBL_EFI_BOOT_REASON_BOOTLOADER => RebootReason::Bootloader,
656         GBL_EFI_BOOT_REASON_FASTBOOTD => RebootReason::FastbootD,
657         _ => RebootReason::Normal,
658     }
659 }
660 
661 /// Converts a [RebootReason] to [GblEfiBootReason].
gbl_to_efi_boot_reason(reason: RebootReason) -> GblEfiBootReason662 fn gbl_to_efi_boot_reason(reason: RebootReason) -> GblEfiBootReason {
663     match reason {
664         RebootReason::Recovery => GBL_EFI_BOOT_REASON_RECOVERY,
665         RebootReason::Bootloader => GBL_EFI_BOOT_REASON_BOOTLOADER,
666         RebootReason::FastbootD => GBL_EFI_BOOT_REASON_FASTBOOTD,
667         RebootReason::Normal => GBL_EFI_BOOT_REASON_COLD,
668     }
669 }
670 
671 /// Inherits everything from `ops` but override a few such as read boot_a from
672 /// bootimg_buffer, avb_write_rollback_index(), slot operation etc
673 pub struct RambootOps<'b, T> {
674     pub ops: &'b mut T,
675     pub bootimg_buffer: &'b mut [u8],
676 }
677 
678 impl<'a, 'd, T: GblOps<'a, 'd>> GblOps<'a, 'd> for RambootOps<'_, T> {
console_out(&mut self) -> Option<&mut dyn Write>679     fn console_out(&mut self) -> Option<&mut dyn Write> {
680         self.ops.console_out()
681     }
682 
should_stop_in_fastboot(&mut self) -> Result<bool>683     fn should_stop_in_fastboot(&mut self) -> Result<bool> {
684         self.ops.should_stop_in_fastboot()
685     }
686 
reboot(&mut self)687     fn reboot(&mut self) {
688         self.ops.reboot()
689     }
690 
disks( &self, ) -> &'a [GblDisk< Disk<impl BlockIo + 'a, impl DerefMut<Target = [u8]> + 'a>, Gpt<impl DerefMut<Target = [u8]> + 'a>, >]691     fn disks(
692         &self,
693     ) -> &'a [GblDisk<
694         Disk<impl BlockIo + 'a, impl DerefMut<Target = [u8]> + 'a>,
695         Gpt<impl DerefMut<Target = [u8]> + 'a>,
696     >] {
697         self.ops.disks()
698     }
699 
expected_os(&mut self) -> Result<Option<Os>>700     fn expected_os(&mut self) -> Result<Option<Os>> {
701         self.ops.expected_os()
702     }
703 
zircon_add_device_zbi_items( &mut self, container: &mut ZbiContainer<&mut [u8]>, ) -> Result<()>704     fn zircon_add_device_zbi_items(
705         &mut self,
706         container: &mut ZbiContainer<&mut [u8]>,
707     ) -> Result<()> {
708         self.ops.zircon_add_device_zbi_items(container)
709     }
710 
get_zbi_bootloader_files_buffer(&mut self) -> Option<&mut [u8]>711     fn get_zbi_bootloader_files_buffer(&mut self) -> Option<&mut [u8]> {
712         self.ops.get_zbi_bootloader_files_buffer()
713     }
714 
load_slot_interface<'c>( &'c mut self, _fnmut: &'c mut dyn FnMut(&mut [u8]) -> Result<()>, _boot_token: BootToken, ) -> GblResult<Cursor<'c>>715     fn load_slot_interface<'c>(
716         &'c mut self,
717         _fnmut: &'c mut dyn FnMut(&mut [u8]) -> Result<()>,
718         _boot_token: BootToken,
719     ) -> GblResult<Cursor<'c>> {
720         self.ops.load_slot_interface(_fnmut, _boot_token)
721     }
722 
avb_read_is_device_unlocked(&mut self) -> AvbIoResult<bool>723     fn avb_read_is_device_unlocked(&mut self) -> AvbIoResult<bool> {
724         self.ops.avb_read_is_device_unlocked()
725     }
726 
avb_read_rollback_index(&mut self, _rollback_index_location: usize) -> AvbIoResult<u64>727     fn avb_read_rollback_index(&mut self, _rollback_index_location: usize) -> AvbIoResult<u64> {
728         self.ops.avb_read_rollback_index(_rollback_index_location)
729     }
730 
avb_write_rollback_index(&mut self, _: usize, _: u64) -> AvbIoResult<()>731     fn avb_write_rollback_index(&mut self, _: usize, _: u64) -> AvbIoResult<()> {
732         // We don't want to persist AVB related data such as updating antirollback indices.
733         Ok(())
734     }
735 
avb_read_persistent_value(&mut self, name: &CStr, value: &mut [u8]) -> AvbIoResult<usize>736     fn avb_read_persistent_value(&mut self, name: &CStr, value: &mut [u8]) -> AvbIoResult<usize> {
737         self.ops.avb_read_persistent_value(name, value)
738     }
739 
avb_write_persistent_value(&mut self, _: &CStr, _: &[u8]) -> AvbIoResult<()>740     fn avb_write_persistent_value(&mut self, _: &CStr, _: &[u8]) -> AvbIoResult<()> {
741         // We don't want to persist AVB related data such as updating current VBH.
742         Ok(())
743     }
744 
avb_erase_persistent_value(&mut self, _: &CStr) -> AvbIoResult<()>745     fn avb_erase_persistent_value(&mut self, _: &CStr) -> AvbIoResult<()> {
746         // We don't want to persist AVB related data such as updating current VBH.
747         Ok(())
748     }
749 
avb_cert_read_permanent_attributes( &mut self, attributes: &mut CertPermanentAttributes, ) -> AvbIoResult<()>750     fn avb_cert_read_permanent_attributes(
751         &mut self,
752         attributes: &mut CertPermanentAttributes,
753     ) -> AvbIoResult<()> {
754         self.ops.avb_cert_read_permanent_attributes(attributes)
755     }
756 
avb_cert_read_permanent_attributes_hash(&mut self) -> AvbIoResult<[u8; SHA256_DIGEST_SIZE]>757     fn avb_cert_read_permanent_attributes_hash(&mut self) -> AvbIoResult<[u8; SHA256_DIGEST_SIZE]> {
758         self.ops.avb_cert_read_permanent_attributes_hash()
759     }
760 
get_image_buffer( &mut self, image_name: &str, size: NonZeroUsize, ) -> GblResult<ImageBuffer<'d>>761     fn get_image_buffer(
762         &mut self,
763         image_name: &str,
764         size: NonZeroUsize,
765     ) -> GblResult<ImageBuffer<'d>> {
766         self.ops.get_image_buffer(image_name, size)
767     }
768 
get_custom_device_tree(&mut self) -> Option<&'a [u8]>769     fn get_custom_device_tree(&mut self) -> Option<&'a [u8]> {
770         self.ops.get_custom_device_tree()
771     }
772 
fixup_os_commandline<'c>( &mut self, commandline: &CStr, fixup_buffer: &'c mut [u8], ) -> Result<Option<&'c str>>773     fn fixup_os_commandline<'c>(
774         &mut self,
775         commandline: &CStr,
776         fixup_buffer: &'c mut [u8],
777     ) -> Result<Option<&'c str>> {
778         self.ops.fixup_os_commandline(commandline, fixup_buffer)
779     }
780 
fixup_bootconfig<'c>( &mut self, bootconfig: &[u8], fixup_buffer: &'c mut [u8], ) -> Result<Option<&'c [u8]>>781     fn fixup_bootconfig<'c>(
782         &mut self,
783         bootconfig: &[u8],
784         fixup_buffer: &'c mut [u8],
785     ) -> Result<Option<&'c [u8]>> {
786         self.ops.fixup_bootconfig(bootconfig, fixup_buffer)
787     }
788 
fixup_device_tree(&mut self, device_tree: &mut [u8]) -> Result<()>789     fn fixup_device_tree(&mut self, device_tree: &mut [u8]) -> Result<()> {
790         self.ops.fixup_device_tree(device_tree)
791     }
792 
select_device_trees( &mut self, components_registry: &mut DeviceTreeComponentsRegistry, ) -> Result<()>793     fn select_device_trees(
794         &mut self,
795         components_registry: &mut DeviceTreeComponentsRegistry,
796     ) -> Result<()> {
797         self.ops.select_device_trees(components_registry)
798     }
799 
read_from_partition_sync( &mut self, part: &str, off: u64, out: &mut (impl SliceMaybeUninit + ?Sized), ) -> Result<()>800     fn read_from_partition_sync(
801         &mut self,
802         part: &str,
803         off: u64,
804         out: &mut (impl SliceMaybeUninit + ?Sized),
805     ) -> Result<()> {
806         if part == "boot_a" {
807             let len = min(self.bootimg_buffer.len() - off as usize, out.len());
808             out.clone_from_slice(&self.bootimg_buffer[off as usize..off as usize + len]);
809             Ok(())
810         } else {
811             self.ops.read_from_partition_sync(part, off, out)
812         }
813     }
814 
avb_handle_verification_result( &mut self, color: BootStateColor, digest: Option<&CStr>, boot_os_version: Option<&[u8]>, boot_security_patch: Option<&[u8]>, system_os_version: Option<&[u8]>, system_security_patch: Option<&[u8]>, vendor_os_version: Option<&[u8]>, vendor_security_patch: Option<&[u8]>, ) -> AvbIoResult<()>815     fn avb_handle_verification_result(
816         &mut self,
817         color: BootStateColor,
818         digest: Option<&CStr>,
819         boot_os_version: Option<&[u8]>,
820         boot_security_patch: Option<&[u8]>,
821         system_os_version: Option<&[u8]>,
822         system_security_patch: Option<&[u8]>,
823         vendor_os_version: Option<&[u8]>,
824         vendor_security_patch: Option<&[u8]>,
825     ) -> AvbIoResult<()> {
826         self.ops.avb_handle_verification_result(
827             color,
828             digest,
829             boot_os_version,
830             boot_security_patch,
831             system_os_version,
832             system_security_patch,
833             vendor_os_version,
834             vendor_security_patch,
835         )
836     }
837 
avb_validate_vbmeta_public_key( &self, public_key: &[u8], public_key_metadata: Option<&[u8]>, ) -> AvbIoResult<KeyValidationStatus>838     fn avb_validate_vbmeta_public_key(
839         &self,
840         public_key: &[u8],
841         public_key_metadata: Option<&[u8]>,
842     ) -> AvbIoResult<KeyValidationStatus> {
843         self.ops.avb_validate_vbmeta_public_key(public_key, public_key_metadata)
844     }
845 
slots_metadata(&mut self) -> Result<SlotsMetadata>846     fn slots_metadata(&mut self) -> Result<SlotsMetadata> {
847         // Ramboot is not suppose to call this interface.
848         unreachable!()
849     }
850 
get_current_slot(&mut self) -> Result<Slot>851     fn get_current_slot(&mut self) -> Result<Slot> {
852         // Ramboot is slotless
853         Err(Error::Unsupported)
854     }
855 
get_next_slot(&mut self, _: bool) -> Result<Slot>856     fn get_next_slot(&mut self, _: bool) -> Result<Slot> {
857         // Ramboot is not suppose to call this interface.
858         unreachable!()
859     }
860 
set_active_slot(&mut self, _: u8) -> Result<()>861     fn set_active_slot(&mut self, _: u8) -> Result<()> {
862         // Ramboot is not suppose to call this interface.
863         unreachable!()
864     }
865 
set_reboot_reason(&mut self, _: RebootReason) -> Result<()>866     fn set_reboot_reason(&mut self, _: RebootReason) -> Result<()> {
867         // Ramboot is not suppose to call this interface.
868         unreachable!()
869     }
870 
get_reboot_reason(&mut self) -> Result<RebootReason>871     fn get_reboot_reason(&mut self) -> Result<RebootReason> {
872         // Assumes that ramboot use normal boot mode. But we might consider supporting recovery
873         // if there is a usecase.
874         Ok(RebootReason::Normal)
875     }
876 
fastboot_variable<'arg>( &mut self, _: &CStr, _: impl Iterator<Item = &'arg CStr> + Clone, _: &mut [u8], ) -> Result<usize>877     fn fastboot_variable<'arg>(
878         &mut self,
879         _: &CStr,
880         _: impl Iterator<Item = &'arg CStr> + Clone,
881         _: &mut [u8],
882     ) -> Result<usize> {
883         // Ramboot should not need this.
884         unreachable!();
885     }
886 
fastboot_visit_all_variables(&mut self, _: impl FnMut(&[&CStr], &CStr)) -> Result<()>887     fn fastboot_visit_all_variables(&mut self, _: impl FnMut(&[&CStr], &CStr)) -> Result<()> {
888         // Ramboot should not need this.
889         unreachable!();
890     }
891 }
892 
893 #[cfg(test)]
894 mod test {
895     use super::*;
896     use efi_mocks::{
897         protocol::{gbl_efi_ab_slot::GblSlotProtocol, gbl_efi_avb::GblAvbProtocol},
898         MockEfi,
899     };
900     use efi_types::GBL_EFI_BOOT_REASON;
901     use mockall::predicate::eq;
902 
903     #[test]
ops_write_trait()904     fn ops_write_trait() {
905         let mut mock_efi = MockEfi::new();
906 
907         mock_efi.con_out.expect_write_str().with(eq("foo bar")).return_const(Ok(()));
908         let installed = mock_efi.install();
909 
910         let mut ops = Ops::new(installed.entry(), &[], None);
911 
912         assert!(write!(&mut ops, "{} {}", "foo", "bar").is_ok());
913     }
914 
915     #[test]
ops_avb_validate_vbmeta_public_key_returns_valid()916     fn ops_avb_validate_vbmeta_public_key_returns_valid() {
917         let mut mock_efi = MockEfi::new();
918         let mut avb = GblAvbProtocol::default();
919         avb.validate_vbmeta_public_key_result =
920             Some(Ok(efi_types::GBL_EFI_AVB_KEY_VALIDATION_STATUS_VALID));
921         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
922 
923         let installed = mock_efi.install();
924         let ops = Ops::new(installed.entry(), &[], None);
925 
926         assert_eq!(ops.avb_validate_vbmeta_public_key(&[], None), Ok(KeyValidationStatus::Valid));
927     }
928 
929     #[test]
ops_avb_validate_vbmeta_public_key_returns_valid_custom_key()930     fn ops_avb_validate_vbmeta_public_key_returns_valid_custom_key() {
931         let mut mock_efi = MockEfi::new();
932         let mut avb = GblAvbProtocol::default();
933         avb.validate_vbmeta_public_key_result =
934             Some(Ok(efi_types::GBL_EFI_AVB_KEY_VALIDATION_STATUS_VALID_CUSTOM_KEY));
935         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
936 
937         let installed = mock_efi.install();
938         let ops = Ops::new(installed.entry(), &[], None);
939 
940         assert_eq!(
941             ops.avb_validate_vbmeta_public_key(&[], None),
942             Ok(KeyValidationStatus::ValidCustomKey)
943         );
944     }
945 
946     #[test]
ops_avb_validate_vbmeta_public_key_returns_invalid()947     fn ops_avb_validate_vbmeta_public_key_returns_invalid() {
948         let mut mock_efi = MockEfi::new();
949         let mut avb = GblAvbProtocol::default();
950         avb.validate_vbmeta_public_key_result =
951             Some(Ok(efi_types::GBL_EFI_AVB_KEY_VALIDATION_STATUS_INVALID));
952         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
953 
954         let installed = mock_efi.install();
955         let ops = Ops::new(installed.entry(), &[], None);
956 
957         assert_eq!(ops.avb_validate_vbmeta_public_key(&[], None), Ok(KeyValidationStatus::Invalid));
958     }
959 
960     #[test]
ops_avb_validate_vbmeta_public_key_failed_error_mapped()961     fn ops_avb_validate_vbmeta_public_key_failed_error_mapped() {
962         let mut mock_efi = MockEfi::new();
963         let mut avb = GblAvbProtocol::default();
964         avb.validate_vbmeta_public_key_result = Some(Err(Error::OutOfResources));
965         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
966 
967         let installed = mock_efi.install();
968         let ops = Ops::new(installed.entry(), &[], None);
969 
970         assert_eq!(ops.avb_validate_vbmeta_public_key(&[], None), Err(AvbIoError::Oom));
971     }
972 
973     #[test]
ops_avb_validate_vbmeta_public_key_protocol_not_found_mapped_to_not_implemented()974     fn ops_avb_validate_vbmeta_public_key_protocol_not_found_mapped_to_not_implemented() {
975         let mut mock_efi = MockEfi::new();
976         mock_efi
977             .boot_services
978             .expect_find_first_and_open::<GblAvbProtocol>()
979             .returning(|| Err(Error::NotFound));
980 
981         let installed = mock_efi.install();
982         let ops = Ops::new(installed.entry(), &[], None);
983 
984         assert_eq!(ops.avb_validate_vbmeta_public_key(&[], None), Err(AvbIoError::NotImplemented));
985     }
986 
987     #[test]
ops_avb_read_is_device_unlocked_returns_true()988     fn ops_avb_read_is_device_unlocked_returns_true() {
989         let mut mock_efi = MockEfi::new();
990         let mut avb = GblAvbProtocol::default();
991         avb.read_is_device_unlocked_result = Some(Ok(true));
992         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
993 
994         let installed = mock_efi.install();
995         let mut ops = Ops::new(installed.entry(), &[], None);
996 
997         assert_eq!(ops.avb_read_is_device_unlocked(), Ok(true));
998     }
999 
1000     #[test]
ops_avb_read_is_device_unlocked_returns_false()1001     fn ops_avb_read_is_device_unlocked_returns_false() {
1002         let mut mock_efi = MockEfi::new();
1003         let mut avb = GblAvbProtocol::default();
1004         avb.read_is_device_unlocked_result = Some(Ok(false));
1005         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
1006 
1007         let installed = mock_efi.install();
1008         let mut ops = Ops::new(installed.entry(), &[], None);
1009 
1010         assert_eq!(ops.avb_read_is_device_unlocked(), Ok(false));
1011     }
1012 
1013     #[test]
ops_avb_read_is_device_unlocked_protocol_not_found()1014     fn ops_avb_read_is_device_unlocked_protocol_not_found() {
1015         let mut mock_efi = MockEfi::new();
1016         mock_efi
1017             .boot_services
1018             .expect_find_first_and_open::<GblAvbProtocol>()
1019             .returning(|| Err(Error::NotFound));
1020 
1021         let installed = mock_efi.install();
1022         let mut ops = Ops::new(installed.entry(), &[], None);
1023 
1024         assert_eq!(ops.avb_read_is_device_unlocked(), Err(AvbIoError::NotImplemented));
1025     }
1026 
1027     #[test]
ops_avb_read_rollback_index_success()1028     fn ops_avb_read_rollback_index_success() {
1029         let mut mock_efi = MockEfi::new();
1030         let mut avb = GblAvbProtocol::default();
1031         avb.read_rollback_index_result = Some(Ok(12345));
1032         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
1033 
1034         let installed = mock_efi.install();
1035         let mut ops = Ops::new(installed.entry(), &[], None);
1036 
1037         assert_eq!(ops.avb_read_rollback_index(0), Ok(12345));
1038     }
1039 
1040     #[test]
ops_avb_read_rollback_index_error()1041     fn ops_avb_read_rollback_index_error() {
1042         let mut mock_efi = MockEfi::new();
1043         let mut avb = GblAvbProtocol::default();
1044         avb.read_rollback_index_result = Some(Err(Error::OutOfResources));
1045         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
1046 
1047         let installed = mock_efi.install();
1048         let mut ops = Ops::new(installed.entry(), &[], None);
1049 
1050         assert_eq!(ops.avb_read_rollback_index(0), Err(AvbIoError::Oom));
1051     }
1052 
1053     #[test]
ops_avb_read_rollback_index_protocol_not_found()1054     fn ops_avb_read_rollback_index_protocol_not_found() {
1055         let mut mock_efi = MockEfi::new();
1056         mock_efi
1057             .boot_services
1058             .expect_find_first_and_open::<GblAvbProtocol>()
1059             .returning(|| Err(Error::NotFound));
1060 
1061         let installed = mock_efi.install();
1062         let mut ops = Ops::new(installed.entry(), &[], None);
1063 
1064         assert_eq!(ops.avb_read_rollback_index(0), Err(AvbIoError::NotImplemented));
1065     }
1066 
1067     #[test]
ops_avb_write_rollback_index_success()1068     fn ops_avb_write_rollback_index_success() {
1069         let mut mock_efi = MockEfi::new();
1070         let mut avb = GblAvbProtocol::default();
1071         avb.write_rollback_index_result = Some(Ok(()));
1072         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
1073 
1074         let installed = mock_efi.install();
1075         let mut ops = Ops::new(installed.entry(), &[], None);
1076 
1077         assert!(ops.avb_write_rollback_index(0, 12345).is_ok());
1078     }
1079 
1080     #[test]
ops_avb_write_rollback_index_error()1081     fn ops_avb_write_rollback_index_error() {
1082         let mut mock_efi = MockEfi::new();
1083         let mut avb = GblAvbProtocol::default();
1084         avb.write_rollback_index_result = Some(Err(Error::InvalidInput));
1085         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
1086 
1087         let installed = mock_efi.install();
1088         let mut ops = Ops::new(installed.entry(), &[], None);
1089 
1090         assert_eq!(ops.avb_write_rollback_index(0, 12345), Err(AvbIoError::InvalidValueSize));
1091     }
1092 
1093     #[test]
ops_avb_write_rollback_index_protocol_not_found()1094     fn ops_avb_write_rollback_index_protocol_not_found() {
1095         let mut mock_efi = MockEfi::new();
1096         mock_efi
1097             .boot_services
1098             .expect_find_first_and_open::<GblAvbProtocol>()
1099             .returning(|| Err(Error::NotFound));
1100 
1101         let installed = mock_efi.install();
1102         let mut ops = Ops::new(installed.entry(), &[], None);
1103 
1104         assert_eq!(ops.avb_write_rollback_index(0, 12345), Err(AvbIoError::NotImplemented));
1105     }
1106 
1107     #[test]
ops_avb_read_persistent_value_success()1108     fn ops_avb_read_persistent_value_success() {
1109         const EXPECTED_LEN: usize = 4;
1110 
1111         let mut mock_efi = MockEfi::new();
1112         let mut avb = GblAvbProtocol::default();
1113         avb.read_persistent_value_result = Some(Ok(EXPECTED_LEN));
1114         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
1115 
1116         let installed = mock_efi.install();
1117         let mut ops = Ops::new(installed.entry(), &[], None);
1118 
1119         let mut buffer = [0u8; EXPECTED_LEN];
1120         assert_eq!(ops.avb_read_persistent_value(c"test", &mut buffer), Ok(EXPECTED_LEN));
1121     }
1122 
1123     #[test]
ops_avb_read_persistent_value_error()1124     fn ops_avb_read_persistent_value_error() {
1125         let mut mock_efi = MockEfi::new();
1126         let mut avb = GblAvbProtocol::default();
1127         avb.read_persistent_value_result = Some(Err(Error::OutOfResources));
1128         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
1129 
1130         let installed = mock_efi.install();
1131         let mut ops = Ops::new(installed.entry(), &[], None);
1132 
1133         let mut buffer = [0u8; 0];
1134         assert_eq!(ops.avb_read_persistent_value(c"test", &mut buffer), Err(AvbIoError::Oom));
1135     }
1136 
1137     #[test]
ops_avb_read_persistent_value_protocol_not_found()1138     fn ops_avb_read_persistent_value_protocol_not_found() {
1139         let mut mock_efi = MockEfi::new();
1140         mock_efi
1141             .boot_services
1142             .expect_find_first_and_open::<GblAvbProtocol>()
1143             .returning(|| Err(Error::NotFound));
1144 
1145         let installed = mock_efi.install();
1146         let mut ops = Ops::new(installed.entry(), &[], None);
1147 
1148         let mut buffer = [0u8; 0];
1149         assert_eq!(
1150             ops.avb_read_persistent_value(c"test", &mut buffer),
1151             Err(AvbIoError::NotImplemented)
1152         );
1153     }
1154 
1155     #[test]
ops_avb_write_persistent_value_success()1156     fn ops_avb_write_persistent_value_success() {
1157         let mut mock_efi = MockEfi::new();
1158         let mut avb = GblAvbProtocol::default();
1159         avb.write_persistent_value_result = Some(Ok(()));
1160         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
1161 
1162         let installed = mock_efi.install();
1163         let mut ops = Ops::new(installed.entry(), &[], None);
1164 
1165         assert_eq!(ops.avb_write_persistent_value(c"test", b""), Ok(()));
1166     }
1167 
1168     #[test]
ops_avb_write_persistent_value_error()1169     fn ops_avb_write_persistent_value_error() {
1170         let mut mock_efi = MockEfi::new();
1171         let mut avb = GblAvbProtocol::default();
1172         avb.write_persistent_value_result = Some(Err(Error::InvalidInput));
1173         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
1174 
1175         let installed = mock_efi.install();
1176         let mut ops = Ops::new(installed.entry(), &[], None);
1177 
1178         assert_eq!(ops.avb_write_persistent_value(c"test", b""), Err(AvbIoError::InvalidValueSize));
1179     }
1180 
1181     #[test]
ops_avb_write_persistent_value_protocol_not_found()1182     fn ops_avb_write_persistent_value_protocol_not_found() {
1183         let mut mock_efi = MockEfi::new();
1184         mock_efi
1185             .boot_services
1186             .expect_find_first_and_open::<GblAvbProtocol>()
1187             .returning(|| Err(Error::NotFound));
1188 
1189         let installed = mock_efi.install();
1190         let mut ops = Ops::new(installed.entry(), &[], None);
1191 
1192         assert_eq!(ops.avb_write_persistent_value(c"test", b""), Err(AvbIoError::NotImplemented));
1193     }
1194 
1195     #[test]
ops_avb_erase_persistent_value_success()1196     fn ops_avb_erase_persistent_value_success() {
1197         let mut mock_efi = MockEfi::new();
1198         let mut avb = GblAvbProtocol::default();
1199         avb.write_persistent_value_result = Some(Ok(()));
1200         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
1201 
1202         let installed = mock_efi.install();
1203         let mut ops = Ops::new(installed.entry(), &[], None);
1204 
1205         assert_eq!(ops.avb_erase_persistent_value(c"test"), Ok(()));
1206     }
1207 
1208     #[test]
ops_avb_erase_persistent_value_error()1209     fn ops_avb_erase_persistent_value_error() {
1210         let mut mock_efi = MockEfi::new();
1211         let mut avb = GblAvbProtocol::default();
1212         avb.write_persistent_value_result = Some(Err(Error::DeviceError));
1213         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
1214 
1215         let installed = mock_efi.install();
1216         let mut ops = Ops::new(installed.entry(), &[], None);
1217 
1218         assert_eq!(ops.avb_erase_persistent_value(c"test"), Err(AvbIoError::Io));
1219     }
1220 
1221     #[test]
ops_avb_erase_persistent_value_protocol_not_found()1222     fn ops_avb_erase_persistent_value_protocol_not_found() {
1223         let mut mock_efi = MockEfi::new();
1224         mock_efi
1225             .boot_services
1226             .expect_find_first_and_open::<GblAvbProtocol>()
1227             .returning(|| Err(Error::NotFound));
1228 
1229         let installed = mock_efi.install();
1230         let mut ops = Ops::new(installed.entry(), &[], None);
1231 
1232         assert_eq!(ops.avb_erase_persistent_value(c"test"), Err(AvbIoError::NotImplemented));
1233     }
1234 
1235     /// Helper for testing `set_boot_reason`
test_set_reboot_reason(input: RebootReason, expect: GBL_EFI_BOOT_REASON)1236     fn test_set_reboot_reason(input: RebootReason, expect: GBL_EFI_BOOT_REASON) {
1237         let mut mock_efi = MockEfi::new();
1238         mock_efi.boot_services.expect_find_first_and_open::<GblSlotProtocol>().times(1).returning(
1239             move || {
1240                 let mut slot = GblSlotProtocol::default();
1241                 slot.expect_set_boot_reason().times(1).returning(move |reason, _| {
1242                     assert_eq!(reason, expect);
1243                     Ok(())
1244                 });
1245                 Ok(slot)
1246             },
1247         );
1248         let installed = mock_efi.install();
1249         let mut ops = Ops::new(installed.entry(), &[], None);
1250         assert_eq!(ops.set_reboot_reason(input), Ok(()));
1251     }
1252 
1253     #[test]
test_set_reboot_reason_normal()1254     fn test_set_reboot_reason_normal() {
1255         test_set_reboot_reason(RebootReason::Normal, GBL_EFI_BOOT_REASON_COLD);
1256     }
1257 
1258     #[test]
test_set_reboot_reason_recovery()1259     fn test_set_reboot_reason_recovery() {
1260         test_set_reboot_reason(RebootReason::Recovery, GBL_EFI_BOOT_REASON_RECOVERY);
1261     }
1262 
1263     #[test]
test_set_reboot_reason_bootloader()1264     fn test_set_reboot_reason_bootloader() {
1265         test_set_reboot_reason(RebootReason::Bootloader, GBL_EFI_BOOT_REASON_BOOTLOADER);
1266     }
1267 
1268     #[test]
test_set_reboot_reason_fastbootd()1269     fn test_set_reboot_reason_fastbootd() {
1270         test_set_reboot_reason(RebootReason::FastbootD, GBL_EFI_BOOT_REASON_FASTBOOTD);
1271     }
1272 
1273     /// Helper for testing `get_boot_reason`
test_get_reboot_reason(input: GBL_EFI_BOOT_REASON, expect: RebootReason)1274     fn test_get_reboot_reason(input: GBL_EFI_BOOT_REASON, expect: RebootReason) {
1275         let mut mock_efi = MockEfi::new();
1276         mock_efi.boot_services.expect_find_first_and_open::<GblSlotProtocol>().times(1).returning(
1277             move || {
1278                 let mut slot = GblSlotProtocol::default();
1279                 slot.expect_get_boot_reason().times(1).returning(move |_| Ok((input, 0)));
1280                 Ok(slot)
1281             },
1282         );
1283         let installed = mock_efi.install();
1284         let mut ops = Ops::new(installed.entry(), &[], None);
1285         assert_eq!(ops.get_reboot_reason().unwrap(), expect)
1286     }
1287 
1288     #[test]
test_get_reboot_reason_normal()1289     fn test_get_reboot_reason_normal() {
1290         test_get_reboot_reason(GBL_EFI_BOOT_REASON_COLD, RebootReason::Normal);
1291     }
1292 
1293     #[test]
test_get_reboot_reason_recovery()1294     fn test_get_reboot_reason_recovery() {
1295         test_get_reboot_reason(GBL_EFI_BOOT_REASON_RECOVERY, RebootReason::Recovery);
1296     }
1297 
1298     #[test]
test_get_reboot_reason_bootloader()1299     fn test_get_reboot_reason_bootloader() {
1300         test_get_reboot_reason(GBL_EFI_BOOT_REASON_BOOTLOADER, RebootReason::Bootloader);
1301     }
1302 
1303     #[test]
test_get_reboot_reason_fastbootd()1304     fn test_get_reboot_reason_fastbootd() {
1305         test_get_reboot_reason(GBL_EFI_BOOT_REASON_FASTBOOTD, RebootReason::FastbootD);
1306     }
1307 }
1308