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