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