diff options
Diffstat (limited to 'embassy-boot/boot/src/lib.rs')
| -rw-r--r-- | embassy-boot/boot/src/lib.rs | 248 |
1 files changed, 141 insertions, 107 deletions
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs index 15d3a4f21..d13eafdd0 100644 --- a/embassy-boot/boot/src/lib.rs +++ b/embassy-boot/boot/src/lib.rs | |||
| @@ -51,10 +51,18 @@ impl<const N: usize> AsMut<[u8]> for AlignedBuffer<N> { | |||
| 51 | 51 | ||
| 52 | #[cfg(test)] | 52 | #[cfg(test)] |
| 53 | mod tests { | 53 | mod tests { |
| 54 | use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; | ||
| 55 | #[cfg(feature = "nightly")] | ||
| 56 | use embedded_storage_async::nor_flash::NorFlash as AsyncNorFlash; | ||
| 54 | use futures::executor::block_on; | 57 | use futures::executor::block_on; |
| 55 | 58 | ||
| 56 | use super::*; | 59 | use super::*; |
| 60 | use crate::boot_loader::BootLoaderConfig; | ||
| 61 | use crate::firmware_updater::FirmwareUpdaterConfig; | ||
| 57 | use crate::mem_flash::MemFlash; | 62 | use crate::mem_flash::MemFlash; |
| 63 | #[cfg(feature = "nightly")] | ||
| 64 | use crate::test_flash::AsyncTestFlash; | ||
| 65 | use crate::test_flash::BlockingTestFlash; | ||
| 58 | 66 | ||
| 59 | /* | 67 | /* |
| 60 | #[test] | 68 | #[test] |
| @@ -73,147 +81,173 @@ mod tests { | |||
| 73 | 81 | ||
| 74 | #[test] | 82 | #[test] |
| 75 | fn test_boot_state() { | 83 | fn test_boot_state() { |
| 76 | const STATE: Partition = Partition::new(0, 4096); | 84 | let flash = BlockingTestFlash::new(BootLoaderConfig { |
| 77 | const ACTIVE: Partition = Partition::new(4096, 61440); | 85 | active: MemFlash::<57344, 4096, 4>::default(), |
| 78 | const DFU: Partition = Partition::new(61440, 122880); | 86 | dfu: MemFlash::<61440, 4096, 4>::default(), |
| 87 | state: MemFlash::<4096, 4096, 4>::default(), | ||
| 88 | }); | ||
| 79 | 89 | ||
| 80 | let mut flash = MemFlash::<131072, 4096, 4>::default(); | 90 | flash.state().write(0, &[BOOT_MAGIC; 4]).unwrap(); |
| 81 | flash.mem[0..4].copy_from_slice(&[BOOT_MAGIC; 4]); | ||
| 82 | let mut flash = SingleFlashConfig::new(&mut flash); | ||
| 83 | 91 | ||
| 84 | let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); | 92 | let mut bootloader = BootLoader::new(BootLoaderConfig { |
| 93 | active: flash.active(), | ||
| 94 | dfu: flash.dfu(), | ||
| 95 | state: flash.state(), | ||
| 96 | }); | ||
| 85 | 97 | ||
| 86 | let mut page = [0; 4096]; | 98 | let mut page = [0; 4096]; |
| 87 | assert_eq!(State::Boot, bootloader.prepare_boot(&mut flash, &mut page).unwrap()); | 99 | assert_eq!(State::Boot, bootloader.prepare_boot(&mut page).unwrap()); |
| 88 | } | 100 | } |
| 89 | 101 | ||
| 90 | #[test] | 102 | #[test] |
| 91 | #[cfg(all(feature = "nightly", not(feature = "_verify")))] | 103 | #[cfg(all(feature = "nightly", not(feature = "_verify")))] |
| 92 | fn test_swap_state() { | 104 | fn test_swap_state() { |
| 93 | const STATE: Partition = Partition::new(0, 4096); | 105 | const FIRMWARE_SIZE: usize = 57344; |
| 94 | const ACTIVE: Partition = Partition::new(4096, 61440); | 106 | let flash = AsyncTestFlash::new(BootLoaderConfig { |
| 95 | const DFU: Partition = Partition::new(61440, 122880); | 107 | active: MemFlash::<FIRMWARE_SIZE, 4096, 4>::default(), |
| 96 | let mut flash = MemFlash::<131072, 4096, 4>::random(); | 108 | dfu: MemFlash::<61440, 4096, 4>::default(), |
| 97 | 109 | state: MemFlash::<4096, 4096, 4>::default(), | |
| 98 | let original = [rand::random::<u8>(); ACTIVE.size() as usize]; | 110 | }); |
| 99 | let update = [rand::random::<u8>(); ACTIVE.size() as usize]; | 111 | |
| 112 | const ORIGINAL: [u8; FIRMWARE_SIZE] = [0x55; FIRMWARE_SIZE]; | ||
| 113 | const UPDATE: [u8; FIRMWARE_SIZE] = [0xAA; FIRMWARE_SIZE]; | ||
| 100 | let mut aligned = [0; 4]; | 114 | let mut aligned = [0; 4]; |
| 101 | 115 | ||
| 102 | flash.program(ACTIVE.from, &original).unwrap(); | 116 | block_on(flash.active().erase(0, ORIGINAL.len() as u32)).unwrap(); |
| 117 | block_on(flash.active().write(0, &ORIGINAL)).unwrap(); | ||
| 118 | |||
| 119 | let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig { | ||
| 120 | dfu: flash.dfu(), | ||
| 121 | state: flash.state(), | ||
| 122 | }); | ||
| 123 | block_on(updater.write_firmware(0, &UPDATE)).unwrap(); | ||
| 124 | block_on(updater.mark_updated(&mut aligned)).unwrap(); | ||
| 103 | 125 | ||
| 104 | let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); | 126 | let flash = flash.into_blocking(); |
| 105 | let mut updater = FirmwareUpdater::new(DFU, STATE); | 127 | let mut bootloader = BootLoader::new(BootLoaderConfig { |
| 106 | block_on(updater.write_firmware(0, &update, &mut flash)).unwrap(); | 128 | active: flash.active(), |
| 107 | block_on(updater.mark_updated(&mut flash, &mut aligned)).unwrap(); | 129 | dfu: flash.dfu(), |
| 130 | state: flash.state(), | ||
| 131 | }); | ||
| 108 | 132 | ||
| 109 | let mut page = [0; 1024]; | 133 | let mut page = [0; 1024]; |
| 110 | assert_eq!( | 134 | assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap()); |
| 111 | State::Swap, | ||
| 112 | bootloader | ||
| 113 | .prepare_boot(&mut SingleFlashConfig::new(&mut flash), &mut page) | ||
| 114 | .unwrap() | ||
| 115 | ); | ||
| 116 | 135 | ||
| 117 | flash.assert_eq(ACTIVE.from, &update); | 136 | let mut read_buf = [0; FIRMWARE_SIZE]; |
| 137 | flash.active().read(0, &mut read_buf).unwrap(); | ||
| 138 | assert_eq!(UPDATE, read_buf); | ||
| 118 | // First DFU page is untouched | 139 | // First DFU page is untouched |
| 119 | flash.assert_eq(DFU.from + 4096, &original); | 140 | flash.dfu().read(4096, &mut read_buf).unwrap(); |
| 141 | assert_eq!(ORIGINAL, read_buf); | ||
| 120 | 142 | ||
| 121 | // Running again should cause a revert | 143 | // Running again should cause a revert |
| 122 | assert_eq!( | 144 | assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap()); |
| 123 | State::Swap, | ||
| 124 | bootloader | ||
| 125 | .prepare_boot(&mut SingleFlashConfig::new(&mut flash), &mut page) | ||
| 126 | .unwrap() | ||
| 127 | ); | ||
| 128 | 145 | ||
| 129 | flash.assert_eq(ACTIVE.from, &original); | 146 | let mut read_buf = [0; FIRMWARE_SIZE]; |
| 130 | // Last page is untouched | 147 | flash.active().read(0, &mut read_buf).unwrap(); |
| 131 | flash.assert_eq(DFU.from, &update); | 148 | assert_eq!(ORIGINAL, read_buf); |
| 149 | // Last DFU page is untouched | ||
| 150 | flash.dfu().read(0, &mut read_buf).unwrap(); | ||
| 151 | assert_eq!(UPDATE, read_buf); | ||
| 132 | 152 | ||
| 133 | // Mark as booted | 153 | // Mark as booted |
| 134 | block_on(updater.mark_booted(&mut flash, &mut aligned)).unwrap(); | 154 | let flash = flash.into_async(); |
| 135 | assert_eq!( | 155 | let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig { |
| 136 | State::Boot, | 156 | dfu: flash.dfu(), |
| 137 | bootloader | 157 | state: flash.state(), |
| 138 | .prepare_boot(&mut SingleFlashConfig::new(&mut flash), &mut page) | 158 | }); |
| 139 | .unwrap() | 159 | block_on(updater.mark_booted(&mut aligned)).unwrap(); |
| 140 | ); | 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 | assert_eq!(State::Boot, bootloader.prepare_boot(&mut page).unwrap()); | ||
| 141 | } | 168 | } |
| 142 | 169 | ||
| 143 | #[test] | 170 | #[test] |
| 144 | #[cfg(all(feature = "nightly", not(feature = "_verify")))] | 171 | #[cfg(all(feature = "nightly", not(feature = "_verify")))] |
| 145 | fn test_separate_flash_active_page_biggest() { | 172 | fn test_swap_state_active_page_biggest() { |
| 146 | const STATE: Partition = Partition::new(2048, 4096); | 173 | const FIRMWARE_SIZE: usize = 12288; |
| 147 | const ACTIVE: Partition = Partition::new(4096, 16384); | 174 | let flash = AsyncTestFlash::new(BootLoaderConfig { |
| 148 | const DFU: Partition = Partition::new(0, 16384); | 175 | active: MemFlash::<12288, 4096, 8>::random(), |
| 149 | 176 | dfu: MemFlash::<16384, 2048, 8>::random(), | |
| 150 | let mut active = MemFlash::<16384, 4096, 8>::random(); | 177 | state: MemFlash::<2048, 128, 4>::random(), |
| 151 | let mut dfu = MemFlash::<16384, 2048, 8>::random(); | 178 | }); |
| 152 | let mut state = MemFlash::<4096, 128, 4>::random(); | 179 | |
| 180 | const ORIGINAL: [u8; FIRMWARE_SIZE] = [0x55; FIRMWARE_SIZE]; | ||
| 181 | const UPDATE: [u8; FIRMWARE_SIZE] = [0xAA; FIRMWARE_SIZE]; | ||
| 153 | let mut aligned = [0; 4]; | 182 | let mut aligned = [0; 4]; |
| 154 | 183 | ||
| 155 | let original = [rand::random::<u8>(); ACTIVE.size() as usize]; | 184 | block_on(flash.active().erase(0, ORIGINAL.len() as u32)).unwrap(); |
| 156 | let update = [rand::random::<u8>(); ACTIVE.size() as usize]; | 185 | block_on(flash.active().write(0, &ORIGINAL)).unwrap(); |
| 157 | 186 | ||
| 158 | active.program(ACTIVE.from, &original).unwrap(); | 187 | let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig { |
| 188 | dfu: flash.dfu(), | ||
| 189 | state: flash.state(), | ||
| 190 | }); | ||
| 191 | block_on(updater.write_firmware(0, &UPDATE)).unwrap(); | ||
| 192 | block_on(updater.mark_updated(&mut aligned)).unwrap(); | ||
| 159 | 193 | ||
| 160 | let mut updater = FirmwareUpdater::new(DFU, STATE); | 194 | let flash = flash.into_blocking(); |
| 195 | let mut bootloader = BootLoader::new(BootLoaderConfig { | ||
| 196 | active: flash.active(), | ||
| 197 | dfu: flash.dfu(), | ||
| 198 | state: flash.state(), | ||
| 199 | }); | ||
| 161 | 200 | ||
| 162 | block_on(updater.write_firmware(0, &update, &mut dfu)).unwrap(); | ||
| 163 | block_on(updater.mark_updated(&mut state, &mut aligned)).unwrap(); | ||
| 164 | |||
| 165 | let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); | ||
| 166 | let mut page = [0; 4096]; | 201 | let mut page = [0; 4096]; |
| 202 | assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap()); | ||
| 167 | 203 | ||
| 168 | assert_eq!( | 204 | let mut read_buf = [0; FIRMWARE_SIZE]; |
| 169 | State::Swap, | 205 | flash.active().read(0, &mut read_buf).unwrap(); |
| 170 | bootloader | 206 | assert_eq!(UPDATE, read_buf); |
| 171 | .prepare_boot(&mut MultiFlashConfig::new(&mut active, &mut state, &mut dfu), &mut page) | ||
| 172 | .unwrap() | ||
| 173 | ); | ||
| 174 | |||
| 175 | active.assert_eq(ACTIVE.from, &update); | ||
| 176 | // First DFU page is untouched | 207 | // First DFU page is untouched |
| 177 | dfu.assert_eq(DFU.from + 4096, &original); | 208 | flash.dfu().read(4096, &mut read_buf).unwrap(); |
| 209 | assert_eq!(ORIGINAL, read_buf); | ||
| 178 | } | 210 | } |
| 179 | 211 | ||
| 180 | #[test] | 212 | #[test] |
| 181 | #[cfg(all(feature = "nightly", not(feature = "_verify")))] | 213 | #[cfg(all(feature = "nightly", not(feature = "_verify")))] |
| 182 | fn test_separate_flash_dfu_page_biggest() { | 214 | fn test_swap_state_dfu_page_biggest() { |
| 183 | const STATE: Partition = Partition::new(2048, 4096); | 215 | const FIRMWARE_SIZE: usize = 12288; |
| 184 | const ACTIVE: Partition = Partition::new(4096, 16384); | 216 | let flash = AsyncTestFlash::new(BootLoaderConfig { |
| 185 | const DFU: Partition = Partition::new(0, 16384); | 217 | active: MemFlash::<FIRMWARE_SIZE, 2048, 4>::random(), |
| 186 | 218 | dfu: MemFlash::<16384, 4096, 8>::random(), | |
| 219 | state: MemFlash::<2048, 128, 4>::random(), | ||
| 220 | }); | ||
| 221 | |||
| 222 | const ORIGINAL: [u8; FIRMWARE_SIZE] = [0x55; FIRMWARE_SIZE]; | ||
| 223 | const UPDATE: [u8; FIRMWARE_SIZE] = [0xAA; FIRMWARE_SIZE]; | ||
| 187 | let mut aligned = [0; 4]; | 224 | let mut aligned = [0; 4]; |
| 188 | let mut active = MemFlash::<16384, 2048, 4>::random(); | ||
| 189 | let mut dfu = MemFlash::<16384, 4096, 8>::random(); | ||
| 190 | let mut state = MemFlash::<4096, 128, 4>::random(); | ||
| 191 | |||
| 192 | let original = [rand::random::<u8>(); ACTIVE.size() as usize]; | ||
| 193 | let update = [rand::random::<u8>(); ACTIVE.size() as usize]; | ||
| 194 | |||
| 195 | active.program(ACTIVE.from, &original).unwrap(); | ||
| 196 | |||
| 197 | let mut updater = FirmwareUpdater::new(DFU, STATE); | ||
| 198 | 225 | ||
| 199 | block_on(updater.write_firmware(0, &update, &mut dfu)).unwrap(); | 226 | block_on(flash.active().erase(0, ORIGINAL.len() as u32)).unwrap(); |
| 200 | block_on(updater.mark_updated(&mut state, &mut aligned)).unwrap(); | 227 | block_on(flash.active().write(0, &ORIGINAL)).unwrap(); |
| 201 | 228 | ||
| 202 | let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); | 229 | let mut updater = FirmwareUpdater::new(FirmwareUpdaterConfig { |
| 230 | dfu: flash.dfu(), | ||
| 231 | state: flash.state(), | ||
| 232 | }); | ||
| 233 | block_on(updater.write_firmware(0, &UPDATE)).unwrap(); | ||
| 234 | block_on(updater.mark_updated(&mut aligned)).unwrap(); | ||
| 235 | |||
| 236 | let flash = flash.into_blocking(); | ||
| 237 | let mut bootloader = BootLoader::new(BootLoaderConfig { | ||
| 238 | active: flash.active(), | ||
| 239 | dfu: flash.dfu(), | ||
| 240 | state: flash.state(), | ||
| 241 | }); | ||
| 203 | let mut page = [0; 4096]; | 242 | let mut page = [0; 4096]; |
| 204 | assert_eq!( | 243 | assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap()); |
| 205 | State::Swap, | ||
| 206 | bootloader | ||
| 207 | .prepare_boot( | ||
| 208 | &mut MultiFlashConfig::new(&mut active, &mut state, &mut dfu,), | ||
| 209 | &mut page | ||
| 210 | ) | ||
| 211 | .unwrap() | ||
| 212 | ); | ||
| 213 | 244 | ||
| 214 | active.assert_eq(ACTIVE.from, &update); | 245 | let mut read_buf = [0; FIRMWARE_SIZE]; |
| 246 | flash.active().read(0, &mut read_buf).unwrap(); | ||
| 247 | assert_eq!(UPDATE, read_buf); | ||
| 215 | // First DFU page is untouched | 248 | // First DFU page is untouched |
| 216 | dfu.assert_eq(DFU.from + 4096, &original); | 249 | flash.dfu().read(4096, &mut read_buf).unwrap(); |
| 250 | assert_eq!(ORIGINAL, read_buf); | ||
| 217 | } | 251 | } |
| 218 | 252 | ||
| 219 | #[test] | 253 | #[test] |
| @@ -239,25 +273,25 @@ mod tests { | |||
| 239 | let public_key: PublicKey = keypair.public; | 273 | let public_key: PublicKey = keypair.public; |
| 240 | 274 | ||
| 241 | // Setup flash | 275 | // Setup flash |
| 242 | 276 | let flash = BlockingTestFlash::new(BootLoaderConfig { | |
| 243 | const STATE: Partition = Partition::new(0, 4096); | 277 | active: MemFlash::<0, 0, 0>::default(), |
| 244 | const DFU: Partition = Partition::new(4096, 8192); | 278 | dfu: MemFlash::<4096, 4096, 4>::default(), |
| 245 | let mut flash = MemFlash::<8192, 4096, 4>::default(); | 279 | state: MemFlash::<4096, 4096, 4>::default(), |
| 280 | }); | ||
| 246 | 281 | ||
| 247 | let firmware_len = firmware.len(); | 282 | let firmware_len = firmware.len(); |
| 248 | 283 | ||
| 249 | let mut write_buf = [0; 4096]; | 284 | let mut write_buf = [0; 4096]; |
| 250 | write_buf[0..firmware_len].copy_from_slice(firmware); | 285 | write_buf[0..firmware_len].copy_from_slice(firmware); |
| 251 | DFU.write_blocking(&mut flash, 0, &write_buf).unwrap(); | 286 | flash.dfu().write(0, &write_buf).unwrap(); |
| 252 | 287 | ||
| 253 | // On with the test | 288 | // On with the test |
| 254 | 289 | let flash = flash.into_async(); | |
| 255 | let mut updater = FirmwareUpdater::new(DFU, STATE); | 290 | let mut updater = FirmwareUpdater::new(flash.dfu(), flash.state()); |
| 256 | 291 | ||
| 257 | let mut aligned = [0; 4]; | 292 | let mut aligned = [0; 4]; |
| 258 | 293 | ||
| 259 | assert!(block_on(updater.verify_and_mark_updated( | 294 | assert!(block_on(updater.verify_and_mark_updated( |
| 260 | &mut flash, | ||
| 261 | &public_key.to_bytes(), | 295 | &public_key.to_bytes(), |
| 262 | &signature.to_bytes(), | 296 | &signature.to_bytes(), |
| 263 | firmware_len as u32, | 297 | firmware_len as u32, |
