1#![no_std]
2#![allow(async_fn_in_trait)]
3#![allow(unsafe_op_in_unsafe_fn)]
4#![warn(missing_docs)]
5#![doc = include_str!("../README.md")]
6
7#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
9
10mod fmt;
11
12mod boot_loader;
13mod digest_adapters;
14mod firmware_updater;
15#[cfg(test)]
16mod mem_flash;
17#[cfg(test)]
18mod test_flash;
19
20#[cfg(not(feature = "flash-erase-zero"))]
23pub(crate) const STATE_ERASE_VALUE: u8 = 0xFF;
24#[cfg(feature = "flash-erase-zero")]
25pub(crate) const STATE_ERASE_VALUE: u8 = 0x00;
26
27pub use boot_loader::{BootError, BootLoader, BootLoaderConfig};
28pub use firmware_updater::{
29 BlockingFirmwareState, BlockingFirmwareUpdater, FirmwareState, FirmwareUpdater, FirmwareUpdaterConfig,
30 FirmwareUpdaterError,
31};
32
33pub(crate) const REVERT_MAGIC: u8 = 0xC0;
34pub(crate) const BOOT_MAGIC: u8 = 0xD0;
35pub(crate) const SWAP_MAGIC: u8 = 0xF0;
36pub(crate) const DFU_DETACH_MAGIC: u8 = 0xE0;
37
38#[derive(PartialEq, Eq, Debug)]
40#[cfg_attr(feature = "defmt", derive(defmt::Format))]
41pub enum State {
42 Boot,
44 Swap,
46 Revert,
48 DfuDetach,
50}
51
52impl<T> From<T> for State
53where
54 T: AsRef<[u8]>,
55{
56 fn from(magic: T) -> State {
57 let magic = magic.as_ref();
58 if !magic.iter().any(|&b| b != SWAP_MAGIC) {
59 State::Swap
60 } else if !magic.iter().any(|&b| b != REVERT_MAGIC) {
61 State::Revert
62 } else if !magic.iter().any(|&b| b != DFU_DETACH_MAGIC) {
63 State::DfuDetach
64 } else {
65 State::Boot
66 }
67 }
68}
69
70#[repr(align(32))]
72pub struct AlignedBuffer<const N: usize>(pub [u8; N]);
73
74impl<const N: usize> AsRef<[u8]> for AlignedBuffer<N> {
75 fn as_ref(&self) -> &[u8] {
76 &self.0
77 }
78}
79
80impl<const N: usize> AsMut<[u8]> for AlignedBuffer<N> {
81 fn as_mut(&mut self) -> &mut [u8] {
82 &mut self.0
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 #![allow(unused_imports)]
89
90 use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
91 use embedded_storage_async::nor_flash::NorFlash as AsyncNorFlash;
92 use futures::executor::block_on;
93
94 use super::*;
95 use crate::boot_loader::BootLoaderConfig;
96 use crate::firmware_updater::FirmwareUpdaterConfig;
97 use crate::mem_flash::MemFlash;
98 use crate::test_flash::{AsyncTestFlash, BlockingTestFlash};
99
100 #[test]
116 fn test_boot_state() {
117 let flash = BlockingTestFlash::new(BootLoaderConfig {
118 active: MemFlash::<57344, 4096, 4>::default(),
119 dfu: MemFlash::<61440, 4096, 4>::default(),
120 state: MemFlash::<4096, 4096, 4>::default(),
121 });
122
123 flash.state().write(0, &[BOOT_MAGIC; 4]).unwrap();
124
125 let mut bootloader = BootLoader::new(BootLoaderConfig {
126 active: flash.active(),
127 dfu: flash.dfu(),
128 state: flash.state(),
129 });
130
131 let mut page = [0; 4096];
132 assert_eq!(State::Boot, bootloader.prepare_boot(&mut page).unwrap());
133 }
134
135 #[test]
136 #[cfg(not(feature = "_verify"))]
137 fn test_swap_state() {
138 const FIRMWARE_SIZE: usize = 57344;
139 let flash = AsyncTestFlash::new(BootLoaderConfig {
140 active: MemFlash::<FIRMWARE_SIZE, 4096, 4>::default(),
141 dfu: MemFlash::<61440, 4096, 4>::default(),
142 state: MemFlash::<4096, 4096, 4>::default(),
143 });
144
145 const ORIGINAL: [u8; FIRMWARE_SIZE] = [0x55; FIRMWARE_SIZE];
146 const UPDATE: [u8; FIRMWARE_SIZE] = [0xAA; FIRMWARE_SIZE];
147 let mut aligned = [0; 4];
148
149 block_on(flash.active().erase(0, ORIGINAL.len() as u32)).unwrap();
150 block_on(flash.active().write(0, &ORIGINAL)).unwrap();
151
152 let mut updater = FirmwareUpdater::new(
153 FirmwareUpdaterConfig {
154 dfu: flash.dfu(),
155 state: flash.state(),
156 },
157 &mut aligned,
158 );
159 block_on(updater.write_firmware(0, &UPDATE)).unwrap();
160 block_on(updater.mark_updated()).unwrap();
161
162 let res: Result<(), FirmwareUpdaterError> = block_on(updater.write_firmware(0, &UPDATE));
164 assert!(matches!(res, Err::<(), _>(FirmwareUpdaterError::BadState)));
165
166 let flash = flash.into_blocking();
167 let mut bootloader = BootLoader::new(BootLoaderConfig {
168 active: flash.active(),
169 dfu: flash.dfu(),
170 state: flash.state(),
171 });
172
173 let mut page = [0; 1024];
174 assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap());
175
176 let mut read_buf = [0; FIRMWARE_SIZE];
177 flash.active().read(0, &mut read_buf).unwrap();
178 assert_eq!(UPDATE, read_buf);
179 flash.dfu().read(4096, &mut read_buf).unwrap();
181 assert_eq!(ORIGINAL, read_buf);
182
183 assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap());
185
186 assert_eq!(State::Revert, bootloader.prepare_boot(&mut page).unwrap());
188
189 let mut read_buf = [0; FIRMWARE_SIZE];
190 flash.active().read(0, &mut read_buf).unwrap();
191 assert_eq!(ORIGINAL, read_buf);
192 flash.dfu().read(0, &mut read_buf).unwrap();
194 assert_eq!(UPDATE, read_buf);
195
196 let flash = flash.into_async();
198 let mut updater = FirmwareUpdater::new(
199 FirmwareUpdaterConfig {
200 dfu: flash.dfu(),
201 state: flash.state(),
202 },
203 &mut aligned,
204 );
205 block_on(updater.mark_booted()).unwrap();
206
207 let flash = flash.into_blocking();
208 let mut bootloader = BootLoader::new(BootLoaderConfig {
209 active: flash.active(),
210 dfu: flash.dfu(),
211 state: flash.state(),
212 });
213 assert_eq!(State::Boot, bootloader.prepare_boot(&mut page).unwrap());
214 }
215
216 #[test]
217 #[cfg(not(feature = "_verify"))]
218 fn test_swap_state_active_page_biggest() {
219 const FIRMWARE_SIZE: usize = 12288;
220 let flash = AsyncTestFlash::new(BootLoaderConfig {
221 active: MemFlash::<12288, 4096, 8>::random(),
222 dfu: MemFlash::<16384, 2048, 8>::random(),
223 state: MemFlash::<2048, 128, 4>::random(),
224 });
225
226 const ORIGINAL: [u8; FIRMWARE_SIZE] = [0x55; FIRMWARE_SIZE];
227 const UPDATE: [u8; FIRMWARE_SIZE] = [0xAA; FIRMWARE_SIZE];
228 let mut aligned = [0; 4];
229
230 block_on(flash.active().erase(0, ORIGINAL.len() as u32)).unwrap();
231 block_on(flash.active().write(0, &ORIGINAL)).unwrap();
232
233 let mut updater = FirmwareUpdater::new(
234 FirmwareUpdaterConfig {
235 dfu: flash.dfu(),
236 state: flash.state(),
237 },
238 &mut aligned,
239 );
240 block_on(updater.write_firmware(0, &UPDATE)).unwrap();
241 block_on(updater.mark_updated()).unwrap();
242
243 let flash = flash.into_blocking();
244 let mut bootloader = BootLoader::new(BootLoaderConfig {
245 active: flash.active(),
246 dfu: flash.dfu(),
247 state: flash.state(),
248 });
249
250 let mut page = [0; 4096];
251 assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap());
252
253 let mut read_buf = [0; FIRMWARE_SIZE];
254 flash.active().read(0, &mut read_buf).unwrap();
255 assert_eq!(UPDATE, read_buf);
256 flash.dfu().read(4096, &mut read_buf).unwrap();
258 assert_eq!(ORIGINAL, read_buf);
259 }
260
261 #[test]
262 #[cfg(not(feature = "_verify"))]
263 fn test_swap_state_dfu_page_biggest() {
264 const FIRMWARE_SIZE: usize = 12288;
265 let flash = AsyncTestFlash::new(BootLoaderConfig {
266 active: MemFlash::<FIRMWARE_SIZE, 2048, 4>::random(),
267 dfu: MemFlash::<16384, 4096, 8>::random(),
268 state: MemFlash::<2048, 128, 4>::random(),
269 });
270
271 const ORIGINAL: [u8; FIRMWARE_SIZE] = [0x55; FIRMWARE_SIZE];
272 const UPDATE: [u8; FIRMWARE_SIZE] = [0xAA; FIRMWARE_SIZE];
273 let mut aligned = [0; 4];
274
275 block_on(flash.active().erase(0, ORIGINAL.len() as u32)).unwrap();
276 block_on(flash.active().write(0, &ORIGINAL)).unwrap();
277
278 let mut updater = FirmwareUpdater::new(
279 FirmwareUpdaterConfig {
280 dfu: flash.dfu(),
281 state: flash.state(),
282 },
283 &mut aligned,
284 );
285 block_on(updater.write_firmware(0, &UPDATE)).unwrap();
286 block_on(updater.mark_updated()).unwrap();
287
288 let flash = flash.into_blocking();
289 let mut bootloader = BootLoader::new(BootLoaderConfig {
290 active: flash.active(),
291 dfu: flash.dfu(),
292 state: flash.state(),
293 });
294 let mut page = [0; 4096];
295 assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap());
296
297 let mut read_buf = [0; FIRMWARE_SIZE];
298 flash.active().read(0, &mut read_buf).unwrap();
299 assert_eq!(UPDATE, read_buf);
300 flash.dfu().read(4096, &mut read_buf).unwrap();
302 assert_eq!(ORIGINAL, read_buf);
303 }
304
305 #[test]
306 #[cfg(feature = "_verify")]
307 fn test_verify() {
308 use ed25519_dalek::{Digest, Sha512, Signature, Signer, SigningKey, VerifyingKey};
312 use rand::rngs::OsRng;
313
314 let mut csprng = OsRng {};
315 let keypair = SigningKey::generate(&mut csprng);
316
317 let firmware: &[u8] = b"This are bytes that would otherwise be firmware bytes for DFU.";
318 let mut digest = Sha512::new();
319 digest.update(&firmware);
320 let message = digest.finalize();
321 let signature: Signature = keypair.sign(&message);
322
323 let public_key = keypair.verifying_key();
324
325 let flash = BlockingTestFlash::new(BootLoaderConfig {
327 active: MemFlash::<0, 0, 0>::default(),
328 dfu: MemFlash::<4096, 4096, 4>::default(),
329 state: MemFlash::<4096, 4096, 4>::default(),
330 });
331
332 let firmware_len = firmware.len();
333
334 let mut write_buf = [0; 4096];
335 write_buf[0..firmware_len].copy_from_slice(firmware);
336 flash.dfu().write(0, &write_buf).unwrap();
337
338 let flash = flash.into_async();
340 let mut aligned = [0; 4];
341 let mut updater = FirmwareUpdater::new(
342 FirmwareUpdaterConfig {
343 dfu: flash.dfu(),
344 state: flash.state(),
345 },
346 &mut aligned,
347 );
348
349 assert!(
350 block_on(updater.verify_and_mark_updated(
351 &public_key.to_bytes(),
352 &signature.to_bytes(),
353 firmware_len as u32,
354 ))
355 .is_ok()
356 );
357 }
358}