1*5225e6b1SAndroid Build Coastguard Worker // Copyright 2023, 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 /// Export the default implementation 16*5225e6b1SAndroid Build Coastguard Worker pub mod fuchsia; 17*5225e6b1SAndroid Build Coastguard Worker 18*5225e6b1SAndroid Build Coastguard Worker /// Reference Android implementation 19*5225e6b1SAndroid Build Coastguard Worker pub mod android; 20*5225e6b1SAndroid Build Coastguard Worker 21*5225e6b1SAndroid Build Coastguard Worker /// Generic functionality for partition backed ABR schemes 22*5225e6b1SAndroid Build Coastguard Worker pub mod partition; 23*5225e6b1SAndroid Build Coastguard Worker 24*5225e6b1SAndroid Build Coastguard Worker use core::mem::size_of; 25*5225e6b1SAndroid Build Coastguard Worker use liberror::Error; 26*5225e6b1SAndroid Build Coastguard Worker 27*5225e6b1SAndroid Build Coastguard Worker /// A type safe container for describing the number of retries a slot has left 28*5225e6b1SAndroid Build Coastguard Worker /// before it becomes unbootable. 29*5225e6b1SAndroid Build Coastguard Worker /// Slot tries can only be compared to, assigned to, or assigned from other 30*5225e6b1SAndroid Build Coastguard Worker /// tries. 31*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] 32*5225e6b1SAndroid Build Coastguard Worker pub struct Tries(usize); 33*5225e6b1SAndroid Build Coastguard Worker 34*5225e6b1SAndroid Build Coastguard Worker impl From<usize> for Tries { from(u: usize) -> Self35*5225e6b1SAndroid Build Coastguard Worker fn from(u: usize) -> Self { 36*5225e6b1SAndroid Build Coastguard Worker Self(u) 37*5225e6b1SAndroid Build Coastguard Worker } 38*5225e6b1SAndroid Build Coastguard Worker } 39*5225e6b1SAndroid Build Coastguard Worker impl From<u8> for Tries { from(u: u8) -> Self40*5225e6b1SAndroid Build Coastguard Worker fn from(u: u8) -> Self { 41*5225e6b1SAndroid Build Coastguard Worker Self(u.into()) 42*5225e6b1SAndroid Build Coastguard Worker } 43*5225e6b1SAndroid Build Coastguard Worker } 44*5225e6b1SAndroid Build Coastguard Worker 45*5225e6b1SAndroid Build Coastguard Worker /// A type safe container for describing the priority of a slot. 46*5225e6b1SAndroid Build Coastguard Worker /// Slot priorities can only be compared to, assigned to, or assigned from 47*5225e6b1SAndroid Build Coastguard Worker /// other priorities. 48*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] 49*5225e6b1SAndroid Build Coastguard Worker pub struct Priority(usize); 50*5225e6b1SAndroid Build Coastguard Worker 51*5225e6b1SAndroid Build Coastguard Worker impl From<usize> for Priority { from(u: usize) -> Self52*5225e6b1SAndroid Build Coastguard Worker fn from(u: usize) -> Self { 53*5225e6b1SAndroid Build Coastguard Worker Self(u) 54*5225e6b1SAndroid Build Coastguard Worker } 55*5225e6b1SAndroid Build Coastguard Worker } 56*5225e6b1SAndroid Build Coastguard Worker impl From<u8> for Priority { from(u: u8) -> Self57*5225e6b1SAndroid Build Coastguard Worker fn from(u: u8) -> Self { 58*5225e6b1SAndroid Build Coastguard Worker Self(u.into()) 59*5225e6b1SAndroid Build Coastguard Worker } 60*5225e6b1SAndroid Build Coastguard Worker } 61*5225e6b1SAndroid Build Coastguard Worker 62*5225e6b1SAndroid Build Coastguard Worker /// A type safe container for describing a slot's suffix. 63*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] 64*5225e6b1SAndroid Build Coastguard Worker pub struct Suffix(pub(crate) char); 65*5225e6b1SAndroid Build Coastguard Worker 66*5225e6b1SAndroid Build Coastguard Worker impl Suffix { 67*5225e6b1SAndroid Build Coastguard Worker // We want lexigraphically lower suffixes 68*5225e6b1SAndroid Build Coastguard Worker // to have higher priority. 69*5225e6b1SAndroid Build Coastguard Worker // A cheater way to do this is to compare 70*5225e6b1SAndroid Build Coastguard Worker // their negative values. 71*5225e6b1SAndroid Build Coastguard Worker // A char is 4 bytes, and a signed 64 bit int 72*5225e6b1SAndroid Build Coastguard Worker // can comfortably contain the negative of a 73*5225e6b1SAndroid Build Coastguard Worker // number represented by an unsigned 32 bit int. rank(&self) -> i6474*5225e6b1SAndroid Build Coastguard Worker fn rank(&self) -> i64 { 75*5225e6b1SAndroid Build Coastguard Worker -i64::from(u32::from(self.0)) 76*5225e6b1SAndroid Build Coastguard Worker } 77*5225e6b1SAndroid Build Coastguard Worker } 78*5225e6b1SAndroid Build Coastguard Worker 79*5225e6b1SAndroid Build Coastguard Worker impl From<char> for Suffix { from(c: char) -> Self80*5225e6b1SAndroid Build Coastguard Worker fn from(c: char) -> Self { 81*5225e6b1SAndroid Build Coastguard Worker Self(c) 82*5225e6b1SAndroid Build Coastguard Worker } 83*5225e6b1SAndroid Build Coastguard Worker } 84*5225e6b1SAndroid Build Coastguard Worker 85*5225e6b1SAndroid Build Coastguard Worker impl TryFrom<usize> for Suffix { 86*5225e6b1SAndroid Build Coastguard Worker type Error = Error; 87*5225e6b1SAndroid Build Coastguard Worker try_from(value: usize) -> Result<Self, Self::Error>88*5225e6b1SAndroid Build Coastguard Worker fn try_from(value: usize) -> Result<Self, Self::Error> { 89*5225e6b1SAndroid Build Coastguard Worker u32::try_from(value).ok().and_then(char::from_u32).ok_or(Error::InvalidInput).map(Self) 90*5225e6b1SAndroid Build Coastguard Worker } 91*5225e6b1SAndroid Build Coastguard Worker } 92*5225e6b1SAndroid Build Coastguard Worker 93*5225e6b1SAndroid Build Coastguard Worker impl TryFrom<u32> for Suffix { 94*5225e6b1SAndroid Build Coastguard Worker type Error = Error; 95*5225e6b1SAndroid Build Coastguard Worker try_from(value: u32) -> Result<Self, Self::Error>96*5225e6b1SAndroid Build Coastguard Worker fn try_from(value: u32) -> Result<Self, Self::Error> { 97*5225e6b1SAndroid Build Coastguard Worker char::from_u32(value).ok_or(Error::InvalidInput).map(Self) 98*5225e6b1SAndroid Build Coastguard Worker } 99*5225e6b1SAndroid Build Coastguard Worker } 100*5225e6b1SAndroid Build Coastguard Worker 101*5225e6b1SAndroid Build Coastguard Worker // Includes a null terminator 102*5225e6b1SAndroid Build Coastguard Worker const SUFFIX_CSTR_MAX_BYTES: usize = size_of::<Suffix>() + 1; 103*5225e6b1SAndroid Build Coastguard Worker 104*5225e6b1SAndroid Build Coastguard Worker /// A buffer large enough to contain the serialized representation of a Suffix. 105*5225e6b1SAndroid Build Coastguard Worker /// Can be turned into a &Cstr like so: 106*5225e6b1SAndroid Build Coastguard Worker /// 107*5225e6b1SAndroid Build Coastguard Worker /// let suffix: Suffix = 'a'.into(); 108*5225e6b1SAndroid Build Coastguard Worker /// let buffer: SuffixBytes = suffix.into(); 109*5225e6b1SAndroid Build Coastguard Worker /// let cstr = CStr::from_bytes_until_nul(&buffer)?; 110*5225e6b1SAndroid Build Coastguard Worker pub type SuffixBytes = [u8; SUFFIX_CSTR_MAX_BYTES]; 111*5225e6b1SAndroid Build Coastguard Worker 112*5225e6b1SAndroid Build Coastguard Worker impl From<Suffix> for SuffixBytes { from(val: Suffix) -> Self113*5225e6b1SAndroid Build Coastguard Worker fn from(val: Suffix) -> Self { 114*5225e6b1SAndroid Build Coastguard Worker let mut buffer: Self = Default::default(); 115*5225e6b1SAndroid Build Coastguard Worker let _ = val.0.encode_utf8(&mut buffer); 116*5225e6b1SAndroid Build Coastguard Worker buffer 117*5225e6b1SAndroid Build Coastguard Worker } 118*5225e6b1SAndroid Build Coastguard Worker } 119*5225e6b1SAndroid Build Coastguard Worker 120*5225e6b1SAndroid Build Coastguard Worker /// Slot metadata describing why that slot is unbootable. 121*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, PartialEq, Eq)] 122*5225e6b1SAndroid Build Coastguard Worker pub enum UnbootableReason { 123*5225e6b1SAndroid Build Coastguard Worker /// No information is given about why this slot is not bootable. 124*5225e6b1SAndroid Build Coastguard Worker Unknown, 125*5225e6b1SAndroid Build Coastguard Worker /// This slot has exhausted its retry budget and cannot be booted. 126*5225e6b1SAndroid Build Coastguard Worker NoMoreTries, 127*5225e6b1SAndroid Build Coastguard Worker /// As part of a system update, the update agent downloads 128*5225e6b1SAndroid Build Coastguard Worker /// an updated image and stores it into a slot other than the current 129*5225e6b1SAndroid Build Coastguard Worker /// active slot. 130*5225e6b1SAndroid Build Coastguard Worker SystemUpdate, 131*5225e6b1SAndroid Build Coastguard Worker /// This slot has been marked unbootable by user request, 132*5225e6b1SAndroid Build Coastguard Worker /// usually as part of a system test. 133*5225e6b1SAndroid Build Coastguard Worker UserRequested, 134*5225e6b1SAndroid Build Coastguard Worker /// This slot has failed a verification check as part of 135*5225e6b1SAndroid Build Coastguard Worker /// Android Verified Boot. 136*5225e6b1SAndroid Build Coastguard Worker VerificationFailure, 137*5225e6b1SAndroid Build Coastguard Worker } 138*5225e6b1SAndroid Build Coastguard Worker 139*5225e6b1SAndroid Build Coastguard Worker impl Default for UnbootableReason { default() -> Self140*5225e6b1SAndroid Build Coastguard Worker fn default() -> Self { 141*5225e6b1SAndroid Build Coastguard Worker Self::Unknown 142*5225e6b1SAndroid Build Coastguard Worker } 143*5225e6b1SAndroid Build Coastguard Worker } 144*5225e6b1SAndroid Build Coastguard Worker 145*5225e6b1SAndroid Build Coastguard Worker impl From<u8> for UnbootableReason { from(val: u8) -> Self146*5225e6b1SAndroid Build Coastguard Worker fn from(val: u8) -> Self { 147*5225e6b1SAndroid Build Coastguard Worker match val { 148*5225e6b1SAndroid Build Coastguard Worker 1 => Self::NoMoreTries, 149*5225e6b1SAndroid Build Coastguard Worker 2 => Self::SystemUpdate, 150*5225e6b1SAndroid Build Coastguard Worker 3 => Self::UserRequested, 151*5225e6b1SAndroid Build Coastguard Worker 4 => Self::VerificationFailure, 152*5225e6b1SAndroid Build Coastguard Worker _ => Self::Unknown, 153*5225e6b1SAndroid Build Coastguard Worker } 154*5225e6b1SAndroid Build Coastguard Worker } 155*5225e6b1SAndroid Build Coastguard Worker } 156*5225e6b1SAndroid Build Coastguard Worker 157*5225e6b1SAndroid Build Coastguard Worker impl From<UnbootableReason> for u8 { from(reason: UnbootableReason) -> Self158*5225e6b1SAndroid Build Coastguard Worker fn from(reason: UnbootableReason) -> Self { 159*5225e6b1SAndroid Build Coastguard Worker match reason { 160*5225e6b1SAndroid Build Coastguard Worker UnbootableReason::Unknown => 0, 161*5225e6b1SAndroid Build Coastguard Worker UnbootableReason::NoMoreTries => 1, 162*5225e6b1SAndroid Build Coastguard Worker UnbootableReason::SystemUpdate => 2, 163*5225e6b1SAndroid Build Coastguard Worker UnbootableReason::UserRequested => 3, 164*5225e6b1SAndroid Build Coastguard Worker UnbootableReason::VerificationFailure => 4, 165*5225e6b1SAndroid Build Coastguard Worker } 166*5225e6b1SAndroid Build Coastguard Worker } 167*5225e6b1SAndroid Build Coastguard Worker } 168*5225e6b1SAndroid Build Coastguard Worker 169*5225e6b1SAndroid Build Coastguard Worker /// Describes whether a slot has successfully booted and, if not, 170*5225e6b1SAndroid Build Coastguard Worker /// why it is not a valid boot target OR the number of attempts it has left. 171*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, PartialEq, Eq)] 172*5225e6b1SAndroid Build Coastguard Worker pub enum Bootability { 173*5225e6b1SAndroid Build Coastguard Worker /// This slot has successfully booted. 174*5225e6b1SAndroid Build Coastguard Worker Successful, 175*5225e6b1SAndroid Build Coastguard Worker /// This slot cannot be booted. 176*5225e6b1SAndroid Build Coastguard Worker Unbootable(UnbootableReason), 177*5225e6b1SAndroid Build Coastguard Worker /// This slot has not successfully booted yet but has 178*5225e6b1SAndroid Build Coastguard Worker /// one or more attempts left before either successfully booting, 179*5225e6b1SAndroid Build Coastguard Worker /// and being marked successful, or failing, and being marked 180*5225e6b1SAndroid Build Coastguard Worker /// unbootable due to having no more tries. 181*5225e6b1SAndroid Build Coastguard Worker Retriable(Tries), 182*5225e6b1SAndroid Build Coastguard Worker } 183*5225e6b1SAndroid Build Coastguard Worker 184*5225e6b1SAndroid Build Coastguard Worker impl Default for Bootability { default() -> Self185*5225e6b1SAndroid Build Coastguard Worker fn default() -> Self { 186*5225e6b1SAndroid Build Coastguard Worker Self::Retriable(7u8.into()) 187*5225e6b1SAndroid Build Coastguard Worker } 188*5225e6b1SAndroid Build Coastguard Worker } 189*5225e6b1SAndroid Build Coastguard Worker 190*5225e6b1SAndroid Build Coastguard Worker /// User-visible representation of a boot slot. 191*5225e6b1SAndroid Build Coastguard Worker /// Describes the slot's moniker (i.e. the suffix), 192*5225e6b1SAndroid Build Coastguard Worker /// its priority, 193*5225e6b1SAndroid Build Coastguard Worker /// and information about its bootability. 194*5225e6b1SAndroid Build Coastguard Worker /// 195*5225e6b1SAndroid Build Coastguard Worker /// Note: structures that implement Manager will probably have a different 196*5225e6b1SAndroid Build Coastguard Worker /// internal representation for slots and will convert and return Slot structures 197*5225e6b1SAndroid Build Coastguard Worker /// on the fly as part of iteration. 198*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] 199*5225e6b1SAndroid Build Coastguard Worker pub struct Slot { 200*5225e6b1SAndroid Build Coastguard Worker /// The partition suffix for the slot. 201*5225e6b1SAndroid Build Coastguard Worker pub suffix: Suffix, 202*5225e6b1SAndroid Build Coastguard Worker /// The slot's priority for booting. 203*5225e6b1SAndroid Build Coastguard Worker pub priority: Priority, 204*5225e6b1SAndroid Build Coastguard Worker /// Information about a slot's boot eligibility and history. 205*5225e6b1SAndroid Build Coastguard Worker pub bootability: Bootability, 206*5225e6b1SAndroid Build Coastguard Worker } 207*5225e6b1SAndroid Build Coastguard Worker 208*5225e6b1SAndroid Build Coastguard Worker impl Slot { 209*5225e6b1SAndroid Build Coastguard Worker /// Returns whether a slot is a valid boot target, 210*5225e6b1SAndroid Build Coastguard Worker /// i.e. return true if its bootability is not Unbootable. is_bootable(&self) -> bool211*5225e6b1SAndroid Build Coastguard Worker pub fn is_bootable(&self) -> bool { 212*5225e6b1SAndroid Build Coastguard Worker !matches!(self.bootability, Bootability::Unbootable(_)) 213*5225e6b1SAndroid Build Coastguard Worker } 214*5225e6b1SAndroid Build Coastguard Worker } 215*5225e6b1SAndroid Build Coastguard Worker 216*5225e6b1SAndroid Build Coastguard Worker /// Describes the platform recovery mode boot target. 217*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, PartialEq, Eq)] 218*5225e6b1SAndroid Build Coastguard Worker pub enum RecoveryTarget { 219*5225e6b1SAndroid Build Coastguard Worker /// The platform uses a dedicated recovery slot with special semantics. 220*5225e6b1SAndroid Build Coastguard Worker /// It can't be marked unbootable, has unlimited retries, 221*5225e6b1SAndroid Build Coastguard Worker /// and often doesn't have an explicit metadata entry. 222*5225e6b1SAndroid Build Coastguard Worker Dedicated, 223*5225e6b1SAndroid Build Coastguard Worker /// The platform enters recovery mode by booting to a regular slot 224*5225e6b1SAndroid Build Coastguard Worker /// but with a special commandline and ramdisk. 225*5225e6b1SAndroid Build Coastguard Worker Slotted(Slot), 226*5225e6b1SAndroid Build Coastguard Worker } 227*5225e6b1SAndroid Build Coastguard Worker 228*5225e6b1SAndroid Build Coastguard Worker /// Describes a system's boot target, which can be a regular boot to a slot 229*5225e6b1SAndroid Build Coastguard Worker /// or a recovery boot. 230*5225e6b1SAndroid Build Coastguard Worker /// Whether the recovery boot target is a dedicated slot or a regular slot 231*5225e6b1SAndroid Build Coastguard Worker /// with a special command line is platform specific. 232*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, PartialEq, Eq)] 233*5225e6b1SAndroid Build Coastguard Worker pub enum BootTarget { 234*5225e6b1SAndroid Build Coastguard Worker /// The system will attempt a normal boot to the given slot. 235*5225e6b1SAndroid Build Coastguard Worker NormalBoot(Slot), 236*5225e6b1SAndroid Build Coastguard Worker /// The system will attempt a recovery boot. 237*5225e6b1SAndroid Build Coastguard Worker /// 238*5225e6b1SAndroid Build Coastguard Worker /// Some platforms, such as Fuchsia, have dedicated recovery partitions with 239*5225e6b1SAndroid Build Coastguard Worker /// special semantics. On these platforms, Recovery contains None. 240*5225e6b1SAndroid Build Coastguard Worker /// 241*5225e6b1SAndroid Build Coastguard Worker /// Other platforms, such as Android, do not have dedicated recovery partitions. 242*5225e6b1SAndroid Build Coastguard Worker /// They enter recovery mode by attempting to boot a regular slot with a special 243*5225e6b1SAndroid Build Coastguard Worker /// kernel command line and ramdisk. 244*5225e6b1SAndroid Build Coastguard Worker /// Under these circomstances, Recovery contains the slot that will be used for recovery. 245*5225e6b1SAndroid Build Coastguard Worker Recovery(RecoveryTarget), 246*5225e6b1SAndroid Build Coastguard Worker } 247*5225e6b1SAndroid Build Coastguard Worker 248*5225e6b1SAndroid Build Coastguard Worker impl BootTarget { 249*5225e6b1SAndroid Build Coastguard Worker /// Gets the suffix for a particular boot target. 250*5225e6b1SAndroid Build Coastguard Worker /// Implemented for BootTarget instead of slot in order to handle 251*5225e6b1SAndroid Build Coastguard Worker /// Fuchsia's recovery partition. suffix(&self) -> Suffix252*5225e6b1SAndroid Build Coastguard Worker pub fn suffix(&self) -> Suffix { 253*5225e6b1SAndroid Build Coastguard Worker match self { 254*5225e6b1SAndroid Build Coastguard Worker Self::NormalBoot(slot) | Self::Recovery(RecoveryTarget::Slotted(slot)) => slot.suffix, 255*5225e6b1SAndroid Build Coastguard Worker Self::Recovery(RecoveryTarget::Dedicated) => 'r'.into(), 256*5225e6b1SAndroid Build Coastguard Worker } 257*5225e6b1SAndroid Build Coastguard Worker } 258*5225e6b1SAndroid Build Coastguard Worker } 259*5225e6b1SAndroid Build Coastguard Worker 260*5225e6b1SAndroid Build Coastguard Worker #[doc(hidden)] 261*5225e6b1SAndroid Build Coastguard Worker pub mod private { 262*5225e6b1SAndroid Build Coastguard Worker use super::*; 263*5225e6b1SAndroid Build Coastguard Worker 264*5225e6b1SAndroid Build Coastguard Worker #[doc(hidden)] 265*5225e6b1SAndroid Build Coastguard Worker pub trait SlotGet { 266*5225e6b1SAndroid Build Coastguard Worker /// Given an index, returns the Slot that corresponds to that index, 267*5225e6b1SAndroid Build Coastguard Worker /// or Error if the index is out of bounds. 268*5225e6b1SAndroid Build Coastguard Worker /// This is intended to abstract storage details for structs that impl Manager. 269*5225e6b1SAndroid Build Coastguard Worker /// Most implementors will use some other, internal representation for slots, 270*5225e6b1SAndroid Build Coastguard Worker /// and will dynamically create and return Slots on the fly. 271*5225e6b1SAndroid Build Coastguard Worker /// 272*5225e6b1SAndroid Build Coastguard Worker /// This method is a helper, implementation detail for SlotIterator. 273*5225e6b1SAndroid Build Coastguard Worker /// It is not intended to be called by other parts of GBL or other users. get_slot_by_number(&self, number: usize) -> Result<Slot, Error>274*5225e6b1SAndroid Build Coastguard Worker fn get_slot_by_number(&self, number: usize) -> Result<Slot, Error>; 275*5225e6b1SAndroid Build Coastguard Worker } 276*5225e6b1SAndroid Build Coastguard Worker } 277*5225e6b1SAndroid Build Coastguard Worker 278*5225e6b1SAndroid Build Coastguard Worker /// A helper structure for iterating over slots. 279*5225e6b1SAndroid Build Coastguard Worker pub struct SlotIterator<'a> { 280*5225e6b1SAndroid Build Coastguard Worker count: usize, 281*5225e6b1SAndroid Build Coastguard Worker slot_getter: &'a dyn private::SlotGet, 282*5225e6b1SAndroid Build Coastguard Worker } 283*5225e6b1SAndroid Build Coastguard Worker 284*5225e6b1SAndroid Build Coastguard Worker impl<'a> SlotIterator<'a> { 285*5225e6b1SAndroid Build Coastguard Worker /// Constructor for SlotIterator new(intf: &'a dyn private::SlotGet) -> Self286*5225e6b1SAndroid Build Coastguard Worker pub fn new(intf: &'a dyn private::SlotGet) -> Self { 287*5225e6b1SAndroid Build Coastguard Worker Self { count: 0, slot_getter: intf } 288*5225e6b1SAndroid Build Coastguard Worker } 289*5225e6b1SAndroid Build Coastguard Worker } 290*5225e6b1SAndroid Build Coastguard Worker 291*5225e6b1SAndroid Build Coastguard Worker impl<'a> Iterator for SlotIterator<'a> { 292*5225e6b1SAndroid Build Coastguard Worker type Item = Slot; 293*5225e6b1SAndroid Build Coastguard Worker next(&mut self) -> Option<Self::Item>294*5225e6b1SAndroid Build Coastguard Worker fn next(&mut self) -> Option<Self::Item> { 295*5225e6b1SAndroid Build Coastguard Worker let maybe_slot = self.slot_getter.get_slot_by_number(self.count).ok(); 296*5225e6b1SAndroid Build Coastguard Worker if maybe_slot.is_some() { 297*5225e6b1SAndroid Build Coastguard Worker self.count += 1; 298*5225e6b1SAndroid Build Coastguard Worker } 299*5225e6b1SAndroid Build Coastguard Worker maybe_slot 300*5225e6b1SAndroid Build Coastguard Worker } 301*5225e6b1SAndroid Build Coastguard Worker } 302*5225e6b1SAndroid Build Coastguard Worker 303*5225e6b1SAndroid Build Coastguard Worker /// Describe a oneshot boot target. 304*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, PartialEq, Eq)] 305*5225e6b1SAndroid Build Coastguard Worker pub enum OneShot { 306*5225e6b1SAndroid Build Coastguard Worker /// The bootloader will stop in some kind of interactive mode. 307*5225e6b1SAndroid Build Coastguard Worker /// This can be Fastboot, a TUI boot menu, or something similar. 308*5225e6b1SAndroid Build Coastguard Worker Bootloader, 309*5225e6b1SAndroid Build Coastguard Worker /// The system will continue to the specified recovery target. 310*5225e6b1SAndroid Build Coastguard Worker Continue(RecoveryTarget), 311*5225e6b1SAndroid Build Coastguard Worker } 312*5225e6b1SAndroid Build Coastguard Worker 313*5225e6b1SAndroid Build Coastguard Worker /// Opaque boot token generated by `mark_boot_attempt` and consumed by `kernel_jump`. 314*5225e6b1SAndroid Build Coastguard Worker /// Used to mandate that `mark_boot_attempt` is called **exactly** once continuing boot. 315*5225e6b1SAndroid Build Coastguard Worker /// 316*5225e6b1SAndroid Build Coastguard Worker /// Custom structs that implement Manager should take a BootToken as an injected parameter 317*5225e6b1SAndroid Build Coastguard Worker /// on construction and return it on the first successful call to mark_boot_attempt. 318*5225e6b1SAndroid Build Coastguard Worker #[derive(Debug, PartialEq, Eq)] 319*5225e6b1SAndroid Build Coastguard Worker pub struct BootToken(pub(crate) ()); 320*5225e6b1SAndroid Build Coastguard Worker 321*5225e6b1SAndroid Build Coastguard Worker /// The boot slot manager trait. 322*5225e6b1SAndroid Build Coastguard Worker /// Responsible for setting boot slot policy and abstracting over on-disk/in-memory 323*5225e6b1SAndroid Build Coastguard Worker /// representation of slot metadata. 324*5225e6b1SAndroid Build Coastguard Worker pub trait Manager: private::SlotGet { 325*5225e6b1SAndroid Build Coastguard Worker /// Returns an iterator over all regular slots on the system. slots_iter(&self) -> SlotIterator326*5225e6b1SAndroid Build Coastguard Worker fn slots_iter(&self) -> SlotIterator; 327*5225e6b1SAndroid Build Coastguard Worker 328*5225e6b1SAndroid Build Coastguard Worker /// Returns the current active slot, 329*5225e6b1SAndroid Build Coastguard Worker /// or Recovery if the system will try to boot to recovery. get_boot_target(&self) -> Result<BootTarget, Error>330*5225e6b1SAndroid Build Coastguard Worker fn get_boot_target(&self) -> Result<BootTarget, Error>; 331*5225e6b1SAndroid Build Coastguard Worker 332*5225e6b1SAndroid Build Coastguard Worker /// Returns the slot last set active. 333*5225e6b1SAndroid Build Coastguard Worker /// Note that this is different from get_boot_target in that 334*5225e6b1SAndroid Build Coastguard Worker /// the slot last set active cannot be Recovery. get_slot_last_set_active(&self) -> Result<Slot, Error>335*5225e6b1SAndroid Build Coastguard Worker fn get_slot_last_set_active(&self) -> Result<Slot, Error> { 336*5225e6b1SAndroid Build Coastguard Worker self.slots_iter() 337*5225e6b1SAndroid Build Coastguard Worker .max_by_key(|slot| (slot.priority, slot.suffix.rank())) 338*5225e6b1SAndroid Build Coastguard Worker .ok_or(Error::Other(Some("Couldn't get slot last set active"))) 339*5225e6b1SAndroid Build Coastguard Worker } 340*5225e6b1SAndroid Build Coastguard Worker 341*5225e6b1SAndroid Build Coastguard Worker /// Updates internal metadata (usually the retry count) 342*5225e6b1SAndroid Build Coastguard Worker /// indicating that the system will have tried to boot the current active slot. 343*5225e6b1SAndroid Build Coastguard Worker /// Returns Ok(BootToken) on success to verify that boot attempt metadata has been updated. 344*5225e6b1SAndroid Build Coastguard Worker /// The token must be consumed by `kernel_jump`. 345*5225e6b1SAndroid Build Coastguard Worker /// 346*5225e6b1SAndroid Build Coastguard Worker /// If the current boot target is a recovery target, 347*5225e6b1SAndroid Build Coastguard Worker /// or if the oneshot target is a recovery target, 348*5225e6b1SAndroid Build Coastguard Worker /// no metadata is updated but the boot token is still returned. 349*5225e6b1SAndroid Build Coastguard Worker /// 350*5225e6b1SAndroid Build Coastguard Worker /// Returns Err if `mark_boot_attempt` has already been called. 351*5225e6b1SAndroid Build Coastguard Worker /// 352*5225e6b1SAndroid Build Coastguard Worker /// Note: mark_boot_attempt is NOT idempotent. 353*5225e6b1SAndroid Build Coastguard Worker /// It is intended to be called EXACTLY once, 354*5225e6b1SAndroid Build Coastguard Worker /// right before jumping into the kernel. mark_boot_attempt(&mut self) -> Result<BootToken, Error>355*5225e6b1SAndroid Build Coastguard Worker fn mark_boot_attempt(&mut self) -> Result<BootToken, Error>; 356*5225e6b1SAndroid Build Coastguard Worker 357*5225e6b1SAndroid Build Coastguard Worker /// Attempts to set the active slot. 358*5225e6b1SAndroid Build Coastguard Worker /// 359*5225e6b1SAndroid Build Coastguard Worker /// Can return Err if the designated slot does not exist, 360*5225e6b1SAndroid Build Coastguard Worker /// if the bootloader does not have permission to set slots active, 361*5225e6b1SAndroid Build Coastguard Worker /// or for other, backend policy reasons. set_active_slot(&mut self, slot_suffix: Suffix) -> Result<(), Error>362*5225e6b1SAndroid Build Coastguard Worker fn set_active_slot(&mut self, slot_suffix: Suffix) -> Result<(), Error>; 363*5225e6b1SAndroid Build Coastguard Worker 364*5225e6b1SAndroid Build Coastguard Worker /// Attempts to mark a slot as unbootable. set_slot_unbootable( &mut self, slot_suffix: Suffix, reason: UnbootableReason, ) -> Result<(), Error>365*5225e6b1SAndroid Build Coastguard Worker fn set_slot_unbootable( 366*5225e6b1SAndroid Build Coastguard Worker &mut self, 367*5225e6b1SAndroid Build Coastguard Worker slot_suffix: Suffix, 368*5225e6b1SAndroid Build Coastguard Worker reason: UnbootableReason, 369*5225e6b1SAndroid Build Coastguard Worker ) -> Result<(), Error>; 370*5225e6b1SAndroid Build Coastguard Worker 371*5225e6b1SAndroid Build Coastguard Worker /// Default for initial tries get_max_retries(&self) -> Result<Tries, Error>372*5225e6b1SAndroid Build Coastguard Worker fn get_max_retries(&self) -> Result<Tries, Error> { 373*5225e6b1SAndroid Build Coastguard Worker Ok(7u8.into()) 374*5225e6b1SAndroid Build Coastguard Worker } 375*5225e6b1SAndroid Build Coastguard Worker 376*5225e6b1SAndroid Build Coastguard Worker /// Optional oneshot boot support 377*5225e6b1SAndroid Build Coastguard Worker 378*5225e6b1SAndroid Build Coastguard Worker /// Gets the current oneshot boot status, 379*5225e6b1SAndroid Build Coastguard Worker /// or None if the system will try to boot normally. 380*5225e6b1SAndroid Build Coastguard Worker /// 381*5225e6b1SAndroid Build Coastguard Worker /// Oneshots are a special feature for temporarily bypassing 382*5225e6b1SAndroid Build Coastguard Worker /// normal boot flow logic. 383*5225e6b1SAndroid Build Coastguard Worker /// This can be used as part of device flashing, for tests, or interactive development. get_oneshot_status(&self) -> Option<OneShot>384*5225e6b1SAndroid Build Coastguard Worker fn get_oneshot_status(&self) -> Option<OneShot> { 385*5225e6b1SAndroid Build Coastguard Worker None 386*5225e6b1SAndroid Build Coastguard Worker } 387*5225e6b1SAndroid Build Coastguard Worker 388*5225e6b1SAndroid Build Coastguard Worker /// Attempts to set the oneshot boot status. 389*5225e6b1SAndroid Build Coastguard Worker /// 390*5225e6b1SAndroid Build Coastguard Worker /// Returns Err if the system does not support oneshot boot, 391*5225e6b1SAndroid Build Coastguard Worker /// if the designated slot does not exist, 392*5225e6b1SAndroid Build Coastguard Worker /// or for other, backend reasons. set_oneshot_status(&mut self, _: OneShot) -> Result<(), Error>393*5225e6b1SAndroid Build Coastguard Worker fn set_oneshot_status(&mut self, _: OneShot) -> Result<(), Error> { 394*5225e6b1SAndroid Build Coastguard Worker Err(Error::OperationProhibited) 395*5225e6b1SAndroid Build Coastguard Worker } 396*5225e6b1SAndroid Build Coastguard Worker 397*5225e6b1SAndroid Build Coastguard Worker /// Clears the oneshot status. clear_oneshot_status(&mut self)398*5225e6b1SAndroid Build Coastguard Worker fn clear_oneshot_status(&mut self); 399*5225e6b1SAndroid Build Coastguard Worker 400*5225e6b1SAndroid Build Coastguard Worker /// If the slot manager caches changes before writing to a backing store, 401*5225e6b1SAndroid Build Coastguard Worker /// writes back and sets the cache status to clean. 402*5225e6b1SAndroid Build Coastguard Worker /// The implementation is responsible for handling any errors, 403*5225e6b1SAndroid Build Coastguard Worker /// e.g. ignoring, logging, or aborting. 404*5225e6b1SAndroid Build Coastguard Worker /// 405*5225e6b1SAndroid Build Coastguard Worker /// This is useful for partition based slot setups, 406*5225e6b1SAndroid Build Coastguard Worker /// where we do not write back every interaction in order to coalesce writes 407*5225e6b1SAndroid Build Coastguard Worker /// and preserve disk lifetime. write_back(&mut self, _: &mut dyn FnMut(&mut [u8]) -> Result<(), Error>)408*5225e6b1SAndroid Build Coastguard Worker fn write_back(&mut self, _: &mut dyn FnMut(&mut [u8]) -> Result<(), Error>) {} 409*5225e6b1SAndroid Build Coastguard Worker } 410*5225e6b1SAndroid Build Coastguard Worker 411*5225e6b1SAndroid Build Coastguard Worker /// RAII helper object for coalescing changes. 412*5225e6b1SAndroid Build Coastguard Worker pub struct Cursor<'a> { 413*5225e6b1SAndroid Build Coastguard Worker /// The backing manager for slot metadata. 414*5225e6b1SAndroid Build Coastguard Worker pub ctx: &'a mut dyn Manager, 415*5225e6b1SAndroid Build Coastguard Worker /// User provided closure for persisting slot metadata bytes. 416*5225e6b1SAndroid Build Coastguard Worker pub persist: &'a mut dyn FnMut(&mut [u8]) -> Result<(), Error>, 417*5225e6b1SAndroid Build Coastguard Worker } 418*5225e6b1SAndroid Build Coastguard Worker 419*5225e6b1SAndroid Build Coastguard Worker impl Drop for Cursor<'_> { drop(&mut self)420*5225e6b1SAndroid Build Coastguard Worker fn drop(&mut self) { 421*5225e6b1SAndroid Build Coastguard Worker self.ctx.write_back(&mut self.persist); 422*5225e6b1SAndroid Build Coastguard Worker } 423*5225e6b1SAndroid Build Coastguard Worker } 424*5225e6b1SAndroid Build Coastguard Worker 425*5225e6b1SAndroid Build Coastguard Worker /// Contains information of the platform's slot scheme. 426*5225e6b1SAndroid Build Coastguard Worker #[derive(Default, Debug, Copy, Clone)] 427*5225e6b1SAndroid Build Coastguard Worker pub struct SlotsMetadata { 428*5225e6b1SAndroid Build Coastguard Worker /// Number of slots on this platform. 429*5225e6b1SAndroid Build Coastguard Worker pub slot_count: usize, 430*5225e6b1SAndroid Build Coastguard Worker } 431*5225e6b1SAndroid Build Coastguard Worker 432*5225e6b1SAndroid Build Coastguard Worker #[cfg(test)] 433*5225e6b1SAndroid Build Coastguard Worker mod test { 434*5225e6b1SAndroid Build Coastguard Worker use super::*; 435*5225e6b1SAndroid Build Coastguard Worker use core::ffi::CStr; 436*5225e6b1SAndroid Build Coastguard Worker 437*5225e6b1SAndroid Build Coastguard Worker #[test] test_suffix_to_cstr()438*5225e6b1SAndroid Build Coastguard Worker fn test_suffix_to_cstr() { 439*5225e6b1SAndroid Build Coastguard Worker let normal: Suffix = 'a'.into(); 440*5225e6b1SAndroid Build Coastguard Worker let normal_buffer: SuffixBytes = normal.into(); 441*5225e6b1SAndroid Build Coastguard Worker let normal_cstr = CStr::from_bytes_until_nul(&normal_buffer); 442*5225e6b1SAndroid Build Coastguard Worker assert!(normal_cstr.is_ok()); 443*5225e6b1SAndroid Build Coastguard Worker 444*5225e6b1SAndroid Build Coastguard Worker // All UTF-8 characters are at most 4 bytes. 445*5225e6b1SAndroid Build Coastguard Worker // The in-memory representation as a chr or Suffix 446*5225e6b1SAndroid Build Coastguard Worker // uses all 4 bytes regardless of the length of the serialized 447*5225e6b1SAndroid Build Coastguard Worker // representation, but we need to make sure that buffer for 448*5225e6b1SAndroid Build Coastguard Worker // the serialized suffix can handle that too. 449*5225e6b1SAndroid Build Coastguard Worker // All emoji are 4 bytes when encoded as UTF-8, 450*5225e6b1SAndroid Build Coastguard Worker // so they're a reasonable test. 451*5225e6b1SAndroid Build Coastguard Worker let squid: Suffix = ''.into(); 452*5225e6b1SAndroid Build Coastguard Worker let squid_buffer: SuffixBytes = squid.into(); 453*5225e6b1SAndroid Build Coastguard Worker let squid_cstr = CStr::from_bytes_until_nul(&squid_buffer); 454*5225e6b1SAndroid Build Coastguard Worker assert!(squid_cstr.is_ok()); 455*5225e6b1SAndroid Build Coastguard Worker } 456*5225e6b1SAndroid Build Coastguard Worker } 457