aboutsummaryrefslogtreecommitdiff
path: root/embassy-boot
diff options
context:
space:
mode:
authorRasmus Melchior Jacobsen <[email protected]>2023-04-04 20:25:55 +0200
committerRasmus Melchior Jacobsen <[email protected]>2023-04-04 20:25:55 +0200
commit9242ad89d436422fd5abdafadb2faf845e730a16 (patch)
treeb9aef12d7fd940868dd20d7d835711a484e59316 /embassy-boot
parent5923e143e35547b1972f2e48082e93dfbe1dadac (diff)
Remove magic buffer argument from prepare_boot
and use the aligned page buffer instead
Diffstat (limited to 'embassy-boot')
-rw-r--r--embassy-boot/boot/src/boot_loader.rs134
-rw-r--r--embassy-boot/boot/src/lib.rs22
2 files changed, 78 insertions, 78 deletions
diff --git a/embassy-boot/boot/src/boot_loader.rs b/embassy-boot/boot/src/boot_loader.rs
index 9d047f778..698075599 100644
--- a/embassy-boot/boot/src/boot_loader.rs
+++ b/embassy-boot/boot/src/boot_loader.rs
@@ -56,6 +56,16 @@ pub trait FlashConfig {
56 fn state(&mut self) -> &mut Self::STATE; 56 fn state(&mut self) -> &mut Self::STATE;
57} 57}
58 58
59trait FlashConfigEx {
60 fn page_size() -> usize;
61}
62
63impl<T: FlashConfig> FlashConfigEx for T {
64 fn page_size() -> usize {
65 core::cmp::max(T::ACTIVE::ERASE_SIZE, T::DFU::ERASE_SIZE)
66 }
67}
68
59/// BootLoader works with any flash implementing embedded_storage and can also work with 69/// BootLoader works with any flash implementing embedded_storage and can also work with
60/// different page sizes and flash write sizes. 70/// different page sizes and flash write sizes.
61pub struct BootLoader { 71pub struct BootLoader {
@@ -91,6 +101,9 @@ impl BootLoader {
91 /// The DFU partition is assumed to be 1 page bigger than the active partition for the swap 101 /// The DFU partition is assumed to be 1 page bigger than the active partition for the swap
92 /// algorithm to work correctly. 102 /// algorithm to work correctly.
93 /// 103 ///
104 /// The provided aligned_buf argument must satisfy any alignment requirements
105 /// given by the partition flashes. All flash operations will use this buffer.
106 ///
94 /// SWAPPING 107 /// SWAPPING
95 /// 108 ///
96 /// Assume a flash size of 3 pages for the active partition, and 4 pages for the DFU partition. 109 /// Assume a flash size of 3 pages for the active partition, and 4 pages for the DFU partition.
@@ -169,87 +182,89 @@ impl BootLoader {
169 /// | DFU | 3 | 3 | 2 | 1 | 3 | 182 /// | DFU | 3 | 3 | 2 | 1 | 3 |
170 /// +-----------+--------------+--------+--------+--------+--------+ 183 /// +-----------+--------------+--------+--------+--------+--------+
171 /// 184 ///
172 pub fn prepare_boot<P: FlashConfig>( 185 pub fn prepare_boot<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<State, BootError> {
173 &mut self,
174 p: &mut P,
175 magic: &mut [u8],
176 page: &mut [u8],
177 ) -> Result<State, BootError> {
178 // Ensure we have enough progress pages to store copy progress 186 // Ensure we have enough progress pages to store copy progress
179 assert_partitions(self.active, self.dfu, self.state, page.len(), P::STATE::WRITE_SIZE); 187 assert_eq!(aligned_buf.len(), P::page_size());
180 assert_eq!(magic.len(), P::STATE::WRITE_SIZE); 188 assert!(aligned_buf.len() >= P::STATE::WRITE_SIZE);
189 assert_partitions(self.active, self.dfu, self.state, P::page_size(), P::STATE::WRITE_SIZE);
181 190
182 // Copy contents from partition N to active 191 // Copy contents from partition N to active
183 let state = self.read_state(p, magic)?; 192 let state = self.read_state(p, aligned_buf)?;
184 if state == State::Swap { 193 if state == State::Swap {
185 // 194 //
186 // Check if we already swapped. If we're in the swap state, this means we should revert 195 // Check if we already swapped. If we're in the swap state, this means we should revert
187 // since the app has failed to mark boot as successful 196 // since the app has failed to mark boot as successful
188 // 197 //
189 if !self.is_swapped(p, magic, page)? { 198 if !self.is_swapped(p, aligned_buf)? {
190 trace!("Swapping"); 199 trace!("Swapping");
191 self.swap(p, magic, page)?; 200 self.swap(p, aligned_buf)?;
192 trace!("Swapping done"); 201 trace!("Swapping done");
193 } else { 202 } else {
194 trace!("Reverting"); 203 trace!("Reverting");
195 self.revert(p, magic, page)?; 204 self.revert(p, aligned_buf)?;
196 205
197 let state_flash = p.state(); 206 let state_flash = p.state();
207 let state_word = &mut aligned_buf[..P::STATE::WRITE_SIZE];
198 208
199 // Invalidate progress 209 // Invalidate progress
200 magic.fill(!P::STATE::ERASE_VALUE); 210 state_word.fill(!P::STATE::ERASE_VALUE);
201 self.state 211 self.state
202 .write_blocking(state_flash, P::STATE::WRITE_SIZE as u32, magic)?; 212 .write_blocking(state_flash, P::STATE::WRITE_SIZE as u32, state_word)?;
203 213
204 // Clear magic and progress 214 // Clear magic and progress
205 self.state.wipe_blocking(state_flash)?; 215 self.state.wipe_blocking(state_flash)?;
206 216
207 // Set magic 217 // Set magic
208 magic.fill(BOOT_MAGIC); 218 state_word.fill(BOOT_MAGIC);
209 self.state.write_blocking(state_flash, 0, magic)?; 219 self.state.write_blocking(state_flash, 0, state_word)?;
210 } 220 }
211 } 221 }
212 Ok(state) 222 Ok(state)
213 } 223 }
214 224
215 fn is_swapped<P: FlashConfig>(&mut self, p: &mut P, magic: &mut [u8], page: &mut [u8]) -> Result<bool, BootError> { 225 fn is_swapped<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<bool, BootError> {
216 let page_size = page.len(); 226 let page_count = self.active.len() / P::page_size();
217 let page_count = self.active.len() / page_size; 227 let progress = self.current_progress(p, aligned_buf)?;
218 let progress = self.current_progress(p, magic)?;
219 228
220 Ok(progress >= page_count * 2) 229 Ok(progress >= page_count * 2)
221 } 230 }
222 231
223 fn current_progress<P: FlashConfig>(&mut self, config: &mut P, aligned: &mut [u8]) -> Result<usize, BootError> { 232 fn current_progress<P: FlashConfig>(&mut self, config: &mut P, aligned_buf: &mut [u8]) -> Result<usize, BootError> {
224 let write_size = aligned.len(); 233 let max_index = ((self.state.len() - P::STATE::WRITE_SIZE) / P::STATE::WRITE_SIZE) - 2;
225 let max_index = ((self.state.len() - write_size) / write_size) - 2;
226 aligned.fill(!P::STATE::ERASE_VALUE);
227
228 let state_flash = config.state(); 234 let state_flash = config.state();
235 let state_word = &mut aligned_buf[..P::STATE::WRITE_SIZE];
229 236
230 self.state 237 self.state
231 .read_blocking(state_flash, P::STATE::WRITE_SIZE as u32, aligned)?; 238 .read_blocking(state_flash, P::STATE::WRITE_SIZE as u32, state_word)?;
232 if aligned.iter().any(|&b| b != P::STATE::ERASE_VALUE) { 239 if state_word.iter().any(|&b| b != P::STATE::ERASE_VALUE) {
233 // Progress is invalid 240 // Progress is invalid
234 return Ok(max_index); 241 return Ok(max_index);
235 } 242 }
236 243
237 for index in 0..max_index { 244 for index in 0..max_index {
238 self.state 245 self.state.read_blocking(
239 .read_blocking(state_flash, (2 + index) as u32 * P::STATE::WRITE_SIZE as u32, aligned)?; 246 state_flash,
247 (2 + index) as u32 * P::STATE::WRITE_SIZE as u32,
248 state_word,
249 )?;
240 250
241 if aligned.iter().any(|&b| b == P::STATE::ERASE_VALUE) { 251 if state_word.iter().any(|&b| b == P::STATE::ERASE_VALUE) {
242 return Ok(index); 252 return Ok(index);
243 } 253 }
244 } 254 }
245 Ok(max_index) 255 Ok(max_index)
246 } 256 }
247 257
248 fn update_progress<P: FlashConfig>(&mut self, index: usize, p: &mut P, magic: &mut [u8]) -> Result<(), BootError> { 258 fn update_progress<P: FlashConfig>(
249 let aligned = magic; 259 &mut self,
250 aligned.fill(!P::STATE::ERASE_VALUE); 260 index: usize,
261 p: &mut P,
262 aligned_buf: &mut [u8],
263 ) -> Result<(), BootError> {
264 let state_word = &mut aligned_buf[..P::STATE::WRITE_SIZE];
265 state_word.fill(!P::STATE::ERASE_VALUE);
251 self.state 266 self.state
252 .write_blocking(p.state(), (2 + index) as u32 * P::STATE::WRITE_SIZE as u32, aligned)?; 267 .write_blocking(p.state(), (2 + index) as u32 * P::STATE::WRITE_SIZE as u32, state_word)?;
253 Ok(()) 268 Ok(())
254 } 269 }
255 270
@@ -259,26 +274,24 @@ impl BootLoader {
259 from_offset: u32, 274 from_offset: u32,
260 to_offset: u32, 275 to_offset: u32,
261 p: &mut P, 276 p: &mut P,
262 magic: &mut [u8], 277 aligned_buf: &mut [u8],
263 page: &mut [u8],
264 ) -> Result<(), BootError> { 278 ) -> Result<(), BootError> {
265 let buf = page; 279 if self.current_progress(p, aligned_buf)? <= idx {
266 if self.current_progress(p, magic)? <= idx {
267 let mut offset = from_offset; 280 let mut offset = from_offset;
268 for chunk in buf.chunks_mut(P::DFU::BLOCK_SIZE) { 281 for chunk in aligned_buf.chunks_mut(P::DFU::BLOCK_SIZE) {
269 self.dfu.read_blocking(p.dfu(), offset, chunk)?; 282 self.dfu.read_blocking(p.dfu(), offset, chunk)?;
270 offset += chunk.len() as u32; 283 offset += chunk.len() as u32;
271 } 284 }
272 285
273 self.active 286 self.active
274 .erase_blocking(p.active(), to_offset, to_offset + buf.len() as u32)?; 287 .erase_blocking(p.active(), to_offset, to_offset + P::page_size() as u32)?;
275 288
276 let mut offset = to_offset; 289 let mut offset = to_offset;
277 for chunk in buf.chunks(P::ACTIVE::BLOCK_SIZE) { 290 for chunk in aligned_buf.chunks(P::ACTIVE::BLOCK_SIZE) {
278 self.active.write_blocking(p.active(), offset, chunk)?; 291 self.active.write_blocking(p.active(), offset, chunk)?;
279 offset += chunk.len() as u32; 292 offset += chunk.len() as u32;
280 } 293 }
281 self.update_progress(idx, p, magic)?; 294 self.update_progress(idx, p, aligned_buf)?;
282 } 295 }
283 Ok(()) 296 Ok(())
284 } 297 }
@@ -289,32 +302,30 @@ impl BootLoader {
289 from_offset: u32, 302 from_offset: u32,
290 to_offset: u32, 303 to_offset: u32,
291 p: &mut P, 304 p: &mut P,
292 magic: &mut [u8], 305 aligned_buf: &mut [u8],
293 page: &mut [u8],
294 ) -> Result<(), BootError> { 306 ) -> Result<(), BootError> {
295 let buf = page; 307 if self.current_progress(p, aligned_buf)? <= idx {
296 if self.current_progress(p, magic)? <= idx {
297 let mut offset = from_offset; 308 let mut offset = from_offset;
298 for chunk in buf.chunks_mut(P::ACTIVE::BLOCK_SIZE) { 309 for chunk in aligned_buf.chunks_mut(P::ACTIVE::BLOCK_SIZE) {
299 self.active.read_blocking(p.active(), offset, chunk)?; 310 self.active.read_blocking(p.active(), offset, chunk)?;
300 offset += chunk.len() as u32; 311 offset += chunk.len() as u32;
301 } 312 }
302 313
303 self.dfu 314 self.dfu
304 .erase_blocking(p.dfu(), to_offset as u32, to_offset + buf.len() as u32)?; 315 .erase_blocking(p.dfu(), to_offset as u32, to_offset + P::page_size() as u32)?;
305 316
306 let mut offset = to_offset; 317 let mut offset = to_offset;
307 for chunk in buf.chunks(P::DFU::BLOCK_SIZE) { 318 for chunk in aligned_buf.chunks(P::DFU::BLOCK_SIZE) {
308 self.dfu.write_blocking(p.dfu(), offset, chunk)?; 319 self.dfu.write_blocking(p.dfu(), offset, chunk)?;
309 offset += chunk.len() as u32; 320 offset += chunk.len() as u32;
310 } 321 }
311 self.update_progress(idx, p, magic)?; 322 self.update_progress(idx, p, aligned_buf)?;
312 } 323 }
313 Ok(()) 324 Ok(())
314 } 325 }
315 326
316 fn swap<P: FlashConfig>(&mut self, p: &mut P, magic: &mut [u8], page: &mut [u8]) -> Result<(), BootError> { 327 fn swap<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<(), BootError> {
317 let page_size = page.len(); 328 let page_size = P::page_size();
318 let page_count = self.active.len() / page_size; 329 let page_count = self.active.len() / page_size;
319 trace!("Page count: {}", page_count); 330 trace!("Page count: {}", page_count);
320 for page_num in 0..page_count { 331 for page_num in 0..page_count {
@@ -326,20 +337,20 @@ impl BootLoader {
326 let active_from_offset = ((page_count - 1 - page_num) * page_size) as u32; 337 let active_from_offset = ((page_count - 1 - page_num) * page_size) as u32;
327 let dfu_to_offset = ((page_count - page_num) * page_size) as u32; 338 let dfu_to_offset = ((page_count - page_num) * page_size) as u32;
328 //trace!("Copy active {} to dfu {}", active_from_offset, dfu_to_offset); 339 //trace!("Copy active {} to dfu {}", active_from_offset, dfu_to_offset);
329 self.copy_page_once_to_dfu(idx, active_from_offset, dfu_to_offset, p, magic, page)?; 340 self.copy_page_once_to_dfu(idx, active_from_offset, dfu_to_offset, p, aligned_buf)?;
330 341
331 // Copy DFU page to the active page 342 // Copy DFU page to the active page
332 let active_to_offset = ((page_count - 1 - page_num) * page_size) as u32; 343 let active_to_offset = ((page_count - 1 - page_num) * page_size) as u32;
333 let dfu_from_offset = ((page_count - 1 - page_num) * page_size) as u32; 344 let dfu_from_offset = ((page_count - 1 - page_num) * page_size) as u32;
334 //trace!("Copy dfy {} to active {}", dfu_from_offset, active_to_offset); 345 //trace!("Copy dfy {} to active {}", dfu_from_offset, active_to_offset);
335 self.copy_page_once_to_active(idx + 1, dfu_from_offset, active_to_offset, p, magic, page)?; 346 self.copy_page_once_to_active(idx + 1, dfu_from_offset, active_to_offset, p, aligned_buf)?;
336 } 347 }
337 348
338 Ok(()) 349 Ok(())
339 } 350 }
340 351
341 fn revert<P: FlashConfig>(&mut self, p: &mut P, magic: &mut [u8], page: &mut [u8]) -> Result<(), BootError> { 352 fn revert<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<(), BootError> {
342 let page_size = page.len(); 353 let page_size = P::page_size();
343 let page_count = self.active.len() / page_size; 354 let page_count = self.active.len() / page_size;
344 for page_num in 0..page_count { 355 for page_num in 0..page_count {
345 let idx = page_count * 2 + page_num * 2; 356 let idx = page_count * 2 + page_num * 2;
@@ -347,21 +358,22 @@ impl BootLoader {
347 // Copy the bad active page to the DFU page 358 // Copy the bad active page to the DFU page
348 let active_from_offset = (page_num * page_size) as u32; 359 let active_from_offset = (page_num * page_size) as u32;
349 let dfu_to_offset = (page_num * page_size) as u32; 360 let dfu_to_offset = (page_num * page_size) as u32;
350 self.copy_page_once_to_dfu(idx, active_from_offset, dfu_to_offset, p, magic, page)?; 361 self.copy_page_once_to_dfu(idx, active_from_offset, dfu_to_offset, p, aligned_buf)?;
351 362
352 // Copy the DFU page back to the active page 363 // Copy the DFU page back to the active page
353 let active_to_offset = (page_num * page_size) as u32; 364 let active_to_offset = (page_num * page_size) as u32;
354 let dfu_from_offset = ((page_num + 1) * page_size) as u32; 365 let dfu_from_offset = ((page_num + 1) * page_size) as u32;
355 self.copy_page_once_to_active(idx + 1, dfu_from_offset, active_to_offset, p, magic, page)?; 366 self.copy_page_once_to_active(idx + 1, dfu_from_offset, active_to_offset, p, aligned_buf)?;
356 } 367 }
357 368
358 Ok(()) 369 Ok(())
359 } 370 }
360 371
361 fn read_state<P: FlashConfig>(&mut self, config: &mut P, magic: &mut [u8]) -> Result<State, BootError> { 372 fn read_state<P: FlashConfig>(&mut self, config: &mut P, aligned_buf: &mut [u8]) -> Result<State, BootError> {
362 self.state.read_blocking(config.state(), 0, magic)?; 373 let state_word = &mut aligned_buf[..P::STATE::WRITE_SIZE];
374 self.state.read_blocking(config.state(), 0, state_word)?;
363 375
364 if !magic.iter().any(|&b| b != SWAP_MAGIC) { 376 if !state_word.iter().any(|&b| b != SWAP_MAGIC) {
365 Ok(State::Swap) 377 Ok(State::Swap)
366 } else { 378 } else {
367 Ok(State::Boot) 379 Ok(State::Boot)
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs
index d53c613a3..896498c0b 100644
--- a/embassy-boot/boot/src/lib.rs
+++ b/embassy-boot/boot/src/lib.rs
@@ -77,12 +77,8 @@ mod tests {
77 77
78 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); 78 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE);
79 79
80 let mut magic = [0; 4];
81 let mut page = [0; 4096]; 80 let mut page = [0; 4096];
82 assert_eq!( 81 assert_eq!(State::Boot, bootloader.prepare_boot(&mut flash, &mut page).unwrap());
83 State::Boot,
84 bootloader.prepare_boot(&mut flash, &mut magic, &mut page).unwrap()
85 );
86 } 82 }
87 83
88 #[test] 84 #[test]
@@ -110,12 +106,11 @@ mod tests {
110 } 106 }
111 block_on(updater.mark_updated(&mut flash, &mut aligned)).unwrap(); 107 block_on(updater.mark_updated(&mut flash, &mut aligned)).unwrap();
112 108
113 let mut magic = [0; 4];
114 let mut page = [0; 4096]; 109 let mut page = [0; 4096];
115 assert_eq!( 110 assert_eq!(
116 State::Swap, 111 State::Swap,
117 bootloader 112 bootloader
118 .prepare_boot(&mut SingleFlashConfig::new(&mut flash), &mut magic, &mut page) 113 .prepare_boot(&mut SingleFlashConfig::new(&mut flash), &mut page)
119 .unwrap() 114 .unwrap()
120 ); 115 );
121 116
@@ -132,7 +127,7 @@ mod tests {
132 assert_eq!( 127 assert_eq!(
133 State::Swap, 128 State::Swap,
134 bootloader 129 bootloader
135 .prepare_boot(&mut SingleFlashConfig::new(&mut flash), &mut magic, &mut page) 130 .prepare_boot(&mut SingleFlashConfig::new(&mut flash), &mut page)
136 .unwrap() 131 .unwrap()
137 ); 132 );
138 133
@@ -150,7 +145,7 @@ mod tests {
150 assert_eq!( 145 assert_eq!(
151 State::Boot, 146 State::Boot,
152 bootloader 147 bootloader
153 .prepare_boot(&mut SingleFlashConfig::new(&mut flash), &mut magic, &mut page) 148 .prepare_boot(&mut SingleFlashConfig::new(&mut flash), &mut page)
154 .unwrap() 149 .unwrap()
155 ); 150 );
156 } 151 }
@@ -184,17 +179,12 @@ mod tests {
184 block_on(updater.mark_updated(&mut state, &mut aligned)).unwrap(); 179 block_on(updater.mark_updated(&mut state, &mut aligned)).unwrap();
185 180
186 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); 181 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE);
187 let mut magic = [0; 4];
188 let mut page = [0; 4096]; 182 let mut page = [0; 4096];
189 183
190 assert_eq!( 184 assert_eq!(
191 State::Swap, 185 State::Swap,
192 bootloader 186 bootloader
193 .prepare_boot( 187 .prepare_boot(&mut MultiFlashConfig::new(&mut active, &mut state, &mut dfu), &mut page)
194 &mut MultiFlashConfig::new(&mut active, &mut state, &mut dfu),
195 &mut magic,
196 &mut page
197 )
198 .unwrap() 188 .unwrap()
199 ); 189 );
200 190
@@ -237,14 +227,12 @@ mod tests {
237 block_on(updater.mark_updated(&mut state, &mut aligned)).unwrap(); 227 block_on(updater.mark_updated(&mut state, &mut aligned)).unwrap();
238 228
239 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); 229 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE);
240 let mut magic = [0; 4];
241 let mut page = [0; 4096]; 230 let mut page = [0; 4096];
242 assert_eq!( 231 assert_eq!(
243 State::Swap, 232 State::Swap,
244 bootloader 233 bootloader
245 .prepare_boot( 234 .prepare_boot(
246 &mut MultiFlashConfig::new(&mut active, &mut state, &mut dfu,), 235 &mut MultiFlashConfig::new(&mut active, &mut state, &mut dfu,),
247 &mut magic,
248 &mut page 236 &mut page
249 ) 237 )
250 .unwrap() 238 .unwrap()