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