• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! 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     ffi::CStr, fmt::Write, mem::MaybeUninit, num::NonZeroUsize, ops::DerefMut, ptr::null,
29     slice::from_raw_parts_mut, time::Duration,
30 };
31 use efi::{
32     efi_print, efi_println,
33     protocol::{
34         dt_fixup::DtFixupProtocol,
35         gbl_efi_ab_slot::GblSlotProtocol,
36         gbl_efi_avb::GblAvbProtocol,
37         gbl_efi_fastboot::GblFastbootProtocol,
38         gbl_efi_image_loading::{EfiImageBufferInfo, GblImageLoadingProtocol},
39         gbl_efi_os_configuration::GblOsConfigurationProtocol,
40     },
41     EfiEntry,
42 };
43 use efi_types::{
44     GblEfiAvbKeyValidationStatus, GblEfiAvbVerificationResult, GblEfiBootReason,
45     GblEfiDeviceTreeMetadata, GblEfiImageInfo, GblEfiVerifiedDeviceTree,
46     GBL_EFI_BOOT_REASON_BOOTLOADER, GBL_EFI_BOOT_REASON_COLD, GBL_EFI_BOOT_REASON_FASTBOOTD,
47     GBL_EFI_BOOT_REASON_RECOVERY, PARTITION_NAME_LEN_U16,
48 };
49 use fdt::Fdt;
50 use gbl_storage::{BlockIo, Disk, Gpt};
51 use liberror::{Error, Result};
52 use libgbl::{
53     constants::{ImageName, BOOTCMD_SIZE},
54     device_tree::{
55         DeviceTreeComponent, DeviceTreeComponentSource, DeviceTreeComponentsRegistry,
56         MAXIMUM_DEVICE_TREE_COMPONENTS,
57     },
58     gbl_avb::state::{BootStateColor, KeyValidationStatus},
59     ops::{
60         AvbIoError, AvbIoResult, CertPermanentAttributes, ImageBuffer, RebootReason, Slot,
61         SlotsMetadata, SHA256_DIGEST_SIZE,
62     },
63     partition::GblDisk,
64     slots::{BootToken, Cursor},
65     GblOps, Os, Result as GblResult,
66 };
67 use safemath::SafeNum;
68 use zbi::ZbiContainer;
69 use zerocopy::IntoBytes;
70 
to_avb_validation_status_or_panic(status: GblEfiAvbKeyValidationStatus) -> KeyValidationStatus71 fn to_avb_validation_status_or_panic(status: GblEfiAvbKeyValidationStatus) -> KeyValidationStatus {
72     match status {
73         efi_types::GBL_EFI_AVB_KEY_VALIDATION_STATUS_VALID => KeyValidationStatus::Valid,
74         efi_types::GBL_EFI_AVB_KEY_VALIDATION_STATUS_VALID_CUSTOM_KEY => {
75             KeyValidationStatus::ValidCustomKey
76         }
77         efi_types::GBL_EFI_AVB_KEY_VALIDATION_STATUS_INVALID => KeyValidationStatus::Invalid,
78         _ => panic!("Unrecognized avb key validation status: {}", status),
79     }
80 }
81 
avb_color_to_efi_color(color: BootStateColor) -> u3282 fn avb_color_to_efi_color(color: BootStateColor) -> u32 {
83     match color {
84         BootStateColor::Green => efi_types::GBL_EFI_AVB_BOOT_STATE_COLOR_GREEN,
85         BootStateColor::Yellow => efi_types::GBL_EFI_AVB_BOOT_STATE_COLOR_YELLOW,
86         BootStateColor::Orange => efi_types::GBL_EFI_AVB_BOOT_STATE_COLOR_ORANGE,
87         BootStateColor::RedEio => efi_types::GBL_EFI_AVB_BOOT_STATE_COLOR_RED_EIO,
88         BootStateColor::Red => efi_types::GBL_EFI_AVB_BOOT_STATE_COLOR_RED,
89     }
90 }
91 
dt_component_to_efi_dt(component: &DeviceTreeComponent) -> GblEfiVerifiedDeviceTree92 fn dt_component_to_efi_dt(component: &DeviceTreeComponent) -> GblEfiVerifiedDeviceTree {
93     let metadata = component.metadata.unwrap_or_default();
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 /// Helper for getting platform reserved buffer from EFI image loading prototol.
get_buffer_from_protocol( efi_entry: &EfiEntry, image_name: &str, size: usize, ) -> Result<EfiImageBufferInfo>138 pub(crate) fn get_buffer_from_protocol(
139     efi_entry: &EfiEntry,
140     image_name: &str,
141     size: usize,
142 ) -> Result<EfiImageBufferInfo> {
143     let mut image_type = [0u16; PARTITION_NAME_LEN_U16];
144     image_type.iter_mut().zip(image_name.encode_utf16()).for_each(|(dst, src)| {
145         *dst = src;
146     });
147     Ok(efi_entry
148         .system_table()
149         .boot_services()
150         .find_first_and_open::<GblImageLoadingProtocol>()?
151         .get_buffer(&GblEfiImageInfo { ImageType: image_type, SizeBytes: size })?)
152 }
153 
154 pub struct Ops<'a, 'b> {
155     pub efi_entry: &'a EfiEntry,
156     pub disks: &'b [EfiGblDisk<'a>],
157     pub zbi_bootloader_files_buffer: Vec<u8>,
158     pub os: Option<Os>,
159 }
160 
161 impl<'a, 'b> Ops<'a, 'b> {
162     /// Creates a new instance of [Ops]
new(efi_entry: &'a EfiEntry, disks: &'b [EfiGblDisk<'a>], os: Option<Os>) -> Self163     pub fn new(efi_entry: &'a EfiEntry, disks: &'b [EfiGblDisk<'a>], os: Option<Os>) -> Self {
164         Self { efi_entry, disks, zbi_bootloader_files_buffer: Default::default(), os }
165     }
166 
167     /// Gets the property of an FDT node from EFI FDT.
168     ///
169     /// Returns `None` if fail to get the node
get_efi_fdt_prop(&self, path: &str, prop: &CStr) -> Option<&'a [u8]>170     fn get_efi_fdt_prop(&self, path: &str, prop: &CStr) -> Option<&'a [u8]> {
171         let (_, fdt_bytes) = get_efi_fdt(&self.efi_entry)?;
172         let fdt = Fdt::new(fdt_bytes).ok()?;
173         fdt.get_property(path, prop).ok()
174     }
175 
176     /// Get buffer for partition loading and verification.
177     /// Uses GBL EFI ImageLoading protocol.
178     ///
179     /// # Arguments
180     /// * `image_name` - image name to differentiate the buffer properties. Processing is limited
181     /// to first [PARTITION_NAME_LEN_U16] symbols, and the remaining will be ignored.
182     /// * `size` - requested buffer size
183     ///
184     /// # Return
185     /// * Ok(ImageBuffer) - Return buffer for partition loading and verification.
186     /// * Err(_) - on error
get_buffer_image_loading( &mut self, image_name: &str, size: NonZeroUsize, ) -> GblResult<ImageBuffer<'static>>187     pub(crate) fn get_buffer_image_loading(
188         &mut self,
189         image_name: &str,
190         size: NonZeroUsize,
191     ) -> GblResult<ImageBuffer<'static>> {
192         // EfiImageBuffer -> ImageBuffer
193         // Make sure not to drop efi_image_buffer since we transferred ownership to ImageBuffer
194         Ok(ImageBuffer::new(
195             get_buffer_from_protocol(self.efi_entry, image_name, size.get())?
196                 .take()
197                 .ok_or(Error::InvalidState)?,
198         ))
199     }
200 
201     /// Get buffer for partition loading and verification.
202     /// Uses provided allocator.
203     ///
204     /// # Arguments
205     /// * `image_name` - image name to differentiate the buffer properties
206     /// * `size` - requested buffer size
207     ///
208     /// # Return
209     /// * Ok(ImageBuffer) - Return buffer for partition loading and verification.
210     /// * Err(_) - on error
211     // SAFETY:
212     // Allocated buffer is leaked intentionally. ImageBuffer is assumed to reference static memory.
213     // ImageBuffer is not expected to be released, and is allocated to hold data necessary for next
214     // 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>>215     fn allocate_image_buffer(image_name: &str, size: NonZeroUsize) -> Result<ImageBuffer<'static>> {
216         let size = match image_name {
217             "ramdisk" => (SafeNum::from(size.get()) + BOOTCMD_SIZE).try_into()?,
218             _ => size.get(),
219         };
220         // Check for `from_raw_parts_mut()` safety requirements.
221         assert!(size < isize::MAX.try_into().unwrap());
222         let align = ImageName::try_from(image_name).map(|i| i.alignment()).unwrap_or(1);
223 
224         let layout = Layout::from_size_align(size, align).or(Err(Error::InvalidAlignment))?;
225         // SAFETY:
226         // `layout.size()` is checked to be not zero.
227         let ptr = unsafe { alloc(layout) } as *mut MaybeUninit<u8>;
228         if ptr.is_null() {
229             handle_alloc_error(layout);
230         }
231 
232         // SAFETY:
233         // `ptr` is checked to be not Null.
234         // `ptr` is a valid pointer to start of a single memory region of `size`-bytes because it
235         // was just returned by alloc. Buffer alignment requirement for u8 is 1-byte which is
236         // always the case.
237         // `alloc()` makes sure there is no other allocation of the same memory region until
238         // current one is released.
239         // `size` is a valid size of the memory region since `alloc()` succeeded.
240         //
241         // Total size of buffer is not greater than `isize::MAX` since it is checked at the
242         // beginning of the function.
243         //
244         // `ptr + size` doesn't wrap since it is returned from alloc and it didn't fail.
245         let buf = unsafe { from_raw_parts_mut(ptr, size) };
246 
247         Ok(ImageBuffer::new(buf))
248     }
249 }
250 
251 impl Write for Ops<'_, '_> {
write_str(&mut self, s: &str) -> core::fmt::Result252     fn write_str(&mut self, s: &str) -> core::fmt::Result {
253         efi_print!(self.efi_entry, "{}", s);
254         Ok(())
255     }
256 }
257 
258 impl<'a, 'b, 'd> GblOps<'b, 'd> for Ops<'a, 'b> {
console_out(&mut self) -> Option<&mut dyn Write>259     fn console_out(&mut self) -> Option<&mut dyn Write> {
260         Some(self)
261     }
262 
263     /// UEFI console uses \r\n newline.
console_newline(&self) -> &'static str264     fn console_newline(&self) -> &'static str {
265         "\r\n"
266     }
267 
should_stop_in_fastboot(&mut self) -> Result<bool>268     fn should_stop_in_fastboot(&mut self) -> Result<bool> {
269         // TODO(b/349829690): also query GblSlotProtocol.get_boot_reason() for board-specific
270         // fastboot triggers.
271 
272         // TODO(b/366520234): Switch to use GblSlotProtocol.should_stop_in_fastboot once available.
273         match self.get_efi_fdt_prop("gbl", c"stop-in-fastboot") {
274             Some(v) => return Ok(*v.get(0).unwrap_or(&0) == 1),
275             _ => {}
276         }
277 
278         efi_println!(self.efi_entry, "Press Backspace to enter fastboot");
279         let found = wait_key_stroke(
280             self.efi_entry,
281             |key| key.unicode_char == 0x08 || (key.unicode_char == 0x0 && key.scan_code == 0x08),
282             Duration::from_secs(2),
283         );
284         if matches!(found, Ok(true)) {
285             efi_println!(self.efi_entry, "Backspace pressed, entering fastboot");
286         }
287         // TODO(b/358377120): pass the UEFI error when liberror::Error support lands.
288         found.or(Err(Error::Other(Some("wait for key stroke error"))))
289     }
290 
291     /// Reboots the system into the last set boot mode.
reboot(&mut self)292     fn reboot(&mut self) {
293         self.efi_entry.system_table().runtime_services().cold_reset();
294     }
295 
disks( &self, ) -> &'b [GblDisk< Disk<impl BlockIo + 'b, impl DerefMut<Target = [u8]> + 'b>, Gpt<impl DerefMut<Target = [u8]> + 'b>, >]296     fn disks(
297         &self,
298     ) -> &'b [GblDisk<
299         Disk<impl BlockIo + 'b, impl DerefMut<Target = [u8]> + 'b>,
300         Gpt<impl DerefMut<Target = [u8]> + 'b>,
301     >] {
302         self.disks
303     }
304 
expected_os(&mut self) -> Result<Option<Os>>305     fn expected_os(&mut self) -> Result<Option<Os>> {
306         Ok(self.os)
307     }
308 
zircon_add_device_zbi_items( &mut self, container: &mut ZbiContainer<&mut [u8]>, ) -> Result<()>309     fn zircon_add_device_zbi_items(
310         &mut self,
311         container: &mut ZbiContainer<&mut [u8]>,
312     ) -> Result<()> {
313         // TODO(b/353272981): Switch to use OS configuration protocol once it is implemented on
314         // existing platforms such as VIM3.
315         Ok(match self.get_efi_fdt_prop("zircon", c"zbi-blob") {
316             Some(blob) => container.extend_unaligned(blob).map_err(|_| "Failed to append ZBI")?,
317             _ => efi_println!(self.efi_entry, "No device ZBI items.\r\n"),
318         })
319     }
320 
get_zbi_bootloader_files_buffer(&mut self) -> Option<&mut [u8]>321     fn get_zbi_bootloader_files_buffer(&mut self) -> Option<&mut [u8]> {
322         // Switches to use get_image_buffer once available.
323         const DEFAULT_SIZE: usize = 4096;
324         if self.zbi_bootloader_files_buffer.is_empty() {
325             self.zbi_bootloader_files_buffer.resize(DEFAULT_SIZE, 0);
326         }
327         Some(self.zbi_bootloader_files_buffer.as_mut_slice())
328     }
329 
load_slot_interface<'c>( &'c mut self, _: &'c mut dyn FnMut(&mut [u8]) -> Result<()>, _: BootToken, ) -> GblResult<Cursor<'c>>330     fn load_slot_interface<'c>(
331         &'c mut self,
332         _: &'c mut dyn FnMut(&mut [u8]) -> Result<()>,
333         _: BootToken,
334     ) -> GblResult<Cursor<'c>> {
335         unimplemented!();
336     }
337 
avb_read_is_device_unlocked(&mut self) -> AvbIoResult<bool>338     fn avb_read_is_device_unlocked(&mut self) -> AvbIoResult<bool> {
339         match self.efi_entry.system_table().boot_services().find_first_and_open::<GblAvbProtocol>()
340         {
341             Ok(protocol) => protocol.read_is_device_unlocked().map_err(efi_error_to_avb_error),
342             Err(_) => Err(AvbIoError::NotImplemented),
343         }
344     }
345 
avb_read_rollback_index(&mut self, rollback_index_location: usize) -> AvbIoResult<u64>346     fn avb_read_rollback_index(&mut self, rollback_index_location: usize) -> AvbIoResult<u64> {
347         match self.efi_entry.system_table().boot_services().find_first_and_open::<GblAvbProtocol>()
348         {
349             Ok(protocol) => protocol
350                 .read_rollback_index(rollback_index_location)
351                 .map_err(efi_error_to_avb_error),
352             Err(_) => Err(AvbIoError::NotImplemented),
353         }
354     }
355 
avb_write_rollback_index( &mut self, rollback_index_location: usize, index: u64, ) -> AvbIoResult<()>356     fn avb_write_rollback_index(
357         &mut self,
358         rollback_index_location: usize,
359         index: u64,
360     ) -> AvbIoResult<()> {
361         match self.efi_entry.system_table().boot_services().find_first_and_open::<GblAvbProtocol>()
362         {
363             Ok(protocol) => protocol
364                 .write_rollback_index(rollback_index_location, index)
365                 .map_err(efi_error_to_avb_error),
366             Err(_) => Err(AvbIoError::NotImplemented),
367         }
368     }
369 
avb_read_persistent_value(&mut self, name: &CStr, value: &mut [u8]) -> AvbIoResult<usize>370     fn avb_read_persistent_value(&mut self, name: &CStr, value: &mut [u8]) -> AvbIoResult<usize> {
371         match self.efi_entry.system_table().boot_services().find_first_and_open::<GblAvbProtocol>()
372         {
373             Ok(protocol) => {
374                 protocol.read_persistent_value(name, value).map_err(efi_error_to_avb_error)
375             }
376             Err(_) => Err(AvbIoError::NotImplemented),
377         }
378     }
379 
avb_write_persistent_value(&mut self, name: &CStr, value: &[u8]) -> AvbIoResult<()>380     fn avb_write_persistent_value(&mut self, name: &CStr, value: &[u8]) -> AvbIoResult<()> {
381         match self.efi_entry.system_table().boot_services().find_first_and_open::<GblAvbProtocol>()
382         {
383             Ok(protocol) => {
384                 protocol.write_persistent_value(name, Some(value)).map_err(efi_error_to_avb_error)
385             }
386             Err(_) => Err(AvbIoError::NotImplemented),
387         }
388     }
389 
avb_erase_persistent_value(&mut self, name: &CStr) -> AvbIoResult<()>390     fn avb_erase_persistent_value(&mut self, name: &CStr) -> AvbIoResult<()> {
391         match self.efi_entry.system_table().boot_services().find_first_and_open::<GblAvbProtocol>()
392         {
393             Ok(protocol) => {
394                 protocol.write_persistent_value(name, None).map_err(efi_error_to_avb_error)
395             }
396             Err(_) => Err(AvbIoError::NotImplemented),
397         }
398     }
399 
avb_validate_vbmeta_public_key( &self, public_key: &[u8], public_key_metadata: Option<&[u8]>, ) -> AvbIoResult<KeyValidationStatus>400     fn avb_validate_vbmeta_public_key(
401         &self,
402         public_key: &[u8],
403         public_key_metadata: Option<&[u8]>,
404     ) -> AvbIoResult<KeyValidationStatus> {
405         match self.efi_entry.system_table().boot_services().find_first_and_open::<GblAvbProtocol>()
406         {
407             Ok(protocol) => protocol
408                 .validate_vbmeta_public_key(public_key, public_key_metadata)
409                 .map(to_avb_validation_status_or_panic)
410                 .map_err(efi_error_to_avb_error),
411             Err(_) => Err(AvbIoError::NotImplemented),
412         }
413     }
414 
avb_cert_read_permanent_attributes( &mut self, attributes: &mut CertPermanentAttributes, ) -> AvbIoResult<()>415     fn avb_cert_read_permanent_attributes(
416         &mut self,
417         attributes: &mut CertPermanentAttributes,
418     ) -> AvbIoResult<()> {
419         // TODO(b/337846185): Switch to use GBL Verified Boot EFI protocol when available.
420         let perm_attr = self
421             .get_efi_fdt_prop("gbl", c"avb-cert-permanent-attributes")
422             .ok_or(AvbIoError::NotImplemented)?;
423         attributes.as_bytes_mut().clone_from_slice(perm_attr);
424         Ok(())
425     }
426 
avb_cert_read_permanent_attributes_hash(&mut self) -> AvbIoResult<[u8; SHA256_DIGEST_SIZE]>427     fn avb_cert_read_permanent_attributes_hash(&mut self) -> AvbIoResult<[u8; SHA256_DIGEST_SIZE]> {
428         // TODO(b/337846185): Switch to use GBL Verified Boot EFI protocol when available.
429         let hash = self
430             .get_efi_fdt_prop("gbl", c"avb-cert-permanent-attributes-hash")
431             .ok_or(AvbIoError::NotImplemented)?;
432         Ok(hash.try_into().map_err(|_| AvbIoError::Io)?)
433     }
434 
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<()>435     fn avb_handle_verification_result(
436         &mut self,
437         color: BootStateColor,
438         digest: Option<&CStr>,
439         boot_os_version: Option<&[u8]>,
440         boot_security_patch: Option<&[u8]>,
441         system_os_version: Option<&[u8]>,
442         system_security_patch: Option<&[u8]>,
443         vendor_os_version: Option<&[u8]>,
444         vendor_security_patch: Option<&[u8]>,
445     ) -> AvbIoResult<()> {
446         match self.efi_entry.system_table().boot_services().find_first_and_open::<GblAvbProtocol>()
447         {
448             Ok(protocol) => protocol
449                 .handle_verification_result(&GblEfiAvbVerificationResult {
450                     color: avb_color_to_efi_color(color),
451                     digest: digest.map_or(null(), |p| p.as_ptr() as _),
452                     boot_version: boot_os_version.map_or(null(), |p| p.as_ptr()),
453                     boot_security_patch: boot_security_patch.map_or(null(), |p| p.as_ptr()),
454                     system_version: system_os_version.map_or(null(), |p| p.as_ptr()),
455                     system_security_patch: system_security_patch.map_or(null(), |p| p.as_ptr()),
456                     vendor_version: vendor_os_version.map_or(null(), |p| p.as_ptr()),
457                     vendor_security_patch: vendor_security_patch.map_or(null(), |p| p.as_ptr()),
458                 })
459                 .map_err(efi_error_to_avb_error),
460             _ => Ok(()),
461         }
462     }
463 
get_image_buffer( &mut self, image_name: &str, size: NonZeroUsize, ) -> GblResult<ImageBuffer<'d>>464     fn get_image_buffer(
465         &mut self,
466         image_name: &str,
467         size: NonZeroUsize,
468     ) -> GblResult<ImageBuffer<'d>> {
469         self.get_buffer_image_loading(image_name, size)
470             .or(Self::allocate_image_buffer(image_name, size)
471                 .map_err(|e| libgbl::IntegrationError::UnificationError(e)))
472     }
473 
get_custom_device_tree(&mut self) -> Option<&'a [u8]>474     fn get_custom_device_tree(&mut self) -> Option<&'a [u8]> {
475         // On Cuttlefish, the device tree comes from the UEFI config tables.
476         // TODO(b/353272981): once we've settled on the device tree UEFI protocol, use that
477         // instead to provide a Cuttlefish-specific backend.
478         Some(get_efi_fdt(&self.efi_entry)?.1)
479     }
480 
fixup_os_commandline<'c>( &mut self, commandline: &CStr, fixup_buffer: &'c mut [u8], ) -> Result<Option<&'c str>>481     fn fixup_os_commandline<'c>(
482         &mut self,
483         commandline: &CStr,
484         fixup_buffer: &'c mut [u8],
485     ) -> Result<Option<&'c str>> {
486         match self
487             .efi_entry
488             .system_table()
489             .boot_services()
490             .find_first_and_open::<GblOsConfigurationProtocol>()
491         {
492             Ok(protocol) => {
493                 protocol.fixup_kernel_commandline(commandline, fixup_buffer)?;
494                 Ok(Some(CStr::from_bytes_until_nul(&fixup_buffer[..])?.to_str()?))
495             }
496             // Protocol is optional.
497             Err(Error::NotFound) => Ok(None),
498             Err(e) => Err(e),
499         }
500     }
501 
fixup_bootconfig<'c>( &mut self, bootconfig: &[u8], fixup_buffer: &'c mut [u8], ) -> Result<Option<&'c [u8]>>502     fn fixup_bootconfig<'c>(
503         &mut self,
504         bootconfig: &[u8],
505         fixup_buffer: &'c mut [u8],
506     ) -> Result<Option<&'c [u8]>> {
507         match self
508             .efi_entry
509             .system_table()
510             .boot_services()
511             .find_first_and_open::<GblOsConfigurationProtocol>()
512         {
513             Ok(protocol) => {
514                 let fixup_size = protocol.fixup_bootconfig(bootconfig, fixup_buffer)?;
515                 Ok(Some(&fixup_buffer[..fixup_size]))
516             }
517             // Protocol is optional.
518             Err(Error::NotFound) => Ok(None),
519             Err(e) => Err(e),
520         }
521     }
522 
fixup_device_tree(&mut self, device_tree: &mut [u8]) -> Result<()>523     fn fixup_device_tree(&mut self, device_tree: &mut [u8]) -> Result<()> {
524         match self.efi_entry.system_table().boot_services().find_first_and_open::<DtFixupProtocol>()
525         {
526             Ok(protocol) => protocol.fixup(device_tree),
527             // Protocol is optional.
528             Err(Error::NotFound) => Ok(()),
529             Err(e) => Err(e),
530         }
531     }
532 
select_device_trees( &mut self, components_registry: &mut DeviceTreeComponentsRegistry, ) -> Result<()>533     fn select_device_trees(
534         &mut self,
535         components_registry: &mut DeviceTreeComponentsRegistry,
536     ) -> Result<()> {
537         match self
538             .efi_entry
539             .system_table()
540             .boot_services()
541             .find_first_and_open::<GblOsConfigurationProtocol>()
542         {
543             Ok(protocol) => {
544                 // Protocol detected, convert to UEFI types.
545                 let mut uefi_components: ArrayVec<_, MAXIMUM_DEVICE_TREE_COMPONENTS> =
546                     components_registry
547                         .components()
548                         .map(|component| dt_component_to_efi_dt(component))
549                         .collect();
550 
551                 protocol.select_device_trees(&mut uefi_components[..])?;
552 
553                 // Propagate selections to the components_registry.
554                 components_registry
555                     .components_mut()
556                     .zip(uefi_components.iter_mut())
557                     .enumerate()
558                     .for_each(|(index, (component, uefi_component))| {
559                         if uefi_component.selected {
560                             efi_println!(
561                                 self.efi_entry,
562                                 "Device tree component at index {} got selected by UEFI call. \
563                                 Source: {}",
564                                 index,
565                                 component.source
566                             );
567                         }
568                         component.selected = uefi_component.selected;
569                     });
570 
571                 Ok(())
572             }
573             // Protocol is optional.
574             Err(Error::NotFound) => components_registry.autoselect(),
575             Err(e) => Err(e),
576         }
577     }
578 
fastboot_variable<'arg>( &mut self, name: &CStr, args: impl Iterator<Item = &'arg CStr> + Clone, out: &mut [u8], ) -> Result<usize>579     fn fastboot_variable<'arg>(
580         &mut self,
581         name: &CStr,
582         args: impl Iterator<Item = &'arg CStr> + Clone,
583         out: &mut [u8],
584     ) -> Result<usize> {
585         self.efi_entry
586             .system_table()
587             .boot_services()
588             .find_first_and_open::<GblFastbootProtocol>()?
589             .get_var(name, args, out)
590     }
591 
fastboot_visit_all_variables(&mut self, cb: impl FnMut(&[&CStr], &CStr)) -> Result<()>592     fn fastboot_visit_all_variables(&mut self, cb: impl FnMut(&[&CStr], &CStr)) -> Result<()> {
593         match self
594             .efi_entry
595             .system_table()
596             .boot_services()
597             .find_first_and_open::<GblFastbootProtocol>()
598         {
599             Ok(v) => v.get_var_all(cb),
600             Err(Error::NotFound) => Ok(()),
601             Err(e) => Err(e),
602         }
603     }
604 
slots_metadata(&mut self) -> Result<SlotsMetadata>605     fn slots_metadata(&mut self) -> Result<SlotsMetadata> {
606         Ok(SlotsMetadata {
607             slot_count: self
608                 .efi_entry
609                 .system_table()
610                 .boot_services()
611                 .find_first_and_open::<GblSlotProtocol>()?
612                 .load_boot_data()?
613                 .slot_count
614                 .try_into()
615                 .unwrap(),
616         })
617     }
618 
619     #[cfg(not(test))]
get_current_slot(&mut self) -> Result<Slot>620     fn get_current_slot(&mut self) -> Result<Slot> {
621         // TODO(b/383620444): GBL EFI slot protocol is currently implemented on a few platforms such
622         // as Cuttlefish but is out of sync. Wait until protocol is more stable and all platforms
623         // pick up the latest before enabling.
624         Err(Error::Unsupported)
625     }
626 
627     #[cfg(not(test))]
get_next_slot(&mut self, _: bool) -> Result<Slot>628     fn get_next_slot(&mut self, _: bool) -> Result<Slot> {
629         // TODO(b/383620444): See `get_current_slot()`.
630         Err(Error::Unsupported)
631     }
632 
633     #[cfg(not(test))]
set_active_slot(&mut self, _: u8) -> Result<()>634     fn set_active_slot(&mut self, _: u8) -> Result<()> {
635         // TODO(b/383620444): See `get_current_slot()`.
636         Err(Error::Unsupported)
637     }
638 
639     #[cfg(not(test))]
set_reboot_reason(&mut self, _: RebootReason) -> Result<()>640     fn set_reboot_reason(&mut self, _: RebootReason) -> Result<()> {
641         // TODO(b/383620444): See `get_current_slot()`.
642         Err(Error::Unsupported)
643     }
644 
645     #[cfg(not(test))]
get_reboot_reason(&mut self) -> Result<RebootReason>646     fn get_reboot_reason(&mut self) -> Result<RebootReason> {
647         // TODO(b/383620444): See `get_current_slot()`.
648         Err(Error::Unsupported)
649     }
650 
651     #[cfg(test)]
get_current_slot(&mut self) -> Result<Slot>652     fn get_current_slot(&mut self) -> Result<Slot> {
653         // TODO(b/363075013): Refactors the opening of slot protocol into a common helper once
654         // `MockBootServices::find_first_and_open` is updated to return Protocol<'_, T>.
655         self.efi_entry
656             .system_table()
657             .boot_services()
658             .find_first_and_open::<GblSlotProtocol>()?
659             .get_current_slot()?
660             .try_into()
661     }
662 
663     #[cfg(test)]
get_next_slot(&mut self, mark_boot_attempt: bool) -> Result<Slot>664     fn get_next_slot(&mut self, mark_boot_attempt: bool) -> Result<Slot> {
665         self.efi_entry
666             .system_table()
667             .boot_services()
668             .find_first_and_open::<GblSlotProtocol>()?
669             .get_next_slot(mark_boot_attempt)?
670             .try_into()
671     }
672 
673     #[cfg(test)]
set_active_slot(&mut self, slot: u8) -> Result<()>674     fn set_active_slot(&mut self, slot: u8) -> Result<()> {
675         self.efi_entry
676             .system_table()
677             .boot_services()
678             .find_first_and_open::<GblSlotProtocol>()?
679             .set_active_slot(slot)
680     }
681 
682     #[cfg(test)]
set_reboot_reason(&mut self, reason: RebootReason) -> Result<()>683     fn set_reboot_reason(&mut self, reason: RebootReason) -> Result<()> {
684         self.efi_entry
685             .system_table()
686             .boot_services()
687             .find_first_and_open::<GblSlotProtocol>()?
688             .set_boot_reason(gbl_to_efi_boot_reason(reason), b"")
689     }
690 
691     #[cfg(test)]
get_reboot_reason(&mut self) -> Result<RebootReason>692     fn get_reboot_reason(&mut self) -> Result<RebootReason> {
693         let mut subreason = [0u8; 128];
694         self.efi_entry
695             .system_table()
696             .boot_services()
697             .find_first_and_open::<GblSlotProtocol>()?
698             .get_boot_reason(&mut subreason[..])
699             .map(|(v, _)| efi_to_gbl_boot_reason(v))
700     }
701 }
702 
703 /// Converts a [GblEfiBootReason] to [RebootReason].
704 // TODO(b/383620444): Remove the attribute once all boards picks up the stable Slot protocol.
705 #[allow(dead_code)]
efi_to_gbl_boot_reason(reason: GblEfiBootReason) -> RebootReason706 fn efi_to_gbl_boot_reason(reason: GblEfiBootReason) -> RebootReason {
707     match reason {
708         GBL_EFI_BOOT_REASON_RECOVERY => RebootReason::Recovery,
709         GBL_EFI_BOOT_REASON_BOOTLOADER => RebootReason::Bootloader,
710         GBL_EFI_BOOT_REASON_FASTBOOTD => RebootReason::FastbootD,
711         _ => RebootReason::Normal,
712     }
713 }
714 
715 /// Converts a [RebootReason] to [GblEfiBootReason].
716 // TODO(b/383620444): Remove the attribute once all boards picks up the stable Slot protocol.
717 #[allow(dead_code)]
gbl_to_efi_boot_reason(reason: RebootReason) -> GblEfiBootReason718 fn gbl_to_efi_boot_reason(reason: RebootReason) -> GblEfiBootReason {
719     match reason {
720         RebootReason::Recovery => GBL_EFI_BOOT_REASON_RECOVERY,
721         RebootReason::Bootloader => GBL_EFI_BOOT_REASON_BOOTLOADER,
722         RebootReason::FastbootD => GBL_EFI_BOOT_REASON_FASTBOOTD,
723         RebootReason::Normal => GBL_EFI_BOOT_REASON_COLD,
724     }
725 }
726 
727 #[cfg(test)]
728 mod test {
729     use super::*;
730     use efi_mocks::{
731         protocol::{gbl_efi_ab_slot::GblSlotProtocol, gbl_efi_avb::GblAvbProtocol},
732         MockEfi,
733     };
734     use efi_types::GBL_EFI_BOOT_REASON;
735     use mockall::predicate::eq;
736     use std::slice;
737 
738     #[test]
ops_write_trait()739     fn ops_write_trait() {
740         let mut mock_efi = MockEfi::new();
741 
742         mock_efi.con_out.expect_write_str().with(eq("foo bar")).return_const(Ok(()));
743         let installed = mock_efi.install();
744 
745         let mut ops = Ops::new(installed.entry(), &[], None);
746 
747         assert!(write!(&mut ops, "{} {}", "foo", "bar").is_ok());
748     }
749 
750     #[test]
ops_avb_validate_vbmeta_public_key_returns_valid()751     fn ops_avb_validate_vbmeta_public_key_returns_valid() {
752         let mut mock_efi = MockEfi::new();
753         let mut avb = GblAvbProtocol::default();
754         avb.validate_vbmeta_public_key_result =
755             Some(Ok(efi_types::GBL_EFI_AVB_KEY_VALIDATION_STATUS_VALID));
756         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
757 
758         let installed = mock_efi.install();
759         let ops = Ops::new(installed.entry(), &[], None);
760 
761         assert_eq!(ops.avb_validate_vbmeta_public_key(&[], None), Ok(KeyValidationStatus::Valid));
762     }
763 
764     #[test]
ops_avb_validate_vbmeta_public_key_returns_valid_custom_key()765     fn ops_avb_validate_vbmeta_public_key_returns_valid_custom_key() {
766         let mut mock_efi = MockEfi::new();
767         let mut avb = GblAvbProtocol::default();
768         avb.validate_vbmeta_public_key_result =
769             Some(Ok(efi_types::GBL_EFI_AVB_KEY_VALIDATION_STATUS_VALID_CUSTOM_KEY));
770         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
771 
772         let installed = mock_efi.install();
773         let ops = Ops::new(installed.entry(), &[], None);
774 
775         assert_eq!(
776             ops.avb_validate_vbmeta_public_key(&[], None),
777             Ok(KeyValidationStatus::ValidCustomKey)
778         );
779     }
780 
781     #[test]
ops_avb_validate_vbmeta_public_key_returns_invalid()782     fn ops_avb_validate_vbmeta_public_key_returns_invalid() {
783         let mut mock_efi = MockEfi::new();
784         let mut avb = GblAvbProtocol::default();
785         avb.validate_vbmeta_public_key_result =
786             Some(Ok(efi_types::GBL_EFI_AVB_KEY_VALIDATION_STATUS_INVALID));
787         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
788 
789         let installed = mock_efi.install();
790         let ops = Ops::new(installed.entry(), &[], None);
791 
792         assert_eq!(ops.avb_validate_vbmeta_public_key(&[], None), Ok(KeyValidationStatus::Invalid));
793     }
794 
795     #[test]
ops_avb_validate_vbmeta_public_key_failed_error_mapped()796     fn ops_avb_validate_vbmeta_public_key_failed_error_mapped() {
797         let mut mock_efi = MockEfi::new();
798         let mut avb = GblAvbProtocol::default();
799         avb.validate_vbmeta_public_key_result = Some(Err(Error::OutOfResources));
800         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
801 
802         let installed = mock_efi.install();
803         let ops = Ops::new(installed.entry(), &[], None);
804 
805         assert_eq!(ops.avb_validate_vbmeta_public_key(&[], None), Err(AvbIoError::Oom));
806     }
807 
808     #[test]
ops_avb_validate_vbmeta_public_key_protocol_not_found_mapped_to_not_implemented()809     fn ops_avb_validate_vbmeta_public_key_protocol_not_found_mapped_to_not_implemented() {
810         let mut mock_efi = MockEfi::new();
811         mock_efi
812             .boot_services
813             .expect_find_first_and_open::<GblAvbProtocol>()
814             .return_const(Err(Error::NotFound));
815 
816         let installed = mock_efi.install();
817         let ops = Ops::new(installed.entry(), &[], None);
818 
819         assert_eq!(ops.avb_validate_vbmeta_public_key(&[], None), Err(AvbIoError::NotImplemented));
820     }
821 
822     #[test]
ops_avb_read_is_device_unlocked_returns_true()823     fn ops_avb_read_is_device_unlocked_returns_true() {
824         let mut mock_efi = MockEfi::new();
825         let mut avb = GblAvbProtocol::default();
826         avb.read_is_device_unlocked_result = Some(Ok(true));
827         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
828 
829         let installed = mock_efi.install();
830         let mut ops = Ops::new(installed.entry(), &[], None);
831 
832         assert_eq!(ops.avb_read_is_device_unlocked(), Ok(true));
833     }
834 
835     #[test]
ops_avb_read_is_device_unlocked_returns_false()836     fn ops_avb_read_is_device_unlocked_returns_false() {
837         let mut mock_efi = MockEfi::new();
838         let mut avb = GblAvbProtocol::default();
839         avb.read_is_device_unlocked_result = Some(Ok(false));
840         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
841 
842         let installed = mock_efi.install();
843         let mut ops = Ops::new(installed.entry(), &[], None);
844 
845         assert_eq!(ops.avb_read_is_device_unlocked(), Ok(false));
846     }
847 
848     #[test]
ops_avb_read_is_device_unlocked_protocol_not_found()849     fn ops_avb_read_is_device_unlocked_protocol_not_found() {
850         let mut mock_efi = MockEfi::new();
851         mock_efi
852             .boot_services
853             .expect_find_first_and_open::<GblAvbProtocol>()
854             .return_const(Err(Error::NotFound));
855 
856         let installed = mock_efi.install();
857         let mut ops = Ops::new(installed.entry(), &[], None);
858 
859         assert_eq!(ops.avb_read_is_device_unlocked(), Err(AvbIoError::NotImplemented));
860     }
861 
862     #[test]
ops_avb_read_rollback_index_success()863     fn ops_avb_read_rollback_index_success() {
864         let mut mock_efi = MockEfi::new();
865         let mut avb = GblAvbProtocol::default();
866         avb.read_rollback_index_result = Some(Ok(12345));
867         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
868 
869         let installed = mock_efi.install();
870         let mut ops = Ops::new(installed.entry(), &[], None);
871 
872         assert_eq!(ops.avb_read_rollback_index(0), Ok(12345));
873     }
874 
875     #[test]
ops_avb_read_rollback_index_error()876     fn ops_avb_read_rollback_index_error() {
877         let mut mock_efi = MockEfi::new();
878         let mut avb = GblAvbProtocol::default();
879         avb.read_rollback_index_result = Some(Err(Error::OutOfResources));
880         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
881 
882         let installed = mock_efi.install();
883         let mut ops = Ops::new(installed.entry(), &[], None);
884 
885         assert_eq!(ops.avb_read_rollback_index(0), Err(AvbIoError::Oom));
886     }
887 
888     #[test]
ops_avb_read_rollback_index_protocol_not_found()889     fn ops_avb_read_rollback_index_protocol_not_found() {
890         let mut mock_efi = MockEfi::new();
891         mock_efi
892             .boot_services
893             .expect_find_first_and_open::<GblAvbProtocol>()
894             .return_const(Err(Error::NotFound));
895 
896         let installed = mock_efi.install();
897         let mut ops = Ops::new(installed.entry(), &[], None);
898 
899         assert_eq!(ops.avb_read_rollback_index(0), Err(AvbIoError::NotImplemented));
900     }
901 
902     #[test]
ops_avb_write_rollback_index_success()903     fn ops_avb_write_rollback_index_success() {
904         let mut mock_efi = MockEfi::new();
905         let mut avb = GblAvbProtocol::default();
906         avb.write_rollback_index_result = Some(Ok(()));
907         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
908 
909         let installed = mock_efi.install();
910         let mut ops = Ops::new(installed.entry(), &[], None);
911 
912         assert!(ops.avb_write_rollback_index(0, 12345).is_ok());
913     }
914 
915     #[test]
ops_avb_write_rollback_index_error()916     fn ops_avb_write_rollback_index_error() {
917         let mut mock_efi = MockEfi::new();
918         let mut avb = GblAvbProtocol::default();
919         avb.write_rollback_index_result = Some(Err(Error::InvalidInput));
920         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
921 
922         let installed = mock_efi.install();
923         let mut ops = Ops::new(installed.entry(), &[], None);
924 
925         assert_eq!(ops.avb_write_rollback_index(0, 12345), Err(AvbIoError::InvalidValueSize));
926     }
927 
928     #[test]
ops_avb_write_rollback_index_protocol_not_found()929     fn ops_avb_write_rollback_index_protocol_not_found() {
930         let mut mock_efi = MockEfi::new();
931         mock_efi
932             .boot_services
933             .expect_find_first_and_open::<GblAvbProtocol>()
934             .return_const(Err(Error::NotFound));
935 
936         let installed = mock_efi.install();
937         let mut ops = Ops::new(installed.entry(), &[], None);
938 
939         assert_eq!(ops.avb_write_rollback_index(0, 12345), Err(AvbIoError::NotImplemented));
940     }
941 
942     #[test]
ops_avb_read_persistent_value_success()943     fn ops_avb_read_persistent_value_success() {
944         const EXPECTED_LEN: usize = 4;
945 
946         let mut mock_efi = MockEfi::new();
947         let mut avb = GblAvbProtocol::default();
948         avb.read_persistent_value_result = Some(Ok(EXPECTED_LEN));
949         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
950 
951         let installed = mock_efi.install();
952         let mut ops = Ops::new(installed.entry(), &[], None);
953 
954         let mut buffer = [0u8; EXPECTED_LEN];
955         assert_eq!(ops.avb_read_persistent_value(c"test", &mut buffer), Ok(EXPECTED_LEN));
956     }
957 
958     #[test]
ops_avb_read_persistent_value_error()959     fn ops_avb_read_persistent_value_error() {
960         let mut mock_efi = MockEfi::new();
961         let mut avb = GblAvbProtocol::default();
962         avb.read_persistent_value_result = Some(Err(Error::OutOfResources));
963         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
964 
965         let installed = mock_efi.install();
966         let mut ops = Ops::new(installed.entry(), &[], None);
967 
968         let mut buffer = [0u8; 0];
969         assert_eq!(ops.avb_read_persistent_value(c"test", &mut buffer), Err(AvbIoError::Oom));
970     }
971 
972     #[test]
ops_avb_read_persistent_value_protocol_not_found()973     fn ops_avb_read_persistent_value_protocol_not_found() {
974         let mut mock_efi = MockEfi::new();
975         mock_efi
976             .boot_services
977             .expect_find_first_and_open::<GblAvbProtocol>()
978             .return_const(Err(Error::NotFound));
979 
980         let installed = mock_efi.install();
981         let mut ops = Ops::new(installed.entry(), &[], None);
982 
983         let mut buffer = [0u8; 0];
984         assert_eq!(
985             ops.avb_read_persistent_value(c"test", &mut buffer),
986             Err(AvbIoError::NotImplemented)
987         );
988     }
989 
990     #[test]
ops_avb_write_persistent_value_success()991     fn ops_avb_write_persistent_value_success() {
992         let mut mock_efi = MockEfi::new();
993         let mut avb = GblAvbProtocol::default();
994         avb.write_persistent_value_result = Some(Ok(()));
995         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
996 
997         let installed = mock_efi.install();
998         let mut ops = Ops::new(installed.entry(), &[], None);
999 
1000         assert_eq!(ops.avb_write_persistent_value(c"test", b""), Ok(()));
1001     }
1002 
1003     #[test]
ops_avb_write_persistent_value_error()1004     fn ops_avb_write_persistent_value_error() {
1005         let mut mock_efi = MockEfi::new();
1006         let mut avb = GblAvbProtocol::default();
1007         avb.write_persistent_value_result = Some(Err(Error::InvalidInput));
1008         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
1009 
1010         let installed = mock_efi.install();
1011         let mut ops = Ops::new(installed.entry(), &[], None);
1012 
1013         assert_eq!(ops.avb_write_persistent_value(c"test", b""), Err(AvbIoError::InvalidValueSize));
1014     }
1015 
1016     #[test]
ops_avb_write_persistent_value_protocol_not_found()1017     fn ops_avb_write_persistent_value_protocol_not_found() {
1018         let mut mock_efi = MockEfi::new();
1019         mock_efi
1020             .boot_services
1021             .expect_find_first_and_open::<GblAvbProtocol>()
1022             .return_const(Err(Error::NotFound));
1023 
1024         let installed = mock_efi.install();
1025         let mut ops = Ops::new(installed.entry(), &[], None);
1026 
1027         assert_eq!(ops.avb_write_persistent_value(c"test", b""), Err(AvbIoError::NotImplemented));
1028     }
1029 
1030     #[test]
ops_avb_erase_persistent_value_success()1031     fn ops_avb_erase_persistent_value_success() {
1032         let mut mock_efi = MockEfi::new();
1033         let mut avb = GblAvbProtocol::default();
1034         avb.write_persistent_value_result = Some(Ok(()));
1035         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
1036 
1037         let installed = mock_efi.install();
1038         let mut ops = Ops::new(installed.entry(), &[], None);
1039 
1040         assert_eq!(ops.avb_erase_persistent_value(c"test"), Ok(()));
1041     }
1042 
1043     #[test]
ops_avb_erase_persistent_value_error()1044     fn ops_avb_erase_persistent_value_error() {
1045         let mut mock_efi = MockEfi::new();
1046         let mut avb = GblAvbProtocol::default();
1047         avb.write_persistent_value_result = Some(Err(Error::DeviceError));
1048         mock_efi.boot_services.expect_find_first_and_open::<GblAvbProtocol>().return_const(Ok(avb));
1049 
1050         let installed = mock_efi.install();
1051         let mut ops = Ops::new(installed.entry(), &[], None);
1052 
1053         assert_eq!(ops.avb_erase_persistent_value(c"test"), Err(AvbIoError::Io));
1054     }
1055 
1056     #[test]
ops_avb_erase_persistent_value_protocol_not_found()1057     fn ops_avb_erase_persistent_value_protocol_not_found() {
1058         let mut mock_efi = MockEfi::new();
1059         mock_efi
1060             .boot_services
1061             .expect_find_first_and_open::<GblAvbProtocol>()
1062             .return_const(Err(Error::NotFound));
1063 
1064         let installed = mock_efi.install();
1065         let mut ops = Ops::new(installed.entry(), &[], None);
1066 
1067         assert_eq!(ops.avb_erase_persistent_value(c"test"), Err(AvbIoError::NotImplemented));
1068     }
1069 
1070     /// Helper for testing `set_boot_reason`
test_set_reboot_reason(input: RebootReason, expect: GBL_EFI_BOOT_REASON)1071     fn test_set_reboot_reason(input: RebootReason, expect: GBL_EFI_BOOT_REASON) {
1072         let mut mock_efi = MockEfi::new();
1073         mock_efi.boot_services.expect_find_first_and_open::<GblSlotProtocol>().return_once(
1074             move || {
1075                 let mut slot = GblSlotProtocol::default();
1076                 slot.expect_set_boot_reason().return_once(move |reason, _| {
1077                     assert_eq!(reason, expect);
1078                     Ok(())
1079                 });
1080                 Ok(slot)
1081             },
1082         );
1083         let installed = mock_efi.install();
1084         let mut ops = Ops::new(installed.entry(), &[], None);
1085         assert_eq!(ops.set_reboot_reason(input), Ok(()));
1086     }
1087 
1088     #[test]
test_set_reboot_reason_normal()1089     fn test_set_reboot_reason_normal() {
1090         test_set_reboot_reason(RebootReason::Normal, GBL_EFI_BOOT_REASON_COLD);
1091     }
1092 
1093     #[test]
test_set_reboot_reason_recovery()1094     fn test_set_reboot_reason_recovery() {
1095         test_set_reboot_reason(RebootReason::Recovery, GBL_EFI_BOOT_REASON_RECOVERY);
1096     }
1097 
1098     #[test]
test_set_reboot_reason_bootloader()1099     fn test_set_reboot_reason_bootloader() {
1100         test_set_reboot_reason(RebootReason::Bootloader, GBL_EFI_BOOT_REASON_BOOTLOADER);
1101     }
1102 
1103     #[test]
test_set_reboot_reason_fastbootd()1104     fn test_set_reboot_reason_fastbootd() {
1105         test_set_reboot_reason(RebootReason::FastbootD, GBL_EFI_BOOT_REASON_FASTBOOTD);
1106     }
1107 
1108     /// Helper for testing `get_boot_reason`
test_get_reboot_reason(input: GBL_EFI_BOOT_REASON, expect: RebootReason)1109     fn test_get_reboot_reason(input: GBL_EFI_BOOT_REASON, expect: RebootReason) {
1110         let mut mock_efi = MockEfi::new();
1111         mock_efi.boot_services.expect_find_first_and_open::<GblSlotProtocol>().return_once(
1112             move || {
1113                 let mut slot = GblSlotProtocol::default();
1114                 slot.expect_get_boot_reason().return_once(move |_| Ok((input, 0)));
1115                 Ok(slot)
1116             },
1117         );
1118         let installed = mock_efi.install();
1119         let mut ops = Ops::new(installed.entry(), &[], None);
1120         assert_eq!(ops.get_reboot_reason().unwrap(), expect)
1121     }
1122 
1123     #[test]
test_get_reboot_reason_normal()1124     fn test_get_reboot_reason_normal() {
1125         test_get_reboot_reason(GBL_EFI_BOOT_REASON_COLD, RebootReason::Normal);
1126     }
1127 
1128     #[test]
test_get_reboot_reason_recovery()1129     fn test_get_reboot_reason_recovery() {
1130         test_get_reboot_reason(GBL_EFI_BOOT_REASON_RECOVERY, RebootReason::Recovery);
1131     }
1132 
1133     #[test]
test_get_reboot_reason_bootloader()1134     fn test_get_reboot_reason_bootloader() {
1135         test_get_reboot_reason(GBL_EFI_BOOT_REASON_BOOTLOADER, RebootReason::Bootloader);
1136     }
1137 
1138     #[test]
test_get_reboot_reason_fastbootd()1139     fn test_get_reboot_reason_fastbootd() {
1140         test_get_reboot_reason(GBL_EFI_BOOT_REASON_FASTBOOTD, RebootReason::FastbootD);
1141     }
1142 
1143     #[test]
test_get_var_all_not_found()1144     fn test_get_var_all_not_found() {
1145         let mut mock_efi = MockEfi::new();
1146         mock_efi
1147             .boot_services
1148             .expect_find_first_and_open::<GblFastbootProtocol>()
1149             .return_once(|| Err(Error::NotFound));
1150         let installed = mock_efi.install();
1151         let mut ops = Ops::new(installed.entry(), &[], None);
1152         ops.fastboot_visit_all_variables(|_, _| {}).unwrap();
1153     }
1154 
1155     #[test]
test_get_var_all_other_errors()1156     fn test_get_var_all_other_errors() {
1157         let mut mock_efi = MockEfi::new();
1158         mock_efi
1159             .boot_services
1160             .expect_find_first_and_open::<GblFastbootProtocol>()
1161             .return_once(|| Err(Error::InvalidInput));
1162         let installed = mock_efi.install();
1163         let mut ops = Ops::new(installed.entry(), &[], None);
1164         assert!(ops.fastboot_visit_all_variables(|_, _| {}).is_err());
1165     }
1166 
1167     /// Helper for testing `GblOsConfigurationProtocol.fixup_os_commandline`
test_fixup_os_commandline<'a>( expected_base: &'static CStr, fixup_buffer: &'a mut [u8], fixup_to_apply: &'static [u8], protocol_lookup_error: Option<Error>, protocol_result: Result<()>, ) -> Result<Option<&'a str>>1168     fn test_fixup_os_commandline<'a>(
1169         expected_base: &'static CStr,
1170         fixup_buffer: &'a mut [u8],
1171         fixup_to_apply: &'static [u8],
1172         protocol_lookup_error: Option<Error>,
1173         protocol_result: Result<()>,
1174     ) -> Result<Option<&'a str>> {
1175         let mut mock_efi = MockEfi::new();
1176         mock_efi
1177             .boot_services
1178             .expect_find_first_and_open::<GblOsConfigurationProtocol>()
1179             .return_once(move || {
1180                 if let Some(error) = protocol_lookup_error {
1181                     return Err(error);
1182                 }
1183 
1184                 let mut os_configuration = GblOsConfigurationProtocol::default();
1185 
1186                 os_configuration.expect_fixup_kernel_commandline().return_once(
1187                     move |base, buffer| {
1188                         assert_eq!(base, expected_base);
1189                         buffer[..fixup_to_apply.len()].copy_from_slice(fixup_to_apply);
1190                         protocol_result
1191                     },
1192                 );
1193 
1194                 Ok(os_configuration)
1195             });
1196 
1197         let installed = mock_efi.install();
1198         let mut ops = Ops::new(installed.entry(), &[], None);
1199 
1200         ops.fixup_os_commandline(expected_base, fixup_buffer)
1201     }
1202 
1203     #[test]
test_fixup_os_commandline_success()1204     fn test_fixup_os_commandline_success() {
1205         const BASE: &CStr = c"key1=value1 key2=value2";
1206         const FIXUP: &CStr = c"fixup1=value1 fixup2=value2";
1207 
1208         let mut fixup_buffer = [0x0; FIXUP.to_bytes_with_nul().len()];
1209         assert_eq!(
1210             test_fixup_os_commandline(
1211                 BASE,
1212                 &mut fixup_buffer,
1213                 FIXUP.to_bytes_with_nul(),
1214                 // No protocol lookup error.
1215                 None,
1216                 // No protocol call error.
1217                 Ok(()),
1218             ),
1219             // Expects fixup applied.
1220             Ok(Some(FIXUP.to_str().unwrap()))
1221         );
1222     }
1223 
1224     #[test]
test_fixup_os_commandline_success_empty_result()1225     fn test_fixup_os_commandline_success_empty_result() {
1226         const BASE: &CStr = c"key1=value1 key2=value2";
1227 
1228         let mut fixup_buffer = [0x0; 1];
1229         assert_eq!(
1230             test_fixup_os_commandline(
1231                 BASE,
1232                 &mut fixup_buffer,
1233                 // Passes empty fixup to apply.
1234                 &[],
1235                 // No protocol lookup error.
1236                 None,
1237                 // No protocol call error.
1238                 Ok(()),
1239             ),
1240             // Expected empty fixup.
1241             Ok(Some("")),
1242         );
1243     }
1244 
1245     #[test]
test_fixup_os_commandline_wrong_fixup()1246     fn test_fixup_os_commandline_wrong_fixup() {
1247         const BASE: &CStr = c"key1=value1 key2=value2";
1248 
1249         // Have no space for null terminator.
1250         let mut fixup_buffer = [0x0; BASE.to_bytes().len()];
1251         assert_eq!(
1252             test_fixup_os_commandline(
1253                 BASE,
1254                 &mut fixup_buffer,
1255                 BASE.to_bytes(),
1256                 // No protocol lookup error.
1257                 None,
1258                 // No protocol call error.
1259                 Ok(()),
1260             ),
1261             // Expected error, cannot build c string.
1262             Err(Error::InvalidInput),
1263         );
1264     }
1265 
1266     #[test]
test_fixup_os_commandline_protocol_error()1267     fn test_fixup_os_commandline_protocol_error() {
1268         const BASE: &CStr = c"key1=value1 key2=value2";
1269 
1270         let mut fixup_buffer = [0x0; 0];
1271         assert_eq!(
1272             test_fixup_os_commandline(
1273                 BASE,
1274                 &mut fixup_buffer,
1275                 &[],
1276                 // No protocol lookup error.
1277                 None,
1278                 // Protocol returns error.
1279                 Err(Error::BufferTooSmall(Some(100))),
1280             ),
1281             // Expected to be catched.
1282             Err(Error::BufferTooSmall(Some(100))),
1283         );
1284     }
1285 
1286     #[test]
test_fixup_os_commandline_protocol_not_found()1287     fn test_fixup_os_commandline_protocol_not_found() {
1288         const BASE: &CStr = c"key1=value1 key2=value2";
1289 
1290         let mut fixup_buffer = [0x0; 0];
1291         assert_eq!(
1292             test_fixup_os_commandline(
1293                 BASE,
1294                 &mut fixup_buffer,
1295                 &[],
1296                 // Protocol not found.
1297                 Some(Error::NotFound),
1298                 // No protocol call error.
1299                 Ok(()),
1300             ),
1301             // No fixup in case protocol not found.
1302             Ok(None),
1303         );
1304     }
1305 
1306     #[test]
test_fixup_os_commandline_protocol_lookup_failed()1307     fn test_fixup_os_commandline_protocol_lookup_failed() {
1308         const BASE: &CStr = c"key1=value1 key2=value2";
1309 
1310         let mut fixup_buffer = [0x0; 0];
1311         assert_eq!(
1312             test_fixup_os_commandline(
1313                 BASE,
1314                 &mut fixup_buffer,
1315                 &[],
1316                 // Protocol lookup failed.
1317                 Some(Error::AccessDenied),
1318                 // No protocol call error.
1319                 Ok(()),
1320             ),
1321             // Error catched.
1322             Err(Error::AccessDenied),
1323         );
1324     }
1325 
1326     /// Helper for testing `GblOsConfigurationProtocol.fixup_bootconfig`
test_fixup_bootconfig<'a>( expected_base: &'static [u8], fixup_buffer: &'a mut [u8], fixup_to_apply: &'static [u8], protocol_lookup_error: Option<Error>, protocol_result_error: Option<Error>, ) -> Result<Option<&'a [u8]>>1327     fn test_fixup_bootconfig<'a>(
1328         expected_base: &'static [u8],
1329         fixup_buffer: &'a mut [u8],
1330         fixup_to_apply: &'static [u8],
1331         protocol_lookup_error: Option<Error>,
1332         protocol_result_error: Option<Error>,
1333     ) -> Result<Option<&'a [u8]>> {
1334         let mut mock_efi = MockEfi::new();
1335         mock_efi
1336             .boot_services
1337             .expect_find_first_and_open::<GblOsConfigurationProtocol>()
1338             .return_once(move || {
1339                 if let Some(error) = protocol_lookup_error {
1340                     return Err(error);
1341                 }
1342 
1343                 let mut os_configuration = GblOsConfigurationProtocol::default();
1344 
1345                 os_configuration.expect_fixup_bootconfig().return_once(move |base, buffer| {
1346                     assert_eq!(base, expected_base);
1347                     buffer[..fixup_to_apply.len()].copy_from_slice(fixup_to_apply);
1348 
1349                     if let Some(protocol_result_error) = protocol_result_error {
1350                         return Err(protocol_result_error);
1351                     }
1352 
1353                     Ok(fixup_to_apply.len())
1354                 });
1355 
1356                 Ok(os_configuration)
1357             });
1358 
1359         let installed = mock_efi.install();
1360         let mut ops = Ops::new(installed.entry(), &[], None);
1361 
1362         ops.fixup_bootconfig(expected_base, fixup_buffer)
1363     }
1364 
1365     #[test]
test_fixup_bootconfig_success()1366     fn test_fixup_bootconfig_success() {
1367         const BASE: &[u8] = b"key1=value1\nkey2=value2";
1368         const FIXUP: &[u8] = b"fixup1=value1\nfixup2=value2";
1369 
1370         let mut fixup_buffer = [0x0; FIXUP.len()];
1371         assert_eq!(
1372             test_fixup_bootconfig(
1373                 BASE,
1374                 &mut fixup_buffer,
1375                 FIXUP,
1376                 // No protocol lookup error.
1377                 None,
1378                 // No protocol call error.
1379                 None,
1380             ),
1381             // Expects fixup applied.
1382             Ok(Some(FIXUP)),
1383         );
1384     }
1385 
1386     #[test]
test_fixup_bootconfig_protocol_error()1387     fn test_fixup_bootconfig_protocol_error() {
1388         const BASE: &[u8] = b"key1=value1\nkey2=value2";
1389         const FIXUP: &[u8] = b"fixup1=value1\nfixup2=value2";
1390 
1391         let mut fixup_buffer = [0x0; FIXUP.len()];
1392         assert_eq!(
1393             test_fixup_bootconfig(
1394                 BASE,
1395                 &mut fixup_buffer,
1396                 FIXUP,
1397                 // No protocol lookup error.
1398                 None,
1399                 // Protocol returns error.
1400                 Some(Error::BufferTooSmall(Some(100))),
1401             ),
1402             // Expected to be catched.
1403             Err(Error::BufferTooSmall(Some(100))),
1404         );
1405     }
1406 
1407     #[test]
test_fixup_bootconfig_protocol_not_found()1408     fn test_fixup_bootconfig_protocol_not_found() {
1409         const BASE: &[u8] = b"key1=value1\nkey2=value2";
1410         const FIXUP: &[u8] = b"fixup1=value1\nfixup2=value2";
1411 
1412         let mut fixup_buffer = [0x0; FIXUP.len()];
1413         assert_eq!(
1414             test_fixup_bootconfig(
1415                 BASE,
1416                 &mut fixup_buffer,
1417                 FIXUP,
1418                 // Protocol not found.
1419                 Some(Error::NotFound),
1420                 // No protocol call error.
1421                 None,
1422             ),
1423             // No fixup in case protocol not found.
1424             Ok(None),
1425         );
1426     }
1427 
1428     #[test]
test_fixup_bootconfig_protocol_lookup_failed()1429     fn test_fixup_bootconfig_protocol_lookup_failed() {
1430         const BASE: &[u8] = b"key1=value1\nkey2=value2";
1431         const FIXUP: &[u8] = b"fixup1=value1\nfixup2=value2";
1432 
1433         let mut fixup_buffer = [0x0; FIXUP.len()];
1434         assert_eq!(
1435             test_fixup_bootconfig(
1436                 BASE,
1437                 &mut fixup_buffer,
1438                 FIXUP,
1439                 // Protocol lookup failed.
1440                 Some(Error::AccessDenied),
1441                 // No protocol call error.
1442                 None,
1443             ),
1444             // Error catched.
1445             Err(Error::AccessDenied),
1446         );
1447     }
1448 
1449     #[test]
test_select_device_tree_components_select_base_and_overlay()1450     fn test_select_device_tree_components_select_base_and_overlay() {
1451         let base = include_bytes!("../../libfdt/test/data/base.dtb").to_vec();
1452         let overlay = include_bytes!("../../libfdt/test/data/overlay_by_path.dtbo").to_vec();
1453         let overlay2 = include_bytes!("../../libfdt/test/data/overlay_by_reference.dtbo").to_vec();
1454         let mut buffer = vec![0u8; 2 * 1024 * 1024]; // 2 MB
1455 
1456         let base_scoped = base.clone();
1457         let overlay_scoped = overlay.clone();
1458         let overlay2_scoped = overlay2.clone();
1459         let mut mock_efi = MockEfi::new();
1460         mock_efi.con_out.expect_write_str().return_const(Ok(()));
1461         mock_efi
1462             .boot_services
1463             .expect_find_first_and_open::<GblOsConfigurationProtocol>()
1464             .return_once(|| {
1465                 let mut os_configuration = GblOsConfigurationProtocol::default();
1466 
1467                 os_configuration.expect_select_device_trees().return_once(move |components| {
1468                     assert_eq!(components.len(), 3);
1469 
1470                     // SAFETY:
1471                     // `components[*].device_trees` are pointing to corresponding base device
1472                     // tree and overlays buffers.
1473                     let (base_passed, overlay_passed, overlay2_passed) = unsafe {
1474                         (
1475                             slice::from_raw_parts(
1476                                 components[0].device_tree as *const u8,
1477                                 base_scoped.len(),
1478                             ),
1479                             slice::from_raw_parts(
1480                                 components[1].device_tree as *const u8,
1481                                 overlay_scoped.len(),
1482                             ),
1483                             slice::from_raw_parts(
1484                                 components[2].device_tree as *const u8,
1485                                 overlay2_scoped.len(),
1486                             ),
1487                         )
1488                     };
1489 
1490                     assert_eq!(base_passed, &base_scoped);
1491                     assert_eq!(overlay_passed, &overlay_scoped[..]);
1492                     assert_eq!(overlay2_passed, &overlay2_scoped[..]);
1493 
1494                     // Select the base device and the second overlay. The first overlay is not
1495                     // being selected.
1496                     components[0].selected = true;
1497                     components[2].selected = true;
1498                     Ok(())
1499                 });
1500 
1501                 Ok(os_configuration)
1502             });
1503 
1504         let installed = mock_efi.install();
1505         let mut ops = Ops::new(installed.entry(), &[], None);
1506 
1507         let mut registry = DeviceTreeComponentsRegistry::new();
1508         let mut current_buffer = &mut buffer[..];
1509         current_buffer = registry
1510             .append(&mut ops, DeviceTreeComponentSource::VendorBoot, &base, current_buffer)
1511             .unwrap();
1512         current_buffer = registry
1513             .append(&mut ops, DeviceTreeComponentSource::Dtbo, &overlay, current_buffer)
1514             .unwrap();
1515         registry
1516             .append(&mut ops, DeviceTreeComponentSource::Dtbo, &overlay2, current_buffer)
1517             .unwrap();
1518 
1519         assert_eq!(ops.select_device_trees(&mut registry), Ok(()));
1520         assert_eq!(registry.selected(), Ok((&base[..], &[&overlay2[..]][..])));
1521     }
1522 
1523     #[test]
test_select_device_tree_protocol_error()1524     fn test_select_device_tree_protocol_error() {
1525         let mut mock_efi = MockEfi::new();
1526         mock_efi
1527             .boot_services
1528             .expect_find_first_and_open::<GblOsConfigurationProtocol>()
1529             .return_once(move || {
1530                 let mut os_configuration = GblOsConfigurationProtocol::default();
1531 
1532                 os_configuration
1533                     .expect_select_device_trees()
1534                     .return_once(move |_components| Err(Error::InvalidInput));
1535 
1536                 Ok(os_configuration)
1537             });
1538 
1539         let installed = mock_efi.install();
1540         let mut ops = Ops::new(installed.entry(), &[], None);
1541 
1542         let mut registry = DeviceTreeComponentsRegistry::new();
1543 
1544         assert_eq!(ops.select_device_trees(&mut registry), Err(Error::InvalidInput));
1545     }
1546 
1547     #[test]
test_select_device_tree_protocol_not_found()1548     fn test_select_device_tree_protocol_not_found() {
1549         let base = include_bytes!("../../libfdt/test/data/base.dtb").to_vec();
1550         let mut buffer = vec![0u8; 2 * 1024 * 1024]; // 2 MB
1551 
1552         let mut mock_efi = MockEfi::new();
1553         mock_efi
1554             .boot_services
1555             .expect_find_first_and_open::<GblOsConfigurationProtocol>()
1556             .return_once(move || Err(Error::NotFound));
1557 
1558         let installed = mock_efi.install();
1559         let mut ops = Ops::new(installed.entry(), &[], None);
1560 
1561         // Appends some data to ensure autoselect is passed.
1562         let mut registry = DeviceTreeComponentsRegistry::new();
1563         let current_buffer = &mut buffer[..];
1564         registry
1565             .append(&mut ops, DeviceTreeComponentSource::VendorBoot, &base, current_buffer)
1566             .unwrap();
1567 
1568         assert_eq!(ops.select_device_trees(&mut registry), Ok(()));
1569     }
1570 
1571     /// Helper for testing `DtFixupProtocol.fixup`
test_fixup_device_tree( base: &mut [u8], base_after_fixup: &'static [u8], protocol_lookup_error: Option<Error>, protocol_result: Result<()>, ) -> Result<()>1572     fn test_fixup_device_tree(
1573         base: &mut [u8],
1574         base_after_fixup: &'static [u8],
1575         protocol_lookup_error: Option<Error>,
1576         protocol_result: Result<()>,
1577     ) -> Result<()> {
1578         let mut mock_efi = MockEfi::new();
1579         mock_efi.boot_services.expect_find_first_and_open::<DtFixupProtocol>().return_once(
1580             move || {
1581                 if let Some(error) = protocol_lookup_error {
1582                     return Err(error);
1583                 }
1584 
1585                 let mut dt_fixup = DtFixupProtocol::default();
1586 
1587                 dt_fixup.expect_fixup().return_once(move |buffer| {
1588                     buffer.copy_from_slice(base_after_fixup);
1589                     protocol_result
1590                 });
1591 
1592                 Ok(dt_fixup)
1593             },
1594         );
1595 
1596         let installed = mock_efi.install();
1597         let mut ops = Ops::new(installed.entry(), &[], None);
1598 
1599         let r = ops.fixup_device_tree(base);
1600         assert_eq!(base, base_after_fixup);
1601         r
1602     }
1603 
1604     #[test]
test_fixup_device_tree_success()1605     fn test_fixup_device_tree_success() {
1606         const WITH_FIXUP: &[u8] = b"device tree after overlay applied";
1607 
1608         let mut device_tree_buffer = [0x0; WITH_FIXUP.len()];
1609         assert_eq!(
1610             test_fixup_device_tree(
1611                 &mut device_tree_buffer,
1612                 WITH_FIXUP,
1613                 // No protocol lookup error.
1614                 None,
1615                 // No protocol call error.
1616                 Ok(()),
1617             ),
1618             Ok(()),
1619         );
1620     }
1621 
1622     #[test]
test_fixup_device_tree_protocol_error()1623     fn test_fixup_device_tree_protocol_error() {
1624         const WITH_FIXUP: &[u8] = b"device tree after overlay applied";
1625 
1626         let mut device_tree_buffer = [0x0; WITH_FIXUP.len()];
1627         assert_eq!(
1628             test_fixup_device_tree(
1629                 &mut device_tree_buffer,
1630                 WITH_FIXUP,
1631                 // No protocol lookup error.
1632                 None,
1633                 // Protocol returns error.
1634                 Err(Error::BufferTooSmall(Some(100))),
1635             ),
1636             // Expected to be catched.
1637             Err(Error::BufferTooSmall(Some(100))),
1638         );
1639     }
1640 
1641     #[test]
test_fixup_device_tree_protocol_not_found()1642     fn test_fixup_device_tree_protocol_not_found() {
1643         assert_eq!(
1644             test_fixup_device_tree(
1645                 &mut [],
1646                 &[],
1647                 // Protocol not found.
1648                 Some(Error::NotFound),
1649                 // No protocol call error.
1650                 Ok(()),
1651             ),
1652             // Protocol is optional, so passed.
1653             Ok(()),
1654         );
1655     }
1656 
1657     #[test]
test_fixup_device_tree_protocol_lookup_failed()1658     fn test_fixup_device_tree_protocol_lookup_failed() {
1659         assert_eq!(
1660             test_fixup_device_tree(
1661                 &mut [],
1662                 &[],
1663                 // Protocol lookup failed.
1664                 Some(Error::AccessDenied),
1665                 // No protocol call error.
1666                 Ok(()),
1667             ),
1668             // Error catched.
1669             Err(Error::AccessDenied),
1670         );
1671     }
1672 }
1673