1*5225e6b1SAndroid Build Coastguard Worker // Copyright 2024, The Android Open Source Project 2*5225e6b1SAndroid Build Coastguard Worker // 3*5225e6b1SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); 4*5225e6b1SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License. 5*5225e6b1SAndroid Build Coastguard Worker // You may obtain a copy of the License at 6*5225e6b1SAndroid Build Coastguard Worker // 7*5225e6b1SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0 8*5225e6b1SAndroid Build Coastguard Worker // 9*5225e6b1SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software 10*5225e6b1SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, 11*5225e6b1SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*5225e6b1SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and 13*5225e6b1SAndroid Build Coastguard Worker // limitations under the License. 14*5225e6b1SAndroid Build Coastguard Worker 15*5225e6b1SAndroid Build Coastguard Worker extern crate gbl_storage; 16*5225e6b1SAndroid Build Coastguard Worker extern crate libgbl as gbl; 17*5225e6b1SAndroid Build Coastguard Worker 18*5225e6b1SAndroid Build Coastguard Worker use core::convert::TryInto; 19*5225e6b1SAndroid Build Coastguard Worker use gbl::slots::{ 20*5225e6b1SAndroid Build Coastguard Worker BootTarget, BootToken, Manager, OneShot, RecoveryTarget, Slot, SlotIterator, Suffix, Tries, 21*5225e6b1SAndroid Build Coastguard Worker UnbootableReason, 22*5225e6b1SAndroid Build Coastguard Worker }; 23*5225e6b1SAndroid Build Coastguard Worker use liberror::{Error, Result}; 24*5225e6b1SAndroid Build Coastguard Worker 25*5225e6b1SAndroid Build Coastguard Worker use efi_types::{ 26*5225e6b1SAndroid Build Coastguard Worker GBL_EFI_BOOT_REASON_BOOTLOADER as REASON_BOOTLOADER, 27*5225e6b1SAndroid Build Coastguard Worker GBL_EFI_BOOT_REASON_EMPTY_BOOT_REASON as REASON_EMPTY, 28*5225e6b1SAndroid Build Coastguard Worker GBL_EFI_BOOT_REASON_RECOVERY as REASON_RECOVERY, 29*5225e6b1SAndroid Build Coastguard Worker }; 30*5225e6b1SAndroid Build Coastguard Worker 31*5225e6b1SAndroid Build Coastguard Worker use crate::protocol::{gbl_efi_ab_slot as ab_slot, Protocol}; 32*5225e6b1SAndroid Build Coastguard Worker 33*5225e6b1SAndroid Build Coastguard Worker const SUBREASON_BUF_LEN: usize = 64; 34*5225e6b1SAndroid Build Coastguard Worker 35*5225e6b1SAndroid Build Coastguard Worker /// Implementation for A/B slot manager based on custom EFI protocol. 36*5225e6b1SAndroid Build Coastguard Worker pub struct ABManager<'a> { 37*5225e6b1SAndroid Build Coastguard Worker protocol: Protocol<'a, ab_slot::GblSlotProtocol>, 38*5225e6b1SAndroid Build Coastguard Worker boot_token: Option<BootToken>, 39*5225e6b1SAndroid Build Coastguard Worker last_set_active_idx: Option<u8>, 40*5225e6b1SAndroid Build Coastguard Worker } 41*5225e6b1SAndroid Build Coastguard Worker 42*5225e6b1SAndroid Build Coastguard Worker impl<'a> ABManager<'a> { 43*5225e6b1SAndroid Build Coastguard Worker #[cfg(test)] new_without_token(protocol: Protocol<'a, ab_slot::GblSlotProtocol>) -> Self44*5225e6b1SAndroid Build Coastguard Worker fn new_without_token(protocol: Protocol<'a, ab_slot::GblSlotProtocol>) -> Self { 45*5225e6b1SAndroid Build Coastguard Worker Self { protocol, boot_token: None, last_set_active_idx: None } 46*5225e6b1SAndroid Build Coastguard Worker } 47*5225e6b1SAndroid Build Coastguard Worker } 48*5225e6b1SAndroid Build Coastguard Worker 49*5225e6b1SAndroid Build Coastguard Worker impl gbl::slots::private::SlotGet for ABManager<'_> { get_slot_by_number(&self, number: usize) -> Result<Slot>50*5225e6b1SAndroid Build Coastguard Worker fn get_slot_by_number(&self, number: usize) -> Result<Slot> { 51*5225e6b1SAndroid Build Coastguard Worker let idx = u8::try_from(number).or(Err(Error::BadIndex(number)))?; 52*5225e6b1SAndroid Build Coastguard Worker let info = self.protocol.get_slot_info(idx).or(Err(Error::BadIndex(number)))?; 53*5225e6b1SAndroid Build Coastguard Worker info.try_into() 54*5225e6b1SAndroid Build Coastguard Worker } 55*5225e6b1SAndroid Build Coastguard Worker } 56*5225e6b1SAndroid Build Coastguard Worker 57*5225e6b1SAndroid Build Coastguard Worker impl Manager for ABManager<'_> { get_boot_target(&self) -> Result<BootTarget>58*5225e6b1SAndroid Build Coastguard Worker fn get_boot_target(&self) -> Result<BootTarget> { 59*5225e6b1SAndroid Build Coastguard Worker let slot = self.get_slot_last_set_active()?; 60*5225e6b1SAndroid Build Coastguard Worker let mut subreason = [0u8; SUBREASON_BUF_LEN]; 61*5225e6b1SAndroid Build Coastguard Worker let (reason, _) = self.protocol.get_boot_reason(subreason.as_mut_slice())?; 62*5225e6b1SAndroid Build Coastguard Worker // Don't currently care about the subreason 63*5225e6b1SAndroid Build Coastguard Worker // CStr::from_bytes_until_nul(&subreason[..strlen])? 64*5225e6b1SAndroid Build Coastguard Worker let target = match reason { 65*5225e6b1SAndroid Build Coastguard Worker REASON_RECOVERY => BootTarget::Recovery(RecoveryTarget::Slotted(slot)), 66*5225e6b1SAndroid Build Coastguard Worker _ => BootTarget::NormalBoot(slot), 67*5225e6b1SAndroid Build Coastguard Worker }; 68*5225e6b1SAndroid Build Coastguard Worker Ok(target) 69*5225e6b1SAndroid Build Coastguard Worker } 70*5225e6b1SAndroid Build Coastguard Worker slots_iter(&self) -> SlotIterator71*5225e6b1SAndroid Build Coastguard Worker fn slots_iter(&self) -> SlotIterator { 72*5225e6b1SAndroid Build Coastguard Worker SlotIterator::new(self) 73*5225e6b1SAndroid Build Coastguard Worker } 74*5225e6b1SAndroid Build Coastguard Worker get_slot_last_set_active(&self) -> Result<Slot>75*5225e6b1SAndroid Build Coastguard Worker fn get_slot_last_set_active(&self) -> Result<Slot> { 76*5225e6b1SAndroid Build Coastguard Worker use gbl::slots::private::SlotGet; 77*5225e6b1SAndroid Build Coastguard Worker 78*5225e6b1SAndroid Build Coastguard Worker if let Some(idx) = self.last_set_active_idx { 79*5225e6b1SAndroid Build Coastguard Worker self.get_slot_by_number(idx.into()) 80*5225e6b1SAndroid Build Coastguard Worker } else { 81*5225e6b1SAndroid Build Coastguard Worker self.protocol.get_current_slot()?.try_into() 82*5225e6b1SAndroid Build Coastguard Worker } 83*5225e6b1SAndroid Build Coastguard Worker } 84*5225e6b1SAndroid Build Coastguard Worker mark_boot_attempt(&mut self) -> Result<BootToken>85*5225e6b1SAndroid Build Coastguard Worker fn mark_boot_attempt(&mut self) -> Result<BootToken> { 86*5225e6b1SAndroid Build Coastguard Worker self.boot_token.take().ok_or(Error::OperationProhibited) 87*5225e6b1SAndroid Build Coastguard Worker } 88*5225e6b1SAndroid Build Coastguard Worker set_active_slot(&mut self, slot_suffix: Suffix) -> Result<()>89*5225e6b1SAndroid Build Coastguard Worker fn set_active_slot(&mut self, slot_suffix: Suffix) -> Result<()> { 90*5225e6b1SAndroid Build Coastguard Worker let idx: u8 = self 91*5225e6b1SAndroid Build Coastguard Worker .slots_iter() 92*5225e6b1SAndroid Build Coastguard Worker .position(|s| s.suffix == slot_suffix) 93*5225e6b1SAndroid Build Coastguard Worker .ok_or(Error::InvalidInput)? 94*5225e6b1SAndroid Build Coastguard Worker .try_into() 95*5225e6b1SAndroid Build Coastguard Worker // This 'or' is technically unreachable because the protocol 96*5225e6b1SAndroid Build Coastguard Worker // can't give us an index larger than a u8. 97*5225e6b1SAndroid Build Coastguard Worker .or(Err(Error::Other(None)))?; 98*5225e6b1SAndroid Build Coastguard Worker self.protocol.set_active_slot(idx).or(Err(Error::Other(None))).and_then(|_| { 99*5225e6b1SAndroid Build Coastguard Worker self.last_set_active_idx = Some(idx); 100*5225e6b1SAndroid Build Coastguard Worker Ok(()) 101*5225e6b1SAndroid Build Coastguard Worker }) 102*5225e6b1SAndroid Build Coastguard Worker } 103*5225e6b1SAndroid Build Coastguard Worker set_slot_unbootable(&mut self, slot_suffix: Suffix, reason: UnbootableReason) -> Result<()>104*5225e6b1SAndroid Build Coastguard Worker fn set_slot_unbootable(&mut self, slot_suffix: Suffix, reason: UnbootableReason) -> Result<()> { 105*5225e6b1SAndroid Build Coastguard Worker let idx: u8 = self 106*5225e6b1SAndroid Build Coastguard Worker .slots_iter() 107*5225e6b1SAndroid Build Coastguard Worker .position(|s| s.suffix == slot_suffix) 108*5225e6b1SAndroid Build Coastguard Worker .ok_or(Error::InvalidInput)? 109*5225e6b1SAndroid Build Coastguard Worker .try_into() 110*5225e6b1SAndroid Build Coastguard Worker // This 'or' is technically unreachable because the protocol 111*5225e6b1SAndroid Build Coastguard Worker // can't give us an index larger than a u8. 112*5225e6b1SAndroid Build Coastguard Worker .or(Err(Error::Other(None)))?; 113*5225e6b1SAndroid Build Coastguard Worker self.protocol.set_slot_unbootable(idx, u8::from(reason).into()) 114*5225e6b1SAndroid Build Coastguard Worker } 115*5225e6b1SAndroid Build Coastguard Worker get_max_retries(&self) -> Result<Tries>116*5225e6b1SAndroid Build Coastguard Worker fn get_max_retries(&self) -> Result<Tries> { 117*5225e6b1SAndroid Build Coastguard Worker Ok(self.protocol.load_boot_data()?.max_retries.into()) 118*5225e6b1SAndroid Build Coastguard Worker } 119*5225e6b1SAndroid Build Coastguard Worker get_oneshot_status(&self) -> Option<OneShot>120*5225e6b1SAndroid Build Coastguard Worker fn get_oneshot_status(&self) -> Option<OneShot> { 121*5225e6b1SAndroid Build Coastguard Worker let mut subreason = [0u8; SUBREASON_BUF_LEN]; 122*5225e6b1SAndroid Build Coastguard Worker let (reason, _) = self.protocol.get_boot_reason(subreason.as_mut_slice()).ok()?; 123*5225e6b1SAndroid Build Coastguard Worker // Currently we only care if the primary boot reason is BOOTLOADER. 124*5225e6b1SAndroid Build Coastguard Worker // CStr::from_bytes_until_nul(&subreason[..strlen]).ok()? 125*5225e6b1SAndroid Build Coastguard Worker match reason { 126*5225e6b1SAndroid Build Coastguard Worker REASON_BOOTLOADER => Some(OneShot::Bootloader), 127*5225e6b1SAndroid Build Coastguard Worker _ => None, 128*5225e6b1SAndroid Build Coastguard Worker } 129*5225e6b1SAndroid Build Coastguard Worker } 130*5225e6b1SAndroid Build Coastguard Worker set_oneshot_status(&mut self, os: OneShot) -> Result<()>131*5225e6b1SAndroid Build Coastguard Worker fn set_oneshot_status(&mut self, os: OneShot) -> Result<()> { 132*5225e6b1SAndroid Build Coastguard Worker // Android doesn't have a concept of OneShot to recovery, 133*5225e6b1SAndroid Build Coastguard Worker // and the subreason shouldn't matter. 134*5225e6b1SAndroid Build Coastguard Worker match os { 135*5225e6b1SAndroid Build Coastguard Worker OneShot::Bootloader => { 136*5225e6b1SAndroid Build Coastguard Worker self.protocol.set_boot_reason(REASON_BOOTLOADER, &[]).or(Err(Error::Other(None))) 137*5225e6b1SAndroid Build Coastguard Worker } 138*5225e6b1SAndroid Build Coastguard Worker _ => Err(Error::OperationProhibited), 139*5225e6b1SAndroid Build Coastguard Worker } 140*5225e6b1SAndroid Build Coastguard Worker } 141*5225e6b1SAndroid Build Coastguard Worker clear_oneshot_status(&mut self)142*5225e6b1SAndroid Build Coastguard Worker fn clear_oneshot_status(&mut self) { 143*5225e6b1SAndroid Build Coastguard Worker let mut subreason = [0u8; SUBREASON_BUF_LEN]; 144*5225e6b1SAndroid Build Coastguard Worker // Only clear if the boot reason is the one we care about. 145*5225e6b1SAndroid Build Coastguard Worker // CStr::from_bytes_until_nul(&subreason[..strlen]).or(Err(Error::Other))? 146*5225e6b1SAndroid Build Coastguard Worker if let Ok((REASON_BOOTLOADER, _)) = self.protocol.get_boot_reason(subreason.as_mut_slice()) 147*5225e6b1SAndroid Build Coastguard Worker { 148*5225e6b1SAndroid Build Coastguard Worker let _ = self.protocol.set_boot_reason(REASON_EMPTY, &[]); 149*5225e6b1SAndroid Build Coastguard Worker } 150*5225e6b1SAndroid Build Coastguard Worker } 151*5225e6b1SAndroid Build Coastguard Worker write_back(&mut self, _: &mut dyn FnMut(&mut [u8]) -> Result<()>)152*5225e6b1SAndroid Build Coastguard Worker fn write_back(&mut self, _: &mut dyn FnMut(&mut [u8]) -> Result<()>) { 153*5225e6b1SAndroid Build Coastguard Worker // Note: `expect` instead of swallowing the error. 154*5225e6b1SAndroid Build Coastguard Worker // It is important that changes are not silently dropped. 155*5225e6b1SAndroid Build Coastguard Worker self.protocol.flush().expect("could not write back modifications to slot metadata"); 156*5225e6b1SAndroid Build Coastguard Worker } 157*5225e6b1SAndroid Build Coastguard Worker } 158*5225e6b1SAndroid Build Coastguard Worker 159*5225e6b1SAndroid Build Coastguard Worker #[cfg(test)] 160*5225e6b1SAndroid Build Coastguard Worker mod test { 161*5225e6b1SAndroid Build Coastguard Worker extern crate avb_sysdeps; 162*5225e6b1SAndroid Build Coastguard Worker 163*5225e6b1SAndroid Build Coastguard Worker use super::*; 164*5225e6b1SAndroid Build Coastguard Worker use crate::protocol::Protocol; 165*5225e6b1SAndroid Build Coastguard Worker use crate::test::*; 166*5225e6b1SAndroid Build Coastguard Worker use crate::EfiEntry; 167*5225e6b1SAndroid Build Coastguard Worker use efi_types::{ 168*5225e6b1SAndroid Build Coastguard Worker EfiStatus, GblEfiABSlotProtocol, GblEfiSlotInfo, GblEfiSlotMetadataBlock, 169*5225e6b1SAndroid Build Coastguard Worker EFI_STATUS_INVALID_PARAMETER, EFI_STATUS_SUCCESS, 170*5225e6b1SAndroid Build Coastguard Worker GBL_EFI_BOOT_REASON_EMPTY_BOOT_REASON as REASON_EMPTY, 171*5225e6b1SAndroid Build Coastguard Worker GBL_EFI_BOOT_REASON_RECOVERY as REASON_RECOVERY, 172*5225e6b1SAndroid Build Coastguard Worker GBL_EFI_BOOT_REASON_WATCHDOG as REASON_WATCHDOG, 173*5225e6b1SAndroid Build Coastguard Worker }; 174*5225e6b1SAndroid Build Coastguard Worker use gbl::{ 175*5225e6b1SAndroid Build Coastguard Worker ops::{ 176*5225e6b1SAndroid Build Coastguard Worker AvbIoResult, CertPermanentAttributes, RebootReason, SlotsMetadata, SHA256_DIGEST_SIZE, 177*5225e6b1SAndroid Build Coastguard Worker }, 178*5225e6b1SAndroid Build Coastguard Worker partition::GblDisk, 179*5225e6b1SAndroid Build Coastguard Worker slots::{Bootability, Cursor, RecoveryTarget, UnbootableReason}, 180*5225e6b1SAndroid Build Coastguard Worker Gbl, GblOps, Os, Result as GblResult, 181*5225e6b1SAndroid Build Coastguard Worker }; 182*5225e6b1SAndroid Build Coastguard Worker use gbl_storage::{BlockIo, BlockIoNull, Disk, Gpt}; 183*5225e6b1SAndroid Build Coastguard Worker use libgbl::{ 184*5225e6b1SAndroid Build Coastguard Worker device_tree::DeviceTreeComponentsRegistry, 185*5225e6b1SAndroid Build Coastguard Worker gbl_avb::state::{BootStateColor, KeyValidationStatus}, 186*5225e6b1SAndroid Build Coastguard Worker ops::ImageBuffer, 187*5225e6b1SAndroid Build Coastguard Worker }; 188*5225e6b1SAndroid Build Coastguard Worker // TODO(b/350526796): use ptr.is_aligned() when Rust 1.79 is in Android 189*5225e6b1SAndroid Build Coastguard Worker use core::ops::DerefMut; 190*5225e6b1SAndroid Build Coastguard Worker use std::{ 191*5225e6b1SAndroid Build Coastguard Worker ffi::CStr, 192*5225e6b1SAndroid Build Coastguard Worker fmt::Write, 193*5225e6b1SAndroid Build Coastguard Worker mem::align_of, 194*5225e6b1SAndroid Build Coastguard Worker num::NonZeroUsize, 195*5225e6b1SAndroid Build Coastguard Worker sync::atomic::{AtomicBool, AtomicU32, Ordering}, 196*5225e6b1SAndroid Build Coastguard Worker }; 197*5225e6b1SAndroid Build Coastguard Worker use zbi::ZbiContainer; 198*5225e6b1SAndroid Build Coastguard Worker 199*5225e6b1SAndroid Build Coastguard Worker // The thread-local atomics are an ugly, ugly hack to pass state between 200*5225e6b1SAndroid Build Coastguard Worker // the protocol method functions and the rest of the test body. 201*5225e6b1SAndroid Build Coastguard Worker // Because the variables are thread-local, it is safe to run tests concurrently 202*5225e6b1SAndroid Build Coastguard Worker // so long as they establish correct initial values. 203*5225e6b1SAndroid Build Coastguard Worker // Also, because no atomic is being read or written to by more than one thread, 204*5225e6b1SAndroid Build Coastguard Worker // Ordering::Relaxed is perfectly fine. 205*5225e6b1SAndroid Build Coastguard Worker thread_local! { 206*5225e6b1SAndroid Build Coastguard Worker static ATOMIC: AtomicBool = AtomicBool::new(false); 207*5225e6b1SAndroid Build Coastguard Worker } 208*5225e6b1SAndroid Build Coastguard Worker 209*5225e6b1SAndroid Build Coastguard Worker thread_local! { 210*5225e6b1SAndroid Build Coastguard Worker static BOOT_REASON: AtomicU32 = AtomicU32::new(REASON_EMPTY); 211*5225e6b1SAndroid Build Coastguard Worker } 212*5225e6b1SAndroid Build Coastguard Worker 213*5225e6b1SAndroid Build Coastguard Worker // This provides reasonable defaults for all tests that need to get slot info. 214*5225e6b1SAndroid Build Coastguard Worker // 215*5225e6b1SAndroid Build Coastguard Worker // SAFETY: checks that `info` is properly aligned and not null. 216*5225e6b1SAndroid Build Coastguard Worker // Caller must make sure `info` points to a valid GblEfiSlotInfo struct. get_info( _: *mut GblEfiABSlotProtocol, idx: u8, info: *mut GblEfiSlotInfo, ) -> EfiStatus217*5225e6b1SAndroid Build Coastguard Worker unsafe extern "C" fn get_info( 218*5225e6b1SAndroid Build Coastguard Worker _: *mut GblEfiABSlotProtocol, 219*5225e6b1SAndroid Build Coastguard Worker idx: u8, 220*5225e6b1SAndroid Build Coastguard Worker info: *mut GblEfiSlotInfo, 221*5225e6b1SAndroid Build Coastguard Worker ) -> EfiStatus { 222*5225e6b1SAndroid Build Coastguard Worker // TODO(b/350526796): use ptr.is_aligned() when Rust 1.79 is in Android 223*5225e6b1SAndroid Build Coastguard Worker if !info.is_null() && (info as usize) % align_of::<GblEfiSlotInfo>() == 0 && idx < 3 { 224*5225e6b1SAndroid Build Coastguard Worker let slot_info = GblEfiSlotInfo { 225*5225e6b1SAndroid Build Coastguard Worker suffix: ('a' as u8 + idx).into(), 226*5225e6b1SAndroid Build Coastguard Worker unbootable_reason: 0, 227*5225e6b1SAndroid Build Coastguard Worker priority: idx + 1, 228*5225e6b1SAndroid Build Coastguard Worker tries: idx, 229*5225e6b1SAndroid Build Coastguard Worker successful: 2 & idx, 230*5225e6b1SAndroid Build Coastguard Worker }; 231*5225e6b1SAndroid Build Coastguard Worker unsafe { *info = slot_info }; 232*5225e6b1SAndroid Build Coastguard Worker EFI_STATUS_SUCCESS 233*5225e6b1SAndroid Build Coastguard Worker } else { 234*5225e6b1SAndroid Build Coastguard Worker EFI_STATUS_INVALID_PARAMETER 235*5225e6b1SAndroid Build Coastguard Worker } 236*5225e6b1SAndroid Build Coastguard Worker } 237*5225e6b1SAndroid Build Coastguard Worker flush(_: *mut GblEfiABSlotProtocol) -> EfiStatus238*5225e6b1SAndroid Build Coastguard Worker extern "C" fn flush(_: *mut GblEfiABSlotProtocol) -> EfiStatus { 239*5225e6b1SAndroid Build Coastguard Worker ATOMIC.with(|a| a.store(true, Ordering::Relaxed)); 240*5225e6b1SAndroid Build Coastguard Worker EFI_STATUS_SUCCESS 241*5225e6b1SAndroid Build Coastguard Worker } 242*5225e6b1SAndroid Build Coastguard Worker 243*5225e6b1SAndroid Build Coastguard Worker struct TestGblOps<'a> { 244*5225e6b1SAndroid Build Coastguard Worker manager: ABManager<'a>, 245*5225e6b1SAndroid Build Coastguard Worker } 246*5225e6b1SAndroid Build Coastguard Worker 247*5225e6b1SAndroid Build Coastguard Worker impl<'a> TestGblOps<'a> { new(protocol: Protocol<'a, ab_slot::GblSlotProtocol>) -> Self248*5225e6b1SAndroid Build Coastguard Worker fn new(protocol: Protocol<'a, ab_slot::GblSlotProtocol>) -> Self { 249*5225e6b1SAndroid Build Coastguard Worker Self { manager: ABManager::new_without_token(protocol) } 250*5225e6b1SAndroid Build Coastguard Worker } 251*5225e6b1SAndroid Build Coastguard Worker } 252*5225e6b1SAndroid Build Coastguard Worker 253*5225e6b1SAndroid Build Coastguard Worker impl<'a, 'd> GblOps<'a, 'd> for TestGblOps<'_> { console_out(&mut self) -> Option<&mut dyn Write>254*5225e6b1SAndroid Build Coastguard Worker fn console_out(&mut self) -> Option<&mut dyn Write> { 255*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 256*5225e6b1SAndroid Build Coastguard Worker } 257*5225e6b1SAndroid Build Coastguard Worker should_stop_in_fastboot(&mut self) -> Result<bool>258*5225e6b1SAndroid Build Coastguard Worker fn should_stop_in_fastboot(&mut self) -> Result<bool> { 259*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 260*5225e6b1SAndroid Build Coastguard Worker } 261*5225e6b1SAndroid Build Coastguard Worker reboot(&mut self)262*5225e6b1SAndroid Build Coastguard Worker fn reboot(&mut self) { 263*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 264*5225e6b1SAndroid Build Coastguard Worker } 265*5225e6b1SAndroid Build Coastguard Worker disks( &self, ) -> &'a [GblDisk< Disk<impl BlockIo + 'a, impl DerefMut<Target = [u8]> + 'a>, Gpt<impl DerefMut<Target = [u8]> + 'a>, >]266*5225e6b1SAndroid Build Coastguard Worker fn disks( 267*5225e6b1SAndroid Build Coastguard Worker &self, 268*5225e6b1SAndroid Build Coastguard Worker ) -> &'a [GblDisk< 269*5225e6b1SAndroid Build Coastguard Worker Disk<impl BlockIo + 'a, impl DerefMut<Target = [u8]> + 'a>, 270*5225e6b1SAndroid Build Coastguard Worker Gpt<impl DerefMut<Target = [u8]> + 'a>, 271*5225e6b1SAndroid Build Coastguard Worker >] { 272*5225e6b1SAndroid Build Coastguard Worker &[] as &[GblDisk<Disk<BlockIoNull, &mut [u8]>, Gpt<&mut [u8]>>] 273*5225e6b1SAndroid Build Coastguard Worker } 274*5225e6b1SAndroid Build Coastguard Worker expected_os(&mut self) -> Result<Option<Os>>275*5225e6b1SAndroid Build Coastguard Worker fn expected_os(&mut self) -> Result<Option<Os>> { 276*5225e6b1SAndroid Build Coastguard Worker Ok(None) 277*5225e6b1SAndroid Build Coastguard Worker } 278*5225e6b1SAndroid Build Coastguard Worker zircon_add_device_zbi_items(&mut self, _: &mut ZbiContainer<&mut [u8]>) -> Result<()>279*5225e6b1SAndroid Build Coastguard Worker fn zircon_add_device_zbi_items(&mut self, _: &mut ZbiContainer<&mut [u8]>) -> Result<()> { 280*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 281*5225e6b1SAndroid Build Coastguard Worker } 282*5225e6b1SAndroid Build Coastguard Worker get_zbi_bootloader_files_buffer(&mut self) -> Option<&mut [u8]>283*5225e6b1SAndroid Build Coastguard Worker fn get_zbi_bootloader_files_buffer(&mut self) -> Option<&mut [u8]> { 284*5225e6b1SAndroid Build Coastguard Worker None 285*5225e6b1SAndroid Build Coastguard Worker } 286*5225e6b1SAndroid Build Coastguard Worker load_slot_interface<'b>( &'b mut self, persist: &'b mut dyn FnMut(&mut [u8]) -> Result<()>, boot_token: BootToken, ) -> GblResult<Cursor<'b>>287*5225e6b1SAndroid Build Coastguard Worker fn load_slot_interface<'b>( 288*5225e6b1SAndroid Build Coastguard Worker &'b mut self, 289*5225e6b1SAndroid Build Coastguard Worker persist: &'b mut dyn FnMut(&mut [u8]) -> Result<()>, 290*5225e6b1SAndroid Build Coastguard Worker boot_token: BootToken, 291*5225e6b1SAndroid Build Coastguard Worker ) -> GblResult<Cursor<'b>> { 292*5225e6b1SAndroid Build Coastguard Worker self.manager.boot_token = Some(boot_token); 293*5225e6b1SAndroid Build Coastguard Worker Ok(Cursor { ctx: &mut self.manager, persist }) 294*5225e6b1SAndroid Build Coastguard Worker } 295*5225e6b1SAndroid Build Coastguard Worker avb_read_is_device_unlocked(&mut self) -> AvbIoResult<bool>296*5225e6b1SAndroid Build Coastguard Worker fn avb_read_is_device_unlocked(&mut self) -> AvbIoResult<bool> { 297*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 298*5225e6b1SAndroid Build Coastguard Worker } 299*5225e6b1SAndroid Build Coastguard Worker avb_read_rollback_index(&mut self, _rollback_index_location: usize) -> AvbIoResult<u64>300*5225e6b1SAndroid Build Coastguard Worker fn avb_read_rollback_index(&mut self, _rollback_index_location: usize) -> AvbIoResult<u64> { 301*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 302*5225e6b1SAndroid Build Coastguard Worker } 303*5225e6b1SAndroid Build Coastguard Worker avb_write_rollback_index( &mut self, _rollback_index_location: usize, _index: u64, ) -> AvbIoResult<()>304*5225e6b1SAndroid Build Coastguard Worker fn avb_write_rollback_index( 305*5225e6b1SAndroid Build Coastguard Worker &mut self, 306*5225e6b1SAndroid Build Coastguard Worker _rollback_index_location: usize, 307*5225e6b1SAndroid Build Coastguard Worker _index: u64, 308*5225e6b1SAndroid Build Coastguard Worker ) -> AvbIoResult<()> { 309*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 310*5225e6b1SAndroid Build Coastguard Worker } 311*5225e6b1SAndroid Build Coastguard Worker avb_validate_vbmeta_public_key( &self, _public_key: &[u8], _public_key_metadata: Option<&[u8]>, ) -> AvbIoResult<KeyValidationStatus>312*5225e6b1SAndroid Build Coastguard Worker fn avb_validate_vbmeta_public_key( 313*5225e6b1SAndroid Build Coastguard Worker &self, 314*5225e6b1SAndroid Build Coastguard Worker _public_key: &[u8], 315*5225e6b1SAndroid Build Coastguard Worker _public_key_metadata: Option<&[u8]>, 316*5225e6b1SAndroid Build Coastguard Worker ) -> AvbIoResult<KeyValidationStatus> { 317*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 318*5225e6b1SAndroid Build Coastguard Worker } 319*5225e6b1SAndroid Build Coastguard Worker avb_cert_read_permanent_attributes( &mut self, _attributes: &mut CertPermanentAttributes, ) -> AvbIoResult<()>320*5225e6b1SAndroid Build Coastguard Worker fn avb_cert_read_permanent_attributes( 321*5225e6b1SAndroid Build Coastguard Worker &mut self, 322*5225e6b1SAndroid Build Coastguard Worker _attributes: &mut CertPermanentAttributes, 323*5225e6b1SAndroid Build Coastguard Worker ) -> AvbIoResult<()> { 324*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 325*5225e6b1SAndroid Build Coastguard Worker } 326*5225e6b1SAndroid Build Coastguard Worker avb_cert_read_permanent_attributes_hash( &mut self, ) -> AvbIoResult<[u8; SHA256_DIGEST_SIZE]>327*5225e6b1SAndroid Build Coastguard Worker fn avb_cert_read_permanent_attributes_hash( 328*5225e6b1SAndroid Build Coastguard Worker &mut self, 329*5225e6b1SAndroid Build Coastguard Worker ) -> AvbIoResult<[u8; SHA256_DIGEST_SIZE]> { 330*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 331*5225e6b1SAndroid Build Coastguard Worker } 332*5225e6b1SAndroid Build Coastguard Worker avb_read_persistent_value( &mut self, _name: &CStr, _value: &mut [u8], ) -> AvbIoResult<usize>333*5225e6b1SAndroid Build Coastguard Worker fn avb_read_persistent_value( 334*5225e6b1SAndroid Build Coastguard Worker &mut self, 335*5225e6b1SAndroid Build Coastguard Worker _name: &CStr, 336*5225e6b1SAndroid Build Coastguard Worker _value: &mut [u8], 337*5225e6b1SAndroid Build Coastguard Worker ) -> AvbIoResult<usize> { 338*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 339*5225e6b1SAndroid Build Coastguard Worker } 340*5225e6b1SAndroid Build Coastguard Worker avb_write_persistent_value(&mut self, _name: &CStr, _value: &[u8]) -> AvbIoResult<()>341*5225e6b1SAndroid Build Coastguard Worker fn avb_write_persistent_value(&mut self, _name: &CStr, _value: &[u8]) -> AvbIoResult<()> { 342*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 343*5225e6b1SAndroid Build Coastguard Worker } 344*5225e6b1SAndroid Build Coastguard Worker avb_erase_persistent_value(&mut self, _name: &CStr) -> AvbIoResult<()>345*5225e6b1SAndroid Build Coastguard Worker fn avb_erase_persistent_value(&mut self, _name: &CStr) -> AvbIoResult<()> { 346*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 347*5225e6b1SAndroid Build Coastguard Worker } 348*5225e6b1SAndroid Build Coastguard Worker 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<()>349*5225e6b1SAndroid Build Coastguard Worker fn avb_handle_verification_result( 350*5225e6b1SAndroid Build Coastguard Worker &mut self, 351*5225e6b1SAndroid Build Coastguard Worker _color: BootStateColor, 352*5225e6b1SAndroid Build Coastguard Worker _digest: Option<&CStr>, 353*5225e6b1SAndroid Build Coastguard Worker _boot_os_version: Option<&[u8]>, 354*5225e6b1SAndroid Build Coastguard Worker _boot_security_patch: Option<&[u8]>, 355*5225e6b1SAndroid Build Coastguard Worker _system_os_version: Option<&[u8]>, 356*5225e6b1SAndroid Build Coastguard Worker _system_security_patch: Option<&[u8]>, 357*5225e6b1SAndroid Build Coastguard Worker _vendor_os_version: Option<&[u8]>, 358*5225e6b1SAndroid Build Coastguard Worker _vendor_security_patch: Option<&[u8]>, 359*5225e6b1SAndroid Build Coastguard Worker ) -> AvbIoResult<()> { 360*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 361*5225e6b1SAndroid Build Coastguard Worker } 362*5225e6b1SAndroid Build Coastguard Worker get_image_buffer( &mut self, _image_name: &str, _size: NonZeroUsize, ) -> GblResult<ImageBuffer<'d>>363*5225e6b1SAndroid Build Coastguard Worker fn get_image_buffer( 364*5225e6b1SAndroid Build Coastguard Worker &mut self, 365*5225e6b1SAndroid Build Coastguard Worker _image_name: &str, 366*5225e6b1SAndroid Build Coastguard Worker _size: NonZeroUsize, 367*5225e6b1SAndroid Build Coastguard Worker ) -> GblResult<ImageBuffer<'d>> { 368*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 369*5225e6b1SAndroid Build Coastguard Worker } 370*5225e6b1SAndroid Build Coastguard Worker get_custom_device_tree(&mut self) -> Option<&'a [u8]>371*5225e6b1SAndroid Build Coastguard Worker fn get_custom_device_tree(&mut self) -> Option<&'a [u8]> { 372*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 373*5225e6b1SAndroid Build Coastguard Worker } 374*5225e6b1SAndroid Build Coastguard Worker fixup_os_commandline<'c>( &mut self, _commandline: &CStr, _fixup_buffer: &'c mut [u8], ) -> Result<Option<&'c str>>375*5225e6b1SAndroid Build Coastguard Worker fn fixup_os_commandline<'c>( 376*5225e6b1SAndroid Build Coastguard Worker &mut self, 377*5225e6b1SAndroid Build Coastguard Worker _commandline: &CStr, 378*5225e6b1SAndroid Build Coastguard Worker _fixup_buffer: &'c mut [u8], 379*5225e6b1SAndroid Build Coastguard Worker ) -> Result<Option<&'c str>> { 380*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 381*5225e6b1SAndroid Build Coastguard Worker } 382*5225e6b1SAndroid Build Coastguard Worker fixup_bootconfig<'c>( &mut self, _bootconfig: &[u8], _fixup_buffer: &'c mut [u8], ) -> Result<Option<&'c [u8]>>383*5225e6b1SAndroid Build Coastguard Worker fn fixup_bootconfig<'c>( 384*5225e6b1SAndroid Build Coastguard Worker &mut self, 385*5225e6b1SAndroid Build Coastguard Worker _bootconfig: &[u8], 386*5225e6b1SAndroid Build Coastguard Worker _fixup_buffer: &'c mut [u8], 387*5225e6b1SAndroid Build Coastguard Worker ) -> Result<Option<&'c [u8]>> { 388*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 389*5225e6b1SAndroid Build Coastguard Worker } 390*5225e6b1SAndroid Build Coastguard Worker fixup_device_tree(&mut self, _device_tree: &mut [u8]) -> Result<()>391*5225e6b1SAndroid Build Coastguard Worker fn fixup_device_tree(&mut self, _device_tree: &mut [u8]) -> Result<()> { 392*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 393*5225e6b1SAndroid Build Coastguard Worker } 394*5225e6b1SAndroid Build Coastguard Worker select_device_trees( &mut self, _components: &mut DeviceTreeComponentsRegistry, ) -> Result<()>395*5225e6b1SAndroid Build Coastguard Worker fn select_device_trees( 396*5225e6b1SAndroid Build Coastguard Worker &mut self, 397*5225e6b1SAndroid Build Coastguard Worker _components: &mut DeviceTreeComponentsRegistry, 398*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> { 399*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 400*5225e6b1SAndroid Build Coastguard Worker } 401*5225e6b1SAndroid Build Coastguard Worker fastboot_variable<'arg>( &mut self, _: &CStr, _: impl Iterator<Item = &'arg CStr> + Clone, _: &mut [u8], ) -> Result<usize>402*5225e6b1SAndroid Build Coastguard Worker fn fastboot_variable<'arg>( 403*5225e6b1SAndroid Build Coastguard Worker &mut self, 404*5225e6b1SAndroid Build Coastguard Worker _: &CStr, 405*5225e6b1SAndroid Build Coastguard Worker _: impl Iterator<Item = &'arg CStr> + Clone, 406*5225e6b1SAndroid Build Coastguard Worker _: &mut [u8], 407*5225e6b1SAndroid Build Coastguard Worker ) -> Result<usize> { 408*5225e6b1SAndroid Build Coastguard Worker unimplemented!() 409*5225e6b1SAndroid Build Coastguard Worker } 410*5225e6b1SAndroid Build Coastguard Worker fastboot_visit_all_variables(&mut self, _: impl FnMut(&[&CStr], &CStr)) -> Result<()>411*5225e6b1SAndroid Build Coastguard Worker fn fastboot_visit_all_variables(&mut self, _: impl FnMut(&[&CStr], &CStr)) -> Result<()> { 412*5225e6b1SAndroid Build Coastguard Worker unimplemented!() 413*5225e6b1SAndroid Build Coastguard Worker } 414*5225e6b1SAndroid Build Coastguard Worker slots_metadata(&mut self) -> Result<SlotsMetadata>415*5225e6b1SAndroid Build Coastguard Worker fn slots_metadata(&mut self) -> Result<SlotsMetadata> { 416*5225e6b1SAndroid Build Coastguard Worker unimplemented!(); 417*5225e6b1SAndroid Build Coastguard Worker } 418*5225e6b1SAndroid Build Coastguard Worker get_current_slot(&mut self) -> Result<Slot>419*5225e6b1SAndroid Build Coastguard Worker fn get_current_slot(&mut self) -> Result<Slot> { 420*5225e6b1SAndroid Build Coastguard Worker unimplemented!() 421*5225e6b1SAndroid Build Coastguard Worker } 422*5225e6b1SAndroid Build Coastguard Worker get_next_slot(&mut self, _: bool) -> Result<Slot>423*5225e6b1SAndroid Build Coastguard Worker fn get_next_slot(&mut self, _: bool) -> Result<Slot> { 424*5225e6b1SAndroid Build Coastguard Worker unimplemented!() 425*5225e6b1SAndroid Build Coastguard Worker } 426*5225e6b1SAndroid Build Coastguard Worker set_active_slot(&mut self, _: u8) -> Result<()>427*5225e6b1SAndroid Build Coastguard Worker fn set_active_slot(&mut self, _: u8) -> Result<()> { 428*5225e6b1SAndroid Build Coastguard Worker unimplemented!() 429*5225e6b1SAndroid Build Coastguard Worker } 430*5225e6b1SAndroid Build Coastguard Worker set_reboot_reason(&mut self, _: RebootReason) -> Result<()>431*5225e6b1SAndroid Build Coastguard Worker fn set_reboot_reason(&mut self, _: RebootReason) -> Result<()> { 432*5225e6b1SAndroid Build Coastguard Worker unimplemented!() 433*5225e6b1SAndroid Build Coastguard Worker } 434*5225e6b1SAndroid Build Coastguard Worker get_reboot_reason(&mut self) -> Result<RebootReason>435*5225e6b1SAndroid Build Coastguard Worker fn get_reboot_reason(&mut self) -> Result<RebootReason> { 436*5225e6b1SAndroid Build Coastguard Worker unimplemented!() 437*5225e6b1SAndroid Build Coastguard Worker } 438*5225e6b1SAndroid Build Coastguard Worker } 439*5225e6b1SAndroid Build Coastguard Worker 440*5225e6b1SAndroid Build Coastguard Worker #[test] test_manager_flush_on_close()441*5225e6b1SAndroid Build Coastguard Worker fn test_manager_flush_on_close() { 442*5225e6b1SAndroid Build Coastguard Worker ATOMIC.with(|a| a.store(false, Ordering::Relaxed)); 443*5225e6b1SAndroid Build Coastguard Worker run_test(|image_handle, systab_ptr| { 444*5225e6b1SAndroid Build Coastguard Worker let mut ab = GblEfiABSlotProtocol { flush: Some(flush), ..Default::default() }; 445*5225e6b1SAndroid Build Coastguard Worker let efi_entry = EfiEntry { image_handle, systab_ptr }; 446*5225e6b1SAndroid Build Coastguard Worker let protocol = generate_protocol::<ab_slot::GblSlotProtocol>(&efi_entry, &mut ab); 447*5225e6b1SAndroid Build Coastguard Worker 448*5225e6b1SAndroid Build Coastguard Worker { 449*5225e6b1SAndroid Build Coastguard Worker let mut persist = |_: &mut [u8]| Ok(()); 450*5225e6b1SAndroid Build Coastguard Worker let mut test_ops = TestGblOps::new(protocol); 451*5225e6b1SAndroid Build Coastguard Worker let mut gbl = Gbl::<TestGblOps>::new(&mut test_ops); 452*5225e6b1SAndroid Build Coastguard Worker let _ = gbl.load_slot_interface(&mut persist).unwrap(); 453*5225e6b1SAndroid Build Coastguard Worker } 454*5225e6b1SAndroid Build Coastguard Worker }); 455*5225e6b1SAndroid Build Coastguard Worker assert!(ATOMIC.with(|a| a.load(Ordering::Relaxed))); 456*5225e6b1SAndroid Build Coastguard Worker } 457*5225e6b1SAndroid Build Coastguard Worker 458*5225e6b1SAndroid Build Coastguard Worker #[test] test_iterator()459*5225e6b1SAndroid Build Coastguard Worker fn test_iterator() { 460*5225e6b1SAndroid Build Coastguard Worker run_test(|image_handle, systab_ptr| { 461*5225e6b1SAndroid Build Coastguard Worker let mut ab = GblEfiABSlotProtocol { 462*5225e6b1SAndroid Build Coastguard Worker get_slot_info: Some(get_info), 463*5225e6b1SAndroid Build Coastguard Worker flush: Some(flush), 464*5225e6b1SAndroid Build Coastguard Worker ..Default::default() 465*5225e6b1SAndroid Build Coastguard Worker }; 466*5225e6b1SAndroid Build Coastguard Worker let efi_entry = EfiEntry { image_handle, systab_ptr }; 467*5225e6b1SAndroid Build Coastguard Worker let protocol = generate_protocol::<ab_slot::GblSlotProtocol>(&efi_entry, &mut ab); 468*5225e6b1SAndroid Build Coastguard Worker let mut persist = |_: &mut [u8]| Ok(()); 469*5225e6b1SAndroid Build Coastguard Worker let mut test_ops = TestGblOps::new(protocol); 470*5225e6b1SAndroid Build Coastguard Worker let mut gbl = Gbl::<TestGblOps>::new(&mut test_ops); 471*5225e6b1SAndroid Build Coastguard Worker let cursor = gbl.load_slot_interface(&mut persist).unwrap(); 472*5225e6b1SAndroid Build Coastguard Worker 473*5225e6b1SAndroid Build Coastguard Worker let slots: Vec<Slot> = cursor.ctx.slots_iter().collect(); 474*5225e6b1SAndroid Build Coastguard Worker assert_eq!( 475*5225e6b1SAndroid Build Coastguard Worker slots, 476*5225e6b1SAndroid Build Coastguard Worker vec![ 477*5225e6b1SAndroid Build Coastguard Worker Slot { 478*5225e6b1SAndroid Build Coastguard Worker suffix: 'a'.into(), 479*5225e6b1SAndroid Build Coastguard Worker priority: 1usize.into(), 480*5225e6b1SAndroid Build Coastguard Worker bootability: Bootability::Unbootable(UnbootableReason::Unknown), 481*5225e6b1SAndroid Build Coastguard Worker }, 482*5225e6b1SAndroid Build Coastguard Worker Slot { 483*5225e6b1SAndroid Build Coastguard Worker suffix: 'b'.into(), 484*5225e6b1SAndroid Build Coastguard Worker priority: 2usize.into(), 485*5225e6b1SAndroid Build Coastguard Worker bootability: Bootability::Retriable(1usize.into()), 486*5225e6b1SAndroid Build Coastguard Worker }, 487*5225e6b1SAndroid Build Coastguard Worker Slot { 488*5225e6b1SAndroid Build Coastguard Worker suffix: 'c'.into(), 489*5225e6b1SAndroid Build Coastguard Worker priority: 3usize.into(), 490*5225e6b1SAndroid Build Coastguard Worker bootability: Bootability::Successful, 491*5225e6b1SAndroid Build Coastguard Worker } 492*5225e6b1SAndroid Build Coastguard Worker ] 493*5225e6b1SAndroid Build Coastguard Worker ) 494*5225e6b1SAndroid Build Coastguard Worker }); 495*5225e6b1SAndroid Build Coastguard Worker } 496*5225e6b1SAndroid Build Coastguard Worker 497*5225e6b1SAndroid Build Coastguard Worker #[test] test_active_slot()498*5225e6b1SAndroid Build Coastguard Worker fn test_active_slot() { 499*5225e6b1SAndroid Build Coastguard Worker // SAFETY: verfies that `info` properly aligned and not null. 500*5225e6b1SAndroid Build Coastguard Worker // It is the callers responsibility to make sure 501*5225e6b1SAndroid Build Coastguard Worker // that `info` points to a valid GblEfiSlotInfo. 502*5225e6b1SAndroid Build Coastguard Worker unsafe extern "C" fn get_current_slot( 503*5225e6b1SAndroid Build Coastguard Worker _: *mut GblEfiABSlotProtocol, 504*5225e6b1SAndroid Build Coastguard Worker info: *mut GblEfiSlotInfo, 505*5225e6b1SAndroid Build Coastguard Worker ) -> EfiStatus { 506*5225e6b1SAndroid Build Coastguard Worker // TODO(b/350526796): use ptr.is_aligned() when Rust 1.79 is in Android 507*5225e6b1SAndroid Build Coastguard Worker if info.is_null() || (info as usize) % align_of::<GblEfiSlotInfo>() != 0 { 508*5225e6b1SAndroid Build Coastguard Worker return EFI_STATUS_INVALID_PARAMETER; 509*5225e6b1SAndroid Build Coastguard Worker } 510*5225e6b1SAndroid Build Coastguard Worker let slot_info = GblEfiSlotInfo { 511*5225e6b1SAndroid Build Coastguard Worker suffix: 'a' as u32, 512*5225e6b1SAndroid Build Coastguard Worker unbootable_reason: 0, 513*5225e6b1SAndroid Build Coastguard Worker priority: 7, 514*5225e6b1SAndroid Build Coastguard Worker tries: 15, 515*5225e6b1SAndroid Build Coastguard Worker successful: 1, 516*5225e6b1SAndroid Build Coastguard Worker }; 517*5225e6b1SAndroid Build Coastguard Worker 518*5225e6b1SAndroid Build Coastguard Worker unsafe { *info = slot_info }; 519*5225e6b1SAndroid Build Coastguard Worker EFI_STATUS_SUCCESS 520*5225e6b1SAndroid Build Coastguard Worker } 521*5225e6b1SAndroid Build Coastguard Worker 522*5225e6b1SAndroid Build Coastguard Worker // SAFETY: verifies that `reason` and `subreason_size` are aligned and not null. 523*5225e6b1SAndroid Build Coastguard Worker // It is the caller's responsibility to make sure that `reason` 524*5225e6b1SAndroid Build Coastguard Worker // and `subreason_size` point to valid output parameters. 525*5225e6b1SAndroid Build Coastguard Worker unsafe extern "C" fn get_boot_reason( 526*5225e6b1SAndroid Build Coastguard Worker _: *mut GblEfiABSlotProtocol, 527*5225e6b1SAndroid Build Coastguard Worker reason: *mut u32, 528*5225e6b1SAndroid Build Coastguard Worker subreason_size: *mut usize, 529*5225e6b1SAndroid Build Coastguard Worker _subreason: *mut u8, 530*5225e6b1SAndroid Build Coastguard Worker ) -> EfiStatus { 531*5225e6b1SAndroid Build Coastguard Worker if reason.is_null() 532*5225e6b1SAndroid Build Coastguard Worker || subreason_size.is_null() 533*5225e6b1SAndroid Build Coastguard Worker // TODO(b/350526796): use ptr.is_aligned() when Rust 1.79 is in Android 534*5225e6b1SAndroid Build Coastguard Worker || (reason as usize) % align_of::<u32>() != 0 535*5225e6b1SAndroid Build Coastguard Worker || (subreason_size as usize) % align_of::<usize>() != 0 536*5225e6b1SAndroid Build Coastguard Worker { 537*5225e6b1SAndroid Build Coastguard Worker return EFI_STATUS_INVALID_PARAMETER; 538*5225e6b1SAndroid Build Coastguard Worker } 539*5225e6b1SAndroid Build Coastguard Worker 540*5225e6b1SAndroid Build Coastguard Worker unsafe { 541*5225e6b1SAndroid Build Coastguard Worker *reason = BOOT_REASON.with(|r| r.load(Ordering::Relaxed)); 542*5225e6b1SAndroid Build Coastguard Worker *subreason_size = 0; 543*5225e6b1SAndroid Build Coastguard Worker } 544*5225e6b1SAndroid Build Coastguard Worker EFI_STATUS_SUCCESS 545*5225e6b1SAndroid Build Coastguard Worker } 546*5225e6b1SAndroid Build Coastguard Worker 547*5225e6b1SAndroid Build Coastguard Worker BOOT_REASON.with(|r| r.store(REASON_EMPTY, Ordering::Relaxed)); 548*5225e6b1SAndroid Build Coastguard Worker run_test(|image_handle, systab_ptr| { 549*5225e6b1SAndroid Build Coastguard Worker let mut ab = GblEfiABSlotProtocol { 550*5225e6b1SAndroid Build Coastguard Worker get_current_slot: Some(get_current_slot), 551*5225e6b1SAndroid Build Coastguard Worker get_boot_reason: Some(get_boot_reason), 552*5225e6b1SAndroid Build Coastguard Worker flush: Some(flush), 553*5225e6b1SAndroid Build Coastguard Worker ..Default::default() 554*5225e6b1SAndroid Build Coastguard Worker }; 555*5225e6b1SAndroid Build Coastguard Worker let efi_entry = EfiEntry { image_handle, systab_ptr }; 556*5225e6b1SAndroid Build Coastguard Worker let protocol = generate_protocol::<ab_slot::GblSlotProtocol>(&efi_entry, &mut ab); 557*5225e6b1SAndroid Build Coastguard Worker let mut persist = |_: &mut [u8]| Ok(()); 558*5225e6b1SAndroid Build Coastguard Worker let mut test_ops = TestGblOps::new(protocol); 559*5225e6b1SAndroid Build Coastguard Worker let mut gbl = Gbl::<TestGblOps>::new(&mut test_ops); 560*5225e6b1SAndroid Build Coastguard Worker let cursor = gbl.load_slot_interface(&mut persist).unwrap(); 561*5225e6b1SAndroid Build Coastguard Worker 562*5225e6b1SAndroid Build Coastguard Worker let slot = Slot { 563*5225e6b1SAndroid Build Coastguard Worker suffix: 'a'.into(), 564*5225e6b1SAndroid Build Coastguard Worker priority: 7usize.into(), 565*5225e6b1SAndroid Build Coastguard Worker bootability: Bootability::Successful, 566*5225e6b1SAndroid Build Coastguard Worker }; 567*5225e6b1SAndroid Build Coastguard Worker assert_eq!(cursor.ctx.get_boot_target().unwrap(), BootTarget::NormalBoot(slot)); 568*5225e6b1SAndroid Build Coastguard Worker assert_eq!(cursor.ctx.get_slot_last_set_active().unwrap(), slot); 569*5225e6b1SAndroid Build Coastguard Worker 570*5225e6b1SAndroid Build Coastguard Worker BOOT_REASON.with(|r| r.store(REASON_RECOVERY, Ordering::Relaxed)); 571*5225e6b1SAndroid Build Coastguard Worker 572*5225e6b1SAndroid Build Coastguard Worker assert_eq!( 573*5225e6b1SAndroid Build Coastguard Worker cursor.ctx.get_boot_target().unwrap(), 574*5225e6b1SAndroid Build Coastguard Worker BootTarget::Recovery(RecoveryTarget::Slotted(slot)) 575*5225e6b1SAndroid Build Coastguard Worker ); 576*5225e6b1SAndroid Build Coastguard Worker }); 577*5225e6b1SAndroid Build Coastguard Worker } 578*5225e6b1SAndroid Build Coastguard Worker 579*5225e6b1SAndroid Build Coastguard Worker #[test] test_mark_boot_attempt()580*5225e6b1SAndroid Build Coastguard Worker fn test_mark_boot_attempt() { 581*5225e6b1SAndroid Build Coastguard Worker run_test(|image_handle, systab_ptr| { 582*5225e6b1SAndroid Build Coastguard Worker let mut ab = GblEfiABSlotProtocol { flush: Some(flush), ..Default::default() }; 583*5225e6b1SAndroid Build Coastguard Worker let efi_entry = EfiEntry { image_handle, systab_ptr }; 584*5225e6b1SAndroid Build Coastguard Worker let protocol = generate_protocol::<ab_slot::GblSlotProtocol>(&efi_entry, &mut ab); 585*5225e6b1SAndroid Build Coastguard Worker let mut persist = |_: &mut [u8]| Ok(()); 586*5225e6b1SAndroid Build Coastguard Worker let mut test_ops = TestGblOps::new(protocol); 587*5225e6b1SAndroid Build Coastguard Worker let mut gbl = Gbl::<TestGblOps>::new(&mut test_ops); 588*5225e6b1SAndroid Build Coastguard Worker let cursor = gbl.load_slot_interface(&mut persist).unwrap(); 589*5225e6b1SAndroid Build Coastguard Worker assert!(cursor.ctx.mark_boot_attempt().is_ok()); 590*5225e6b1SAndroid Build Coastguard Worker 591*5225e6b1SAndroid Build Coastguard Worker assert_eq!(cursor.ctx.mark_boot_attempt(), Err(Error::OperationProhibited)); 592*5225e6b1SAndroid Build Coastguard Worker }); 593*5225e6b1SAndroid Build Coastguard Worker } 594*5225e6b1SAndroid Build Coastguard Worker 595*5225e6b1SAndroid Build Coastguard Worker #[test] test_get_max_retries()596*5225e6b1SAndroid Build Coastguard Worker fn test_get_max_retries() { 597*5225e6b1SAndroid Build Coastguard Worker // SAFETY: verifies that `meta` is properly aligned and not null. 598*5225e6b1SAndroid Build Coastguard Worker // It is the caller's responsibility to make sure that `meta` points to 599*5225e6b1SAndroid Build Coastguard Worker // a valid GblEfiSlotMetadataBlock. 600*5225e6b1SAndroid Build Coastguard Worker unsafe extern "C" fn load_boot_data( 601*5225e6b1SAndroid Build Coastguard Worker _: *mut GblEfiABSlotProtocol, 602*5225e6b1SAndroid Build Coastguard Worker meta: *mut GblEfiSlotMetadataBlock, 603*5225e6b1SAndroid Build Coastguard Worker ) -> EfiStatus { 604*5225e6b1SAndroid Build Coastguard Worker // TODO(b/350526796): use ptr.is_aligned() when Rust 1.79 is in Android 605*5225e6b1SAndroid Build Coastguard Worker if meta.is_null() || (meta as usize) % align_of::<GblEfiSlotMetadataBlock>() != 0 { 606*5225e6b1SAndroid Build Coastguard Worker return EFI_STATUS_INVALID_PARAMETER; 607*5225e6b1SAndroid Build Coastguard Worker } 608*5225e6b1SAndroid Build Coastguard Worker 609*5225e6b1SAndroid Build Coastguard Worker let meta_block = GblEfiSlotMetadataBlock { 610*5225e6b1SAndroid Build Coastguard Worker unbootable_metadata: 1, 611*5225e6b1SAndroid Build Coastguard Worker max_retries: 66, 612*5225e6b1SAndroid Build Coastguard Worker slot_count: 32, // why not? 613*5225e6b1SAndroid Build Coastguard Worker merge_status: 0, 614*5225e6b1SAndroid Build Coastguard Worker }; 615*5225e6b1SAndroid Build Coastguard Worker 616*5225e6b1SAndroid Build Coastguard Worker unsafe { *meta = meta_block }; 617*5225e6b1SAndroid Build Coastguard Worker EFI_STATUS_SUCCESS 618*5225e6b1SAndroid Build Coastguard Worker } 619*5225e6b1SAndroid Build Coastguard Worker 620*5225e6b1SAndroid Build Coastguard Worker run_test(|image_handle, systab_ptr| { 621*5225e6b1SAndroid Build Coastguard Worker let mut ab = GblEfiABSlotProtocol { 622*5225e6b1SAndroid Build Coastguard Worker load_boot_data: Some(load_boot_data), 623*5225e6b1SAndroid Build Coastguard Worker flush: Some(flush), 624*5225e6b1SAndroid Build Coastguard Worker ..Default::default() 625*5225e6b1SAndroid Build Coastguard Worker }; 626*5225e6b1SAndroid Build Coastguard Worker let efi_entry = EfiEntry { image_handle, systab_ptr }; 627*5225e6b1SAndroid Build Coastguard Worker let protocol = generate_protocol::<ab_slot::GblSlotProtocol>(&efi_entry, &mut ab); 628*5225e6b1SAndroid Build Coastguard Worker let mut persist = |_: &mut [u8]| Ok(()); 629*5225e6b1SAndroid Build Coastguard Worker let mut test_ops = TestGblOps::new(protocol); 630*5225e6b1SAndroid Build Coastguard Worker let mut gbl = Gbl::<TestGblOps>::new(&mut test_ops); 631*5225e6b1SAndroid Build Coastguard Worker let cursor = gbl.load_slot_interface(&mut persist).unwrap(); 632*5225e6b1SAndroid Build Coastguard Worker assert_eq!(cursor.ctx.get_max_retries().unwrap(), 66usize.into()); 633*5225e6b1SAndroid Build Coastguard Worker }); 634*5225e6b1SAndroid Build Coastguard Worker } 635*5225e6b1SAndroid Build Coastguard Worker 636*5225e6b1SAndroid Build Coastguard Worker #[test] test_set_active_slot()637*5225e6b1SAndroid Build Coastguard Worker fn test_set_active_slot() { 638*5225e6b1SAndroid Build Coastguard Worker extern "C" fn set_active_slot(_: *mut GblEfiABSlotProtocol, idx: u8) -> EfiStatus { 639*5225e6b1SAndroid Build Coastguard Worker // This is deliberate: we want to make sure that other logic catches 640*5225e6b1SAndroid Build Coastguard Worker // 'no such slot' first but we also want to verify that errors propagate. 641*5225e6b1SAndroid Build Coastguard Worker if idx != 2 { 642*5225e6b1SAndroid Build Coastguard Worker EFI_STATUS_SUCCESS 643*5225e6b1SAndroid Build Coastguard Worker } else { 644*5225e6b1SAndroid Build Coastguard Worker EFI_STATUS_INVALID_PARAMETER 645*5225e6b1SAndroid Build Coastguard Worker } 646*5225e6b1SAndroid Build Coastguard Worker } 647*5225e6b1SAndroid Build Coastguard Worker 648*5225e6b1SAndroid Build Coastguard Worker run_test(|image_handle, systab_ptr| { 649*5225e6b1SAndroid Build Coastguard Worker let mut ab = GblEfiABSlotProtocol { 650*5225e6b1SAndroid Build Coastguard Worker get_slot_info: Some(get_info), 651*5225e6b1SAndroid Build Coastguard Worker set_active_slot: Some(set_active_slot), 652*5225e6b1SAndroid Build Coastguard Worker flush: Some(flush), 653*5225e6b1SAndroid Build Coastguard Worker ..Default::default() 654*5225e6b1SAndroid Build Coastguard Worker }; 655*5225e6b1SAndroid Build Coastguard Worker let efi_entry = EfiEntry { image_handle, systab_ptr }; 656*5225e6b1SAndroid Build Coastguard Worker let protocol = generate_protocol::<ab_slot::GblSlotProtocol>(&efi_entry, &mut ab); 657*5225e6b1SAndroid Build Coastguard Worker let mut persist = |_: &mut [u8]| Ok(()); 658*5225e6b1SAndroid Build Coastguard Worker let mut test_ops = TestGblOps::new(protocol); 659*5225e6b1SAndroid Build Coastguard Worker let mut gbl = Gbl::<TestGblOps>::new(&mut test_ops); 660*5225e6b1SAndroid Build Coastguard Worker let cursor = gbl.load_slot_interface(&mut persist).unwrap(); 661*5225e6b1SAndroid Build Coastguard Worker 662*5225e6b1SAndroid Build Coastguard Worker assert_eq!(cursor.ctx.set_active_slot('b'.into()), Ok(())); 663*5225e6b1SAndroid Build Coastguard Worker assert_eq!(cursor.ctx.set_active_slot('c'.into()), Err(Error::Other(None))); 664*5225e6b1SAndroid Build Coastguard Worker 665*5225e6b1SAndroid Build Coastguard Worker let bad_suffix = '$'.into(); 666*5225e6b1SAndroid Build Coastguard Worker assert_eq!(cursor.ctx.set_active_slot(bad_suffix), Err(Error::InvalidInput)); 667*5225e6b1SAndroid Build Coastguard Worker }); 668*5225e6b1SAndroid Build Coastguard Worker } 669*5225e6b1SAndroid Build Coastguard Worker 670*5225e6b1SAndroid Build Coastguard Worker #[test] test_set_slot_unbootable()671*5225e6b1SAndroid Build Coastguard Worker fn test_set_slot_unbootable() { 672*5225e6b1SAndroid Build Coastguard Worker extern "C" fn set_slot_unbootable( 673*5225e6b1SAndroid Build Coastguard Worker _: *mut GblEfiABSlotProtocol, 674*5225e6b1SAndroid Build Coastguard Worker idx: u8, 675*5225e6b1SAndroid Build Coastguard Worker _: u32, 676*5225e6b1SAndroid Build Coastguard Worker ) -> EfiStatus { 677*5225e6b1SAndroid Build Coastguard Worker // Same thing here as with set_active_slot. 678*5225e6b1SAndroid Build Coastguard Worker // We want to make sure that iteration over the slots 679*5225e6b1SAndroid Build Coastguard Worker // catches invalid suffixes, but we also want to make sure 680*5225e6b1SAndroid Build Coastguard Worker // that errors from the protocol percolate up. 681*5225e6b1SAndroid Build Coastguard Worker if idx == 0 { 682*5225e6b1SAndroid Build Coastguard Worker EFI_STATUS_SUCCESS 683*5225e6b1SAndroid Build Coastguard Worker } else { 684*5225e6b1SAndroid Build Coastguard Worker EFI_STATUS_INVALID_PARAMETER 685*5225e6b1SAndroid Build Coastguard Worker } 686*5225e6b1SAndroid Build Coastguard Worker } 687*5225e6b1SAndroid Build Coastguard Worker 688*5225e6b1SAndroid Build Coastguard Worker run_test(|image_handle, systab_ptr| { 689*5225e6b1SAndroid Build Coastguard Worker let mut ab = GblEfiABSlotProtocol { 690*5225e6b1SAndroid Build Coastguard Worker get_slot_info: Some(get_info), 691*5225e6b1SAndroid Build Coastguard Worker set_slot_unbootable: Some(set_slot_unbootable), 692*5225e6b1SAndroid Build Coastguard Worker flush: Some(flush), 693*5225e6b1SAndroid Build Coastguard Worker ..Default::default() 694*5225e6b1SAndroid Build Coastguard Worker }; 695*5225e6b1SAndroid Build Coastguard Worker let efi_entry = EfiEntry { image_handle, systab_ptr }; 696*5225e6b1SAndroid Build Coastguard Worker let protocol = generate_protocol::<ab_slot::GblSlotProtocol>(&efi_entry, &mut ab); 697*5225e6b1SAndroid Build Coastguard Worker let mut persist = |_: &mut [u8]| Ok(()); 698*5225e6b1SAndroid Build Coastguard Worker let mut test_ops = TestGblOps::new(protocol); 699*5225e6b1SAndroid Build Coastguard Worker let mut gbl = Gbl::<TestGblOps>::new(&mut test_ops); 700*5225e6b1SAndroid Build Coastguard Worker let cursor = gbl.load_slot_interface(&mut persist).unwrap(); 701*5225e6b1SAndroid Build Coastguard Worker 702*5225e6b1SAndroid Build Coastguard Worker assert_eq!( 703*5225e6b1SAndroid Build Coastguard Worker cursor.ctx.set_slot_unbootable('a'.into(), UnbootableReason::SystemUpdate), 704*5225e6b1SAndroid Build Coastguard Worker Ok(()) 705*5225e6b1SAndroid Build Coastguard Worker ); 706*5225e6b1SAndroid Build Coastguard Worker 707*5225e6b1SAndroid Build Coastguard Worker assert_eq!( 708*5225e6b1SAndroid Build Coastguard Worker cursor.ctx.set_slot_unbootable('b'.into(), UnbootableReason::UserRequested), 709*5225e6b1SAndroid Build Coastguard Worker Err(Error::InvalidInput) 710*5225e6b1SAndroid Build Coastguard Worker ); 711*5225e6b1SAndroid Build Coastguard Worker }); 712*5225e6b1SAndroid Build Coastguard Worker } 713*5225e6b1SAndroid Build Coastguard Worker 714*5225e6b1SAndroid Build Coastguard Worker #[test] test_oneshot()715*5225e6b1SAndroid Build Coastguard Worker fn test_oneshot() { 716*5225e6b1SAndroid Build Coastguard Worker // SAFETY: checks that `reason` is not null and is properly aligned. 717*5225e6b1SAndroid Build Coastguard Worker // Caller must make sure reason points to a valid u32. 718*5225e6b1SAndroid Build Coastguard Worker unsafe extern "C" fn get_boot_reason( 719*5225e6b1SAndroid Build Coastguard Worker _: *mut GblEfiABSlotProtocol, 720*5225e6b1SAndroid Build Coastguard Worker reason: *mut u32, 721*5225e6b1SAndroid Build Coastguard Worker _: *mut usize, 722*5225e6b1SAndroid Build Coastguard Worker _: *mut u8, 723*5225e6b1SAndroid Build Coastguard Worker ) -> EfiStatus { 724*5225e6b1SAndroid Build Coastguard Worker // TODO(b/350526796): use ptr.is_aligned() when Rust 1.79 is in Android 725*5225e6b1SAndroid Build Coastguard Worker if reason.is_null() || (reason as usize) % align_of::<u32>() != 0 { 726*5225e6b1SAndroid Build Coastguard Worker return EFI_STATUS_INVALID_PARAMETER; 727*5225e6b1SAndroid Build Coastguard Worker } 728*5225e6b1SAndroid Build Coastguard Worker 729*5225e6b1SAndroid Build Coastguard Worker unsafe { *reason = BOOT_REASON.with(|r| r.load(Ordering::Relaxed)) }; 730*5225e6b1SAndroid Build Coastguard Worker 731*5225e6b1SAndroid Build Coastguard Worker EFI_STATUS_SUCCESS 732*5225e6b1SAndroid Build Coastguard Worker } 733*5225e6b1SAndroid Build Coastguard Worker 734*5225e6b1SAndroid Build Coastguard Worker extern "C" fn set_boot_reason( 735*5225e6b1SAndroid Build Coastguard Worker _: *mut GblEfiABSlotProtocol, 736*5225e6b1SAndroid Build Coastguard Worker reason: u32, 737*5225e6b1SAndroid Build Coastguard Worker _: usize, 738*5225e6b1SAndroid Build Coastguard Worker _: *const u8, 739*5225e6b1SAndroid Build Coastguard Worker ) -> EfiStatus { 740*5225e6b1SAndroid Build Coastguard Worker BOOT_REASON.with(|r| r.store(reason, Ordering::Relaxed)); 741*5225e6b1SAndroid Build Coastguard Worker EFI_STATUS_SUCCESS 742*5225e6b1SAndroid Build Coastguard Worker } 743*5225e6b1SAndroid Build Coastguard Worker 744*5225e6b1SAndroid Build Coastguard Worker BOOT_REASON.with(|r| r.store(REASON_EMPTY, Ordering::Relaxed)); 745*5225e6b1SAndroid Build Coastguard Worker run_test(|image_handle, systab_ptr| { 746*5225e6b1SAndroid Build Coastguard Worker let mut ab = GblEfiABSlotProtocol { 747*5225e6b1SAndroid Build Coastguard Worker get_boot_reason: Some(get_boot_reason), 748*5225e6b1SAndroid Build Coastguard Worker set_boot_reason: Some(set_boot_reason), 749*5225e6b1SAndroid Build Coastguard Worker flush: Some(flush), 750*5225e6b1SAndroid Build Coastguard Worker ..Default::default() 751*5225e6b1SAndroid Build Coastguard Worker }; 752*5225e6b1SAndroid Build Coastguard Worker let efi_entry = EfiEntry { image_handle, systab_ptr }; 753*5225e6b1SAndroid Build Coastguard Worker let protocol = generate_protocol::<ab_slot::GblSlotProtocol>(&efi_entry, &mut ab); 754*5225e6b1SAndroid Build Coastguard Worker let mut persist = |_: &mut [u8]| Ok(()); 755*5225e6b1SAndroid Build Coastguard Worker let mut test_ops = TestGblOps::new(protocol); 756*5225e6b1SAndroid Build Coastguard Worker let mut gbl = Gbl::<TestGblOps>::new(&mut test_ops); 757*5225e6b1SAndroid Build Coastguard Worker let cursor = gbl.load_slot_interface(&mut persist).unwrap(); 758*5225e6b1SAndroid Build Coastguard Worker 759*5225e6b1SAndroid Build Coastguard Worker assert_eq!(cursor.ctx.get_oneshot_status(), None); 760*5225e6b1SAndroid Build Coastguard Worker assert_eq!( 761*5225e6b1SAndroid Build Coastguard Worker cursor.ctx.set_oneshot_status(OneShot::Continue(RecoveryTarget::Dedicated)), 762*5225e6b1SAndroid Build Coastguard Worker Err(Error::OperationProhibited) 763*5225e6b1SAndroid Build Coastguard Worker ); 764*5225e6b1SAndroid Build Coastguard Worker assert_eq!(cursor.ctx.set_oneshot_status(OneShot::Bootloader), Ok(())); 765*5225e6b1SAndroid Build Coastguard Worker assert_eq!(cursor.ctx.get_oneshot_status(), Some(OneShot::Bootloader)); 766*5225e6b1SAndroid Build Coastguard Worker 767*5225e6b1SAndroid Build Coastguard Worker cursor.ctx.clear_oneshot_status(); 768*5225e6b1SAndroid Build Coastguard Worker assert_eq!(cursor.ctx.get_oneshot_status(), None); 769*5225e6b1SAndroid Build Coastguard Worker 770*5225e6b1SAndroid Build Coastguard Worker BOOT_REASON.with(|r| r.store(REASON_WATCHDOG, Ordering::Relaxed)); 771*5225e6b1SAndroid Build Coastguard Worker assert_eq!(cursor.ctx.get_oneshot_status(), None); 772*5225e6b1SAndroid Build Coastguard Worker cursor.ctx.clear_oneshot_status(); 773*5225e6b1SAndroid Build Coastguard Worker assert_eq!(BOOT_REASON.with(|r| r.load(Ordering::Relaxed)), REASON_WATCHDOG); 774*5225e6b1SAndroid Build Coastguard Worker }); 775*5225e6b1SAndroid Build Coastguard Worker } 776*5225e6b1SAndroid Build Coastguard Worker } 777