aboutsummaryrefslogtreecommitdiff
path: root/embassy-boot
diff options
context:
space:
mode:
authorRasmus Melchior Jacobsen <[email protected]>2023-05-27 19:26:45 +0200
committerRasmus Melchior Jacobsen <[email protected]>2023-05-29 22:00:44 +0200
commit94046f30ffefc96a7b110ed1d9bb60d64cb4780f (patch)
tree1b999590c16db6ec738cadc7125dc939d3c14574 /embassy-boot
parent3b38079490b0c283899cab42308c4feab4c47fdc (diff)
Remove the usage of the local Partition type in BootLoader
Diffstat (limited to 'embassy-boot')
-rw-r--r--embassy-boot/boot/Cargo.toml1
-rw-r--r--embassy-boot/boot/src/boot_loader.rs340
2 files changed, 112 insertions, 229 deletions
diff --git a/embassy-boot/boot/Cargo.toml b/embassy-boot/boot/Cargo.toml
index f641d5e1c..3fdf69c5e 100644
--- a/embassy-boot/boot/Cargo.toml
+++ b/embassy-boot/boot/Cargo.toml
@@ -39,6 +39,7 @@ env_logger = "0.9"
39rand = "0.7" # ed25519-dalek v1.0.1 depends on this exact version 39rand = "0.7" # ed25519-dalek v1.0.1 depends on this exact version
40futures = { version = "0.3", features = ["executor"] } 40futures = { version = "0.3", features = ["executor"] }
41sha1 = "0.10.5" 41sha1 = "0.10.5"
42embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
42 43
43[dev-dependencies.ed25519-dalek] 44[dev-dependencies.ed25519-dalek]
44default_features = false 45default_features = false
diff --git a/embassy-boot/boot/src/boot_loader.rs b/embassy-boot/boot/src/boot_loader.rs
index b959de2c4..50eb5e668 100644
--- a/embassy-boot/boot/src/boot_loader.rs
+++ b/embassy-boot/boot/src/boot_loader.rs
@@ -1,6 +1,8 @@
1use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; 1use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
2 2
3use crate::{Partition, State, BOOT_MAGIC, SWAP_MAGIC}; 3use crate::{State, BOOT_MAGIC, SWAP_MAGIC};
4
5const STATE_ERASE_VALUE: u8 = 0xFF;
4 6
5/// Errors returned by bootloader 7/// Errors returned by bootloader
6#[derive(PartialEq, Eq, Debug)] 8#[derive(PartialEq, Eq, Debug)]
@@ -30,65 +32,39 @@ where
30 } 32 }
31} 33}
32 34
33/// Trait defining the flash handles used for active and DFU partition. 35/// BootLoader works with any flash implementing embedded_storage.
34pub trait FlashConfig { 36pub struct BootLoader<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> {
35 /// The erase value of the state flash. Typically the default of 0xFF is used, but some flashes use a different value. 37 /// Flash type used for the active partition - the partition which will be booted from.
36 const STATE_ERASE_VALUE: u8 = 0xFF; 38 active: ACTIVE,
39 /// Flash type used for the dfu partition - he partition which will be swapped in when requested.
40 dfu: DFU,
37 /// Flash type used for the state partition. 41 /// Flash type used for the state partition.
38 type STATE: NorFlash; 42 ///
39 /// Flash type used for the active partition. 43 /// The state partition has the following format:
40 type ACTIVE: NorFlash; 44 /// All ranges are in multiples of WRITE_SIZE bytes.
41 /// Flash type used for the dfu partition. 45 /// | Range | Description |
42 type DFU: NorFlash; 46 /// | 0..1 | Magic indicating bootloader state. BOOT_MAGIC means boot, SWAP_MAGIC means swap. |
43 47 /// | 1..2 | Progress validity. ERASE_VALUE means valid, !ERASE_VALUE means invalid. |
44 /// Return flash instance used to write/read to/from active partition. 48 /// | 2..2 + N | Progress index used while swapping or reverting
45 fn active(&mut self) -> &mut Self::ACTIVE; 49 state: STATE,
46 /// Return flash instance used to write/read to/from dfu partition.
47 fn dfu(&mut self) -> &mut Self::DFU;
48 /// Return flash instance used to write/read to/from bootloader state.
49 fn state(&mut self) -> &mut Self::STATE;
50}
51
52trait FlashConfigEx {
53 fn page_size() -> u32;
54} 50}
55 51
56impl<T: FlashConfig> FlashConfigEx for T { 52impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, STATE> {
57 /// Get the page size which is the "unit of operation" within the bootloader. 53 /// Get the page size which is the "unit of operation" within the bootloader.
58 fn page_size() -> u32 { 54 const PAGE_SIZE: u32 = if ACTIVE::ERASE_SIZE > DFU::ERASE_SIZE {
59 core::cmp::max(T::ACTIVE::ERASE_SIZE, T::DFU::ERASE_SIZE) as u32 55 ACTIVE::ERASE_SIZE as u32
60 } 56 } else {
61} 57 DFU::ERASE_SIZE as u32
58 };
62 59
63/// BootLoader works with any flash implementing embedded_storage. 60 /// Create a new instance of a bootloader with the flash partitions.
64pub struct BootLoader {
65 // Page with current state of bootloader. The state partition has the following format:
66 // All ranges are in multiples of WRITE_SIZE bytes.
67 // | Range | Description |
68 // | 0..1 | Magic indicating bootloader state. BOOT_MAGIC means boot, SWAP_MAGIC means swap. |
69 // | 1..2 | Progress validity. ERASE_VALUE means valid, !ERASE_VALUE means invalid. |
70 // | 2..2 + N | Progress index used while swapping or reverting |
71 state: Partition,
72 // Location of the partition which will be booted from
73 active: Partition,
74 // Location of the partition which will be swapped in when requested
75 dfu: Partition,
76}
77
78impl BootLoader {
79 /// Create a new instance of a bootloader with the given partitions.
80 /// 61 ///
81 /// - All partitions must be aligned with the PAGE_SIZE const generic parameter. 62 /// - All partitions must be aligned with the PAGE_SIZE const generic parameter.
82 /// - The dfu partition must be at least PAGE_SIZE bigger than the active partition. 63 /// - The dfu partition must be at least PAGE_SIZE bigger than the active partition.
83 pub fn new(active: Partition, dfu: Partition, state: Partition) -> Self { 64 pub fn new(active: ACTIVE, dfu: DFU, state: STATE) -> Self {
84 Self { active, dfu, state } 65 Self { active, dfu, state }
85 } 66 }
86 67
87 /// Return the offset of the active partition into the active flash.
88 pub fn boot_address(&self) -> usize {
89 self.active.from as usize
90 }
91
92 /// Perform necessary boot preparations like swapping images. 68 /// Perform necessary boot preparations like swapping images.
93 /// 69 ///
94 /// The DFU partition is assumed to be 1 page bigger than the active partition for the swap 70 /// The DFU partition is assumed to be 1 page bigger than the active partition for the swap
@@ -175,195 +151,174 @@ impl BootLoader {
175 /// | DFU | 3 | 3 | 2 | 1 | 3 | 151 /// | DFU | 3 | 3 | 2 | 1 | 3 |
176 /// +-----------+--------------+--------+--------+--------+--------+ 152 /// +-----------+--------------+--------+--------+--------+--------+
177 /// 153 ///
178 pub fn prepare_boot<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<State, BootError> { 154 pub fn prepare_boot(&mut self, aligned_buf: &mut [u8]) -> Result<State, BootError> {
179 // Ensure we have enough progress pages to store copy progress 155 // Ensure we have enough progress pages to store copy progress
180 assert_eq!(0, P::page_size() % aligned_buf.len() as u32); 156 assert_eq!(0, Self::PAGE_SIZE % aligned_buf.len() as u32);
181 assert_eq!(0, P::page_size() % P::ACTIVE::WRITE_SIZE as u32); 157 assert_eq!(0, Self::PAGE_SIZE % ACTIVE::WRITE_SIZE as u32);
182 assert_eq!(0, P::page_size() % P::ACTIVE::ERASE_SIZE as u32); 158 assert_eq!(0, Self::PAGE_SIZE % ACTIVE::ERASE_SIZE as u32);
183 assert_eq!(0, P::page_size() % P::DFU::WRITE_SIZE as u32); 159 assert_eq!(0, Self::PAGE_SIZE % DFU::WRITE_SIZE as u32);
184 assert_eq!(0, P::page_size() % P::DFU::ERASE_SIZE as u32); 160 assert_eq!(0, Self::PAGE_SIZE % DFU::ERASE_SIZE as u32);
185 assert!(aligned_buf.len() >= P::STATE::WRITE_SIZE); 161 assert!(aligned_buf.len() >= STATE::WRITE_SIZE);
186 assert_eq!(0, aligned_buf.len() % P::ACTIVE::WRITE_SIZE); 162 assert_eq!(0, aligned_buf.len() % ACTIVE::WRITE_SIZE);
187 assert_eq!(0, aligned_buf.len() % P::DFU::WRITE_SIZE); 163 assert_eq!(0, aligned_buf.len() % DFU::WRITE_SIZE);
188 assert_partitions(self.active, self.dfu, self.state, P::page_size(), P::STATE::WRITE_SIZE); 164
165 assert_partitions(&self.active, &self.dfu, &self.state, Self::PAGE_SIZE);
189 166
190 // Copy contents from partition N to active 167 // Copy contents from partition N to active
191 let state = self.read_state(p, aligned_buf)?; 168 let state = self.read_state(aligned_buf)?;
192 if state == State::Swap { 169 if state == State::Swap {
193 // 170 //
194 // Check if we already swapped. If we're in the swap state, this means we should revert 171 // Check if we already swapped. If we're in the swap state, this means we should revert
195 // since the app has failed to mark boot as successful 172 // since the app has failed to mark boot as successful
196 // 173 //
197 if !self.is_swapped(p, aligned_buf)? { 174 if !self.is_swapped(aligned_buf)? {
198 trace!("Swapping"); 175 trace!("Swapping");
199 self.swap(p, aligned_buf)?; 176 self.swap(aligned_buf)?;
200 trace!("Swapping done"); 177 trace!("Swapping done");
201 } else { 178 } else {
202 trace!("Reverting"); 179 trace!("Reverting");
203 self.revert(p, aligned_buf)?; 180 self.revert(aligned_buf)?;
204 181
205 let state_flash = p.state(); 182 let state_word = &mut aligned_buf[..STATE::WRITE_SIZE];
206 let state_word = &mut aligned_buf[..P::STATE::WRITE_SIZE];
207 183
208 // Invalidate progress 184 // Invalidate progress
209 state_word.fill(!P::STATE_ERASE_VALUE); 185 state_word.fill(!STATE_ERASE_VALUE);
210 self.state 186 self.state.write(STATE::WRITE_SIZE as u32, state_word)?;
211 .write_blocking(state_flash, P::STATE::WRITE_SIZE as u32, state_word)?;
212 187
213 // Clear magic and progress 188 // Clear magic and progress
214 self.state.wipe_blocking(state_flash)?; 189 self.state.erase(0, self.state.capacity() as u32)?;
215 190
216 // Set magic 191 // Set magic
217 state_word.fill(BOOT_MAGIC); 192 state_word.fill(BOOT_MAGIC);
218 self.state.write_blocking(state_flash, 0, state_word)?; 193 self.state.write(0, state_word)?;
219 } 194 }
220 } 195 }
221 Ok(state) 196 Ok(state)
222 } 197 }
223 198
224 fn is_swapped<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<bool, BootError> { 199 fn is_swapped(&mut self, aligned_buf: &mut [u8]) -> Result<bool, BootError> {
225 let page_count = (self.active.size() / P::page_size()) as usize; 200 let page_count = self.active.capacity() / Self::PAGE_SIZE as usize;
226 let progress = self.current_progress(p, aligned_buf)?; 201 let progress = self.current_progress(aligned_buf)?;
227 202
228 Ok(progress >= page_count * 2) 203 Ok(progress >= page_count * 2)
229 } 204 }
230 205
231 fn current_progress<P: FlashConfig>(&mut self, config: &mut P, aligned_buf: &mut [u8]) -> Result<usize, BootError> { 206 fn current_progress(&mut self, aligned_buf: &mut [u8]) -> Result<usize, BootError> {
232 let write_size = P::STATE::WRITE_SIZE as u32; 207 let write_size = STATE::WRITE_SIZE as u32;
233 let max_index = (((self.state.size() - write_size) / write_size) - 2) as usize; 208 let max_index = ((self.state.capacity() - STATE::WRITE_SIZE) / STATE::WRITE_SIZE) - 2;
234 let state_flash = config.state();
235 let state_word = &mut aligned_buf[..write_size as usize]; 209 let state_word = &mut aligned_buf[..write_size as usize];
236 210
237 self.state.read_blocking(state_flash, write_size, state_word)?; 211 self.state.read(write_size, state_word)?;
238 if state_word.iter().any(|&b| b != P::STATE_ERASE_VALUE) { 212 if state_word.iter().any(|&b| b != STATE_ERASE_VALUE) {
239 // Progress is invalid 213 // Progress is invalid
240 return Ok(max_index); 214 return Ok(max_index);
241 } 215 }
242 216
243 for index in 0..max_index { 217 for index in 0..max_index {
244 self.state 218 self.state.read((2 + index) as u32 * write_size, state_word)?;
245 .read_blocking(state_flash, (2 + index) as u32 * write_size, state_word)?;
246 219
247 if state_word.iter().any(|&b| b == P::STATE_ERASE_VALUE) { 220 if state_word.iter().any(|&b| b == STATE_ERASE_VALUE) {
248 return Ok(index); 221 return Ok(index);
249 } 222 }
250 } 223 }
251 Ok(max_index) 224 Ok(max_index)
252 } 225 }
253 226
254 fn update_progress<P: FlashConfig>( 227 fn update_progress(&mut self, progress_index: usize, aligned_buf: &mut [u8]) -> Result<(), BootError> {
255 &mut self, 228 let state_word = &mut aligned_buf[..STATE::WRITE_SIZE];
256 progress_index: usize, 229 state_word.fill(!STATE_ERASE_VALUE);
257 p: &mut P, 230 self.state
258 aligned_buf: &mut [u8], 231 .write((2 + progress_index) as u32 * STATE::WRITE_SIZE as u32, state_word)?;
259 ) -> Result<(), BootError> {
260 let state_word = &mut aligned_buf[..P::STATE::WRITE_SIZE];
261 state_word.fill(!P::STATE_ERASE_VALUE);
262 self.state.write_blocking(
263 p.state(),
264 (2 + progress_index) as u32 * P::STATE::WRITE_SIZE as u32,
265 state_word,
266 )?;
267 Ok(()) 232 Ok(())
268 } 233 }
269 234
270 fn copy_page_once_to_active<P: FlashConfig>( 235 fn copy_page_once_to_active(
271 &mut self, 236 &mut self,
272 progress_index: usize, 237 progress_index: usize,
273 from_offset: u32, 238 from_offset: u32,
274 to_offset: u32, 239 to_offset: u32,
275 p: &mut P,
276 aligned_buf: &mut [u8], 240 aligned_buf: &mut [u8],
277 ) -> Result<(), BootError> { 241 ) -> Result<(), BootError> {
278 if self.current_progress(p, aligned_buf)? <= progress_index { 242 if self.current_progress(aligned_buf)? <= progress_index {
279 let page_size = P::page_size() as u32; 243 let page_size = Self::PAGE_SIZE as u32;
280 244
281 self.active 245 self.active.erase(to_offset, to_offset + page_size)?;
282 .erase_blocking(p.active(), to_offset, to_offset + page_size)?;
283 246
284 for offset_in_page in (0..page_size).step_by(aligned_buf.len()) { 247 for offset_in_page in (0..page_size).step_by(aligned_buf.len()) {
285 self.dfu 248 self.dfu.read(from_offset + offset_in_page as u32, aligned_buf)?;
286 .read_blocking(p.dfu(), from_offset + offset_in_page as u32, aligned_buf)?; 249 self.active.write(to_offset + offset_in_page as u32, aligned_buf)?;
287 self.active
288 .write_blocking(p.active(), to_offset + offset_in_page as u32, aligned_buf)?;
289 } 250 }
290 251
291 self.update_progress(progress_index, p, aligned_buf)?; 252 self.update_progress(progress_index, aligned_buf)?;
292 } 253 }
293 Ok(()) 254 Ok(())
294 } 255 }
295 256
296 fn copy_page_once_to_dfu<P: FlashConfig>( 257 fn copy_page_once_to_dfu(
297 &mut self, 258 &mut self,
298 progress_index: usize, 259 progress_index: usize,
299 from_offset: u32, 260 from_offset: u32,
300 to_offset: u32, 261 to_offset: u32,
301 p: &mut P,
302 aligned_buf: &mut [u8], 262 aligned_buf: &mut [u8],
303 ) -> Result<(), BootError> { 263 ) -> Result<(), BootError> {
304 if self.current_progress(p, aligned_buf)? <= progress_index { 264 if self.current_progress(aligned_buf)? <= progress_index {
305 let page_size = P::page_size() as u32; 265 let page_size = Self::PAGE_SIZE as u32;
306 266
307 self.dfu 267 self.dfu.erase(to_offset as u32, to_offset + page_size)?;
308 .erase_blocking(p.dfu(), to_offset as u32, to_offset + page_size)?;
309 268
310 for offset_in_page in (0..page_size).step_by(aligned_buf.len()) { 269 for offset_in_page in (0..page_size).step_by(aligned_buf.len()) {
311 self.active 270 self.active.read(from_offset + offset_in_page as u32, aligned_buf)?;
312 .read_blocking(p.active(), from_offset + offset_in_page as u32, aligned_buf)?; 271 self.dfu.write(to_offset + offset_in_page as u32, aligned_buf)?;
313 self.dfu
314 .write_blocking(p.dfu(), to_offset + offset_in_page as u32, aligned_buf)?;
315 } 272 }
316 273
317 self.update_progress(progress_index, p, aligned_buf)?; 274 self.update_progress(progress_index, aligned_buf)?;
318 } 275 }
319 Ok(()) 276 Ok(())
320 } 277 }
321 278
322 fn swap<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<(), BootError> { 279 fn swap(&mut self, aligned_buf: &mut [u8]) -> Result<(), BootError> {
323 let page_size = P::page_size(); 280 let page_count = self.active.capacity() as u32 / Self::PAGE_SIZE;
324 let page_count = self.active.size() / page_size;
325 for page_num in 0..page_count { 281 for page_num in 0..page_count {
326 let progress_index = (page_num * 2) as usize; 282 let progress_index = (page_num * 2) as usize;
327 283
328 // Copy active page to the 'next' DFU page. 284 // Copy active page to the 'next' DFU page.
329 let active_from_offset = (page_count - 1 - page_num) * page_size; 285 let active_from_offset = (page_count - 1 - page_num) * Self::PAGE_SIZE;
330 let dfu_to_offset = (page_count - page_num) * page_size; 286 let dfu_to_offset = (page_count - page_num) * Self::PAGE_SIZE;
331 //trace!("Copy active {} to dfu {}", active_from_offset, dfu_to_offset); 287 //trace!("Copy active {} to dfu {}", active_from_offset, dfu_to_offset);
332 self.copy_page_once_to_dfu(progress_index, active_from_offset, dfu_to_offset, p, aligned_buf)?; 288 self.copy_page_once_to_dfu(progress_index, active_from_offset, dfu_to_offset, aligned_buf)?;
333 289
334 // Copy DFU page to the active page 290 // Copy DFU page to the active page
335 let active_to_offset = (page_count - 1 - page_num) * page_size; 291 let active_to_offset = (page_count - 1 - page_num) * Self::PAGE_SIZE;
336 let dfu_from_offset = (page_count - 1 - page_num) * page_size; 292 let dfu_from_offset = (page_count - 1 - page_num) * Self::PAGE_SIZE;
337 //trace!("Copy dfy {} to active {}", dfu_from_offset, active_to_offset); 293 //trace!("Copy dfy {} to active {}", dfu_from_offset, active_to_offset);
338 self.copy_page_once_to_active(progress_index + 1, dfu_from_offset, active_to_offset, p, aligned_buf)?; 294 self.copy_page_once_to_active(progress_index + 1, dfu_from_offset, active_to_offset, aligned_buf)?;
339 } 295 }
340 296
341 Ok(()) 297 Ok(())
342 } 298 }
343 299
344 fn revert<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<(), BootError> { 300 fn revert(&mut self, aligned_buf: &mut [u8]) -> Result<(), BootError> {
345 let page_size = P::page_size(); 301 let page_count = self.active.capacity() as u32 / Self::PAGE_SIZE;
346 let page_count = self.active.size() / page_size;
347 for page_num in 0..page_count { 302 for page_num in 0..page_count {
348 let progress_index = (page_count * 2 + page_num * 2) as usize; 303 let progress_index = (page_count * 2 + page_num * 2) as usize;
349 304
350 // Copy the bad active page to the DFU page 305 // Copy the bad active page to the DFU page
351 let active_from_offset = page_num * page_size; 306 let active_from_offset = page_num * Self::PAGE_SIZE;
352 let dfu_to_offset = page_num * page_size; 307 let dfu_to_offset = page_num * Self::PAGE_SIZE;
353 self.copy_page_once_to_dfu(progress_index, active_from_offset, dfu_to_offset, p, aligned_buf)?; 308 self.copy_page_once_to_dfu(progress_index, active_from_offset, dfu_to_offset, aligned_buf)?;
354 309
355 // Copy the DFU page back to the active page 310 // Copy the DFU page back to the active page
356 let active_to_offset = page_num * page_size; 311 let active_to_offset = page_num * Self::PAGE_SIZE;
357 let dfu_from_offset = (page_num + 1) * page_size; 312 let dfu_from_offset = (page_num + 1) * Self::PAGE_SIZE;
358 self.copy_page_once_to_active(progress_index + 1, dfu_from_offset, active_to_offset, p, aligned_buf)?; 313 self.copy_page_once_to_active(progress_index + 1, dfu_from_offset, active_to_offset, aligned_buf)?;
359 } 314 }
360 315
361 Ok(()) 316 Ok(())
362 } 317 }
363 318
364 fn read_state<P: FlashConfig>(&mut self, config: &mut P, aligned_buf: &mut [u8]) -> Result<State, BootError> { 319 fn read_state(&mut self, aligned_buf: &mut [u8]) -> Result<State, BootError> {
365 let state_word = &mut aligned_buf[..P::STATE::WRITE_SIZE]; 320 let state_word = &mut aligned_buf[..STATE::WRITE_SIZE];
366 self.state.read_blocking(config.state(), 0, state_word)?; 321 self.state.read(0, state_word)?;
367 322
368 if !state_word.iter().any(|&b| b != SWAP_MAGIC) { 323 if !state_word.iter().any(|&b| b != SWAP_MAGIC) {
369 Ok(State::Swap) 324 Ok(State::Swap)
@@ -373,11 +328,16 @@ impl BootLoader {
373 } 328 }
374} 329}
375 330
376fn assert_partitions(active: Partition, dfu: Partition, state: Partition, page_size: u32, state_write_size: usize) { 331fn assert_partitions<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash>(
377 assert_eq!(active.size() % page_size, 0); 332 active: &ACTIVE,
378 assert_eq!(dfu.size() % page_size, 0); 333 dfu: &DFU,
379 assert!(dfu.size() - active.size() >= page_size); 334 state: &STATE,
380 assert!(2 + 2 * (active.size() / page_size) <= state.size() / state_write_size as u32); 335 page_size: u32,
336) {
337 assert_eq!(active.capacity() as u32 % page_size, 0);
338 assert_eq!(dfu.capacity() as u32 % page_size, 0);
339 assert!(dfu.capacity() as u32 - active.capacity() as u32 >= page_size);
340 assert!(2 + 2 * (active.capacity() as u32 / page_size) <= state.capacity() as u32 / STATE::WRITE_SIZE as u32);
381} 341}
382 342
383/// A flash wrapper implementing the Flash and embedded_storage traits. 343/// A flash wrapper implementing the Flash and embedded_storage traits.
@@ -436,98 +396,20 @@ where
436 } 396 }
437} 397}
438 398
439/// Convenience provider that uses a single flash for all partitions.
440pub struct SingleFlashConfig<'a, F>
441where
442 F: NorFlash,
443{
444 flash: &'a mut F,
445}
446
447impl<'a, F> SingleFlashConfig<'a, F>
448where
449 F: NorFlash,
450{
451 /// Create a provider for a single flash.
452 pub fn new(flash: &'a mut F) -> Self {
453 Self { flash }
454 }
455}
456
457impl<'a, F> FlashConfig for SingleFlashConfig<'a, F>
458where
459 F: NorFlash,
460{
461 type STATE = F;
462 type ACTIVE = F;
463 type DFU = F;
464
465 fn active(&mut self) -> &mut Self::STATE {
466 self.flash
467 }
468 fn dfu(&mut self) -> &mut Self::ACTIVE {
469 self.flash
470 }
471 fn state(&mut self) -> &mut Self::DFU {
472 self.flash
473 }
474}
475
476/// Convenience flash provider that uses separate flash instances for each partition.
477pub struct MultiFlashConfig<'a, ACTIVE, STATE, DFU>
478where
479 ACTIVE: NorFlash,
480 STATE: NorFlash,
481 DFU: NorFlash,
482{
483 active: &'a mut ACTIVE,
484 state: &'a mut STATE,
485 dfu: &'a mut DFU,
486}
487
488impl<'a, ACTIVE, STATE, DFU> MultiFlashConfig<'a, ACTIVE, STATE, DFU>
489where
490 ACTIVE: NorFlash,
491 STATE: NorFlash,
492 DFU: NorFlash,
493{
494 /// Create a new flash provider with separate configuration for all three partitions.
495 pub fn new(active: &'a mut ACTIVE, state: &'a mut STATE, dfu: &'a mut DFU) -> Self {
496 Self { active, state, dfu }
497 }
498}
499
500impl<'a, ACTIVE, STATE, DFU> FlashConfig for MultiFlashConfig<'a, ACTIVE, STATE, DFU>
501where
502 ACTIVE: NorFlash,
503 STATE: NorFlash,
504 DFU: NorFlash,
505{
506 type STATE = STATE;
507 type ACTIVE = ACTIVE;
508 type DFU = DFU;
509
510 fn active(&mut self) -> &mut Self::ACTIVE {
511 self.active
512 }
513 fn dfu(&mut self) -> &mut Self::DFU {
514 self.dfu
515 }
516 fn state(&mut self) -> &mut Self::STATE {
517 self.state
518 }
519}
520
521#[cfg(test)] 399#[cfg(test)]
522mod tests { 400mod tests {
523 use super::*; 401 use super::*;
402 use crate::mem_flash::MemFlash;
524 403
525 #[test] 404 #[test]
526 #[should_panic] 405 #[should_panic]
527 fn test_range_asserts() { 406 fn test_range_asserts() {
528 const ACTIVE: Partition = Partition::new(4096, 4194304); 407 const ACTIVE_SIZE: usize = 4194304 - 4096;
529 const DFU: Partition = Partition::new(4194304, 2 * 4194304); 408 const DFU_SIZE: usize = 4194304;
530 const STATE: Partition = Partition::new(0, 4096); 409 const STATE_SIZE: usize = 4096;
531 assert_partitions(ACTIVE, DFU, STATE, 4096, 4); 410 static ACTIVE: MemFlash<ACTIVE_SIZE, 4, 4> = MemFlash::new(0xFF);
411 static DFU: MemFlash<DFU_SIZE, 4, 4> = MemFlash::new(0xFF);
412 static STATE: MemFlash<STATE_SIZE, 4, 4> = MemFlash::new(0xFF);
413 assert_partitions(&ACTIVE, &DFU, &STATE, 4096);
532 } 414 }
533} 415}