@@ -137,6 +137,11 @@ enum Trace {
137
137
#[ count( children) ]
138
138
message : SpToHost ,
139
139
} ,
140
+ APOBWriteError {
141
+ offset : u64 ,
142
+ #[ count( children) ]
143
+ err : APOBError ,
144
+ } ,
140
145
}
141
146
142
147
counted_ringbuf ! ( Trace , 20 , Trace :: None ) ;
@@ -163,6 +168,31 @@ enum Timers {
163
168
TxPeriodicZeroByte ,
164
169
}
165
170
171
+ #[ derive( Copy , Clone , Debug , Eq , PartialEq , counters:: Count ) ]
172
+ enum APOBError {
173
+ OffsetOverflow {
174
+ offset : u64 ,
175
+ } ,
176
+ NotErased {
177
+ offset : u32 ,
178
+ } ,
179
+ EraseFailed {
180
+ offset : u32 ,
181
+ #[ count( children) ]
182
+ err : drv_hf_api:: HfError ,
183
+ } ,
184
+ WriteFailed {
185
+ offset : u32 ,
186
+ #[ count( children) ]
187
+ err : drv_hf_api:: HfError ,
188
+ } ,
189
+ ReadFailed {
190
+ offset : u32 ,
191
+ #[ count( children) ]
192
+ err : drv_hf_api:: HfError ,
193
+ } ,
194
+ }
195
+
166
196
#[ export_name = "main" ]
167
197
fn main ( ) -> ! {
168
198
let mut server = ServerImpl :: claim_static_resources ( ) ;
@@ -965,6 +995,15 @@ impl ServerImpl {
965
995
} ) ,
966
996
}
967
997
}
998
+ HostToSp :: APOB { offset } => {
999
+ Some ( match Self :: apob_write ( & self . hf , offset, data) {
1000
+ Ok ( ( ) ) => SpToHost :: APOBResult ( 0 ) ,
1001
+ Err ( err) => {
1002
+ ringbuf_entry ! ( Trace :: APOBWriteError { offset, err } ) ;
1003
+ SpToHost :: APOBResult ( 1 )
1004
+ }
1005
+ } )
1006
+ }
968
1007
} ;
969
1008
970
1009
if let Some ( response) = response {
@@ -993,6 +1032,51 @@ impl ServerImpl {
993
1032
Ok ( ( ) )
994
1033
}
995
1034
1035
+ /// Write data to the bonus region of flash
1036
+ ///
1037
+ /// This does not take `&self` because we need to force a split borrow
1038
+ fn apob_write (
1039
+ hf : & HostFlash ,
1040
+ mut offset : u64 ,
1041
+ data : & [ u8 ] ,
1042
+ ) -> Result < ( ) , APOBError > {
1043
+ for chunk in data. chunks ( drv_hf_api:: PAGE_SIZE_BYTES ) {
1044
+ Self :: apob_write_page (
1045
+ hf,
1046
+ offset
1047
+ . try_into ( )
1048
+ . map_err ( |_| APOBError :: OffsetOverflow { offset } ) ?,
1049
+ chunk,
1050
+ ) ?;
1051
+ offset += chunk. len ( ) as u64 ;
1052
+ }
1053
+ Ok ( ( ) )
1054
+ }
1055
+
1056
+ /// Write a single page of data to the bonus region of flash
1057
+ ///
1058
+ /// This does not take `&self` because we need to force a split borrow
1059
+ fn apob_write_page (
1060
+ hf : & HostFlash ,
1061
+ offset : u32 ,
1062
+ data : & [ u8 ] ,
1063
+ ) -> Result < ( ) , APOBError > {
1064
+ if offset as usize % drv_hf_api:: SECTOR_SIZE_BYTES == 0 {
1065
+ hf. bonus_sector_erase ( offset)
1066
+ . map_err ( |err| APOBError :: EraseFailed { offset, err } ) ?;
1067
+ } else {
1068
+ // Read back the page and confirm that it's all empty
1069
+ let mut scratch = [ 0u8 ; drv_hf_api:: PAGE_SIZE_BYTES ] ;
1070
+ hf. bonus_read ( offset, & mut scratch[ ..data. len ( ) ] )
1071
+ . map_err ( |err| APOBError :: ReadFailed { offset, err } ) ?;
1072
+ if !scratch[ ..data. len ( ) ] . iter ( ) . all ( |b| * b == 0xFF ) {
1073
+ return Err ( APOBError :: NotErased { offset } ) ;
1074
+ }
1075
+ }
1076
+ hf. bonus_page_program ( offset, data)
1077
+ . map_err ( |err| APOBError :: WriteFailed { offset, err } )
1078
+ }
1079
+
996
1080
fn handle_sprot (
997
1081
& mut self ,
998
1082
sequence : u64 ,
0 commit comments