xref: /aosp_15_r20/bootable/libbootloader/gbl/libgbl/src/slots.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
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