aboutsummaryrefslogtreecommitdiff
path: root/embassy-boot
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2023-12-14 19:56:04 +0000
committerGitHub <[email protected]>2023-12-14 19:56:04 +0000
commit5ec2fbe3a2ce3234ed6477fe5923c3d2425b55a7 (patch)
tree94b50831f7e5d606643eba7e0c9c1e5c7bf1ec86 /embassy-boot
parent485765320aaef82adbd4865b25e7171fb8f4041a (diff)
parent33e8943e5b6e637b82f13c77bd88bb56d55ab515 (diff)
Merge pull request #2284 from Redrield/feature/embassy-usb-dfu
Add embassy-usb-dfu crate, with related modifications to embassy-boot
Diffstat (limited to 'embassy-boot')
-rw-r--r--embassy-boot/boot/src/boot_loader.rs4
-rw-r--r--embassy-boot/boot/src/firmware_updater/asynch.rs23
-rw-r--r--embassy-boot/boot/src/firmware_updater/blocking.rs27
-rw-r--r--embassy-boot/boot/src/lib.rs3
-rw-r--r--embassy-boot/stm32/src/lib.rs9
5 files changed, 59 insertions, 7 deletions
diff --git a/embassy-boot/boot/src/boot_loader.rs b/embassy-boot/boot/src/boot_loader.rs
index 65b12dc5f..e568001bc 100644
--- a/embassy-boot/boot/src/boot_loader.rs
+++ b/embassy-boot/boot/src/boot_loader.rs
@@ -5,7 +5,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex;
5use embassy_sync::blocking_mutex::Mutex; 5use embassy_sync::blocking_mutex::Mutex;
6use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; 6use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind};
7 7
8use crate::{State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; 8use crate::{State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC};
9 9
10/// Errors returned by bootloader 10/// Errors returned by bootloader
11#[derive(PartialEq, Eq, Debug)] 11#[derive(PartialEq, Eq, Debug)]
@@ -371,6 +371,8 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S
371 371
372 if !state_word.iter().any(|&b| b != SWAP_MAGIC) { 372 if !state_word.iter().any(|&b| b != SWAP_MAGIC) {
373 Ok(State::Swap) 373 Ok(State::Swap)
374 } else if !state_word.iter().any(|&b| b != DFU_DETACH_MAGIC) {
375 Ok(State::DfuDetach)
374 } else { 376 } else {
375 Ok(State::Boot) 377 Ok(State::Boot)
376 } 378 }
diff --git a/embassy-boot/boot/src/firmware_updater/asynch.rs b/embassy-boot/boot/src/firmware_updater/asynch.rs
index ae713bb6f..d8d85c3d2 100644
--- a/embassy-boot/boot/src/firmware_updater/asynch.rs
+++ b/embassy-boot/boot/src/firmware_updater/asynch.rs
@@ -6,7 +6,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex;
6use embedded_storage_async::nor_flash::NorFlash; 6use embedded_storage_async::nor_flash::NorFlash;
7 7
8use super::FirmwareUpdaterConfig; 8use super::FirmwareUpdaterConfig;
9use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; 9use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC};
10 10
11/// FirmwareUpdater is an application API for interacting with the BootLoader without the ability to 11/// FirmwareUpdater is an application API for interacting with the BootLoader without the ability to
12/// 'mess up' the internal bootloader state 12/// 'mess up' the internal bootloader state
@@ -161,6 +161,12 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> {
161 self.state.mark_updated().await 161 self.state.mark_updated().await
162 } 162 }
163 163
164 /// Mark to trigger USB DFU on next boot.
165 pub async fn mark_dfu(&mut self) -> Result<(), FirmwareUpdaterError> {
166 self.state.verify_booted().await?;
167 self.state.mark_dfu().await
168 }
169
164 /// Mark firmware boot successful and stop rollback on reset. 170 /// Mark firmware boot successful and stop rollback on reset.
165 pub async fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { 171 pub async fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
166 self.state.mark_booted().await 172 self.state.mark_booted().await
@@ -207,6 +213,16 @@ pub struct FirmwareState<'d, STATE> {
207} 213}
208 214
209impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> { 215impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> {
216 /// Create a firmware state instance from a FirmwareUpdaterConfig with a buffer for magic content and state partition.
217 ///
218 /// # Safety
219 ///
220 /// The `aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being read from
221 /// and written to.
222 pub fn from_config<DFU: NorFlash>(config: FirmwareUpdaterConfig<DFU, STATE>, aligned: &'d mut [u8]) -> Self {
223 Self::new(config.state, aligned)
224 }
225
210 /// Create a firmware state instance with a buffer for magic content and state partition. 226 /// Create a firmware state instance with a buffer for magic content and state partition.
211 /// 227 ///
212 /// # Safety 228 /// # Safety
@@ -247,6 +263,11 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> {
247 self.set_magic(SWAP_MAGIC).await 263 self.set_magic(SWAP_MAGIC).await
248 } 264 }
249 265
266 /// Mark to trigger USB DFU on next boot.
267 pub async fn mark_dfu(&mut self) -> Result<(), FirmwareUpdaterError> {
268 self.set_magic(DFU_DETACH_MAGIC).await
269 }
270
250 /// Mark firmware boot successful and stop rollback on reset. 271 /// Mark firmware boot successful and stop rollback on reset.
251 pub async fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { 272 pub async fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
252 self.set_magic(BOOT_MAGIC).await 273 self.set_magic(BOOT_MAGIC).await
diff --git a/embassy-boot/boot/src/firmware_updater/blocking.rs b/embassy-boot/boot/src/firmware_updater/blocking.rs
index 76e4264a0..c4c142169 100644
--- a/embassy-boot/boot/src/firmware_updater/blocking.rs
+++ b/embassy-boot/boot/src/firmware_updater/blocking.rs
@@ -6,7 +6,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex;
6use embedded_storage::nor_flash::NorFlash; 6use embedded_storage::nor_flash::NorFlash;
7 7
8use super::FirmwareUpdaterConfig; 8use super::FirmwareUpdaterConfig;
9use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; 9use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC};
10 10
11/// Blocking FirmwareUpdater is an application API for interacting with the BootLoader without the ability to 11/// Blocking FirmwareUpdater is an application API for interacting with the BootLoader without the ability to
12/// 'mess up' the internal bootloader state 12/// 'mess up' the internal bootloader state
@@ -168,6 +168,12 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE>
168 self.state.mark_updated() 168 self.state.mark_updated()
169 } 169 }
170 170
171 /// Mark to trigger USB DFU device on next boot.
172 pub fn mark_dfu(&mut self) -> Result<(), FirmwareUpdaterError> {
173 self.state.verify_booted()?;
174 self.state.mark_dfu()
175 }
176
171 /// Mark firmware boot successful and stop rollback on reset. 177 /// Mark firmware boot successful and stop rollback on reset.
172 pub fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { 178 pub fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
173 self.state.mark_booted() 179 self.state.mark_booted()
@@ -213,6 +219,16 @@ pub struct BlockingFirmwareState<'d, STATE> {
213} 219}
214 220
215impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { 221impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> {
222 /// Creates a firmware state instance from a FirmwareUpdaterConfig, with a buffer for magic content and state partition.
223 ///
224 /// # Safety
225 ///
226 /// The `aligned` buffer must have a size of STATE::WRITE_SIZE, and follow the alignment rules for the flash being read from
227 /// and written to.
228 pub fn from_config<DFU: NorFlash>(config: FirmwareUpdaterConfig<DFU, STATE>, aligned: &'d mut [u8]) -> Self {
229 Self::new(config.state, aligned)
230 }
231
216 /// Create a firmware state instance with a buffer for magic content and state partition. 232 /// Create a firmware state instance with a buffer for magic content and state partition.
217 /// 233 ///
218 /// # Safety 234 /// # Safety
@@ -226,7 +242,7 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> {
226 242
227 // Make sure we are running a booted firmware to avoid reverting to a bad state. 243 // Make sure we are running a booted firmware to avoid reverting to a bad state.
228 fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> { 244 fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
229 if self.get_state()? == State::Boot { 245 if self.get_state()? == State::Boot || self.get_state()? == State::DfuDetach {
230 Ok(()) 246 Ok(())
231 } else { 247 } else {
232 Err(FirmwareUpdaterError::BadState) 248 Err(FirmwareUpdaterError::BadState)
@@ -243,6 +259,8 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> {
243 259
244 if !self.aligned.iter().any(|&b| b != SWAP_MAGIC) { 260 if !self.aligned.iter().any(|&b| b != SWAP_MAGIC) {
245 Ok(State::Swap) 261 Ok(State::Swap)
262 } else if !self.aligned.iter().any(|&b| b != DFU_DETACH_MAGIC) {
263 Ok(State::DfuDetach)
246 } else { 264 } else {
247 Ok(State::Boot) 265 Ok(State::Boot)
248 } 266 }
@@ -253,6 +271,11 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> {
253 self.set_magic(SWAP_MAGIC) 271 self.set_magic(SWAP_MAGIC)
254 } 272 }
255 273
274 /// Mark to trigger USB DFU on next boot.
275 pub fn mark_dfu(&mut self) -> Result<(), FirmwareUpdaterError> {
276 self.set_magic(DFU_DETACH_MAGIC)
277 }
278
256 /// Mark firmware boot successful and stop rollback on reset. 279 /// Mark firmware boot successful and stop rollback on reset.
257 pub fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> { 280 pub fn mark_booted(&mut self) -> Result<(), FirmwareUpdaterError> {
258 self.set_magic(BOOT_MAGIC) 281 self.set_magic(BOOT_MAGIC)
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs
index 9e70a4dca..15b69f69d 100644
--- a/embassy-boot/boot/src/lib.rs
+++ b/embassy-boot/boot/src/lib.rs
@@ -23,6 +23,7 @@ pub use firmware_updater::{
23 23
24pub(crate) const BOOT_MAGIC: u8 = 0xD0; 24pub(crate) const BOOT_MAGIC: u8 = 0xD0;
25pub(crate) const SWAP_MAGIC: u8 = 0xF0; 25pub(crate) const SWAP_MAGIC: u8 = 0xF0;
26pub(crate) const DFU_DETACH_MAGIC: u8 = 0xE0;
26 27
27/// The state of the bootloader after running prepare. 28/// The state of the bootloader after running prepare.
28#[derive(PartialEq, Eq, Debug)] 29#[derive(PartialEq, Eq, Debug)]
@@ -32,6 +33,8 @@ pub enum State {
32 Boot, 33 Boot,
33 /// Bootloader has swapped the active partition with the dfu partition and will attempt boot. 34 /// Bootloader has swapped the active partition with the dfu partition and will attempt boot.
34 Swap, 35 Swap,
36 /// Application has received a request to reboot into DFU mode to apply an update.
37 DfuDetach,
35} 38}
36 39
37/// Buffer aligned to 32 byte boundary, largest known alignment requirement for embassy-boot. 40/// Buffer aligned to 32 byte boundary, largest known alignment requirement for embassy-boot.
diff --git a/embassy-boot/stm32/src/lib.rs b/embassy-boot/stm32/src/lib.rs
index c418cb262..4b4091ac9 100644
--- a/embassy-boot/stm32/src/lib.rs
+++ b/embassy-boot/stm32/src/lib.rs
@@ -10,7 +10,10 @@ pub use embassy_boot::{
10use embedded_storage::nor_flash::NorFlash; 10use embedded_storage::nor_flash::NorFlash;
11 11
12/// A bootloader for STM32 devices. 12/// A bootloader for STM32 devices.
13pub struct BootLoader; 13pub struct BootLoader {
14 /// The reported state of the bootloader after preparing for boot
15 pub state: State,
16}
14 17
15impl BootLoader { 18impl BootLoader {
16 /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware 19 /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware
@@ -19,8 +22,8 @@ impl BootLoader {
19 ) -> Self { 22 ) -> Self {
20 let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]); 23 let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]);
21 let mut boot = embassy_boot::BootLoader::new(config); 24 let mut boot = embassy_boot::BootLoader::new(config);
22 boot.prepare_boot(aligned_buf.as_mut()).expect("Boot prepare error"); 25 let state = boot.prepare_boot(aligned_buf.as_mut()).expect("Boot prepare error");
23 Self 26 Self { state }
24 } 27 }
25 28
26 /// Boots the application. 29 /// Boots the application.