@@ -145,6 +145,11 @@ enum Trace {
145145 #[ count( children) ]
146146 message : SpToHost ,
147147 } ,
148+ APOBWriteError {
149+ offset : u64 ,
150+ #[ count( children) ]
151+ err : APOBError ,
152+ } ,
148153}
149154
150155counted_ringbuf ! ( Trace , 20 , Trace :: None ) ;
@@ -171,6 +176,31 @@ enum Timers {
171176 TxPeriodicZeroByte ,
172177}
173178
179+ #[ derive( Copy , Clone , Debug , Eq , PartialEq , counters:: Count ) ]
180+ enum APOBError {
181+ OffsetOverflow {
182+ offset : u64 ,
183+ } ,
184+ NotErased {
185+ offset : u32 ,
186+ } ,
187+ EraseFailed {
188+ offset : u32 ,
189+ #[ count( children) ]
190+ err : drv_hf_api:: HfError ,
191+ } ,
192+ WriteFailed {
193+ offset : u32 ,
194+ #[ count( children) ]
195+ err : drv_hf_api:: HfError ,
196+ } ,
197+ ReadFailed {
198+ offset : u32 ,
199+ #[ count( children) ]
200+ err : drv_hf_api:: HfError ,
201+ } ,
202+ }
203+
174204#[ export_name = "main" ]
175205fn main ( ) -> ! {
176206 let mut server = ServerImpl :: claim_static_resources ( ) ;
@@ -993,6 +1023,15 @@ impl ServerImpl {
9931023 } ) ,
9941024 }
9951025 }
1026+ HostToSp :: APOB { offset } => {
1027+ Some ( match Self :: apob_write ( & self . hf , offset, data) {
1028+ Ok ( ( ) ) => SpToHost :: APOBResult ( 0 ) ,
1029+ Err ( err) => {
1030+ ringbuf_entry ! ( Trace :: APOBWriteError { offset, err } ) ;
1031+ SpToHost :: APOBResult ( 1 )
1032+ }
1033+ } )
1034+ }
9961035 } ;
9971036
9981037 if let Some ( response) = response {
@@ -1021,6 +1060,51 @@ impl ServerImpl {
10211060 Ok ( ( ) )
10221061 }
10231062
1063+ /// Write data to the bonus region of flash
1064+ ///
1065+ /// This does not take `&self` because we need to force a split borrow
1066+ fn apob_write (
1067+ hf : & HostFlash ,
1068+ mut offset : u64 ,
1069+ data : & [ u8 ] ,
1070+ ) -> Result < ( ) , APOBError > {
1071+ for chunk in data. chunks ( drv_hf_api:: PAGE_SIZE_BYTES ) {
1072+ Self :: apob_write_page (
1073+ hf,
1074+ offset
1075+ . try_into ( )
1076+ . map_err ( |_| APOBError :: OffsetOverflow { offset } ) ?,
1077+ chunk,
1078+ ) ?;
1079+ offset += chunk. len ( ) as u64 ;
1080+ }
1081+ Ok ( ( ) )
1082+ }
1083+
1084+ /// Write a single page of data to the bonus region of flash
1085+ ///
1086+ /// This does not take `&self` because we need to force a split borrow
1087+ fn apob_write_page (
1088+ hf : & HostFlash ,
1089+ offset : u32 ,
1090+ data : & [ u8 ] ,
1091+ ) -> Result < ( ) , APOBError > {
1092+ if offset as usize % drv_hf_api:: SECTOR_SIZE_BYTES == 0 {
1093+ hf. bonus_sector_erase ( offset)
1094+ . map_err ( |err| APOBError :: EraseFailed { offset, err } ) ?;
1095+ } else {
1096+ // Read back the page and confirm that it's all empty
1097+ let mut scratch = [ 0u8 ; drv_hf_api:: PAGE_SIZE_BYTES ] ;
1098+ hf. bonus_read ( offset, & mut scratch[ ..data. len ( ) ] )
1099+ . map_err ( |err| APOBError :: ReadFailed { offset, err } ) ?;
1100+ if !scratch[ ..data. len ( ) ] . iter ( ) . all ( |b| * b == 0xFF ) {
1101+ return Err ( APOBError :: NotErased { offset } ) ;
1102+ }
1103+ }
1104+ hf. bonus_page_program ( offset, data)
1105+ . map_err ( |err| APOBError :: WriteFailed { offset, err } )
1106+ }
1107+
10241108 fn handle_sprot (
10251109 & mut self ,
10261110 sequence : u64 ,
0 commit comments