diff options
| author | Badr Bouslikhin <[email protected]> | 2024-02-11 20:02:28 +0100 |
|---|---|---|
| committer | Badr Bouslikhin <[email protected]> | 2024-02-11 20:16:17 +0100 |
| commit | eb3bd39b068ae34892520ec38f111704ea357355 (patch) | |
| tree | 7014d70ee32db54af4b229c6edbf3818080064c0 /embassy-boot/src/firmware_updater/blocking.rs | |
| parent | 72ab04c45335ceb725076a38a252749e781a8cf6 (diff) | |
feat(boot): enhance firmware write functionality
Diffstat (limited to 'embassy-boot/src/firmware_updater/blocking.rs')
| -rw-r--r-- | embassy-boot/src/firmware_updater/blocking.rs | 70 |
1 files changed, 62 insertions, 8 deletions
diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index 4044871f0..45ae966f3 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs | |||
| @@ -207,20 +207,69 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> | |||
| 207 | self.state.mark_booted() | 207 | self.state.mark_booted() |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | /// Write data to a flash page. | 210 | /// Writes firmware data to the device. |
| 211 | /// | 211 | /// |
| 212 | /// The buffer must follow alignment requirements of the target flash and a multiple of page size big. | 212 | /// This function writes the given data to the firmware area starting at the specified offset. |
| 213 | /// It handles sector erasures and data writes while verifying the device is in a proper state | ||
| 214 | /// for firmware updates. The function ensures that only unerased sectors are erased before | ||
| 215 | /// writing and efficiently handles the writing process across sector boundaries and in | ||
| 216 | /// various configurations (data size, page size, etc.). | ||
| 213 | /// | 217 | /// |
| 214 | /// # Safety | 218 | /// # Arguments |
| 219 | /// | ||
| 220 | /// * `offset` - The starting offset within the firmware area where data writing should begin. | ||
| 221 | /// * `data` - A slice of bytes representing the firmware data to be written. It must be a | ||
| 222 | /// multiple of NorFlash WRITE_SIZE. | ||
| 223 | /// | ||
| 224 | /// # Returns | ||
| 225 | /// | ||
| 226 | /// A `Result<(), FirmwareUpdaterError>` indicating the success or failure of the write operation. | ||
| 227 | /// | ||
| 228 | /// # Errors | ||
| 229 | /// | ||
| 230 | /// This function will return an error if: | ||
| 215 | /// | 231 | /// |
| 216 | /// Failing to meet alignment and size requirements may result in a panic. | 232 | /// - The device is not in a proper state to receive firmware updates (e.g., not booted). |
| 233 | /// - There is a failure erasing a sector before writing. | ||
| 234 | /// - There is a failure writing data to the device. | ||
| 217 | pub fn write_firmware(&mut self, offset: usize, data: &[u8]) -> Result<(), FirmwareUpdaterError> { | 235 | pub fn write_firmware(&mut self, offset: usize, data: &[u8]) -> Result<(), FirmwareUpdaterError> { |
| 218 | assert!(data.len() >= DFU::ERASE_SIZE); | 236 | // Make sure we are running a booted firmware to avoid reverting to a bad state. |
| 219 | self.state.verify_booted()?; | 237 | self.state.verify_booted()?; |
| 220 | 238 | ||
| 221 | self.dfu.erase(offset as u32, (offset + data.len()) as u32)?; | 239 | // Initialize variables to keep track of the remaining data and the current offset. |
| 240 | let mut remaining_data = data; | ||
| 241 | let mut offset = offset; | ||
| 242 | |||
| 243 | // Continue writing as long as there is data left to write. | ||
| 244 | while !remaining_data.is_empty() { | ||
| 245 | // Compute the current sector and its boundaries. | ||
| 246 | let current_sector = offset / DFU::ERASE_SIZE; | ||
| 247 | let sector_start = current_sector * DFU::ERASE_SIZE; | ||
| 248 | let sector_end = sector_start + DFU::ERASE_SIZE; | ||
| 249 | // Determine if the current sector needs to be erased before writing. | ||
| 250 | let need_erase = self | ||
| 251 | .state | ||
| 252 | .last_erased_dfu_page_index | ||
| 253 | .map_or(true, |last_erased_sector| current_sector != last_erased_sector); | ||
| 254 | |||
| 255 | // If the sector needs to be erased, erase it and update the last erased sector index. | ||
| 256 | if need_erase { | ||
| 257 | self.dfu.erase(sector_start as u32, sector_end as u32)?; | ||
| 258 | self.state.last_erased_dfu_page_index = Some(current_sector); | ||
| 259 | } | ||
| 260 | |||
| 261 | // Calculate the size of the data chunk that can be written in the current iteration. | ||
| 262 | let write_size = core::cmp::min(remaining_data.len(), sector_end - offset); | ||
| 263 | // Split the data to get the current chunk to be written and the remaining data. | ||
| 264 | let (data_chunk, rest) = remaining_data.split_at(write_size); | ||
| 265 | |||
| 266 | // Write the current data chunk. | ||
| 267 | self.dfu.write(offset as u32, data_chunk)?; | ||
| 222 | 268 | ||
| 223 | self.dfu.write(offset as u32, data)?; | 269 | // Update the offset and remaining data for the next iteration. |
| 270 | remaining_data = rest; | ||
| 271 | offset += write_size; | ||
| 272 | } | ||
| 224 | 273 | ||
| 225 | Ok(()) | 274 | Ok(()) |
| 226 | } | 275 | } |
| @@ -244,6 +293,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> | |||
| 244 | pub struct BlockingFirmwareState<'d, STATE> { | 293 | pub struct BlockingFirmwareState<'d, STATE> { |
| 245 | state: STATE, | 294 | state: STATE, |
| 246 | aligned: &'d mut [u8], | 295 | aligned: &'d mut [u8], |
| 296 | last_erased_dfu_page_index: Option<usize>, | ||
| 247 | } | 297 | } |
| 248 | 298 | ||
| 249 | impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { | 299 | impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { |
| @@ -265,7 +315,11 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { | |||
| 265 | /// and written to. | 315 | /// and written to. |
| 266 | pub fn new(state: STATE, aligned: &'d mut [u8]) -> Self { | 316 | pub fn new(state: STATE, aligned: &'d mut [u8]) -> Self { |
| 267 | assert_eq!(aligned.len(), STATE::WRITE_SIZE); | 317 | assert_eq!(aligned.len(), STATE::WRITE_SIZE); |
| 268 | Self { state, aligned } | 318 | Self { |
| 319 | state, | ||
| 320 | aligned, | ||
| 321 | last_erased_dfu_page_index: None, | ||
| 322 | } | ||
| 269 | } | 323 | } |
| 270 | 324 | ||
| 271 | // Make sure we are running a booted firmware to avoid reverting to a bad state. | 325 | // Make sure we are running a booted firmware to avoid reverting to a bad state. |
