1- use std:: { fmt:: Display , str:: FromStr } ;
1+ use std:: { fmt:: Display , fs , path :: Path , str:: FromStr } ;
22
33use derive_more:: Display ;
44use efivar:: EfiVarData ;
5- use orb_info:: orb_os_release:: OrbOsPlatform ;
65
76pub type Result < T > = std:: result:: Result < T , Error > ;
87
@@ -14,16 +13,16 @@ pub enum Error {
1413 InvalidEfiVarLen { expected : usize , actual : usize } ,
1514 #[ error( "invalid slot configuration" ) ]
1615 InvalidSlotData ,
16+ #[ error( "invalid bootchain-firmware status" ) ]
17+ InvalidBootChainFwStatusData ,
1718 #[ error( "invalid rootfs status" ) ]
1819 InvalidRootFsStatusData ,
19- #[ error( "failed reading scratch register: {0}" ) ]
20- CouldNotReadScratchReg ( String ) ,
20+ #[ error( "failed opening scratch register: {0}" ) ]
21+ CouldNotOpenScratchReg ( String ) ,
2122 #[ error( "invalid retry counter({counter}), exceeding the maximum ({max})" ) ]
2223 ExceedingRetryCount { counter : u8 , max : u8 } ,
2324 #[ error( "{0}" ) ]
2425 EfiVar ( #[ from] color_eyre:: Report ) ,
25- #[ error( "unsupported orb type: {0}" ) ]
26- UnsupportedOrbType ( OrbOsPlatform ) ,
2726}
2827
2928#[ derive( Debug , Clone , Copy , PartialEq , Eq , Display ) ]
@@ -95,13 +94,14 @@ impl TryFrom<u8> for BootChainFwStatus {
9594 16 => Ok ( Self :: ErrorSettingScratch ) ,
9695 17 => Ok ( Self :: ErrorUpdateBrBctFlagSet ) ,
9796 18 => Ok ( Self :: ErrorSettingPrevious ) ,
98- _ => Err ( Error :: InvalidRootFsStatusData ) ,
97+ _ => Err ( Error :: InvalidBootChainFwStatusData ) ,
9998 }
10099 }
101100}
102101
103102/// Representation of the slot.
104103#[ derive( Clone , Copy , Debug , PartialEq , Eq , Display ) ]
104+ #[ repr( u8 ) ]
105105pub enum Slot {
106106 #[ display( "a" ) ]
107107 A = 0 ,
@@ -111,38 +111,28 @@ pub enum Slot {
111111
112112/// Representation of the rootfs status.
113113#[ derive( Debug , PartialEq , Eq , Clone , Copy , Display ) ]
114+ #[ repr( u8 ) ]
114115pub enum RootFsStatus {
115116 /// Default status of the rootfs.
116- Normal ,
117- /// Status of the rootfs where the partitions during an update are written.
118- UpdateInProcess ,
119- /// Status of the rootfs where the boot slot was just switched to it.
120- UpdateDone ,
121- /// Status of the rootfs is considered unbootable.
122- Unbootable ,
117+ Normal = 0x0 ,
118+ /// Rootfs status signifying that an update consumption has initiated
119+ UpdateInProcess = 0x1 ,
120+ /// Rootfs status signifying that an update was done & active slot switched
121+ UpdateDone = 0x2 ,
122+ /// Rootfs status signifying that the target slot is considered unbootable.
123+ Unbootable = 0x3 ,
123124}
124125
125126#[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
126127pub struct RetryCounts {
127- pub efi_var : Option < EfiRetryCount > ,
128- pub scratch_reg : Option < ScratchRegRetryCount > ,
128+ pub efi_var : EfiRetryCount ,
129+ pub sr_rf : ScratchRegRetryCount ,
129130}
130131
131132impl Display for RetryCounts {
132133 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
133- const NA : & str = "unavailable in this platform" ;
134-
135- write ! ( f, "efi var: " ) ?;
136- match self . efi_var {
137- Some ( v) => write ! ( f, "{v}" ) ?,
138- None => write ! ( f, "{NA}" ) ?,
139- } ;
140-
141- write ! ( f, "\n scratch register: " ) ?;
142- match self . scratch_reg {
143- Some ( v) => write ! ( f, "{v}" ) ?,
144- None => write ! ( f, "{NA}" ) ?,
145- } ;
134+ writeln ! ( f, "efi var: {}" , & self . efi_var) ?;
135+ writeln ! ( f, "SR_RF: {}" , & self . sr_rf) ?;
146136
147137 Ok ( ( ) )
148138 }
@@ -152,10 +142,32 @@ impl Display for RetryCounts {
152142pub struct ScratchRegRetryCount ( pub u8 ) ;
153143
154144impl ScratchRegRetryCount {
155- pub ( crate ) const DIAMOND_COUNT_A_PATH : & str =
145+ pub ( crate ) const DIAMOND_REG_PATH_A : & str =
156146 "sys/devices/platform/bus@0/c360000.pmc/rootfs_retry_count_a" ;
157- pub ( crate ) const DIAMOND_COUNT_B_PATH : & str =
147+ pub ( crate ) const DIAMOND_REG_PATH_B : & str =
158148 "sys/devices/platform/bus@0/c360000.pmc/rootfs_retry_count_b" ;
149+ pub ( crate ) const PEARL_REG_PATH_A : & str =
150+ "sys/devices/platform/c360000.pmc/rootfs_retry_count_a" ;
151+ pub ( crate ) const PEARL_REG_PATH_B : & str =
152+ "sys/devices/platform/c360000.pmc/rootfs_retry_count_b" ;
153+ pub ( crate ) const SR_RF_COUNT_MAX : u8 = 0x3 ;
154+
155+ pub ( crate ) fn new ( sr_rf_path : impl AsRef < Path > ) -> Result < Self > {
156+ let raw = fs:: read_to_string ( sr_rf_path)
157+ . map_err ( |e| Error :: CouldNotOpenScratchReg ( e. to_string ( ) ) ) ?;
158+
159+ let hex = raw. trim ( ) . strip_prefix ( "0x" ) . ok_or_else ( || {
160+ Error :: CouldNotOpenScratchReg ( format ! (
161+ "scratch register retry count in unexpected format: {raw}"
162+ ) )
163+ } ) ?;
164+
165+ let count = hex
166+ . parse :: < u8 > ( )
167+ . map_err ( |e| Error :: CouldNotOpenScratchReg ( format ! ( "{e}: '{hex}'" ) ) ) ?;
168+
169+ Ok ( ScratchRegRetryCount ( count) )
170+ }
159171}
160172
161173#[ derive( Clone , Copy , Debug , PartialEq , Eq , Display ) ]
@@ -201,8 +213,8 @@ impl FromStr for Slot {
201213}
202214
203215impl Slot {
204- pub ( crate ) const SLOT_A_BYTES : [ u8 ; 4 ] = [ 0x00 , 0x00 , 0x00 , 0x00 ] ;
205- pub ( crate ) const SLOT_B_BYTES : [ u8 ; 4 ] = [ 0x01 , 0x00 , 0x00 , 0x00 ] ;
216+ const SLOT_A_BYTES : [ u8 ; 4 ] = [ 0x00 , 0x00 , 0x00 , 0x00 ] ;
217+ const SLOT_B_BYTES : [ u8 ; 4 ] = [ 0x01 , 0x00 , 0x00 , 0x00 ] ;
206218
207219 pub ( crate ) const CURRENT_SLOT_PATH : & str =
208220 "BootChainFwCurrent-781e084c-a330-417c-b678-38e696380cb9" ;
@@ -215,12 +227,17 @@ impl Slot {
215227 }
216228
217229 pub fn from_efivar_data ( data : & EfiVarData ) -> Result < Slot > {
218- if Slot :: SLOT_A_BYTES == data. value ( ) {
219- Ok ( Slot :: A )
220- } else if Slot :: SLOT_B_BYTES == data. value ( ) {
221- Ok ( Slot :: B )
222- } else {
223- Err ( Error :: InvalidSlotData )
230+ if data. len ( ) != 8 {
231+ return Err ( Error :: InvalidEfiVarLen {
232+ expected : 8 ,
233+ actual : data. len ( ) ,
234+ } ) ;
235+ }
236+
237+ match data. value ( ) {
238+ val if val == Self :: SLOT_A_BYTES => Ok ( Slot :: A ) ,
239+ val if val == Self :: SLOT_B_BYTES => Ok ( Slot :: B ) ,
240+ _ => Err ( Error :: InvalidSlotData ) ,
224241 }
225242 }
226243}
@@ -231,83 +248,43 @@ impl FromStr for RootFsStatus {
231248 fn from_str ( s : & str ) -> Result < Self > {
232249 match s. to_lowercase ( ) . as_str ( ) {
233250 "normal" | "0" => Ok ( RootFsStatus :: Normal ) ,
234- "updateinprocess" | "updinprocess" | "1" => {
235- Ok ( RootFsStatus :: UpdateInProcess )
236- }
237- "updatedone" | "upddone" | "2" => Ok ( RootFsStatus :: UpdateDone ) ,
251+ "updateinprocess" | "1" => Ok ( RootFsStatus :: UpdateInProcess ) ,
252+ "updatedone" | "2" => Ok ( RootFsStatus :: UpdateDone ) ,
238253 "unbootable" | "3" => Ok ( RootFsStatus :: Unbootable ) ,
239- _ => Err ( Error :: InvalidSlotData ) ,
254+ _ => Err ( Error :: InvalidRootFsStatusData ) ,
240255 }
241256 }
242257}
243258
244259impl RootFsStatus {
245- // Right now Pearl has extra states in the update status, some thing
246- // we will probably get rid of in the future. Values were also altered and are
247- // different than the default NVIDIA ones (used by Diamond)
248- // https://github.com/worldcoin/edk2-nvidia/blob/ede09eb66b00d5d185ba93b7992390f2a483b46f/Silicon/NVIDIA/Include/NVIDIAConfiguration.h#L23
249- pub ( crate ) const PEARL_NORMAL : [ u8 ; 4 ] = [ 0x00 , 0x00 , 0x00 , 0x00 ] ;
250- pub ( crate ) const PEARL_UPDATE_IN_PROGRESS : [ u8 ; 4 ] = [ 0x01 , 0x00 , 0x00 , 0x00 ] ;
251- pub ( crate ) const PEARL_UPDATE_DONE : [ u8 ; 4 ] = [ 0x02 , 0x00 , 0x00 , 0x00 ] ;
252- pub ( crate ) const PEARL_UNBOOTABLE : [ u8 ; 4 ] = [ 0x03 , 0x00 , 0x00 , 0x00 ] ;
253-
254- // https://github.com/worldcoin/edk2-nvidia/blob/86a32d95373d6aaf87278093a855ccf193b9c61f/Silicon/NVIDIA/Include/NVIDIAConfiguration.h#L23
255- pub ( crate ) const DIAMOND_NORMAL : [ u8 ; 4 ] = [ 0x00 , 0x00 , 0x00 , 0x00 ] ;
256- pub ( crate ) const DIAMOND_UNBOOTABLE : [ u8 ; 4 ] = [ 0xFF , 0x00 , 0x00 , 0x00 ] ;
260+ const NORMAL : [ u8 ; 4 ] = [ 0x00 , 0x00 , 0x00 , 0x00 ] ;
261+ const UPDATE_IN_PROGRESS : [ u8 ; 4 ] = [ 0x01 , 0x00 , 0x00 , 0x00 ] ;
262+ const UPDATE_DONE : [ u8 ; 4 ] = [ 0x02 , 0x00 , 0x00 , 0x00 ] ;
263+ const UNBOOTABLE : [ u8 ; 4 ] = [ 0x03 , 0x00 , 0x00 , 0x00 ] ;
257264
258265 pub ( crate ) const STATUS_A_PATH : & str =
259266 "RootfsStatusSlotA-781e084c-a330-417c-b678-38e696380cb9" ;
260267 pub ( crate ) const STATUS_B_PATH : & str =
261268 "RootfsStatusSlotB-781e084c-a330-417c-b678-38e696380cb9" ;
262269
263- pub fn to_efivar_data ( & self , orb : OrbOsPlatform ) -> Result < EfiVarData > {
264- let value = match ( self , orb) {
265- ( Self :: Normal , OrbOsPlatform :: Pearl ) => & Self :: PEARL_NORMAL ,
266- ( Self :: UpdateInProcess , OrbOsPlatform :: Pearl ) => {
267- & Self :: PEARL_UPDATE_IN_PROGRESS
268- }
269- ( Self :: UpdateDone , OrbOsPlatform :: Pearl ) => & Self :: PEARL_UPDATE_DONE ,
270- ( Self :: Unbootable , OrbOsPlatform :: Pearl ) => & Self :: PEARL_UNBOOTABLE ,
271- ( Self :: Normal , OrbOsPlatform :: Diamond ) => & Self :: DIAMOND_NORMAL ,
272- ( Self :: Unbootable , OrbOsPlatform :: Diamond ) => & Self :: DIAMOND_UNBOOTABLE ,
273- _ => return Err ( Error :: InvalidRootFsStatusData ) ,
274- } ;
275-
276- Ok ( EfiVarData :: new ( 0x7 , value) )
270+ pub fn to_efivar_data ( & self ) -> EfiVarData {
271+ EfiVarData :: new ( 0x7 , [ * self as u8 , 0x0 , 0x0 , 0x0 ] )
277272 }
278273
279274 /// RootFsStatus from EfiVar raw bytes
280- pub fn from_efivar_data (
281- data : & EfiVarData ,
282- orb : OrbOsPlatform ,
283- ) -> Result < RootFsStatus > {
284- let bytes = data. value ( ) ;
285-
286- match orb {
287- OrbOsPlatform :: Pearl if bytes == Self :: PEARL_NORMAL => {
288- Ok ( RootFsStatus :: Normal )
289- }
290-
291- OrbOsPlatform :: Pearl if bytes == Self :: PEARL_UPDATE_IN_PROGRESS => {
292- Ok ( RootFsStatus :: UpdateInProcess )
293- }
294-
295- OrbOsPlatform :: Pearl if bytes == Self :: PEARL_UPDATE_DONE => {
296- Ok ( RootFsStatus :: UpdateDone )
297- }
298-
299- OrbOsPlatform :: Pearl if bytes == Self :: PEARL_UNBOOTABLE => {
300- Ok ( RootFsStatus :: Unbootable )
301- }
302-
303- OrbOsPlatform :: Diamond if bytes == Self :: DIAMOND_NORMAL => {
304- Ok ( RootFsStatus :: Normal )
305- }
306-
307- OrbOsPlatform :: Diamond if bytes == Self :: DIAMOND_UNBOOTABLE => {
308- Ok ( RootFsStatus :: Unbootable )
309- }
275+ pub fn from_efivar_data ( data : & EfiVarData ) -> Result < RootFsStatus > {
276+ if data. len ( ) != 8 {
277+ return Err ( Error :: InvalidEfiVarLen {
278+ expected : 8 ,
279+ actual : data. len ( ) ,
280+ } ) ;
281+ }
310282
283+ match data. value ( ) {
284+ val if val == Self :: NORMAL => Ok ( Self :: Normal ) ,
285+ val if val == Self :: UPDATE_IN_PROGRESS => Ok ( Self :: UpdateInProcess ) ,
286+ val if val == Self :: UPDATE_DONE => Ok ( Self :: UpdateDone ) ,
287+ val if val == Self :: UNBOOTABLE => Ok ( Self :: Unbootable ) ,
311288 _ => Err ( Error :: InvalidRootFsStatusData ) ,
312289 }
313290 }
0 commit comments