aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRasmus Melchior Jacobsen <[email protected]>2023-04-04 12:29:24 +0200
committerRasmus Melchior Jacobsen <[email protected]>2023-04-04 12:29:24 +0200
commitc38eb9660bc697bab40dd9aad97048db97618cf0 (patch)
tree9012e377cbfb9460dcd7a1bccd801ded6db525f2
parentdf3a1e1b9d337c17e08faf41c6e3c50c35eb9a6c (diff)
parent36ad82a52b540eec5e94052b08de8e8e6308f2ce (diff)
Merge remote-tracking branch 'upstream/master' into avoid-write-before-erase
-rw-r--r--embassy-boot/boot/src/firmware_updater.rs25
-rw-r--r--embassy-boot/boot/src/firmware_writer.rs55
-rw-r--r--embassy-boot/boot/src/lib.rs8
-rw-r--r--rust-toolchain.toml2
-rw-r--r--tests/nrf/src/bin/timer.rs25
5 files changed, 38 insertions, 77 deletions
diff --git a/embassy-boot/boot/src/firmware_updater.rs b/embassy-boot/boot/src/firmware_updater.rs
index fe3c0452f..2b5cc72fa 100644
--- a/embassy-boot/boot/src/firmware_updater.rs
+++ b/embassy-boot/boot/src/firmware_updater.rs
@@ -1,7 +1,7 @@
1use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; 1use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind};
2use embedded_storage_async::nor_flash::NorFlash as AsyncNorFlash; 2use embedded_storage_async::nor_flash::NorFlash as AsyncNorFlash;
3 3
4use crate::{FirmwareWriter, Partition, State, BOOT_MAGIC, SWAP_MAGIC}; 4use crate::{Partition, State, BOOT_MAGIC, SWAP_MAGIC};
5 5
6/// Errors returned by FirmwareUpdater 6/// Errors returned by FirmwareUpdater
7#[derive(Debug)] 7#[derive(Debug)]
@@ -256,7 +256,6 @@ impl FirmwareUpdater {
256 offset: usize, 256 offset: usize,
257 data: &[u8], 257 data: &[u8],
258 dfu_flash: &mut F, 258 dfu_flash: &mut F,
259 block_size: usize,
260 ) -> Result<(), FirmwareUpdaterError> { 259 ) -> Result<(), FirmwareUpdaterError> {
261 assert!(data.len() >= F::ERASE_SIZE); 260 assert!(data.len() >= F::ERASE_SIZE);
262 261
@@ -264,25 +263,23 @@ impl FirmwareUpdater {
264 .erase(dfu_flash, offset as u32, (offset + data.len()) as u32) 263 .erase(dfu_flash, offset as u32, (offset + data.len()) as u32)
265 .await?; 264 .await?;
266 265
267 FirmwareWriter(self.dfu) 266 self.dfu.write(dfu_flash, offset as u32, data).await?;
268 .write_block(offset, data, dfu_flash, block_size)
269 .await?;
270 267
271 Ok(()) 268 Ok(())
272 } 269 }
273 270
274 /// Prepare for an incoming DFU update by erasing the entire DFU area and 271 /// Prepare for an incoming DFU update by erasing the entire DFU area and
275 /// returning a `FirmwareWriter`. 272 /// returning its `Partition`.
276 /// 273 ///
277 /// Using this instead of `write_firmware` allows for an optimized API in 274 /// Using this instead of `write_firmware` allows for an optimized API in
278 /// exchange for added complexity. 275 /// exchange for added complexity.
279 pub async fn prepare_update<F: AsyncNorFlash>( 276 pub async fn prepare_update<F: AsyncNorFlash>(
280 &mut self, 277 &mut self,
281 dfu_flash: &mut F, 278 dfu_flash: &mut F,
282 ) -> Result<FirmwareWriter, FirmwareUpdaterError> { 279 ) -> Result<Partition, FirmwareUpdaterError> {
283 self.dfu.wipe(dfu_flash).await?; 280 self.dfu.wipe(dfu_flash).await?;
284 281
285 Ok(FirmwareWriter(self.dfu)) 282 Ok(self.dfu)
286 } 283 }
287 284
288 // 285 //
@@ -469,29 +466,25 @@ impl FirmwareUpdater {
469 offset: usize, 466 offset: usize,
470 data: &[u8], 467 data: &[u8],
471 dfu_flash: &mut F, 468 dfu_flash: &mut F,
472 block_size: usize,
473 ) -> Result<(), FirmwareUpdaterError> { 469 ) -> Result<(), FirmwareUpdaterError> {
474 assert!(data.len() >= F::ERASE_SIZE); 470 assert!(data.len() >= F::ERASE_SIZE);
475 471
476 self.dfu 472 self.dfu
477 .erase_blocking(dfu_flash, offset as u32, (offset + data.len()) as u32)?; 473 .erase_blocking(dfu_flash, offset as u32, (offset + data.len()) as u32)?;
478 474
479 FirmwareWriter(self.dfu).write_block_blocking(offset, data, dfu_flash, block_size)?; 475 self.dfu.write_blocking(dfu_flash, offset as u32, data)?;
480 476
481 Ok(()) 477 Ok(())
482 } 478 }
483 479
484 /// Prepare for an incoming DFU update by erasing the entire DFU area and 480 /// Prepare for an incoming DFU update by erasing the entire DFU area and
485 /// returning a `FirmwareWriter`. 481 /// returning its `Partition`.
486 /// 482 ///
487 /// Using this instead of `write_firmware_blocking` allows for an optimized 483 /// Using this instead of `write_firmware_blocking` allows for an optimized
488 /// API in exchange for added complexity. 484 /// API in exchange for added complexity.
489 pub fn prepare_update_blocking<F: NorFlash>( 485 pub fn prepare_update_blocking<F: NorFlash>(&mut self, flash: &mut F) -> Result<Partition, FirmwareUpdaterError> {
490 &mut self,
491 flash: &mut F,
492 ) -> Result<FirmwareWriter, FirmwareUpdaterError> {
493 self.dfu.wipe_blocking(flash)?; 486 self.dfu.wipe_blocking(flash)?;
494 487
495 Ok(FirmwareWriter(self.dfu)) 488 Ok(self.dfu)
496 } 489 }
497} 490}
diff --git a/embassy-boot/boot/src/firmware_writer.rs b/embassy-boot/boot/src/firmware_writer.rs
deleted file mode 100644
index 46079e731..000000000
--- a/embassy-boot/boot/src/firmware_writer.rs
+++ /dev/null
@@ -1,55 +0,0 @@
1use embedded_storage::nor_flash::NorFlash;
2use embedded_storage_async::nor_flash::NorFlash as AsyncNorFlash;
3
4use crate::Partition;
5
6/// FirmwareWriter allows writing blocks to an already erased flash.
7pub struct FirmwareWriter(pub(crate) Partition);
8
9impl FirmwareWriter {
10 /// Write data to a flash page.
11 ///
12 /// The buffer must follow alignment requirements of the target flash and a multiple of page size big.
13 ///
14 /// # Safety
15 ///
16 /// Failing to meet alignment and size requirements may result in a panic.
17 pub async fn write_block<F: AsyncNorFlash>(
18 &mut self,
19 offset: usize,
20 data: &[u8],
21 flash: &mut F,
22 block_size: usize,
23 ) -> Result<(), F::Error> {
24 let mut offset = offset as u32;
25 for chunk in data.chunks(block_size) {
26 self.0.write(flash, offset, chunk).await?;
27 offset += chunk.len() as u32;
28 }
29
30 Ok(())
31 }
32
33 /// Write data to a flash page.
34 ///
35 /// The buffer must follow alignment requirements of the target flash and a multiple of page size big.
36 ///
37 /// # Safety
38 ///
39 /// Failing to meet alignment and size requirements may result in a panic.
40 pub fn write_block_blocking<F: NorFlash>(
41 &mut self,
42 offset: usize,
43 data: &[u8],
44 flash: &mut F,
45 block_size: usize,
46 ) -> Result<(), F::Error> {
47 let mut offset = offset as u32;
48 for chunk in data.chunks(block_size) {
49 self.0.write_blocking(flash, offset, chunk)?;
50 offset += chunk.len() as u32;
51 }
52
53 Ok(())
54 }
55}
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs
index 597ce3fa3..cb12f9dc7 100644
--- a/embassy-boot/boot/src/lib.rs
+++ b/embassy-boot/boot/src/lib.rs
@@ -7,13 +7,11 @@ mod fmt;
7 7
8mod boot_loader; 8mod boot_loader;
9mod firmware_updater; 9mod firmware_updater;
10mod firmware_writer;
11mod mem_flash; 10mod mem_flash;
12mod partition; 11mod partition;
13 12
14pub use boot_loader::{BootError, BootFlash, BootLoader, Flash, FlashConfig, MultiFlashConfig, SingleFlashConfig}; 13pub use boot_loader::{BootError, BootFlash, BootLoader, Flash, FlashConfig, MultiFlashConfig, SingleFlashConfig};
15pub use firmware_updater::{FirmwareUpdater, FirmwareUpdaterError}; 14pub use firmware_updater::{FirmwareUpdater, FirmwareUpdaterError};
16pub use firmware_writer::FirmwareWriter;
17pub use partition::Partition; 15pub use partition::Partition;
18 16
19pub(crate) const BOOT_MAGIC: u8 = 0xD0; 17pub(crate) const BOOT_MAGIC: u8 = 0xD0;
@@ -107,7 +105,7 @@ mod tests {
107 let mut updater = FirmwareUpdater::new(DFU, STATE); 105 let mut updater = FirmwareUpdater::new(DFU, STATE);
108 let mut offset = 0; 106 let mut offset = 0;
109 for chunk in update.chunks(4096) { 107 for chunk in update.chunks(4096) {
110 block_on(updater.write_firmware(offset, chunk, &mut flash, 4096)).unwrap(); 108 block_on(updater.write_firmware(offset, chunk, &mut flash)).unwrap();
111 offset += chunk.len(); 109 offset += chunk.len();
112 } 110 }
113 block_on(updater.mark_updated(&mut flash, &mut aligned)).unwrap(); 111 block_on(updater.mark_updated(&mut flash, &mut aligned)).unwrap();
@@ -180,7 +178,7 @@ mod tests {
180 178
181 let mut offset = 0; 179 let mut offset = 0;
182 for chunk in update.chunks(2048) { 180 for chunk in update.chunks(2048) {
183 block_on(updater.write_firmware(offset, chunk, &mut dfu, chunk.len())).unwrap(); 181 block_on(updater.write_firmware(offset, chunk, &mut dfu)).unwrap();
184 offset += chunk.len(); 182 offset += chunk.len();
185 } 183 }
186 block_on(updater.mark_updated(&mut state, &mut aligned)).unwrap(); 184 block_on(updater.mark_updated(&mut state, &mut aligned)).unwrap();
@@ -233,7 +231,7 @@ mod tests {
233 231
234 let mut offset = 0; 232 let mut offset = 0;
235 for chunk in update.chunks(4096) { 233 for chunk in update.chunks(4096) {
236 block_on(updater.write_firmware(offset, chunk, &mut dfu, chunk.len())).unwrap(); 234 block_on(updater.write_firmware(offset, chunk, &mut dfu)).unwrap();
237 offset += chunk.len(); 235 offset += chunk.len();
238 } 236 }
239 block_on(updater.mark_updated(&mut state, &mut aligned)).unwrap(); 237 block_on(updater.mark_updated(&mut state, &mut aligned)).unwrap();
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
index da75fa53a..22abacdea 100644
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,7 +1,7 @@
1# Before upgrading check that everything is available on all tier1 targets here: 1# Before upgrading check that everything is available on all tier1 targets here:
2# https://rust-lang.github.io/rustup-components-history 2# https://rust-lang.github.io/rustup-components-history
3[toolchain] 3[toolchain]
4channel = "nightly-2023-02-07" 4channel = "nightly-2023-04-02"
5components = [ "rust-src", "rustfmt", "llvm-tools-preview" ] 5components = [ "rust-src", "rustfmt", "llvm-tools-preview" ]
6targets = [ 6targets = [
7 "thumbv7em-none-eabi", 7 "thumbv7em-none-eabi",
diff --git a/tests/nrf/src/bin/timer.rs b/tests/nrf/src/bin/timer.rs
new file mode 100644
index 000000000..9b9b5fb28
--- /dev/null
+++ b/tests/nrf/src/bin/timer.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{assert, info};
6use embassy_executor::Spawner;
7use embassy_time::{Duration, Instant, Timer};
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let _p = embassy_nrf::init(Default::default());
13 info!("Hello World!");
14
15 let start = Instant::now();
16 Timer::after(Duration::from_millis(100)).await;
17 let end = Instant::now();
18 let ms = (end - start).as_millis();
19 info!("slept for {} ms", ms);
20 assert!(ms >= 99);
21 assert!(ms < 110);
22
23 info!("Test OK");
24 cortex_m::asm::bkpt();
25}